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 std::{fs, io};
use mingling::{
Grouped, RenderResult, Routable, ShellContext, Suggest, SuggestItem,
macros::{arg, chain, command, completion, metadata, pack, pack_err, renderer, routeify},
metadata::Description,
picker::{EntryPicker, PickerArg},
};
use crate::{
Next, eprintln_cargo,
pkg_mgr::{
ErrorNoDataDirectory, ErrorPackageNameRequired, ErrorPackageSpecInvalid, ResPackagesDir,
},
println_cargo,
};
/// Positional argument: package name
pub static ARG_NAME: PickerArg<String> = arg![String];
pack_err!(ErrorPackageNotEnabled = String);
// The name of the package to disable
pack!(StatePkgDisable = String);
#[derive(Debug, Default, Grouped)]
pub struct ResultPkgDisable {
pub name: String,
pub removed: bool,
}
#[metadata(EntryPkgDisable)]
pub fn desc_pkg_disable() -> Description {
"Disable the specified package".into()
}
#[command(node = "pkg-disable", routeify)]
pub fn package_disable(args: EntryPkgDisable, packages_dir: &ResPackagesDir) -> Next {
let name = args
.pick_or_route(&ARG_NAME, || ErrorPackageNameRequired::default().to_chain())
.to_result()?;
let packages_dir = &packages_dir.path;
if packages_dir.as_os_str().is_empty() {
return ErrorNoDataDirectory::default().to_chain();
}
if name.contains('/') || name.contains('\\') || name.contains("..") || name.contains('@') {
return ErrorPackageSpecInvalid::new(name).to_chain();
}
StatePkgDisable::new(name).to_chain()
}
#[chain(routeify)]
pub fn handle_state_pkg_disable(p: StatePkgDisable, packages_dir: &ResPackagesDir) -> Next {
let name = p.inner;
let packages_dir = &packages_dir.path;
if packages_dir.as_os_str().is_empty() {
return ErrorNoDataDirectory::default().to_chain();
}
let file = packages_dir.join(&name);
if !file.is_file() {
return ErrorPackageNotEnabled::new(name).to_chain();
}
fs::remove_file(&file).map_err(|e| {
io::Error::new(
e.kind(),
format!("failed to remove {}: {e}", file.display()),
)
})?;
ResultPkgDisable {
name,
removed: true,
}
.to_chain()
}
#[renderer]
pub fn render_result_pkg_disable(result: ResultPkgDisable) -> RenderResult {
let mut r = RenderResult::new();
println_cargo!(r, "Disabled: {}", result.name);
r
}
#[renderer]
pub fn render_error_package_not_enabled(err: ErrorPackageNotEnabled) -> RenderResult {
let mut r = RenderResult::new();
eprintln_cargo!(r, "package is not enabled: {}", err.info);
r
}
#[completion(EntryPkgDisable)]
pub fn complete_pkg_disable(ctx: &ShellContext, packages_dir: &ResPackagesDir) -> Suggest {
if ctx.previous_word != "pkg-disable" {
return Suggest::FileCompletion;
}
let mut suggest = Suggest::new();
if let Ok(entries) = fs::read_dir(&packages_dir.path) {
for entry in entries.flatten() {
if !entry.file_type().is_ok_and(|t| t.is_file()) {
continue;
}
if let Some(name) = entry.file_name().to_str() {
suggest.insert(SuggestItem::Simple(name.to_string()));
}
}
}
suggest
}
|