aboutsummaryrefslogtreecommitdiff
path: root/dotup_cli/src/commands/status.rs
diff options
context:
space:
mode:
Diffstat (limited to 'dotup_cli/src/commands/status.rs')
-rw-r--r--dotup_cli/src/commands/status.rs175
1 files changed, 0 insertions, 175 deletions
diff --git a/dotup_cli/src/commands/status.rs b/dotup_cli/src/commands/status.rs
deleted file mode 100644
index b7221db..0000000
--- a/dotup_cli/src/commands/status.rs
+++ /dev/null
@@ -1,175 +0,0 @@
1use std::path::{Path, PathBuf};
2
3use ansi_term::Colour;
4use clap::Parser;
5use dotup::{Depot, Link};
6
7use crate::{utils, Config};
8
9/// Shows information about links
10///
11/// If a link is created for a file that already had a link then the old link will be overwritten.
12/// By default creating a link to a directory will recursively link all files under that
13/// directory, to actually link a directory use the --directory flag.
14#[derive(Parser)]
15pub struct Opts {
16 /// The location where links will be installed to.
17 /// Defaults to the home directory.
18 #[clap(long)]
19 install_base: Option<PathBuf>,
20
21 /// The paths to show the status of
22 paths: Vec<PathBuf>,
23}
24
25#[derive(Debug)]
26struct State {
27 max_depth: u32,
28 install_path: PathBuf,
29}
30
31pub fn main(config: Config, opts: Opts) -> anyhow::Result<()> {
32 let mut depot = utils::read_depot(&config.archive_path)?;
33
34 // walk dir
35 // if node is file:
36 // if linked
37 // print name in green and destination blue
38 // if invalid
39 // print name and destination red
40 // if not linked
41 // print name in gray
42 // if node is directory:
43 // if linked
44 // print name in green and destination blue
45 // if invalid
46 // print name and destination red
47 // if not linked:
48 // print name in gray
49 // if contains files that are linked/invalid:
50 // recurse into directory
51 //
52
53 let depot_base = depot.base_path();
54 let mut paths = Vec::new();
55 for path in opts.paths {
56 let canonical = dotup::utils::weakly_canonical(&path);
57 if canonical.starts_with(depot_base) {
58 paths.push(canonical);
59 } else {
60 log::warn!("Path '{}' is outside the depot", path.display());
61 }
62 }
63
64 if paths.is_empty() {
65 paths.push(PathBuf::from("."));
66 }
67
68 let state = State {
69 max_depth: u32::MAX,
70 install_path: config.install_path,
71 };
72
73 let (directories, files) = utils::collect_read_dir_split(".")?;
74 for path in directories.into_iter().chain(files.into_iter()) {
75 display_status_path(&depot, &state, &path, 0);
76 }
77
78 utils::write_depot(&depot)?;
79
80 Ok(())
81}
82
83fn display_status_path(depot: &Depot, state: &State, path: &Path, depth: u32) {
84 if depth == state.max_depth {
85 return;
86 }
87
88 if path.is_dir() {
89 display_status_directory(depot, state, path, depth);
90 } else {
91 display_status_file(depot, state, path, depth);
92 }
93}
94
95fn display_status_directory(depot: &Depot, state: &State, path: &Path, depth: u32) {
96 assert!(path.is_dir());
97 if depth == state.max_depth || !depot.subpath_has_links(path) {
98 return;
99 }
100
101 if let Some(link) = depot.get_link_by_path(path) {
102 print_link(depot, state, link, depth);
103 } else {
104 for entry in std::fs::read_dir(path).unwrap() {
105 let entry = match entry {
106 Ok(entry) => entry,
107 Err(_) => continue,
108 };
109 let entry_path = entry.path().canonicalize().unwrap();
110 let entry_path_stripped = entry_path
111 .strip_prefix(std::env::current_dir().unwrap())
112 .unwrap();
113
114 print_identation(depth);
115 println!(
116 "{}",
117 Colour::Yellow.paint(&format!("{}", path.file_name().unwrap().to_string_lossy()))
118 );
119
120 display_status_path(depot, state, &entry_path_stripped, depth + 1);
121 }
122 }
123}
124
125fn display_status_file(depot: &Depot, state: &State, path: &Path, depth: u32) {
126 print_identation(depth);
127 if let Some(link) = depot.get_link_by_path(path) {
128 print_link(depot, state, link, depth);
129 } else {
130 print_unlinked(path, depth);
131 }
132}
133
134fn print_link(depot: &Depot, state: &State, link: &Link, depth: u32) {
135 let origin = link.origin();
136 let dest = link.destination();
137 let filename = match origin.file_name() {
138 Some(filename) => filename,
139 None => return,
140 };
141
142 print_identation(depth);
143 if depot.is_link_installed(link, &state.install_path) {
144 println!(
145 "{} -> {}",
146 Colour::Green.paint(&format!("{}", filename.to_string_lossy())),
147 Colour::Blue.paint(&format!("{}", dest.display())),
148 );
149 } else {
150 println!(
151 "{}",
152 Colour::Red.paint(&format!(
153 "{} -> {}",
154 filename.to_string_lossy(),
155 dest.display()
156 ))
157 );
158 }
159}
160
161fn print_unlinked(path: &Path, depth: u32) {
162 let filename = match path.file_name() {
163 Some(filename) => filename,
164 None => return,
165 };
166
167 print_identation(depth);
168 println!("{}", filename.to_string_lossy());
169}
170
171fn print_identation(depth: u32) {
172 for i in 0..depth {
173 print!(" ");
174 }
175}