Skip to main content

unlab_gpu/
pkg_cmds.rs

1//
2// Copyright (c) 2026 Ɓukasz Szpakowski
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at https://mozilla.org/MPL/2.0/.
7//
8//! A module of package commands.
9use std::env::current_dir;
10use std::env::set_current_dir;
11use std::env::split_paths;
12use std::ffi::OsString;
13#[cfg(target_family = "unix")]
14use std::fs;
15use std::fs::File;
16use std::fs::create_dir_all;
17use std::fs::remove_dir;
18#[cfg(target_family = "unix")]
19use std::fs::set_permissions;
20use std::io;
21use std::io::stdout;
22use std::io::BufWriter;
23use std::io::Write;
24#[cfg(target_family = "unix")]
25use std::os::unix::fs::PermissionsExt;
26use std::path;
27use std::path::Path;
28use std::path::PathBuf;
29use std::sync::Arc;
30use std::sync::RwLock;
31use crate::toml;
32use crate::backend::*;
33use crate::error::*;
34use crate::fs::*;
35use crate::home::*;
36use crate::main_loop::*;
37use crate::mod_node::*;
38use crate::pkg;
39use crate::pkg::*;
40use crate::tester;
41use crate::tester::*;
42use crate::utils::*;
43use crate::value::*;
44
45fn create_home<F>(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, is_work_dir: bool, f: F) -> Option<Home>
46    where F: FnOnce(&mut Home) -> bool
47{
48    match Home::new(home_dir, bin_path, lib_path, doc_path, is_work_dir) {
49        Some(mut home) => {
50            if !f(&mut home) {
51                return None;
52            }
53            Some(home)
54        },
55        None => {
56            eprintln!("no unlab-gpu home directory");
57            None
58        },
59    }
60}
61
62fn create_pkg_manager<F>(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, is_work_dir: bool, f: F) -> Option<PkgManager>
63    where F: FnOnce(&mut Home) -> bool
64{
65    let home = create_home(home_dir, bin_path, lib_path, doc_path, is_work_dir, f)?;
66    let home_dir = PathBuf::from(home.home_dir());
67    let work_dir = if !is_work_dir {
68        PathBuf::from(home.home_dir())
69    } else {
70        PathBuf::from("work")
71    };
72    let bin_dir = match split_paths(home.bin_path()).next() {
73        Some(tmp_bin_dir) => PathBuf::from(tmp_bin_dir),
74        None => {
75            eprintln!("no binary directory");
76            return None;
77        },
78    };
79    let lib_dir = match split_paths(home.lib_path()).next() {
80        Some(tmp_lib_dir) => PathBuf::from(tmp_lib_dir),
81        None => {
82            eprintln!("no library directory");
83            return None;
84        },
85    };
86    let doc_dir = match split_paths(home.doc_path()).next() {
87        Some(tmp_doc_dir) => PathBuf::from(tmp_doc_dir),
88        None => {
89            eprintln!("no documentation directory");
90            return None;
91        },
92    };
93    if is_work_dir {
94        match PkgManager::manifest() {
95            Ok(_) => (),
96            Err(err) => {
97                eprint_error(&err);
98                return None;
99            },
100        }
101    }
102    match PkgManager::new(home_dir, work_dir, bin_dir, lib_dir, doc_dir, src_factories, Arc::new(pkg::StdPrinter::new())) {
103        Ok(pkg_manager) => Some(pkg_manager),
104        Err(err) => {
105            eprint_error(&err);
106            None
107        },
108    }
109}
110
111fn parse_pkg_name(s: &str) -> Option<PkgName>
112{
113    match PkgName::parse(s) {
114        Ok(pkg_name) => Some(pkg_name),
115        Err(err) => {
116            eprint_error(&err);
117            None
118        },
119    }
120}
121
122fn parse_pkg_names(ss: &[String]) -> Option<Vec<PkgName>>
123{
124    let mut pkg_names: Vec<PkgName> = Vec::new();
125    for s in ss {
126        pkg_names.push(parse_pkg_name(s.as_str())?);
127    }
128    Some(pkg_names)
129}
130
131fn parse_idents(s: &str) -> Vec<String>
132{
133    let s_without_first_colons = if s.starts_with("::") {
134        &s[2..]
135    } else {
136        s
137    };
138    let idents: Vec<String> = s_without_first_colons.split("::").map(String::from).collect();
139    match idents.first() {
140        Some(ident) if ident == &String::from("root") => (&idents[1..]).to_vec(),
141        Some(_) => idents,
142        None => Vec::new(),
143    }
144}
145
146fn parse_idents_and_ident(s: &str) -> Option<(Vec<String>, String)>
147{
148    let idents = parse_idents(s);
149    match idents.last() {
150        Some(ident) => Some(((&idents[0..(idents.len() - 1)]).to_vec(), ident.clone())),
151        None => {
152            eprintln!("invalid test name");
153            None
154        },
155    }
156}
157
158fn res_list(pkg_manager: &PkgManager, are_deps: bool) -> Result<()>
159{
160    pkg_manager.check_last_op(are_deps)?;
161    pkg_manager.pkg_versions_in(|name, version| {
162            println!("{} v{}", name, version);
163            Ok(())
164    })?;
165    Ok(())
166}
167
168fn list_with_dep_flag<F>(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, are_deps: bool, f: F) -> Option<i32>
169    where F: FnOnce(&mut Home) -> bool
170{
171    let pkg_manager = match create_pkg_manager(home_dir, bin_path, lib_path, doc_path, src_factories, are_deps, f) {
172        Some(tmp_pkg_manager) => tmp_pkg_manager,
173        None => return Some(1),
174    };
175    match res_list(&pkg_manager, are_deps) {
176        Ok(()) => None,
177        Err(err) => {
178            pkg_manager.printer().print_lf_for_error();
179            eprint_error(&err);
180            Some(1)
181        },
182    }
183}
184
185/// A `list` command.
186pub fn list<F>(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
187    where F: FnOnce(&mut Home) -> bool
188{ list_with_dep_flag(home_dir, bin_path, lib_path, doc_path, src_factories, false, f) }
189
190/// A `list-deps` command.
191pub fn list_deps<F>(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
192    where F: FnOnce(&mut Home) -> bool
193{ list_with_dep_flag(home_dir, bin_path, lib_path, doc_path, src_factories, true, f) }
194
195fn res_search(pkg_manager: &PkgManager, patterns :&[String], are_deps: bool) -> Result<()>
196{
197    pkg_manager.check_last_op(are_deps)?;
198    pkg_manager.pkg_versions_in(|name, version| {
199            match pkg_manager.pkg_manifest(name)? {
200                Some(manifest) => {
201                    if patterns.iter().all(|p| name.name().contains(p.as_str()) || manifest.package.description.as_ref().map(|d| d.contains(p.as_str())).unwrap_or(false)) {
202                        println!("{} v{}", name, version);
203                    }
204                },
205                None => (),
206            }
207            Ok(())
208    })?;
209    Ok(())
210}
211
212fn search_with_dep_flag<F>(patterns :&[String], home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, are_deps: bool, f: F) -> Option<i32>
213    where F: FnOnce(&mut Home) -> bool
214{
215    let pkg_manager = match create_pkg_manager(home_dir, bin_path, lib_path, doc_path, src_factories, are_deps, f) {
216        Some(tmp_pkg_manager) => tmp_pkg_manager,
217        None => return Some(1),
218    };
219    match res_search(&pkg_manager, patterns, are_deps) {
220        Ok(()) => None,
221        Err(err) => {
222            pkg_manager.printer().print_lf_for_error();
223            eprint_error(&err);
224            Some(1)
225        },
226    }
227}
228
229/// A `search` command.
230pub fn search<F>(patterns :&[String], home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
231    where F: FnOnce(&mut Home) -> bool
232{ search_with_dep_flag(patterns, home_dir, bin_path, lib_path, doc_path, src_factories, false, f) }
233
234/// A `search-deps` command.
235pub fn search_deps<F>(patterns :&[String], home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
236    where F: FnOnce(&mut Home) -> bool
237{ search_with_dep_flag(patterns, home_dir, bin_path, lib_path, doc_path, src_factories, true, f) }
238
239fn res_show(pkg_manager: &PkgManager, pkg_name: &PkgName, is_manifest: bool, are_dependents: bool, are_paths: bool, is_dep: bool) -> Result<()>
240{
241    pkg_manager.check_last_op(is_dep)?;
242    let version = match pkg_manager.pkg_version(pkg_name)? {
243        Some(tmp_version) => tmp_version,
244        None => return Err(Error::PkgName(pkg_name.clone(), String::from("not found package"))),
245    };
246    let manifest = match pkg_manager.pkg_manifest(pkg_name)? {
247        Some(tmp_manifest) => tmp_manifest,
248        None => return Err(Error::PkgName(pkg_name.clone(), String::from("no package manifest"))),
249    };
250    let dependents = match pkg_manager.pkg_dependents(pkg_name)? {
251        Some(tmp_dependents) => tmp_dependents,
252        None => return Err(Error::PkgName(pkg_name.clone(), String::from("no package dependents"))),
253    };
254    let paths = match pkg_manager.pkg_paths(pkg_name)? {
255        Some(tmp_paths) => tmp_paths,
256        None => return Err(Error::PkgName(pkg_name.clone(), String::from("no package paths"))),
257    };
258    println!("{} v{}", pkg_name, version);
259    if is_manifest || (!is_manifest && !are_dependents && !are_paths) {
260        println!("Manifest:");
261        match toml::to_string_pretty(&manifest) {
262            Ok(s) => println!("{}", s),
263            Err(err) => return Err(Error::TomlSer(err)),
264        }
265    }
266    if are_dependents {
267        println!("Dependents:");
268        match toml::to_string_pretty(&dependents) {
269            Ok(s) => println!("{}", s),
270            Err(err) => return Err(Error::TomlSer(err)),
271        }
272    }
273    if are_paths {
274        println!("Paths:");
275        match toml::to_string_pretty(&paths) {
276            Ok(s) => println!("{}", s),
277            Err(err) => return Err(Error::TomlSer(err)),
278        }
279    }
280    Ok(())
281}
282
283fn show_with_dep_flag<F>(name :&str, is_manifest: bool, are_dependents: bool, are_paths: bool, home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, is_dep: bool, f: F) -> Option<i32>
284    where F: FnOnce(&mut Home) -> bool
285{
286    let pkg_name = match parse_pkg_name(name) {
287        Some(tmp_pkg_name) => tmp_pkg_name,
288        None => return Some(1),
289    };
290    let pkg_manager = match create_pkg_manager(home_dir, bin_path, lib_path, doc_path, src_factories, is_dep, f) {
291        Some(tmp_pkg_manager) => tmp_pkg_manager,
292        None => return Some(1),
293    };
294    match res_show(&pkg_manager, &pkg_name, is_manifest, are_dependents, are_paths, is_dep) {
295        Ok(()) => None,
296        Err(err) => {
297            pkg_manager.printer().print_lf_for_error();
298            eprint_error(&err);
299            Some(1)
300        },
301    }
302}
303
304/// A `show` command.
305pub fn show<F>(name :&str, is_manifest: bool, are_dependents: bool, are_paths: bool, home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
306    where F: FnOnce(&mut Home) -> bool
307{ show_with_dep_flag(name, is_manifest, are_dependents, are_paths, home_dir, bin_path, lib_path, doc_path, src_factories, false, f) }
308
309/// A `show-dep` command.
310pub fn show_dep<F>(name :&str, is_manifest: bool, are_dependents: bool, are_paths: bool, home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
311    where F: FnOnce(&mut Home) -> bool
312{ show_with_dep_flag(name, is_manifest, are_dependents, are_paths, home_dir, bin_path, lib_path, doc_path, src_factories, true, f) }
313
314fn res_update(pkg_manager: &PkgManager, pkg_names: &[PkgName], are_deps: bool) -> Result<()>
315{
316    pkg_manager.check_last_op(are_deps)?;
317    if pkg_names.is_empty() {
318        pkg_manager.update_all()?;
319    } else {
320        pkg_manager.update(pkg_names)?;
321    }
322    Ok(())
323}
324
325fn update_with_dep_flag<F>(names: &[String], home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, are_deps: bool, f: F) -> Option<i32>
326    where F: FnOnce(&mut Home) -> bool
327{
328    let pkg_names = match parse_pkg_names(names) {
329        Some(tmp_pkg_names) => tmp_pkg_names,
330        None => return Some(1),
331    };
332    let pkg_manager = match create_pkg_manager(home_dir, bin_path, lib_path, doc_path, src_factories, are_deps, f) {
333        Some(tmp_pkg_manager) => tmp_pkg_manager,
334        None => return Some(1),
335    };
336    match res_update(&pkg_manager, pkg_names.as_slice(), are_deps) {
337        Ok(()) => None,
338        Err(err) => {
339            pkg_manager.printer().print_lf_for_error();
340            eprint_error(&err);
341            Some(1)
342        },
343    }
344}
345
346/// A `update` command.
347pub fn update<F>(names: &[String], home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
348    where F: FnOnce(&mut Home) -> bool
349{ update_with_dep_flag(names, home_dir, bin_path, lib_path, doc_path, src_factories, false, f) }
350
351/// A `update-deps` command.
352pub fn update_deps<F>(names: &[String], home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
353    where F: FnOnce(&mut Home) -> bool
354{ update_with_dep_flag(names, home_dir, bin_path, lib_path, doc_path, src_factories, true, f) }
355
356fn res_install(pkg_manager: &mut PkgManager, pkg_names: &[PkgName], is_update: bool, is_force: bool, is_doc: bool) -> Result<()>
357{
358    pkg_manager.check_last_op(false)?;
359    pkg_manager.load_constraints()?;
360    pkg_manager.load_sources()?;
361    pkg_manager.install(pkg_names, is_update, is_force, is_doc)?;
362    Ok(())
363}
364
365/// An `install` command.
366pub fn install<F>(names: &[String], is_update: bool, is_force: bool, is_doc: bool, home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
367    where F: FnOnce(&mut Home) -> bool
368{
369    let pkg_names = match parse_pkg_names(names) {
370        Some(tmp_pkg_names) => tmp_pkg_names,
371        None => return Some(1),
372    };
373    let mut pkg_manager = match create_pkg_manager(home_dir, bin_path, lib_path, doc_path, src_factories, false, f) {
374        Some(tmp_pkg_manager) => tmp_pkg_manager,
375        None => return Some(1),
376    };
377    match res_install(&mut pkg_manager, pkg_names.as_slice(), is_update, is_force, is_doc) {
378        Ok(()) => None,
379        Err(err) => {
380            pkg_manager.printer().print_lf_for_error();
381            eprint_error(&err);
382            Some(1)
383        },
384    }
385}
386
387fn res_install_all(pkg_manager: &mut PkgManager, is_update: bool, is_force: bool, is_doc: bool) -> Result<()>
388{
389    pkg_manager.check_last_op(false)?;
390    pkg_manager.load_constraints()?;
391    pkg_manager.load_sources()?;
392    pkg_manager.install_all(is_update, is_force, is_doc)?;
393    Ok(())
394}
395
396/// An `install-all` command.
397pub fn install_all<F>(is_update: bool, is_force: bool, is_doc: bool, home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
398    where F: FnOnce(&mut Home) -> bool
399{
400    let mut pkg_manager = match create_pkg_manager(home_dir, bin_path, lib_path, doc_path, src_factories, false, f) {
401        Some(tmp_pkg_manager) => tmp_pkg_manager,
402        None => return Some(1),
403    };
404    match res_install_all(&mut pkg_manager, is_update, is_force, is_doc) {
405        Ok(()) => None,
406        Err(err) => {
407            pkg_manager.printer().print_lf_for_error();
408            eprint_error(&err);
409            Some(1)
410        },
411    }
412}
413
414fn res_install_deps(pkg_manager: &mut PkgManager, is_update: bool, is_force: bool, is_doc: bool, is_locked: bool, is_unlocked: bool) -> Result<()>
415{
416    pkg_manager.check_last_op(true)?;
417    if (!is_update || is_locked) && (!is_unlocked || is_locked) {
418        pkg_manager.load_locks()?;
419    }
420    pkg_manager.install_deps(is_update, is_force, is_doc)?;
421    pkg_manager.save_locks_from_pkg_versions()?;
422    Ok(())
423}
424
425/// An `install-deps` command.
426pub fn install_deps<F>(is_update: bool, is_force: bool, is_doc: bool, is_locked: bool, is_unlocked: bool, home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
427    where F: FnOnce(&mut Home) -> bool
428{
429    let mut pkg_manager = match create_pkg_manager(home_dir, bin_path, lib_path, doc_path, src_factories, true, f) {
430        Some(tmp_pkg_manager) => tmp_pkg_manager,
431        None => return Some(1),
432    };
433    match res_install_deps(&mut pkg_manager, is_update, is_force, is_doc, is_locked, is_unlocked) {
434        Ok(()) => None,
435        Err(err) => {
436            pkg_manager.printer().print_lf_for_error();
437            eprint_error(&err);
438            Some(1)
439        },
440    }
441}
442
443fn res_remove(pkg_manager: &mut PkgManager, pkg_names: &[PkgName]) -> Result<()>
444{
445    pkg_manager.check_last_op(false)?;
446    pkg_manager.remove(pkg_names)?;
447    Ok(())
448}
449
450/// A `remove` command.
451pub fn remove<F>(names: &[String], home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
452    where F: FnOnce(&mut Home) -> bool
453{
454    let pkg_names = match parse_pkg_names(names) {
455        Some(tmp_pkg_names) => tmp_pkg_names,
456        None => return Some(1),
457    };
458    let mut pkg_manager = match create_pkg_manager(home_dir, bin_path, lib_path, doc_path, src_factories, false, f) {
459        Some(tmp_pkg_manager) => tmp_pkg_manager,
460        None => return Some(1),
461    };
462    match res_remove(&mut pkg_manager, pkg_names.as_slice()) {
463        Ok(()) => None,
464        Err(err) => {
465            pkg_manager.printer().print_lf_for_error();
466            eprint_error(&err);
467            Some(1)
468        },
469    }
470}
471
472fn check_with_dep_flag<F>(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, are_deps: bool, f: F) -> Option<i32>
473    where F: FnOnce(&mut Home) -> bool
474{
475    let pkg_manager = match create_pkg_manager(home_dir, bin_path, lib_path, doc_path, src_factories, are_deps, f) {
476        Some(tmp_pkg_manager) => tmp_pkg_manager,
477        None => return Some(1),
478    };
479    match pkg_manager.check_last_op(are_deps) {
480        Ok(()) => None,
481        Err(err) => {
482            pkg_manager.printer().print_lf_for_error();
483            eprint_error(&err);
484            Some(1)
485        },
486    }
487}
488
489/// A `check` command.
490pub fn check<F>(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
491    where F: FnOnce(&mut Home) -> bool
492{ check_with_dep_flag(home_dir, bin_path, lib_path, doc_path, src_factories, false, f) }
493
494/// A `check-deps` command.
495pub fn check_deps<F>(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
496    where F: FnOnce(&mut Home) -> bool
497{ check_with_dep_flag(home_dir, bin_path, lib_path, doc_path, src_factories, true, f) }
498
499fn res_continue(pkg_manager: &PkgManager, is_doc: bool, are_deps: bool) -> Result<()>
500{
501    pkg_manager.cont(is_doc, are_deps)?;
502    if are_deps {
503        pkg_manager.save_locks_from_pkg_versions()?;
504    }
505    Ok(())
506}
507
508fn continue_with_dep_flag<F>(is_doc: bool, home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, are_deps: bool, f: F) -> Option<i32>
509    where F: FnOnce(&mut Home) -> bool
510{
511    let pkg_manager = match create_pkg_manager(home_dir, bin_path, lib_path, doc_path, src_factories, are_deps, f) {
512        Some(tmp_pkg_manager) => tmp_pkg_manager,
513        None => return Some(1),
514    };
515    match res_continue(&pkg_manager, is_doc, are_deps) {
516        Ok(()) => None,
517        Err(err) => {
518            pkg_manager.printer().print_lf_for_error();
519            eprint_error(&err);
520            Some(1)
521        },
522    }
523}
524
525/// A `continue` command.
526pub fn cont<F>(is_doc: bool, home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
527    where F: FnOnce(&mut Home) -> bool
528{ continue_with_dep_flag(is_doc, home_dir, bin_path, lib_path, doc_path, src_factories, false, f) }
529
530/// A `continue-deps` command.
531pub fn continue_deps<F>(is_doc: bool, home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
532    where F: FnOnce(&mut Home) -> bool
533{ continue_with_dep_flag(is_doc, home_dir, bin_path, lib_path, doc_path, src_factories, true, f) }
534
535fn clean_with_dep_flag<F>(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, are_deps: bool, f: F) -> Option<i32>
536    where F: FnOnce(&mut Home) -> bool
537{
538    let pkg_manager = match create_pkg_manager(home_dir, bin_path, lib_path, doc_path, src_factories, are_deps, f) {
539        Some(tmp_pkg_manager) => tmp_pkg_manager,
540        None => return Some(1),
541    };
542    match pkg_manager.clean() {
543        Ok(()) => None,
544        Err(err) => {
545            pkg_manager.printer().print_lf_for_error();
546            eprint_error(&err);
547            Some(1)
548        },
549    }
550}
551
552/// A `clean` command.
553pub fn clean<F>(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
554    where F: FnOnce(&mut Home) -> bool
555{ clean_with_dep_flag(home_dir, bin_path, lib_path, doc_path, src_factories, false, f) }
556
557/// A `clean-deps` command.
558pub fn clean_deps<F>(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
559    where F: FnOnce(&mut Home) -> bool
560{ clean_with_dep_flag(home_dir, bin_path, lib_path, doc_path, src_factories, true, f) }
561
562fn res_lock(pkg_manager: &PkgManager) -> Result<()>
563{
564    pkg_manager.check_last_op(true)?;
565    pkg_manager.save_locks_from_pkg_versions()?;
566    Ok(())
567}
568
569/// A `lock` command.
570pub fn lock<F>(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
571    where F: FnOnce(&mut Home) -> bool
572{
573    let pkg_manager = match create_pkg_manager(home_dir, bin_path, lib_path, doc_path, src_factories, true, f) {
574        Some(tmp_pkg_manager) => tmp_pkg_manager,
575        None => return Some(1),
576    };
577    match res_lock(&pkg_manager) {
578        Ok(()) => None,
579        Err(err) => {
580            pkg_manager.printer().print_lf_for_error();
581            eprint_error(&err);
582            Some(1)
583        },
584    }
585}
586
587fn io_res_clean_dir<P: AsRef<Path>>(dir: P, msg: &str) -> io::Result<()>
588{
589    print!("{}", msg);
590    let _res = stdout().flush();
591    recursively_remove(dir, true)?;
592    println!(" done");
593    Ok(())
594}
595
596/// A `clean-index` command.
597pub fn clean_index<F>(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, f: F) -> Option<i32>
598    where F: FnOnce(&mut Home) -> bool
599{
600    let home = match create_home(home_dir, bin_path, lib_path, doc_path, false, f) {
601        Some(tmp_home) => tmp_home,
602        None => return Some(1),
603    };
604    match io_res_clean_dir(index_dir(home.home_dir()), "Cleaning index ...") {
605        Ok(()) => None,
606        Err(err) => {
607            println!("");
608            eprint_error(&Error::Io(err));
609            Some(1)
610        },
611    }
612}
613
614/// A `clean-cache` command.
615pub fn clean_cache<F>(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, f: F) -> Option<i32>
616    where F: FnOnce(&mut Home) -> bool
617{
618    let home = match create_home(home_dir, bin_path, lib_path, doc_path, false, f) {
619        Some(tmp_home) => tmp_home,
620        None => return Some(1),
621    };
622    match io_res_clean_dir(cache_dir(home.home_dir()), "Cleaning cache ...") {
623        Ok(()) => None,
624        Err(err) => {
625            println!("");
626            eprint_error(&Error::Io(err));
627            Some(1)
628        },
629    }
630}
631
632fn res_clean_work() -> Result<()>
633{
634    PkgManager::manifest()?;
635    match io_res_clean_dir("work", "Cleaning work ...") {
636        Ok(()) => Ok(()),
637        Err(err) => {
638            println!("");
639            Err(Error::Io(err))
640        },
641    }
642}
643
644/// A `clean-work` command.
645pub fn clean_work<F>(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, f: F) -> Option<i32>
646    where F: FnOnce(&mut Home) -> bool
647{
648    match create_home(home_dir, bin_path, lib_path, doc_path, true, f) {
649        Some(_) => (),
650        None => return Some(1),
651    }
652    match res_clean_work() {
653        Ok(()) => None,
654        Err(err) => {
655            eprint_error(&err);
656            Some(1)
657        },
658    }
659}
660
661fn res_config(home: &Home, account: &Option<String>, domain: &Option<String>) -> Result<()>
662{
663    let config = PkgConfig::load_opt(home.pkg_config_file())?;
664    if account.is_none() && domain.is_none() {
665        println!("Configuration:");
666        match &config {
667            Some(config) => {
668                match toml::to_string_pretty(&config) {
669                    Ok(s) => println!("{}", s),
670                    Err(err) => return Err(Error::TomlSer(err)),
671                }
672            },
673            None => println!(""),
674        }
675    } else {
676        let mut old_account: Option<String> = None;
677        let mut old_domain: Option<String> = None;
678        match config {
679            Some(config) => {
680                old_account = config.account.clone();
681                old_domain = config.domain.clone();
682            },
683            None => (),
684        }
685        let new_config = PkgConfig::new(account.clone().or(old_account), domain.clone().or(old_domain));
686        new_config.save(home.pkg_config_file())?;
687    }
688    Ok(())
689}
690
691/// A `config` command.
692pub fn config<F>(account: &Option<String>, domain: &Option<String>, home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, f: F) -> Option<i32>
693    where F: FnOnce(&mut Home) -> bool
694{
695    let home = match create_home(home_dir, bin_path, lib_path, doc_path, false, f) {
696        Some(tmp_home) => tmp_home,
697        None => return Some(1),
698    };
699    match res_config(&home, account, domain) {
700        Ok(()) => None,
701        Err(err) => {
702            eprint_error(&err);
703            Some(1)
704        },
705    }
706}
707
708fn io_res_init(bin_name: &str, lib_name: &str, is_bin: bool, is_lib: bool, are_tests: bool) -> io::Result<()>
709{
710    {
711        let file = File::create(".gitignore")?;
712        let mut w = BufWriter::new(file);
713        writeln!(&mut w, "/work")?;
714    }
715    if is_bin {
716        let mut path_buf = PathBuf::from("bin");
717        create_dir_all(path_buf.as_path())?;
718        path_buf.push(bin_name);
719        let file = File::create(path_buf.as_path())?;
720        let mut w = BufWriter::new(file);
721        writeln!(&mut w, "#!/usr/bin/env unlab-gpu --")?;
722        writeln!(&mut w, "")?;
723        writeln!(&mut w, "println(\"Hello world!!!\")")?;
724        #[cfg(target_family = "unix")]
725        let mut perms = fs::metadata(path_buf.as_path())?.permissions();
726        #[cfg(target_family = "unix")]
727        perms.set_mode(perms.mode() | ((perms.mode() >> 2) & 0o111));
728        #[cfg(target_family = "unix")]
729        set_permissions(path_buf.as_path(), perms)?;
730    }
731    if is_lib || (!is_bin && !is_lib) {
732        let mut path_buf = PathBuf::from("lib");
733        path_buf.push(lib_name.replace('/', path::MAIN_SEPARATOR_STR));
734        create_dir_all(path_buf.as_path())?;
735        path_buf.push("lib.un");
736        let file = File::create(path_buf)?;
737        let mut w = BufWriter::new(file);
738        writeln!(&mut w, "module {}", str_to_ident(lib_name))?;
739        writeln!(&mut w, "    function add(x, y)")?;
740        writeln!(&mut w, "        x + y")?;
741        writeln!(&mut w, "    end")?;
742        writeln!(&mut w, "end")?;
743    }
744    if are_tests {
745        let mut path_buf = PathBuf::from("tests");
746        path_buf.push(lib_name.replace('/', path::MAIN_SEPARATOR_STR));
747        create_dir_all(path_buf.as_path())?;
748        path_buf.push("tests.un");
749        let file = File::create(path_buf)?;
750        let mut w = BufWriter::new(file);
751        let lib_name_without_domain = match lib_name.split_once('/') {
752            Some((_, tmp_lib_name_without_domain)) => tmp_lib_name_without_domain,
753            None => lib_name,
754        };
755        writeln!(&mut w, "uselib(\"{}\")", lib_name_without_domain)?;
756        writeln!(&mut w, "")?;
757        writeln!(&mut w, "module {}_tests", str_to_ident(lib_name))?;
758        writeln!(&mut w, "    tests()")?;
759        writeln!(&mut w, "    usevars(\"{}\")", str_to_ident(lib_name))?;
760        writeln!(&mut w, "")?;
761        writeln!(&mut w, "    function test_add_adds()")?;
762        writeln!(&mut w, "        asserteq(4, add(2, 2))")?;
763        writeln!(&mut w, "    end")?;
764        writeln!(&mut w, "end")?;
765    }
766    Ok(())
767}
768
769fn res_init(pkg_name: &PkgName, bin_name: &str, lib_name: &str, is_bin: bool, is_lib: bool, are_tests: bool) -> Result<()>
770{
771    let manifest = Manifest::new(pkg_name.clone());
772    PkgManager::save_manifest(&manifest)?;
773    match io_res_init(bin_name, lib_name, is_bin, is_lib, are_tests) {
774        Ok(()) => Ok(()),
775        Err(err) => Err(Error::Io(err)),
776    }
777}
778
779/// A `init` command.
780pub fn init<F>(path: &Option<String>, name: &Option<String>, account: &Option<String>, domain: &Option<String>, is_bin: bool, is_lib: bool, are_tests: bool, home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, f: F) -> Option<i32>
781    where F: FnOnce(&mut Home) -> bool
782{
783    match path {
784        Some(path) => {
785            match set_current_dir(path) {
786                Ok(()) => (),
787                Err(err) => {
788                    eprint_error(&Error::Io(err));
789                    return Some(1);
790                },
791            }
792        },
793        None => (),
794    }
795    let home = match create_home(home_dir, bin_path, lib_path, doc_path, false, f) {
796        Some(tmp_home) => tmp_home,
797        None => return Some(1),
798    };
799    let config = match PkgConfig::load_opt(home.pkg_config_file()) {
800        Ok(tmp_config) => tmp_config,
801        Err(err) => {
802            eprint_error(&err);
803            return Some(1);
804        },
805    };
806    let mut config_account: Option<String> = None;
807    let mut config_domain: Option<String> = None;
808    match config {
809        Some(config) => {
810            config_account = config.account.clone();
811            config_domain = config.domain.clone();
812        },
813        None => (),
814    }
815    let account = account.clone().or(config_account);
816    let domain = domain.clone().or(config_domain);
817    let name = match name {
818        Some(tmp_new_name) => tmp_new_name.clone(),
819        None => {
820            let dir = match current_dir() {
821                Ok(tmp_dir) => tmp_dir,
822                Err(err) => {
823                    eprint_error(&Error::Io(err));
824                    return Some(1);
825                },
826            };
827            let dir_name = match dir.file_name() {
828                Some(file_name) => {
829                    match file_name.to_str() {
830                        Some(tmp_dir_name) => tmp_dir_name,
831                        None => {
832                            eprintln!("directory name contains invalid UTF-8 character");
833                            return Some(1);
834                        },
835                    }
836                },
837                None => {
838                    eprintln!("no directory name");
839                    return Some(1);
840                },
841            };
842            let mut tmp_name = match &account {
843                Some(account) => account.clone(),
844                None => {
845                    eprintln!("no account");
846                    return Some(1);
847                }
848            };
849            tmp_name.push('/');
850            tmp_name.push_str(dir_name);
851            tmp_name
852        },
853    };
854    let pkg_name = match parse_pkg_name(name.as_str()) {
855        Some(tmp_pkg_name) => tmp_pkg_name,
856        None => return Some(1),
857    };
858    let ss: Vec<&str> = pkg_name.name().split('/').collect();
859    let last_pkg_name_comp = match ss.last() {
860        Some(tmp_last_pkg_name_comp) => String::from(*tmp_last_pkg_name_comp),
861        None => {
862            eprintln!("no last package name component");
863            return Some(1);
864        },
865    };
866    let bin_name = last_pkg_name_comp.clone();
867    let lib_name = match &domain {
868        Some(domain) => {
869            let mut tmp_lib_name = domain.clone();
870            tmp_lib_name.push('/');
871            tmp_lib_name.push_str(last_pkg_name_comp.as_str());
872            tmp_lib_name
873        },
874        None => {
875            eprintln!("no domain");
876            return Some(1);
877        },
878    };
879    match res_init(&pkg_name, bin_name.as_str(), lib_name.as_str(), is_bin, is_lib, are_tests) {
880        Ok(()) => None,
881        Err(err) => {
882            eprint_error(&err);
883            Some(1)
884        },
885    }
886}
887
888fn create_and_change_dir<P: AsRef<Path>>(path: P) -> io::Result<PathBuf>
889{
890    let saved_current_dir = current_dir()?;
891    create_dir_all(path.as_ref())?;
892    match set_current_dir(path.as_ref()) {
893        Ok(()) => Ok(saved_current_dir),
894        Err(err) => {
895            remove_dir(path.as_ref())?;
896            return Err(err);
897        },
898    }
899}
900
901fn change_and_remove_dir<P: AsRef<Path>, Q: AsRef<Path>>(path: P, saved_current_dir: Q) -> io::Result<()>
902{
903    set_current_dir(saved_current_dir)?;
904    remove_dir(path)?;
905    Ok(())
906}
907
908/// A `new` command.
909pub fn new<F>(path: &str, name: &Option<String>, account: &Option<String>, domain: &Option<String>, is_bin: bool, is_lib: bool, are_tests: bool, home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, f: F) -> Option<i32>
910    where F: FnOnce(&mut Home) -> bool
911{
912    let saved_current_dir = match create_and_change_dir(path) {
913        Ok(tmp_saved_current_dir) => tmp_saved_current_dir,
914        Err(err) => {
915            eprint_error(&Error::Io(err));
916            return Some(1);
917        },
918    };
919    match init(&None, name, account, domain, is_bin, is_lib, are_tests, home_dir, bin_path, lib_path, doc_path, f) {
920        None => None,
921        Some(exit_code) => {
922            match change_and_remove_dir(path, saved_current_dir) {
923                Ok(()) => (),
924                Err(err) => {
925                    eprint_error(&Error::Io(err));
926                    return Some(1);
927                },
928            }
929            Some(exit_code)
930        },
931    }
932}
933
934fn run_with_opt_name<F, G>(name: Option<&str>, args: Vec<String>, is_ctrl_c_intr_checker: bool, are_plotter_windows: bool, home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, f: F, g: G) -> Option<i32>
935    where F: FnOnce(&mut Home) -> bool,
936        G: FnOnce(&mut ModNode<Value, ()>)
937{
938    let mut home = match create_home(home_dir, bin_path, lib_path, doc_path, true, f) {
939        Some(tmp_home) => tmp_home,
940        None => return Some(1),
941    };
942    match home.add_dirs_to_bin_path(&[String::from("bin")]) {
943        Ok(()) => (),
944        Err(err) => {
945            eprintln!("{}", err);
946            return Some(1);
947        },
948    }
949    match home.add_dirs_to_lib_path(&[String::from("lib")]) {
950        Ok(()) => (),
951        Err(err) => {
952            eprintln!("{}", err);
953            return Some(1);
954        },
955    }
956    match PkgManager::manifest() {
957        Ok(_) => (),
958        Err(err) => {
959            eprint_error(&err);
960            return None;
961        },
962    }
963    match initialize_backend(home.backend_config_file()) {
964        Ok(()) => (),
965        Err(err) => {
966            eprint_error(&err);
967            return Some(1);
968        },
969    }
970    let script_file = match &name {
971        Some(name) => {
972            let mut tmp_script_file = String::from("bin");
973            tmp_script_file.push(path::MAIN_SEPARATOR);
974            tmp_script_file.push_str(name);
975            Some(tmp_script_file)
976        },
977        None => None,
978    };
979    let exit_code = {
980        let mut root_mod: ModNode<Value, ()> = ModNode::new(());
981        g(&mut root_mod);
982        let root_mod_arc = Arc::new(RwLock::new(root_mod));
983        main_loop(script_file, args, PathBuf::from(home.history_file()), root_mod_arc, OsString::from(home.lib_path()), OsString::from(home.doc_path()), is_ctrl_c_intr_checker, are_plotter_windows)
984    };
985    match finalize_backend() {
986        Ok(()) => (),
987        Err(err) => {
988            eprint_error(&err);
989            return Some(1);
990        },
991    }
992    exit_code
993}
994
995/// A `run` command.
996pub fn run<F, G>(name: &str, args: Vec<String>, is_ctrl_c_intr_checker: bool, are_plotter_windows: bool, home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, f: F, g: G) -> Option<i32>
997    where F: FnOnce(&mut Home) -> bool,
998        G: FnOnce(&mut ModNode<Value, ()>)
999{ run_with_opt_name(Some(name), args, is_ctrl_c_intr_checker, are_plotter_windows, home_dir, bin_path, lib_path, doc_path, f, g) }
1000
1001/// A `console` command.
1002pub fn console<F, G>(is_ctrl_c_intr_checker: bool, are_plotter_windows: bool, home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, f: F, g: G) -> Option<i32>
1003    where F: FnOnce(&mut Home) -> bool,
1004        G: FnOnce(&mut ModNode<Value, ()>)
1005{ run_with_opt_name(None, Vec::new(), is_ctrl_c_intr_checker, are_plotter_windows, home_dir, bin_path, lib_path, doc_path, f, g) }
1006
1007fn res_doc(pkg_manager: &PkgManager) -> Result<()>
1008{
1009    pkg_manager.check_last_op(true)?;
1010    pkg_manager.generate_doc()?;
1011    Ok(())
1012}
1013
1014/// A `doc` command.
1015pub fn doc<F>(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
1016    where F: FnOnce(&mut Home) -> bool
1017{
1018    let pkg_manager = match create_pkg_manager(home_dir, bin_path, lib_path, doc_path, src_factories, true, f) {
1019        Some(tmp_pkg_manager) => tmp_pkg_manager,
1020        None => return Some(1),
1021    };
1022    match res_doc(&pkg_manager) {
1023        Ok(()) => None,
1024        Err(err) => {
1025            pkg_manager.printer().print_lf_for_error();
1026            eprint_error(&err);
1027            Some(1)
1028        },
1029    }
1030}
1031
1032#[derive(Clone, Debug)]
1033enum TestName
1034{
1035    Test(Vec<String>, String),
1036    TestSuite(Vec<String>),
1037}
1038
1039fn res_test(tester: &mut Tester, test_name: &Option<TestName>, are_success_outputs: bool) -> Result<()>
1040{
1041    tester.load()?;
1042    match test_name {
1043        Some(TestName::Test(idents, ident)) => tester.run_test(idents, ident)?,
1044        Some(TestName::TestSuite(idents)) => tester.run_tests_in_test_suite(idents)?,
1045        None => tester.run_all_tests()?,
1046    }
1047    tester.print_empty_line();
1048    if are_success_outputs {
1049        tester.print_successes()?;
1050    }
1051    tester.print_failures()?;
1052    tester.print_test_counts();
1053    Ok(())
1054}
1055
1056/// A `test` command.
1057pub fn test<F, G>(name: &Option<String>, is_test_suite: bool, are_success_outputs: bool, are_output_cursors: bool, home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, f: F, g: G) -> Option<i32>
1058    where F: FnOnce(&mut Home) -> bool,
1059        G: FnOnce(&mut ModNode<Value, ()>)
1060{
1061    let test_name = match name {
1062        Some(name) => {
1063            if is_test_suite {
1064                Some(TestName::TestSuite(parse_idents(name.as_str())))
1065            } else {
1066                match parse_idents_and_ident(name.as_str()) {
1067                    Some((idents, ident)) => Some(TestName::Test(idents, ident)),
1068                    None => return Some(1),
1069                }
1070            }
1071        },
1072        None => None,
1073    };
1074    let mut home = match create_home(home_dir, bin_path, lib_path, doc_path, true, f) {
1075        Some(tmp_home) => tmp_home,
1076        None => return Some(1),
1077    };
1078    match home.add_dirs_to_bin_path(&[String::from("bin")]) {
1079        Ok(()) => (),
1080        Err(err) => {
1081            eprintln!("{}", err);
1082            return Some(1);
1083        },
1084    }
1085    match home.add_dirs_to_lib_path(&[String::from("lib")]) {
1086        Ok(()) => (),
1087        Err(err) => {
1088            eprintln!("{}", err);
1089            return Some(1);
1090        },
1091    }
1092    match PkgManager::manifest() {
1093        Ok(_) => (),
1094        Err(err) => {
1095            eprint_error(&err);
1096            return None;
1097        },
1098    }
1099    match initialize_backend(home.backend_config_file()) {
1100        Ok(()) => (),
1101        Err(err) => {
1102            eprint_error(&err);
1103            return Some(1);
1104        },
1105    }
1106    let exit_code = {
1107        let mut root_mod: ModNode<Value, ()> = ModNode::new(());
1108        g(&mut root_mod);
1109        let root_mod_arc = Arc::new(RwLock::new(root_mod));
1110        let mut tester = Tester::new(root_mod_arc, OsString::from(home.lib_path()), OsString::from(home.doc_path()), Arc::new(tester::StdPrinter::new()), are_output_cursors, are_output_cursors);
1111        match res_test(&mut tester, &test_name, are_success_outputs) {
1112            Ok(()) => None,
1113            Err(err) => {
1114                tester.printer().print_lf_for_error();
1115                eprint_error_with_stack_trace(&err, tester.stack_trace());
1116                Some(1)
1117            },
1118        }
1119    };
1120    match finalize_backend() {
1121        Ok(()) => (),
1122        Err(err) => {
1123            eprint_error(&err);
1124            return Some(1);
1125        },
1126    }
1127    exit_code
1128}
1129
1130fn res_clean_test() -> Result<()>
1131{
1132    PkgManager::manifest()?;
1133    let mut work_test_dir = PathBuf::from("work");
1134    work_test_dir.push("test");
1135    match io_res_clean_dir(work_test_dir, "Cleaning test ...") {
1136        Ok(()) => Ok(()),
1137        Err(err) => {
1138            println!("");
1139            Err(Error::Io(err))
1140        },
1141    }
1142}
1143
1144/// A `clean-test` command.
1145pub fn clean_test<F>(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, f: F) -> Option<i32>
1146    where F: FnOnce(&mut Home) -> bool
1147{
1148    match create_home(home_dir, bin_path, lib_path, doc_path, true, f) {
1149        Some(_) => (),
1150        None => return Some(1),
1151    }
1152    match res_clean_test() {
1153        Ok(()) => None,
1154        Err(err) => {
1155            eprint_error(&err);
1156            Some(1)
1157        },
1158    }
1159}
1160
1161fn res_std_doc(pkg_manager: &PkgManager, are_deps: bool) -> Result<()>
1162{
1163    pkg_manager.check_last_op(are_deps)?;
1164    pkg_manager.generate_std_doc()?;
1165    Ok(())
1166}
1167
1168fn std_doc_with_dep_flag<F>(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, are_deps: bool, f: F) -> Option<i32>
1169    where F: FnOnce(&mut Home) -> bool
1170{
1171    let pkg_manager = match create_pkg_manager(home_dir, bin_path, lib_path, doc_path, src_factories, are_deps, f) {
1172        Some(tmp_pkg_manager) => tmp_pkg_manager,
1173        None => return Some(1),
1174    };
1175    match res_std_doc(&pkg_manager, are_deps) {
1176        Ok(()) => None,
1177        Err(err) => {
1178            pkg_manager.printer().print_lf_for_error();
1179            eprint_error(&err);
1180            Some(1)
1181        },
1182    }
1183}
1184
1185/// A `std-doc` command.
1186pub fn std_doc<F>(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
1187    where F: FnOnce(&mut Home) -> bool
1188{ std_doc_with_dep_flag(home_dir, bin_path, lib_path, doc_path, src_factories, false, f) }
1189
1190/// A `std-doc-deps` command.
1191pub fn std_doc_deps<F>(home_dir: &Option<String>, bin_path: &Option<String>, lib_path: &Option<String>, doc_path: &Option<String>, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, f: F) -> Option<i32>
1192    where F: FnOnce(&mut Home) -> bool
1193{ std_doc_with_dep_flag(home_dir, bin_path, lib_path, doc_path, src_factories, true, f) }