Skip to main content

unlab_gpu/
pkg.rs

1//
2// Copyright (c) 2025-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 package module.
9use std::collections::BTreeMap;
10use std::collections::BTreeSet;
11use std::collections::HashMap;
12use std::collections::HashSet;
13use std::fmt;
14use std::fs;
15use std::fs::File;
16use std::fs::copy;
17use std::fs::create_dir_all;
18use std::fs::remove_dir;
19use std::fs::rename;
20use std::io;
21use std::io::BufReader;
22use std::io::ErrorKind;
23use std::io::Read;
24use std::io::Write;
25use std::io::stdout;
26use std::path;
27use std::path::Path;
28use std::path::PathBuf;
29use std::result;
30use std::sync::atomic::AtomicBool;
31use std::sync::atomic::Ordering;
32use std::sync::Arc;
33use std::sync::Mutex;
34use std::sync::RwLock;
35use bzip2::read::BzDecoder;
36use flate2::read::GzDecoder;
37use jammdb::Bucket;
38use jammdb::DB;
39use jammdb::KVPair;
40use jammdb::ToBytes;
41use jammdb::Tx;
42use liblzma::read::XzDecoder;
43use zip::read::ZipArchive;
44use crate::curl;
45use crate::curl::easy::List;
46use crate::serde::de;
47use crate::serde::de::Visitor;
48use crate::serde::Deserialize;
49use crate::serde::Deserializer;
50use crate::serde::Serialize;
51use crate::serde::Serializer;
52use crate::builtin_doc::*;
53use crate::dfs::*;
54use crate::doc::*;
55use crate::error::*;
56use crate::fs::*;
57use crate::mod_node::*;
58use crate::utils::*;
59use crate::version::*;
60
61pub mod bitbucket;
62pub mod github;
63pub mod gitlab;
64
65/// An User-Agent HTTP header for Curl.
66pub const USER_AGENT_HTTP_HEADER: &'static str = concat!("User-Agent: Unlab-pkg/", env!("CARGO_PKG_VERSION"));
67
68/// A printer trait.
69///
70/// The printer prints messages for a package manager. Some methods of printer has the done flag.
71/// the flag should be set if an operation is completed, othersise the flag should be unset.
72pub trait Print
73{
74    /// Prints the "Updating:" message.
75    fn print_updating(&self);
76
77    /// Prints the "Pre-installing:" message.
78    fn print_pre_installing(&self);
79    
80    /// Prints the "Installing:" message.
81    fn print_installing(&self);
82
83    /// Prints the "Pre-removing:" message.
84    fn print_pre_removing(&self);
85
86    /// Prints the "Removing:" message.
87    fn print_removing(&self);
88
89    /// Prints the "Documenting:" message.
90    fn print_documenting(&self);
91
92    /// Prints the "Updating package ..." message.
93    fn print_updating_pkg_versions(&self, name: &PkgName, is_done: bool);
94    
95    /// Prints the "Downloading package ..." message.
96    fn print_downloading_pkg_file(&self, name: &PkgName, is_done: bool) -> Result<()>;
97
98    /// Prints the "Downloading package ..." message with progress.
99    fn print_downloading_pkg_file_with_progress(&self, name: &PkgName, byte_count: f64, total_byte_count: f64) -> Result<()>;
100 
101    /// Prints the "Extracting package ..." message. 
102    fn print_extracting_pkg_file(&self, name: &PkgName, is_done: bool);
103    
104    /// Prints the "Checking dependent version requirements ..." message.
105    fn print_checking_dependent_version_reqs(&self, is_done: bool);
106
107    /// Prints the "Searching path conflicts ..." message.
108    fn print_searching_path_conflicts(&self, is_done: bool);
109
110    /// Prints the "Documenting package ..." message.
111    fn print_documenting_pkg(&self, name: &PkgName, is_done: bool);
112    
113    /// Prints the "Installing package ..." message.
114    fn print_installing_pkg(&self, name: &PkgName, is_done: bool);
115
116    /// Prints the "Removing package ..." message.
117    fn print_removing_pkg(&self, name: &PkgName, is_done: bool);
118
119    /// Prints the "Removing package documentation ..." message.
120    fn print_removing_pkg_doc(&self, name: &PkgName, is_done: bool);
121    
122    /// Prints the "Cleaning after installation ..." message.
123    fn print_cleaning_after_install(&self, is_done: bool);
124
125    /// Prints the "Cleaning before removal ..." messgage.
126    fn print_cleaning_before_removal(&self, is_done: bool);
127
128    /// Prints the "Cleaning after error ..." message.
129    fn print_cleaning_after_error(&self, is_done: bool);
130
131    /// Prints the "Cleaning ..." message.
132    fn print_cleaning(&self, is_done: bool);
133    
134    /// Prints the newline character for an occurred error.
135    fn print_lf_for_error(&self);
136    
137    /// Prints the error.
138    fn eprint_error(&self, err: &Error);
139}
140
141/// A structure of empty printer.
142///
143/// The empty printer is dummy that doesn't print any messages.
144#[derive(Copy, Clone, Debug)]
145pub struct EmptyPrinter;
146
147impl EmptyPrinter
148{
149    /// Creates an empty printer.
150    pub fn new() -> Self
151    { EmptyPrinter }
152}
153
154impl Print for EmptyPrinter
155{
156    fn print_updating(&self)
157    {}
158
159    fn print_pre_installing(&self)
160    {}
161    
162    fn print_installing(&self)
163    {}
164
165    fn print_pre_removing(&self)
166    {}
167
168    fn print_removing(&self)
169    {}
170
171    fn print_documenting(&self)
172    {}
173
174    fn print_updating_pkg_versions(&self, _name: &PkgName, _is_done: bool)
175    {}
176
177    fn print_downloading_pkg_file(&self, _name: &PkgName, _is_done: bool) -> Result<()>
178    { Ok(()) }
179
180    fn print_downloading_pkg_file_with_progress(&self, _name: &PkgName, _byte_count: f64, _total_byte_count: f64) -> Result<()>
181    { Ok(()) }
182    
183    fn print_extracting_pkg_file(&self, _name: &PkgName, _is_done: bool)
184    {}
185    
186    fn print_checking_dependent_version_reqs(&self, _is_done: bool)
187    {}
188
189    fn print_searching_path_conflicts(&self, _is_done: bool)
190    {}
191
192    fn print_documenting_pkg(&self, _name: &PkgName, _is_done: bool)
193    {}
194    
195    fn print_installing_pkg(&self, _name: &PkgName, _is_done: bool)
196    {}
197
198    fn print_removing_pkg(&self, _name: &PkgName, _is_done: bool)
199    {}
200
201    fn print_removing_pkg_doc(&self, _name: &PkgName, _is_done: bool)
202    {}
203
204    fn print_cleaning_after_install(&self, _is_done: bool)
205    {}
206
207    fn print_cleaning_before_removal(&self, _is_done: bool)
208    {}
209
210    fn print_cleaning_after_error(&self, _is_done: bool)
211    {}
212
213    fn print_cleaning(&self, _is_done: bool)
214    {}
215    
216    fn print_lf_for_error(&self)
217    {}
218    
219    fn eprint_error(&self, _err: &Error)
220    {}
221}
222
223/// A structure of standard printer.
224///
225/// The standard printer prints messages to the standard output and error messages to the
226/// standard error.
227#[derive(Debug)]
228pub struct StdPrinter
229{
230    byte_count: Mutex<f64>,
231    has_lf_for_error: AtomicBool,
232}
233
234impl StdPrinter
235{
236    /// Creates a standard printer.
237    pub fn new() -> Self
238    { StdPrinter { byte_count: Mutex::new(0.0), has_lf_for_error: AtomicBool::new(false), } }
239}
240
241impl Print for StdPrinter
242{
243    fn print_updating(&self)
244    { println!("Updating:"); }
245
246    fn print_pre_installing(&self)
247    { println!("Pre-installing:"); }
248    
249    fn print_installing(&self)
250    { println!("Installing:"); }
251
252    fn print_pre_removing(&self)
253    { println!("Pre-removing:"); }
254
255    fn print_removing(&self)
256    { println!("Removing:"); }
257
258    fn print_documenting(&self)
259    { println!("Documenting:"); }
260
261    fn print_updating_pkg_versions(&self, name: &PkgName, is_done: bool)
262    {
263        if is_done {
264            println!(" done");
265            self.has_lf_for_error.store(false, Ordering::SeqCst);
266        } else {
267            print!("Updating {} ...", name);
268            let _res = stdout().flush();
269            self.has_lf_for_error.store(true, Ordering::SeqCst);
270        }
271    }
272    
273    fn print_downloading_pkg_file(&self, name: &PkgName, is_done: bool) -> Result<()>
274    {
275        if is_done {
276            let byte_count = {
277                let byte_count_g = mutex_lock(&self.byte_count)?;
278                *byte_count_g
279            };
280            println!("  progress: {}KiB (100%)", (byte_count / 1024.0).ceil());
281        } else {
282            {
283                let mut byte_count_g = mutex_lock(&self.byte_count)?;
284                *byte_count_g = 0.0;
285            }
286            println!("Downloading {} ...", name);
287        }
288        self.has_lf_for_error.store(false, Ordering::SeqCst);
289        Ok(())
290    }
291
292    fn print_downloading_pkg_file_with_progress(&self, _name: &PkgName, byte_count: f64, total_byte_count: f64) -> Result<()>
293    {
294        if total_byte_count != 0.0 {
295            print!("  progress: {}KiB ({}%)\r", (byte_count / 1024.0).ceil(), ((byte_count * 100.0) / total_byte_count).floor());
296        } else {
297            print!("  progress: {}KiB (?%)\r", (byte_count / 1024.0).ceil());
298        }
299        let _res = stdout().flush();
300        self.has_lf_for_error.store(true, Ordering::SeqCst);
301        {
302            let mut byte_count_g = mutex_lock(&self.byte_count)?;
303            *byte_count_g = byte_count;
304        }
305        Ok(())
306    }
307    
308    fn print_extracting_pkg_file(&self, name: &PkgName, is_done: bool)
309    {
310        if is_done {
311            println!(" done");
312            self.has_lf_for_error.store(false, Ordering::SeqCst);
313        } else {
314            print!("Extracting {} ...", name);
315            let _res = stdout().flush();
316            self.has_lf_for_error.store(true, Ordering::SeqCst);
317        }
318    }
319    
320    fn print_checking_dependent_version_reqs(&self, is_done: bool)
321    {
322        if is_done {
323            println!(" done");
324            self.has_lf_for_error.store(false, Ordering::SeqCst);
325        } else {
326            print!("Checking dependent version requirements ...");
327            let _res = stdout().flush();
328            self.has_lf_for_error.store(true, Ordering::SeqCst);
329        }
330    }
331
332    fn print_searching_path_conflicts(&self, is_done: bool)
333    {
334        if is_done {
335            println!(" done");
336            self.has_lf_for_error.store(false, Ordering::SeqCst);
337        } else {
338            print!("Searching path conflicts ...");
339            let _res = stdout().flush();
340            self.has_lf_for_error.store(true, Ordering::SeqCst);
341        }
342    }
343
344    fn print_documenting_pkg(&self, name: &PkgName, is_done: bool)
345    {
346        if is_done {
347            println!(" done");
348            self.has_lf_for_error.store(false, Ordering::SeqCst);
349        } else {
350            print!("Documenting {} ...", name);
351            let _res = stdout().flush();
352            self.has_lf_for_error.store(true, Ordering::SeqCst);
353        }
354    }
355    
356    fn print_installing_pkg(&self, name: &PkgName, is_done: bool)
357    {
358        if is_done {
359            println!(" done");
360            self.has_lf_for_error.store(false, Ordering::SeqCst);
361        } else {
362            print!("Installing {} ...", name);
363            let _res = stdout().flush();
364            self.has_lf_for_error.store(true, Ordering::SeqCst);
365        }
366    }
367
368    fn print_removing_pkg(&self, name: &PkgName, is_done: bool)
369    {
370        if is_done {
371            println!(" done");
372            self.has_lf_for_error.store(false, Ordering::SeqCst);
373        } else {
374            print!("Removing {} ...", name);
375            let _res = stdout().flush();
376            self.has_lf_for_error.store(true, Ordering::SeqCst);
377        }
378    }
379
380    fn print_removing_pkg_doc(&self, name: &PkgName, is_done: bool)
381    {
382        if is_done {
383            println!(" done");
384            self.has_lf_for_error.store(false, Ordering::SeqCst);
385        } else {
386            print!("Removing {} documentation ...", name);
387            let _res = stdout().flush();
388            self.has_lf_for_error.store(true, Ordering::SeqCst);
389        }
390    }
391
392    fn print_cleaning_after_install(&self, is_done: bool)
393    {
394        if is_done {
395            println!(" done");
396            self.has_lf_for_error.store(false, Ordering::SeqCst);
397        } else {
398            print!("Cleaning after installation ...");
399            let _res = stdout().flush();
400            self.has_lf_for_error.store(true, Ordering::SeqCst);
401        }
402    }
403
404    fn print_cleaning_before_removal(&self, is_done: bool)
405    {
406        if is_done {
407            println!(" done");
408            self.has_lf_for_error.store(false, Ordering::SeqCst);
409        } else {
410            print!("Cleaning before removal ...");
411            let _res = stdout().flush();
412            self.has_lf_for_error.store(true, Ordering::SeqCst);
413        }
414    }
415    
416    fn print_cleaning_after_error(&self, is_done: bool)
417    {
418        if is_done {
419            println!(" done");
420            self.has_lf_for_error.store(false, Ordering::SeqCst);
421        } else {
422            self.print_lf_for_error();
423            print!("Cleaning after error ...");
424            let _res = stdout().flush();
425            self.has_lf_for_error.store(true, Ordering::SeqCst);
426        }
427    }
428
429    fn print_cleaning(&self, is_done: bool)
430    {
431        if is_done {
432            println!(" done");
433            self.has_lf_for_error.store(false, Ordering::SeqCst);
434        } else {
435            print!("Cleaning ...");
436            let _res = stdout().flush();
437            self.has_lf_for_error.store(true, Ordering::SeqCst);
438        }
439    }
440    
441    fn print_lf_for_error(&self)
442    {
443        if self.has_lf_for_error.swap(false, Ordering::SeqCst) {
444            println!("");
445        }
446    }
447    
448    fn eprint_error(&self, err: &Error)
449    {
450        self.print_lf_for_error();
451        eprintln!("{}", err);
452    }
453}
454
455/// A source trait.
456///
457/// The source allows to access a package diractory. The package is automatically updated,
458/// downaloded, and extracted by the source if it is necessery. Also, the packege source allows
459/// to manually update the package versions. The package updating is called the updating of
460/// package versions.
461pub trait Source
462{
463    /// Updating the package versions.
464    fn update(&mut self) -> Result<()>;
465    
466    /// Returns the package versions.
467    fn versions(&mut self) -> Result<&BTreeSet<Version>>;
468    
469    /// Sets the current package version.
470    fn set_current_version(&mut self, version: Version);
471
472    /// Returns the package directory.
473    fn dir(&mut self) -> Result<&Path>;
474}
475
476/// A trait of source factory.
477///
478/// The source factory creates source for the specified package.
479pub trait SourceCreate
480{
481    /// Creates a source.
482    fn create(&self, name: PkgName, old_name: Option<PkgName>, home_dir: PathBuf, work_dir: PathBuf, printer: Arc<dyn Print + Send + Sync>) -> Option<Box<dyn Source + Send + Sync>>;
483}
484
485/// A structure of package name.
486///
487/// The package name often consists an account and a repository name. The account often contains
488/// the git hosting service and a login. The package name should contain one slash character.
489#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
490pub struct PkgName
491{
492    name: String,
493}
494
495impl PkgName
496{
497    /// Creates a package name.
498    pub fn new(name: String) -> Self
499    { PkgName { name, } }
500
501    /// Parses the string slice to a package name.
502    ///
503    /// This method indeed checks whether the package name is correct.
504    pub fn parse(s: &str) -> Result<Self>
505    {
506        if s.split('/').count() < 2 {
507            return Err(Error::InvalidPkgName);
508        }
509        let ss = s.split('/');
510        for t in ss {
511            if t.is_empty() || t.contains('\\') || t == "." || t == ".." {
512                return Err(Error::InvalidPkgName);
513            }
514        }
515        Ok(Self::new(String::from(s)))
516    }
517    
518    /// Returns the name as the string slice.
519    pub fn name(&self) -> &str
520    { self.name.as_str() }
521    
522    /// Converts the package name to a path buffer.
523    pub fn to_path_buf(&self) -> PathBuf
524    { PathBuf::from(self.name.replace('/', path::MAIN_SEPARATOR_STR)) }
525}
526
527impl fmt::Display for PkgName
528{
529    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
530    { write!(f, "{}", self.name) }
531}
532
533impl Serialize for PkgName
534{
535    fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
536        where S: Serializer
537    { serializer.serialize_str(format!("{}", self).as_str()) }
538}
539
540struct PkgNameVisitor;
541
542impl<'de> Visitor<'de> for PkgNameVisitor
543{
544    type Value = PkgName;
545
546    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result
547    { write!(formatter, "a package name") }
548
549    fn visit_str<E>(self, v: &str) -> result::Result<Self::Value, E>
550        where E: de::Error
551    {
552        match PkgName::parse(v) {
553            Ok(pkg_name) => Ok(pkg_name),
554            Err(err) => Err(E::custom(format!("{}", err))),
555        }
556    }
557}
558
559impl<'de> Deserialize<'de> for PkgName
560{
561    fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
562        where D: Deserializer<'de>
563    { deserializer.deserialize_str(PkgNameVisitor) }
564}
565
566/// A structure of package information.
567#[derive(Clone, Debug, Serialize, Deserialize)]
568pub struct PkgInfo
569{
570    /// A package name.
571    pub name: PkgName,
572    /// A package description.
573    pub description: Option<String>,
574    /// A package authors.
575    pub authors: Option<Vec<String>>,
576    /// A package license.
577    pub license: Option<String>,
578    /// A required Unlab-gpu version.
579    #[serde(rename = "unlab-gpu-version")]
580    pub unlab_gpu_version: Option<VersionReq>,
581}
582
583/// An enumeration of source information of version.
584#[derive(Clone, Debug, Serialize, Deserialize)]
585pub enum VersionSrcInfo
586{
587    /// A path to package directory.
588    #[serde(rename = "dir")]
589    Dir(String),
590    /// A path to package archive.
591    #[serde(rename = "file")]
592    File(String),
593    /// An URL to package archive.
594    #[serde(rename = "url")]
595    Url(String),
596}
597
598/// An enumeration of source information.
599#[derive(Clone, Debug, Serialize, Deserialize)]
600pub enum SrcInfo
601{
602    /// A new package name. 
603    #[serde(rename = "renamed")]
604    Renamed(PkgName),
605    /// Version with version source informations.
606    #[serde(rename = "versions")]
607    Versions(Arc<BTreeMap<Version, VersionSrcInfo>>),
608}
609
610/// A structure of package manifest.
611///
612/// The package manifest contains basic informations about package for example a package name,
613/// package description, and package dependencies. These informations can be used to package
614/// installation.
615#[derive(Clone, Debug, Serialize, Deserialize)]
616pub struct Manifest
617{
618    /// A package information.
619    pub package: PkgInfo,
620    /// Package dependencies.
621    pub dependencies: Option<HashMap<PkgName, VersionReq>>,
622    /// Package constraints.
623    pub constraints: Option<Arc<HashMap<PkgName, VersionReq>>>,
624    /// Custrom sources.
625    pub sources: Option<Arc<HashMap<PkgName, SrcInfo>>>,
626}
627
628impl Manifest
629{
630    /// Creates a package manifest.
631    pub fn new(name: PkgName) -> Self
632    {
633        Manifest {
634            package: PkgInfo {
635                name,
636                description: None,
637                authors: None,
638                license: None,
639                unlab_gpu_version: None,
640            },
641            dependencies: Some(HashMap::new()),
642            constraints: None,
643            sources: None,
644        }
645    }
646    
647    /// Reads a package manifest from the reader.
648    pub fn read(r: &mut dyn Read) -> Result<Self>
649    {
650        let mut s = String::new();
651        match r.read_to_string(&mut s) {
652            Ok(_) => {
653                match toml::from_str(s.as_str()) {
654                    Ok(manifest) => Ok(manifest),
655                    Err(err) => Err(Error::TomlDe(err)),
656                }
657            },
658            Err(err) => Err(Error::Io(err)),
659        }
660    }
661
662    /// Writes the package manifest to the writer.
663    pub fn write(&self, w: &mut dyn Write) -> Result<()>
664    {
665        match toml::to_string(self) {
666            Ok(s) => {
667                match write!(w, "{}", s) {
668                    Ok(()) => Ok(()),
669                    Err(err) => Err(Error::Io(err)),
670                }
671            },
672            Err(err) => Err(Error::TomlSer(err)),
673        }
674    }
675
676    /// Loads a package manifest from the file.
677    pub fn load<P: AsRef<Path>>(path: P) -> Result<Self>
678    {
679        match File::open(path) {
680            Ok(mut file) => Self::read(&mut file),
681            Err(err) => Err(Error::Io(err)),
682        }
683    }
684
685    /// Loads a package manifest from the file if the file exists, otherwise this method returns
686    /// `None`.
687    pub fn load_opt<P: AsRef<Path>>(path: P) -> Result<Option<Self>>
688    {
689        match File::open(path) {
690            Ok(mut file) => Ok(Some(Self::read(&mut file)?)),
691            Err(err) if err.kind() == ErrorKind::NotFound => Ok(None), 
692            Err(err) => Err(Error::Io(err)),
693        }
694    }
695
696    /// Saves the package manifest to a file.
697    pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<()>
698    {
699        match File::create(path) {
700            Ok(mut file) => self.write(&mut file),
701            Err(err) => Err(Error::Io(err)),
702        }
703    }
704}
705
706/// A structure of paths.
707#[derive(Clone, Debug, Serialize, Deserialize)]
708pub struct Paths
709{
710    /// Paths to binaries.
711    pub bin: Vec<String>,
712    /// Paths to libraries.
713    pub lib: Vec<String>,
714}
715
716impl Paths
717{
718    /// Creates paths.
719    pub fn new(bin: Vec<String>, lib: Vec<String>) -> Self
720    { Paths { bin, lib, } }
721    
722    /// Reads paths from the reader.
723    pub fn read(r: &mut dyn Read) -> Result<Self>
724    {
725        let mut s = String::new();
726        match r.read_to_string(&mut s) {
727            Ok(_) => {
728                match toml::from_str(s.as_str()) {
729                    Ok(paths) => Ok(paths),
730                    Err(err) => Err(Error::TomlDe(err)),
731                }
732            },
733            Err(err) => Err(Error::Io(err)),
734        }
735    }
736
737    /// Writes the paths to the writer.
738    pub fn write(&self, w: &mut dyn Write) -> Result<()>
739    {
740        match toml::to_string(self) {
741            Ok(s) => {
742                match write!(w, "{}", s) {
743                    Ok(()) => Ok(()),
744                    Err(err) => Err(Error::Io(err)),
745                }
746            },
747            Err(err) => Err(Error::TomlSer(err)),
748        }
749    }
750    
751    /// Loads paths from the file.
752    pub fn load<P: AsRef<Path>>(path: P) -> Result<Self>
753    {
754        match File::open(path) {
755            Ok(mut file) => Self::read(&mut file),
756            Err(err) => Err(Error::Io(err)),
757        }
758    }
759
760    /// Loads paths from the file if the file exists, otherwise this method returns `None`.
761    pub fn load_opt<P: AsRef<Path>>(path: P) -> Result<Option<Self>>
762    {
763        match File::open(path) {
764            Ok(mut file) => Ok(Some(Self::read(&mut file)?)),
765            Err(err) if err.kind() == ErrorKind::NotFound => Ok(None), 
766            Err(err) => Err(Error::Io(err)),
767        }
768    }
769
770    /// Saves the paths to a file.
771    pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<()>
772    {
773        match File::create(path) {
774            Ok(mut file) => self.write(&mut file),
775            Err(err) => Err(Error::Io(err)),
776        }
777    }
778}
779
780/// A structure of documentation paths.
781#[derive(Clone, Debug, Serialize, Deserialize)]
782pub struct DocPaths
783{
784    /// Paths to documentation.
785    pub doc: Vec<String>,
786}
787
788impl DocPaths
789{
790    /// Creates documentation paths.
791    pub fn new(doc: Vec<String>) -> Self
792    { DocPaths { doc, } }
793    
794    /// Reads documentation paths from the reader.
795    pub fn read(r: &mut dyn Read) -> Result<Self>
796    {
797        let mut s = String::new();
798        match r.read_to_string(&mut s) {
799            Ok(_) => {
800                match toml::from_str(s.as_str()) {
801                    Ok(doc_paths) => Ok(doc_paths),
802                    Err(err) => Err(Error::TomlDe(err)),
803                }
804            },
805            Err(err) => Err(Error::Io(err)),
806        }
807    }
808
809    /// Writes the documentation paths to the writer.
810    pub fn write(&self, w: &mut dyn Write) -> Result<()>
811    {
812        match toml::to_string(self) {
813            Ok(s) => {
814                match write!(w, "{}", s) {
815                    Ok(()) => Ok(()),
816                    Err(err) => Err(Error::Io(err)),
817                }
818            },
819            Err(err) => Err(Error::TomlSer(err)),
820        }
821    }
822    
823    /// Loads documentation paths from the file.
824    pub fn load<P: AsRef<Path>>(path: P) -> Result<Self>
825    {
826        match File::open(path) {
827            Ok(mut file) => Self::read(&mut file),
828            Err(err) => Err(Error::Io(err)),
829        }
830    }
831
832    /// Loads documentation paths from the file if the file exists, otherwise this method returns
833    /// `None`.
834    pub fn load_opt<P: AsRef<Path>>(path: P) -> Result<Option<Self>>
835    {
836        match File::open(path) {
837            Ok(mut file) => Ok(Some(Self::read(&mut file)?)),
838            Err(err) if err.kind() == ErrorKind::NotFound => Ok(None), 
839            Err(err) => Err(Error::Io(err)),
840        }
841    }
842
843    /// Saves the documentation paths to a file.
844    pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<()>
845    {
846        match File::create(path) {
847            Ok(mut file) => self.write(&mut file),
848            Err(err) => Err(Error::Io(err)),
849        }
850    }
851}
852
853/// A structure of package versions.
854#[derive(Clone, Debug, Serialize, Deserialize)]
855pub struct Versions
856{
857    /// Package versions.
858    pub versions: BTreeSet<Version>,
859}
860
861impl Versions
862{
863    /// Creates package versions.
864    pub fn new(versions: BTreeSet<Version>) -> Self
865    { Versions { versions, } }
866    
867    /// Reads package versions from the reader.
868    pub fn read(r: &mut dyn Read) -> Result<Self>
869    {
870        let mut s = String::new();
871        match r.read_to_string(&mut s) {
872            Ok(_) => {
873                match toml::from_str(s.as_str()) {
874                    Ok(versions) => Ok(versions),
875                    Err(err) => Err(Error::TomlDe(err)),
876                }
877            },
878            Err(err) => Err(Error::Io(err)),
879        }
880    }
881
882    /// Writes the package versions to the writer.
883    pub fn write(&self, w: &mut dyn Write) -> Result<()>
884    {
885        match toml::to_string(self) {
886            Ok(s) => {
887                match write!(w, "{}", s) {
888                    Ok(()) => Ok(()),
889                    Err(err) => Err(Error::Io(err)),
890                }
891            },
892            Err(err) => Err(Error::TomlSer(err)),
893        }
894    }
895    
896    /// Loads package versions from the file.
897    pub fn load<P: AsRef<Path>>(path: P) -> Result<Self>
898    {
899        match File::open(path) {
900            Ok(mut file) => Self::read(&mut file),
901            Err(err) => Err(Error::Io(err)),
902        }
903    }
904
905    /// Loads package versions from the file if the file exists, otherwise this method returns
906    /// `None`.
907    pub fn load_opt<P: AsRef<Path>>(path: P) -> Result<Option<Self>>
908    {
909        match File::open(path) {
910            Ok(mut file) => Ok(Some(Self::read(&mut file)?)),
911            Err(err) if err.kind() == ErrorKind::NotFound => Ok(None), 
912            Err(err) => Err(Error::Io(err)),
913        }
914    }
915
916    /// Saves the package versions to a file.
917    pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<()>
918    {
919        match File::create(path) {
920            Ok(mut file) => self.write(&mut file),
921            Err(err) => Err(Error::Io(err)),
922        }
923    }
924}
925
926/// A strcuture of package configuration.
927#[derive(Clone, Debug, Serialize, Deserialize)]
928pub struct PkgConfig
929{
930    /// An account.
931    pub account: Option<String>,
932    /// A domain.
933    pub domain: Option<String>,
934}
935
936impl PkgConfig
937{
938    /// Creates a package configuration.
939    pub fn new(account: Option<String>, domain: Option<String>) -> Self
940    { PkgConfig { account, domain, } }
941    
942    /// Reads a package configuration from the reader.
943    pub fn read(r: &mut dyn Read) -> Result<Self>
944    {
945        let mut s = String::new();
946        match r.read_to_string(&mut s) {
947            Ok(_) => {
948                match toml::from_str(s.as_str()) {
949                    Ok(config) => Ok(config),
950                    Err(err) => Err(Error::TomlDe(err)),
951                }
952            },
953            Err(err) => Err(Error::Io(err)),
954        }
955    }
956
957    /// Writes the package configuration to the writer.
958    pub fn write(&self, w: &mut dyn Write) -> Result<()>
959    {
960        match toml::to_string(self) {
961            Ok(s) => {
962                match write!(w, "{}", s) {
963                    Ok(()) => Ok(()),
964                    Err(err) => Err(Error::Io(err)),
965                }
966            },
967            Err(err) => Err(Error::TomlSer(err)),
968        }
969    }
970    
971    /// Loads a package configuration from the file.
972    pub fn load<P: AsRef<Path>>(path: P) -> Result<Self>
973    {
974        match File::open(path) {
975            Ok(mut file) => Self::read(&mut file),
976            Err(err) => Err(Error::Io(err)),
977        }
978    }
979
980    /// Loads a package configuration from the file if the file exists, otherwise this method
981    /// returns `None`.
982    pub fn load_opt<P: AsRef<Path>>(path: P) -> Result<Option<Self>>
983    {
984        match File::open(path) {
985            Ok(mut file) => Ok(Some(Self::read(&mut file)?)),
986            Err(err) if err.kind() == ErrorKind::NotFound => Ok(None), 
987            Err(err) => Err(Error::Io(err)),
988        }
989    }
990
991    /// Saves the package configurataion to a file.
992    pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<()>
993    {
994        match File::create(path) {
995            Ok(mut file) => self.write(&mut file),
996            Err(err) => Err(Error::Io(err)),
997        }
998    }
999}
1000
1001/// Reads versions from the reader.
1002pub fn read_versions(r: &mut dyn Read) -> Result<HashMap<PkgName, Version>>
1003{
1004    let mut s = String::new();
1005    match r.read_to_string(&mut s) {
1006        Ok(_) => {
1007            match toml::from_str::<HashMap<PkgName, Version>>(s.as_str()) {
1008                Ok(src_infos) => Ok(src_infos),
1009                Err(err) => Err(Error::TomlDe(err)),
1010            }
1011        },
1012        Err(err) => Err(Error::Io(err)),
1013    }
1014}
1015
1016/// Writes the versions to the writer.
1017pub fn write_versions(w: &mut dyn Write, versions: &HashMap<PkgName, Version>) -> Result<()>
1018{
1019    match toml::to_string(versions) {
1020        Ok(s) => {
1021            match write!(w, "{}", s) {
1022                Ok(()) => Ok(()),
1023                Err(err) => Err(Error::Io(err)),
1024            }
1025        },
1026        Err(err) => Err(Error::TomlSer(err)),
1027    }
1028}
1029
1030/// Loads versions from the file.
1031pub fn load_versions<P: AsRef<Path>>(path: P) -> Result<HashMap<PkgName, Version>>
1032{
1033    match File::open(path) {
1034        Ok(mut file) => read_versions(&mut file),
1035        Err(err) => Err(Error::Io(err)),
1036    }
1037}
1038
1039/// Loads versions from the file if the file exists, otherwise this function returns `None`.
1040pub fn load_opt_versions<P: AsRef<Path>>(path: P) -> Result<Option<HashMap<PkgName, Version>>>
1041{
1042    match File::open(path) {
1043        Ok(mut file) => Ok(Some(read_versions(&mut file)?)),
1044        Err(err) if err.kind() == ErrorKind::NotFound => Ok(None),
1045        Err(err) => Err(Error::Io(err)),
1046    }
1047}
1048
1049/// Loads versions from the file if the file exists, otherwise this function returns an empty
1050/// hash map.
1051pub fn load_versions_or_empty<P: AsRef<Path>>(path: P) -> Result<HashMap<PkgName, Version>>
1052{
1053    match File::open(path) {
1054        Ok(mut file) => read_versions(&mut file),
1055        Err(err) if err.kind() == ErrorKind::NotFound => Ok(HashMap::new()),
1056        Err(err) => Err(Error::Io(err)),
1057    }
1058}
1059
1060/// Saves the versions to a file.
1061pub fn save_versions<P: AsRef<Path>>(path: P, versions: &HashMap<PkgName, Version>) -> Result<()>
1062{
1063    match File::create(path) {
1064        Ok(mut file) => write_versions(&mut file, versions),
1065        Err(err) => Err(Error::Io(err)),
1066    }
1067}
1068
1069/// Reads version requirements from the reader.
1070pub fn read_version_reqs(r: &mut dyn Read) -> Result<HashMap<PkgName, VersionReq>>
1071{
1072    let mut s = String::new();
1073    match r.read_to_string(&mut s) {
1074        Ok(_) => {
1075            match toml::from_str::<HashMap<PkgName, VersionReq>>(s.as_str()) {
1076                Ok(version_reqs) => Ok(version_reqs),
1077                Err(err) => Err(Error::TomlDe(err)),
1078            }
1079        },
1080        Err(err) => Err(Error::Io(err)),
1081    }
1082}
1083
1084/// Writes the version requirements to the writer.
1085pub fn write_version_reqs(w: &mut dyn Write, version_reqs: &HashMap<PkgName, VersionReq>) -> Result<()>
1086{
1087    match toml::to_string(version_reqs) {
1088        Ok(s) => {
1089            match write!(w, "{}", s) {
1090                Ok(()) => Ok(()),
1091                Err(err) => Err(Error::Io(err)),
1092            }
1093        },
1094        Err(err) => Err(Error::TomlSer(err)),
1095    }
1096}
1097
1098/// Loads version requirements from the file.
1099pub fn load_version_reqs<P: AsRef<Path>>(path: P) -> Result<HashMap<PkgName, VersionReq>>
1100{
1101    match File::open(path) {
1102        Ok(mut file) => read_version_reqs(&mut file),
1103        Err(err) => Err(Error::Io(err)),
1104    }
1105}
1106
1107/// Loads version requirements from the file if the file exists, otherwise this function returns
1108/// `None`.
1109pub fn load_opt_version_reqs<P: AsRef<Path>>(path: P) -> Result<Option<HashMap<PkgName, VersionReq>>>
1110{
1111    match File::open(path) {
1112        Ok(mut file) => Ok(Some(read_version_reqs(&mut file)?)),
1113        Err(err) if err.kind() == ErrorKind::NotFound => Ok(None),
1114        Err(err) => Err(Error::Io(err)),
1115    }
1116}
1117
1118/// Loads version requirements from the file if the file exists, otherwise this function returns
1119/// an empty hash map.
1120pub fn load_version_reqs_or_empty<P: AsRef<Path>>(path: P) -> Result<HashMap<PkgName, VersionReq>>
1121{
1122    match File::open(path) {
1123        Ok(mut file) => read_version_reqs(&mut file),
1124        Err(err) if err.kind() == ErrorKind::NotFound => Ok(HashMap::new()),
1125        Err(err) => Err(Error::Io(err)),
1126    }
1127}
1128
1129/// Saves the version requirements to a file.
1130pub fn save_version_reqs<P: AsRef<Path>>(path: P, version_reqs: &HashMap<PkgName, VersionReq>) -> Result<()>
1131{
1132    match File::create(path) {
1133        Ok(mut file) => write_version_reqs(&mut file, version_reqs),
1134        Err(err) => Err(Error::Io(err)),
1135    }
1136}
1137
1138/// Reads source informations from the reader.
1139pub fn read_src_infos(r: &mut dyn Read) -> Result<HashMap<PkgName, SrcInfo>>
1140{
1141    let mut s = String::new();
1142    match r.read_to_string(&mut s) {
1143        Ok(_) => {
1144            match toml::from_str::<HashMap<PkgName, SrcInfo>>(s.as_str()) {
1145                Ok(src_infos) => Ok(src_infos),
1146                Err(err) => Err(Error::TomlDe(err)),
1147            }
1148        },
1149        Err(err) => Err(Error::Io(err)),
1150    }
1151}
1152
1153/// Writes the source informations to the writer.
1154pub fn write_src_infos(w: &mut dyn Write, src_infos: &HashMap<PkgName, SrcInfo>) -> Result<()>
1155{
1156    match toml::to_string(src_infos) {
1157        Ok(s) => {
1158            match write!(w, "{}", s) {
1159                Ok(()) => Ok(()),
1160                Err(err) => Err(Error::Io(err)),
1161            }
1162        },
1163        Err(err) => Err(Error::TomlSer(err)),
1164    }
1165}
1166
1167/// Loads source informations from the file.
1168pub fn load_src_infos<P: AsRef<Path>>(path: P) -> Result<HashMap<PkgName, SrcInfo>>
1169{
1170    match File::open(path) {
1171        Ok(mut file) => read_src_infos(&mut file),
1172        Err(err) => Err(Error::Io(err)),
1173    }
1174}
1175
1176/// Loads source informations from the file if the file exists, otherwise this function returns
1177/// `None`.
1178pub fn load_opt_src_infos<P: AsRef<Path>>(path: P) -> Result<Option<HashMap<PkgName, SrcInfo>>>
1179{
1180    match File::open(path) {
1181        Ok(mut file) => Ok(Some(read_src_infos(&mut file)?)),
1182        Err(err) if err.kind() == ErrorKind::NotFound => Ok(None),
1183        Err(err) => Err(Error::Io(err)),
1184    }
1185}
1186
1187/// Loads source informations from the file if the file exists, otherwise this function returns
1188/// an empty hash map.
1189pub fn load_src_infos_or_empty<P: AsRef<Path>>(path: P) -> Result<HashMap<PkgName, SrcInfo>>
1190{
1191    match File::open(path) {
1192        Ok(mut file) => read_src_infos(&mut file),
1193        Err(err) if err.kind() == ErrorKind::NotFound => Ok(HashMap::new()),
1194        Err(err) => Err(Error::Io(err)),
1195    }
1196}
1197
1198/// Saves the source informations to a file.
1199pub fn save_src_infos<P: AsRef<Path>>(path: P, src_infos: &HashMap<PkgName, SrcInfo>) -> Result<()>
1200{
1201    match File::create(path) {
1202        Ok(mut file) => write_src_infos(&mut file, src_infos),
1203        Err(err) => Err(Error::Io(err)),
1204    }
1205}
1206
1207/// Converts the tag name to a version.
1208pub fn tag_name_to_version(tag_name: &str) -> Option<Version>
1209{
1210    if tag_name.starts_with("v") {
1211        match Version::parse(&tag_name[1..]) {
1212            Ok(version) => Some(version),
1213            Err(_) => None,
1214        }
1215    } else {
1216        None
1217    }
1218}
1219
1220/// Converts the version to a tag name.
1221pub fn version_to_tag_name(version: &Version) -> String
1222{ format!("v{}", version) }
1223
1224/// Returns a path to the variable directory.
1225pub fn var_dir<P: AsRef<Path>>(home_dir: P) -> PathBuf
1226{
1227    let mut dir = PathBuf::from(home_dir.as_ref());
1228    dir.push("var");
1229    dir
1230}
1231
1232/// Returns a path to the temporary director.
1233pub fn tmp_dir<P: AsRef<Path>>(work_dir: P) -> PathBuf
1234{
1235    let mut dir = PathBuf::from(work_dir.as_ref());
1236    dir.push("tmp");
1237    dir
1238}
1239
1240/// Returns a path to the index directory.
1241pub fn index_dir<P: AsRef<Path>>(home_dir: P) -> PathBuf
1242{
1243    let mut dir = var_dir(home_dir);
1244    dir.push("index");
1245    dir
1246}
1247
1248/// Returns a path to the cache directory.
1249pub fn cache_dir<P: AsRef<Path>>(home_dir: P) -> PathBuf
1250{
1251    let mut dir = var_dir(home_dir);
1252    dir.push("cache");
1253    dir
1254}
1255
1256/// Returns a path to the index directory for the specified package.
1257pub fn pkg_index_dir<P: AsRef<Path>>(home_dir: P, name: &PkgName) -> PathBuf
1258{
1259    let mut dir = index_dir(home_dir);
1260    dir.push(name.to_path_buf());
1261    dir
1262}
1263
1264/// Returns a path to the variable directory for the specified package.
1265pub fn pkg_cache_dir<P: AsRef<Path>>(home_dir: P, name: &PkgName, version: &Version) -> PathBuf
1266{
1267    let mut dir = cache_dir(home_dir);
1268    dir.push(name.to_path_buf());
1269    dir.push(format!("{}", version).as_str());
1270    dir
1271}
1272
1273/// Returns a path to the temporary directory for the specified package.
1274pub fn pkg_tmp_dir<P: AsRef<Path>>(work_dir: P, name: &PkgName, version: &Version) -> PathBuf
1275{
1276    let mut dir = tmp_dir(work_dir);
1277    dir.push(name.to_path_buf());
1278    dir.push(format!("{}", version).as_str());
1279    dir
1280}
1281
1282/// Returns a path to the package directory while extracting.
1283pub fn pkg_part_dir<P: AsRef<Path>>(work_dir: P, name: &PkgName, version: &Version) -> PathBuf
1284{
1285    let mut dir = pkg_tmp_dir(work_dir, name, version);
1286    dir.push("dir.part");
1287    dir
1288}
1289
1290/// Returns a path to the package directory after extracting.
1291pub fn pkg_dir<P: AsRef<Path>>(work_dir: P, name: &PkgName, version: &Version) -> PathBuf
1292{
1293    let mut dir = pkg_tmp_dir(work_dir, name, version);
1294    dir.push("dir");
1295    dir
1296}
1297
1298fn io_res_remove_and_rename_for_updated_pkg_versions(new_part_path: &Path, new_path: &Path, path: &Path) -> io::Result<()>
1299{
1300    recursively_remove(new_path, true)?;
1301    rename(new_part_path, new_path)?;
1302    recursively_remove(path, true)?;
1303    rename(new_path, path)?;
1304    Ok(())
1305}
1306
1307fn io_res_remove_and_rename_for_unupdated_pkg_versions(new_part_path: &Path, new_path: &Path, path: &Path) -> io::Result<()>
1308{
1309    recursively_remove(new_part_path, true)?;
1310    match fs::metadata(new_path) {
1311        Ok(_) => {
1312            recursively_remove(path, true)?;
1313            rename(new_path, path)?;
1314            Ok(())
1315        },
1316        Err(err) if err.kind() == ErrorKind::NotFound => Ok(()), 
1317        Err(err) => Err(err),
1318    }
1319}
1320
1321/// Updates the package versions for the specified package.
1322///
1323/// This method overwrites the package versions if the package versions exist and the update flag
1324/// is set, otherwise the package versios isn't overwritten.
1325pub fn update_pkg_versions<P: AsRef<Path>, F, G>(name: &PkgName, old_name: &Option<PkgName>, home_dir: P, is_update: bool, printer: &Arc<dyn Print + Send + Sync>, f: F, g: G) -> Result<BTreeSet<Version>>
1326    where F: FnOnce() -> result::Result<curl::easy::Easy, curl::Error>,
1327        G: FnOnce(&[u8]) -> Result<BTreeSet<Version>>
1328{
1329    let path_buf = pkg_index_dir(home_dir.as_ref(), old_name.as_ref().unwrap_or(name));
1330    let mut new_part_versions_path_buf = path_buf.clone();
1331    new_part_versions_path_buf.push("versions.toml.new.part");
1332    let mut new_versions_path_buf = path_buf.clone();
1333    new_versions_path_buf.push("versions.toml.new");
1334    let mut versions_path_buf = path_buf.clone();
1335    versions_path_buf.push("versions.toml");
1336    let is_to_update = match fs::metadata(versions_path_buf.as_path()) {
1337        Ok(_) => is_update,
1338        Err(err) if err.kind() == ErrorKind::NotFound => {
1339            match fs::metadata(new_versions_path_buf.as_path()) {
1340                Ok(_) => is_update,
1341                Err(err) if err.kind() == ErrorKind::NotFound => true,
1342                Err(err) => return Err(Error::Io(err)),
1343            }
1344        },
1345        Err(err) => return Err(Error::Io(err)),
1346    };
1347    if is_to_update {
1348        printer.print_updating_pkg_versions(name, false);
1349        match recursively_remove(new_part_versions_path_buf.as_path(), true) {
1350            Ok(()) => (),
1351            Err(err) => return Err(Error::Io(err)),
1352        }
1353        let data: Arc<Mutex<Vec<u8>>> = Arc::new(Mutex::new(Vec::new()));
1354        let data2 = data.clone();
1355        let mut easy = match f() {
1356            Ok(tmp_easy) => tmp_easy,
1357            Err(err) => return Err(Error::Curl(err)),
1358        };
1359        match easy.fail_on_error(true) {
1360            Ok(()) => (),
1361            Err(err) => return Err(Error::Curl(err)),
1362        }
1363        match easy.write_function(move |buf| {
1364                let mut data2_g = data2.lock().unwrap();
1365                data2_g.extend_from_slice(buf);
1366                Ok(buf.len())
1367        }) {
1368            Ok(()) => (),
1369            Err(err) => return Err(Error::Curl(err)),
1370        }
1371        match easy.perform() {
1372            Ok(()) => (),
1373            Err(err) => return Err(Error::Curl(err)),
1374        }
1375        let versions = {
1376            let mut data_g = mutex_lock(&data)?;
1377            let res = g(data_g.as_slice());
1378            data_g.clear();
1379            Versions::new(res?)
1380        };
1381        match create_dir_all(path_buf.as_path()) {
1382            Ok(()) => (),
1383            Err(err) => return Err(Error::Io(err)),
1384        }
1385        versions.save(new_part_versions_path_buf.as_path())?;
1386        match io_res_remove_and_rename_for_updated_pkg_versions(new_part_versions_path_buf.as_path(), new_versions_path_buf.as_path(), versions_path_buf.as_path()) {
1387            Ok(()) => (),
1388            Err(err) => return Err(Error::Io(err)),
1389        }
1390        printer.print_updating_pkg_versions(name, true);
1391    } else {
1392        match io_res_remove_and_rename_for_unupdated_pkg_versions(new_part_versions_path_buf.as_path(), new_versions_path_buf.as_path(), versions_path_buf.as_path()) {
1393            Ok(()) => (),
1394            Err(err) => return Err(Error::Io(err)),
1395        }
1396    }
1397    Ok(Versions::load(versions_path_buf)?.versions)
1398}
1399
1400fn curl_res_download_pkg_file(name: &PkgName, url: &str, part_file_path: &Path, printer: &Arc<dyn Print + Send + Sync>) -> result::Result<(), curl::Error>
1401{
1402    let mut easy = curl::easy::Easy::new();
1403    easy.url(url)?;
1404    let mut http_headers = List::new();
1405    http_headers.append(USER_AGENT_HTTP_HEADER)?;
1406    easy.http_headers(http_headers)?;
1407    easy.follow_location(true)?;
1408    easy.fail_on_error(true)?;
1409    easy.progress(true)?;
1410    let name2 = name.clone();
1411    let printer2 = printer.clone();
1412    easy.progress_function(move |total_byte_count, byte_count, _, _| {
1413            match printer2.print_downloading_pkg_file_with_progress(&name2, byte_count, total_byte_count) {
1414                Ok(()) => (),
1415                Err(err) => printer2.eprint_error(&err),
1416            }
1417            true
1418    })?;
1419    let part_file_path_buf = PathBuf::from(part_file_path);
1420    let printer2 = printer.clone();
1421    easy.write_function(move |buf| {
1422            match File::options().create(true).append(true).open(part_file_path_buf.as_path()) {
1423                Ok(mut file) => {
1424                    match file.write_all(buf) {
1425                        Ok(()) => (),
1426                        Err(err) => printer2.eprint_error(&Error::Io(err)),
1427                    }
1428                },
1429                Err(err) => printer2.eprint_error(&Error::Io(err)),
1430            }
1431            Ok(buf.len())
1432    })?;
1433    easy.perform()
1434}
1435
1436/// Downloads the package archive for the specified package.
1437///
1438/// If the old package name is passed, this function writes the package archive in the directory
1439/// for the old package name.
1440pub fn download_pkg_file<P: AsRef<Path>>(name: &PkgName, old_name: &Option<PkgName>, version: &Version, url: &str, home_dir: P, printer: &Arc<dyn Print + Send + Sync>) -> Result<PathBuf>
1441{
1442    let path_buf = pkg_cache_dir(home_dir.as_ref(), old_name.as_ref().unwrap_or(name), version);
1443    let first_url_part = match url.split_once('?') {
1444        Some((tmp_first_url_part, _)) => tmp_first_url_part,
1445        None => url,
1446    };
1447    let (part_file_name, file_name) = if first_url_part.ends_with(".zip") {
1448        ("file.zip.part", "file.zip")
1449    } else if first_url_part.ends_with(".tar.gz") {
1450        ("file.tar.gz.part", "file.tar.gz")
1451    } else if first_url_part.ends_with(".tar.bz2") {
1452        ("file.tar.bz2.part", "file.tar.bz2")
1453    } else if first_url_part.ends_with(".tar.xz") {
1454        ("file.tar.xz.part", "file.tar.xz")
1455    } else if first_url_part.ends_with(".tar") {
1456        ("file.tar.part", "file.tar")
1457    } else {
1458        ("file.part", "file")
1459    };
1460    let mut part_file_path_buf = path_buf.clone();
1461    part_file_path_buf.push(part_file_name);
1462    let mut file_path_buf = path_buf.clone();
1463    file_path_buf.push(file_name);
1464    match fs::metadata(file_path_buf.as_path()) {
1465        Ok(_) => (),
1466        Err(err) if err.kind() == ErrorKind::NotFound => {
1467            printer.print_downloading_pkg_file(name, false)?;
1468            match create_dir_all(path_buf.as_path()) {
1469                Ok(()) => (),
1470                Err(err) => return Err(Error::Io(err)),
1471            }
1472            match recursively_remove(part_file_path_buf.as_path(), true) {
1473                Ok(()) => (),
1474                Err(err) => return Err(Error::Io(err)),
1475            }
1476            match curl_res_download_pkg_file(name, url, part_file_path_buf.as_path(), printer) {
1477                Ok(()) => (),
1478                Err(err) => return Err(Error::Curl(err)),
1479            }
1480            match rename(part_file_path_buf.as_path(), file_path_buf.as_path()) {
1481                Ok(()) => (),
1482                Err(err) => return Err(Error::Io(err)),
1483            }
1484            printer.print_downloading_pkg_file(name, true)?;
1485        },
1486        Err(err) => return Err(Error::Io(err)),
1487    }
1488    Ok(file_path_buf)
1489}
1490
1491/// Extracts the package archive for the specified package.
1492pub fn extract_pkg_file<P: AsRef<Path>, F>(name: &PkgName, version: &Version, work_dir: P, printer: &Arc<dyn Print + Send + Sync>, f: F) -> Result<PathBuf>
1493    where F: FnOnce() -> Result<PathBuf>
1494{
1495    let part_path_buf = pkg_part_dir(work_dir.as_ref(), name, version);
1496    let path_buf = pkg_dir(work_dir.as_ref(), name, version);
1497    match fs::metadata(path_buf.as_path()) {
1498        Ok(_) => (),
1499        Err(err) if err.kind() == ErrorKind::NotFound => {
1500            let archive_path_buf = f()?;
1501            printer.print_extracting_pkg_file(name, false);
1502            match recursively_remove(part_path_buf.as_path(), true) {
1503                Ok(()) => (),
1504                Err(err) => return Err(Error::Io(err)),
1505            }
1506            match create_dir_all(part_path_buf.as_path()) {
1507                Ok(()) => (),
1508                Err(err) => return Err(Error::Io(err)),
1509            }
1510            if archive_path_buf.to_string_lossy().into_owned().ends_with(".zip") {
1511                match File::open(archive_path_buf) {
1512                    Ok(file) => {
1513                        let mut r = BufReader::new(file); 
1514                        let mut archive = match ZipArchive::new(&mut r) {
1515                            Ok(tmp_archive) => tmp_archive,
1516                            Err(err) => return Err(Error::Zip(Box::new(err))),
1517                        };
1518                        match archive.extract(part_path_buf.as_path()) {
1519                            Ok(()) => (),
1520                            Err(err) => return Err(Error::Zip(Box::new(err))),
1521                        }
1522                    },
1523                    Err(err) => return Err(Error::Io(err)),
1524                }
1525            } else if archive_path_buf.to_string_lossy().into_owned().ends_with(".tar.gz") {
1526                match File::open(archive_path_buf) {
1527                    Ok(file) => {
1528                        let mut r = BufReader::new(file); 
1529                        let mut decoder = GzDecoder::new(&mut r);
1530                        let mut archive = tar::Archive::new(&mut decoder);
1531                        match archive.unpack(part_path_buf.as_path()) {
1532                            Ok(()) => (),
1533                            Err(err) => return Err(Error::Io(err)),
1534                        }
1535                    },
1536                    Err(err) => return Err(Error::Io(err)),
1537                }
1538            } else if archive_path_buf.to_string_lossy().into_owned().ends_with(".tar.bz2") {
1539                match File::open(archive_path_buf) {
1540                    Ok(file) => {
1541                        let mut r = BufReader::new(file); 
1542                        let mut decoder = BzDecoder::new(&mut r);
1543                        let mut archive = tar::Archive::new(&mut decoder);
1544                        match archive.unpack(part_path_buf.as_path()) {
1545                            Ok(()) => (),
1546                            Err(err) => return Err(Error::Io(err)),
1547                        }
1548                    },
1549                    Err(err) => return Err(Error::Io(err)),
1550                }
1551            } else if archive_path_buf.to_string_lossy().into_owned().ends_with(".tar.xz") {
1552                match File::open(archive_path_buf) {
1553                    Ok(file) => {
1554                        let mut r = BufReader::new(file); 
1555                        let mut decoder = XzDecoder::new(&mut r);
1556                        let mut archive = tar::Archive::new(&mut decoder);
1557                        match archive.unpack(part_path_buf.as_path()) {
1558                            Ok(()) => (),
1559                            Err(err) => return Err(Error::Io(err)),
1560                        }
1561                    },
1562                    Err(err) => return Err(Error::Io(err)),
1563                }
1564            } else {
1565                match File::open(archive_path_buf) {
1566                    Ok(file) => {
1567                        let mut r = BufReader::new(file); 
1568                        let mut archive = tar::Archive::new(&mut r);
1569                        match archive.unpack(part_path_buf.as_path()) {
1570                            Ok(()) => (),
1571                            Err(err) => return Err(Error::Io(err)),
1572                        }
1573                    },
1574                    Err(err) => return Err(Error::Io(err)),
1575                }
1576            }
1577            match rename(part_path_buf.as_path(), path_buf.as_path()) {
1578                Ok(()) => (),
1579                Err(err) => return Err(Error::Io(err)),
1580            }
1581            printer.print_extracting_pkg_file(name, true);
1582        },
1583        Err(err) => return Err(Error::Io(err)),
1584    }
1585    match only_one_dir_in_dir(path_buf.as_path()) {
1586        Ok(Some(only_one_dir)) => Ok(only_one_dir),
1587        Ok(None) => Ok(path_buf),
1588        Err(err) => Err(Error::Io(err)),
1589    }
1590}
1591
1592/// A structure of custom source.
1593///
1594/// The custom source is defined by an user. The user can specify the package versions and how to
1595/// get a package.
1596#[derive(Clone)]
1597pub struct CustomSrc
1598{
1599    name: PkgName,
1600    home_dir: PathBuf,
1601    work_dir: PathBuf,
1602    version_src_infos: Arc<BTreeMap<Version, VersionSrcInfo>>,
1603    printer: Arc<dyn Print + Send + Sync>,
1604    versions: Arc<BTreeSet<Version>>,
1605    current_version: Option<Version>,
1606    dir: Option<PathBuf>,
1607}
1608
1609impl CustomSrc
1610{
1611    /// Creates a custom source.
1612    pub fn new(name: PkgName, home_dir: PathBuf, work_dir: PathBuf, version_src_infos: Arc<BTreeMap<Version, VersionSrcInfo>>, printer: Arc<dyn Print + Send + Sync>) -> Self
1613    {
1614        let versions: Arc<BTreeSet<Version>> = Arc::new(version_src_infos.keys().map(|v| v.clone()).collect()); 
1615        CustomSrc {
1616            name,
1617            home_dir,
1618            work_dir,
1619            version_src_infos,
1620            printer,
1621            versions,
1622            current_version: None,
1623            dir: None,
1624        }
1625    }
1626    
1627    /// Returns the package name.
1628    pub fn name(&self) -> &PkgName
1629    { &self.name }
1630
1631    /// Returns the path to the Unlab-gpu home directory.
1632    pub fn home_dir(&self) -> &Path
1633    { self.home_dir.as_path() }
1634
1635    /// Returns the path to the work directory of current package.
1636    pub fn work_dir(&self) -> &Path
1637    { self.work_dir.as_path() }
1638
1639    /// Returns the source informations of versions.
1640    pub fn version_src_infos(&self) -> &Arc<BTreeMap<Version, VersionSrcInfo>>
1641    { &self.version_src_infos }
1642
1643    /// Returns the printer.
1644    pub fn printer(&self) -> &Arc<dyn Print + Send + Sync>
1645    { &self.printer }
1646
1647    /// Returns the current package version.
1648    pub fn current_version(&self) -> Option<&Version>
1649    { 
1650        match &self.current_version {
1651            Some(current_version) => Some(current_version),
1652            None => None,
1653        }
1654    }
1655}
1656
1657impl Source for CustomSrc
1658{
1659    fn update(&mut self) -> Result<()>
1660    { Ok(()) }
1661    
1662    fn versions(&mut self) -> Result<&BTreeSet<Version>>
1663    { Ok(&self.versions) }
1664    
1665    fn set_current_version(&mut self, version: Version)
1666    { self.current_version = Some(version); }
1667    
1668    fn dir(&mut self) -> Result<&Path>
1669    {
1670        if self.dir.is_none() {
1671            match &self.current_version {
1672                Some(current_version) => {
1673                    match self.version_src_infos.get(current_version) {
1674                        Some(version_src_info) => {
1675                            self.dir = match version_src_info {
1676                                VersionSrcInfo::Dir(tmp_dir) => Some(PathBuf::from(tmp_dir.replace('/', path::MAIN_SEPARATOR_STR))),
1677                                VersionSrcInfo::File(file) => Some(extract_pkg_file(&self.name, current_version, &self.work_dir, &self.printer, || Ok(PathBuf::from(file.replace('/', path::MAIN_SEPARATOR_STR))))?),
1678                                VersionSrcInfo::Url(url) => {
1679                                    Some(extract_pkg_file(&self.name, current_version, &self.work_dir, &self.printer, || {
1680                                            download_pkg_file(&self.name, &None, current_version, url, &self.home_dir, &self.printer)
1681                                    })?)
1682                                },
1683                            };
1684                        },
1685                        None => return Err(Error::PkgName(self.name.clone(), String::from("not found version"))),
1686                    }
1687                },
1688                None => return Err(Error::PkgName(self.name.clone(), String::from("no current version"))),
1689            }
1690        }
1691        Ok(self.dir.as_ref().unwrap().as_path())
1692    }
1693}
1694
1695#[derive(Clone, Debug)]
1696struct Pkg
1697{
1698    dir: Option<PathBuf>,
1699    info_dir: Option<PathBuf>,
1700    new_part_info_dir: Option<PathBuf>,
1701    is_added_by_dependent: bool,
1702    has_new_version_from_bucket: bool,
1703}
1704
1705impl Pkg
1706{
1707    fn new() -> Self
1708    {
1709        Pkg {
1710            dir: Some(PathBuf::from(".")),
1711            info_dir: None,
1712            new_part_info_dir: None,
1713            is_added_by_dependent: false,
1714            has_new_version_from_bucket: true,
1715        }
1716    }
1717
1718    fn io_res_copy_info_files(dir: &Option<PathBuf>, info_dir: &PathBuf, new_part_info_dir: &PathBuf) -> io::Result<()>
1719    {
1720        create_dir_all(new_part_info_dir)?;
1721        match dir {
1722            Some(dir) => {
1723                let mut src_manifest_file = dir.clone();
1724                src_manifest_file.push("Unlab.toml");
1725                let mut dst_manifest_file = new_part_info_dir.clone();
1726                dst_manifest_file.push("manifest.toml");
1727                copy(src_manifest_file, dst_manifest_file)?;
1728            },
1729            None => (),
1730        }
1731        let mut src_dependents_file = info_dir.clone();
1732        src_dependents_file.push("dependents.toml");
1733        let mut dst_dependents_file = new_part_info_dir.clone();
1734        dst_dependents_file.push("dependents.toml");
1735        match fs::metadata(dst_dependents_file.as_path()) {
1736            Ok(_) => (),
1737            Err(err) if err.kind() == ErrorKind::NotFound => {
1738                match copy(src_dependents_file.as_path(), dst_dependents_file.as_path()) {
1739                    Ok(_) => (),
1740                    Err(err) if err.kind() == ErrorKind::NotFound => {
1741                        let _res = File::create(dst_dependents_file)?;
1742                    },
1743                    Err(err) => return Err(err),
1744                }
1745            },
1746            Err(err) => return Err(err),
1747        }
1748        Ok(())
1749    }
1750
1751    fn copy_info_files(dir: &Option<PathBuf>, info_dir: &PathBuf, new_part_info_dir: &PathBuf) -> Result<()>
1752    {
1753        match Self::io_res_copy_info_files(dir, info_dir, new_part_info_dir) {
1754            Ok(()) => Ok(()),
1755            Err(err) => Err(Error::Io(err)),
1756        }
1757    }
1758    
1759    fn new_with_copying_and_flags(dir: Option<PathBuf>, info_dir: PathBuf, new_part_info_dir: PathBuf, is_added_by_dependent: bool, is_new_version_from_bucket: bool) -> Result<Self>
1760    {
1761        Self::copy_info_files(&dir, &info_dir, &new_part_info_dir)?;
1762        Ok(Pkg {
1763                dir,
1764                info_dir: Some(info_dir),
1765                new_part_info_dir: Some(new_part_info_dir),
1766                is_added_by_dependent,
1767                has_new_version_from_bucket: is_new_version_from_bucket,
1768        })
1769    }
1770
1771    fn new_with_copying(dir: Option<PathBuf>, info_dir: PathBuf, new_part_info_dir: PathBuf) -> Result<Self>
1772    { Self::new_with_copying_and_flags(dir, info_dir, new_part_info_dir, false, true) }
1773
1774    fn new_without_copying_with_flags(info_dir: PathBuf, is_added_by_dependent: bool, is_new_version_from_bucket: bool) -> Self
1775    {
1776        Pkg {
1777            dir: None,
1778            info_dir: Some(info_dir),
1779            new_part_info_dir: None,
1780            is_added_by_dependent,
1781            has_new_version_from_bucket: is_new_version_from_bucket,
1782        }
1783    }
1784
1785    fn new_without_copying(info_dir: PathBuf) -> Self
1786    { Self::new_without_copying_with_flags(info_dir, false, true) }
1787    
1788    fn old_manifest(&self) -> Result<Option<Manifest>>
1789    {
1790        match &self.new_part_info_dir {
1791            Some(new_part_info_dir) => {
1792                match &self.info_dir {
1793                    Some(info_dir) => {
1794                        let mut new_manifest_file = new_part_info_dir.clone();
1795                        new_manifest_file.push("manifest.toml");
1796                        let is_new_manifest = match fs::metadata(new_manifest_file) {
1797                            Ok(_) => true,
1798                            Err(err) if err.kind() == ErrorKind::NotFound => false,
1799                            Err(err) => return Err(Error::Io(err)),
1800                        };
1801                        if is_new_manifest {
1802                            let mut old_manifest_file = info_dir.clone();
1803                            old_manifest_file.push("manifest.toml");
1804                            match Manifest::load(old_manifest_file) {
1805                                Ok(tmp_old_manifest) => Ok(Some(tmp_old_manifest)),
1806                                Err(Error::Io(io_err)) if io_err.kind() == ErrorKind::NotFound => Ok(None),
1807                                Err(err) => Err(err),
1808                            }
1809                        } else {
1810                            Ok(None)
1811                        }
1812                    },
1813                    None => Ok(None),
1814                }
1815            },
1816            None => Ok(None),
1817        }
1818    }
1819
1820    fn manifest(&self) -> Result<Manifest>
1821    {
1822        let mut manifest = match &self.new_part_info_dir {
1823            Some(new_part_info_dir) => {
1824                let mut manifest_file = new_part_info_dir.clone();
1825                manifest_file.push("manifest.toml");
1826                Manifest::load_opt(manifest_file)?
1827            },
1828            None => None
1829        };
1830        if manifest.is_none() {
1831            manifest = match &self.info_dir {
1832                Some(info_dir) => {
1833                    let mut manifest_file = info_dir.clone();
1834                    manifest_file.push("manifest.toml");
1835                    Manifest::load_opt(manifest_file)?
1836                },
1837                None => None,
1838            };
1839        }
1840        if manifest.is_none() {
1841            match &self.dir {
1842                Some(dir) => {
1843                    let mut manifest_file = dir.clone();
1844                    manifest_file.push("Unlab.toml");
1845                    match Manifest::load_opt(manifest_file)? {
1846                        Some(manifest) => Ok(manifest),
1847                        None => Err(Error::Pkg(String::from("no manifest file"))),
1848                    }
1849                },
1850                None => Err(Error::Pkg(String::from("no manifest file"))),
1851            }
1852        } else {
1853            match manifest {
1854                Some(manifest) => Ok(manifest),
1855                None => Err(Error::Pkg(String::from("no manifest file"))),
1856            }
1857        }
1858    }
1859
1860    fn dependents(&self) -> Result<HashMap<PkgName, VersionReq>>
1861    {
1862        match &self.new_part_info_dir {
1863            Some(new_part_info_dir) => {
1864                let mut dependents_file = new_part_info_dir.clone();
1865                dependents_file.push("dependents.toml");
1866                load_version_reqs_or_empty(dependents_file)
1867            },
1868            None => Ok(HashMap::new()),
1869        }
1870    }
1871
1872    fn save_dependents(&self, dependents: &HashMap<PkgName, VersionReq>) -> Result<()>
1873    {
1874        match &self.new_part_info_dir {
1875            Some(new_part_info_dir) => {
1876                let mut dependents_file = new_part_info_dir.clone();
1877                dependents_file.push("dependents.toml");
1878                save_version_reqs(dependents_file, dependents)
1879            },
1880            None => Ok(()),
1881        }
1882    }
1883
1884    fn is_to_install(&self) -> Result<bool>
1885    {
1886        match &self.new_part_info_dir {
1887            Some(new_part_info_dir) => {
1888                let mut manifest_file = new_part_info_dir.clone();
1889                manifest_file.push("manifest.toml");
1890                match fs::metadata(manifest_file) {
1891                    Ok(_) => Ok(true),
1892                    Err(err) if err.kind() == ErrorKind::NotFound => Ok(false),
1893                    Err(err) => Err(Error::Io(err)),
1894                }
1895            },
1896            None => Ok(false),
1897        }
1898    }
1899}
1900
1901fn db_tx(db: &DB, writable: bool) -> Result<Tx<'_>>
1902{
1903    match db.tx(writable) {
1904        Ok(tx) => Ok(tx),
1905        Err(err) => Err(Error::Jammdb(Box::new(err))),
1906    }
1907}
1908
1909fn tx_get_or_create_bucket<'b, 'tx, T: ToBytes<'tx>>(tx: &'b Tx<'tx>, name: T) -> Result<Bucket<'b, 'tx>>
1910{
1911    match tx.get_or_create_bucket(name) {
1912        Ok(bucket) => Ok(bucket),
1913        Err(err) => Err(Error::Jammdb(Box::new(err))),
1914    }
1915}
1916
1917/// Returns the factories of default sources.
1918pub fn default_src_factories() -> Vec<Arc<dyn SourceCreate + Send + Sync>>
1919{
1920    vec![
1921        Arc::new(github::GitHubSrcFactory::new()),
1922        Arc::new(gitlab::GitLabSrcFactory::new()),
1923        Arc::new(bitbucket::BitbucketSrcFactory::new())
1924    ]
1925}
1926
1927fn tx_delete_bucket<'tx, T: ToBytes<'tx>>(tx: &Tx<'tx>, name: T) -> Result<()>
1928{
1929    match tx.delete_bucket(name) {
1930        Ok(()) => Ok(()),
1931        Err(err) => Err(Error::Jammdb(Box::new(err))),
1932    }
1933}
1934
1935fn tx_commit<'tx>(tx: Tx<'tx>) -> Result<()>
1936{
1937    match tx.commit() {
1938        Ok(()) => Ok(()),
1939        Err(err) => Err(Error::Jammdb(Box::new(err))),
1940    }
1941}
1942
1943fn bucket_put<'a, 'b, 'tx, T: ToBytes<'tx>, S: ToBytes<'tx>>(bucket: &'a Bucket<'b, 'tx>, key: T, value: S) -> Result<Option<KVPair<'b, 'tx>>>
1944{
1945    match bucket.put(key, value) {
1946        Ok(kv_pair) => Ok(kv_pair),
1947        Err(err) => Err(Error::Jammdb(Box::new(err))),
1948    }
1949}
1950
1951fn max_pkg_version(versions: &BTreeSet<Version>, version_req: Option<&VersionReq>, constraint: Option<&VersionReq>, locked_version: Option<&Version>) -> Option<Version>
1952{
1953    let mut version_reqs: Vec<&VersionReq> = Vec::new();
1954    match version_req {
1955        Some(version_req) => version_reqs.push(version_req),
1956        None => (),
1957    }
1958    match constraint {
1959        Some(constraint) => version_reqs.push(constraint),
1960        None => (),
1961    }
1962    match locked_version {
1963        Some(locked_version) => {
1964            match versions.get(locked_version) {
1965                Some(version) if version_reqs.iter().all(|r| r.matches(version)) => return Some(version.clone()),
1966                _ => (),
1967            }
1968        },
1969        None => (),
1970    }
1971    let mut max_version: Option<Version> = None;
1972    for version in versions {
1973        if version_reqs.iter().all(|r| r.matches(version)) {
1974            max_version = Some(version.clone());
1975        }
1976    }
1977    max_version
1978}
1979
1980fn check_dir(path: &Path, err_msg: &str) -> Result<()>
1981{
1982    match fs::metadata(path) {
1983        Ok(metadata) if metadata.is_dir() => Ok(()),
1984        Ok(_) => Err(Error::Pkg(String::from(err_msg))),
1985        Err(err) if err.kind() == ErrorKind::NotFound => Ok(()),
1986        Err(err) => Err(Error::Io(err)),
1987    }
1988}
1989
1990fn check_dir_for_pkg(path: &Path, name: &PkgName, err_msg: &str) -> Result<()>
1991{
1992    match fs::metadata(path) {
1993        Ok(metadata) if metadata.is_dir() => Ok(()),
1994        Ok(_) => Err(Error::PkgName(name.clone(), String::from(err_msg))),
1995        Err(err) if err.kind() == ErrorKind::NotFound => Ok(()),
1996        Err(err) => Err(Error::Io(err)),
1997    }
1998}
1999
2000/// A structure of package manager.
2001///
2002/// The package manager is used to install packages and remove package. Default sources can be
2003/// used to download and extract the packages by the package manager. The package manager
2004/// installs the packages to the Unlab-gpu home directory by default where they are available
2005/// for a user. Also, the packages can be installed as dependencies of current package by
2006/// default.
2007#[derive(Clone)]
2008pub struct PkgManager
2009{
2010    pkg_db: DB,
2011    home_dir: PathBuf,
2012    work_dir: PathBuf,
2013    bin_dir: PathBuf,
2014    lib_dir: PathBuf,
2015    doc_dir: PathBuf,
2016    pkgs: HashMap<PkgName, Pkg>,
2017    locks: HashMap<PkgName, Version>,
2018    constraints: Arc<HashMap<PkgName, VersionReq>>,
2019    sources: Arc<HashMap<PkgName, SrcInfo>>,
2020    src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>,
2021    printer: Arc<dyn Print + Send + Sync>,
2022}
2023
2024impl PkgManager
2025{
2026    /// Creates a package manager.
2027    ///
2028    /// This method takes paths to the Unlab-gpu home directory, the work directory, the binary
2029    /// dirtectory, the library directory, and the documentation directory. The factories of
2030    /// default soruces which allows to access to the package. Also, this method takes the
2031    /// printer that prints messages. If the packages isn't installed as the dependencies for
2032    /// the current package, the path of work directory should be the path to the the Unlab-gpu
2033    /// home directory.
2034    pub fn new(home_dir: PathBuf, work_dir: PathBuf, bin_dir: PathBuf, lib_dir: PathBuf, doc_dir: PathBuf, src_factories: Vec<Arc<dyn SourceCreate + Send + Sync>>, printer: Arc<dyn Print + Send + Sync>) -> Result<Self>
2035    {
2036        let mut work_var_dir = work_dir.clone();
2037        work_var_dir.push("var");
2038        match create_dir_all(work_var_dir.as_path()) {
2039            Ok(()) => (),
2040            Err(err) => return Err(Error::Io(err)),
2041        }
2042        let mut pkg_db_file = work_var_dir.clone();
2043        pkg_db_file.push("pkg.db");
2044        let pkg_db = match DB::open(pkg_db_file) {
2045            Ok(tmp_pkg_db) => tmp_pkg_db,
2046            Err(err) => return Err(Error::Jammdb(Box::new(err))),
2047        };
2048        Ok(PkgManager {
2049                pkg_db,
2050                home_dir,
2051                work_dir,
2052                bin_dir,
2053                lib_dir,
2054                doc_dir,
2055                pkgs: HashMap::new(),
2056                locks: HashMap::new(),
2057                constraints: Arc::new(HashMap::new()),
2058                sources: Arc::new(HashMap::new()),
2059                src_factories,
2060                printer,
2061        })
2062    }
2063    
2064    /// Returns the path to the Unlab-gpu home directory.
2065    pub fn home_dir(&self) -> &Path
2066    { self.home_dir.as_path() }
2067
2068    /// Returns the path to the work directory of current package.
2069    pub fn work_dir(&self) -> &Path
2070    { self.work_dir.as_path() }
2071
2072    /// Returns the path to the binary directory.
2073    pub fn bin_dir(&self) -> &Path
2074    { self.bin_dir.as_path() }
2075
2076    /// Returns the path to the library directory.
2077    pub fn lib_dir(&self) -> &Path
2078    { self.lib_dir.as_path() }
2079    
2080    /// Returns the path to the documentation directory.
2081    pub fn doc_dir(&self) -> &Path
2082    { self.doc_dir.as_path() }
2083
2084    /// Returns the locked versions of packages
2085    pub fn locks(&self) -> &HashMap<PkgName, Version>
2086    { &self.locks }
2087
2088    /// Sets the locked versions of packages.
2089    pub fn set_locks(&mut self, locks: HashMap<PkgName, Version>)
2090    { self.locks = locks; }
2091
2092    /// Loads the locked versions of packages.
2093    pub fn load_locks(&mut self) -> Result<()>
2094    {
2095        self.locks = load_versions_or_empty("Unlab.lock")?;
2096        Ok(())
2097    }
2098
2099    /// Saves the locked versions of packages.
2100    pub fn save_locks(&self) -> Result<()>
2101    { save_versions("Unlab.lock", &self.locks) }
2102    
2103    /// Saves the locked version packages from the database.
2104    pub fn save_locks_from_pkg_versions(&self) -> Result<()>
2105    {
2106        let mut locks: HashMap<PkgName, Version> = HashMap::new();
2107        self.pkg_versions_for_bucket_in("versions", |name, version| {
2108                locks.insert(name.clone(), version.clone());
2109                Ok(())
2110        })?;
2111        save_versions("Unlab.lock", &locks)
2112    }
2113    
2114    /// Returns the constraints.
2115    pub fn constraints(&self) -> &Arc<HashMap<PkgName, VersionReq>>
2116    { &self.constraints }
2117
2118    /// Sets the constraints.
2119    pub fn set_constraints(&mut self, constraints: Arc<HashMap<PkgName, VersionReq>>)
2120    { self.constraints = constraints; }
2121
2122    /// Loads the constraints.
2123    pub fn load_constraints(&mut self) -> Result<()>
2124    {
2125        self.constraints = Arc::new(load_version_reqs_or_empty(self.constraints_file())?);
2126        Ok(())
2127    }
2128    
2129    /// Returns the custom sources.
2130    pub fn sources(&self) -> &Arc<HashMap<PkgName, SrcInfo>>
2131    { &self.sources }
2132
2133    /// Sets the custom sources.
2134    pub fn set_sources(&mut self, sources: Arc<HashMap<PkgName, SrcInfo>>)
2135    { self.sources = sources; }
2136
2137    /// Loads the custom sources.
2138    pub fn load_sources(&mut self) -> Result<()>
2139    {
2140        self.sources = Arc::new(load_src_infos_or_empty(self.sources_file())?);
2141        Ok(())
2142    }
2143
2144    /// Returns the factories of sources.
2145    pub fn src_factories(&self) -> &[Arc<dyn SourceCreate + Send + Sync>]
2146    { self.src_factories.as_slice() }
2147
2148    /// Returns the printer.
2149    pub fn printer(&self) -> &Arc<dyn Print + Send + Sync>
2150    { &self.printer }
2151    
2152    /// Loads the manifest of current package.
2153    pub fn manifest() -> Result<Manifest>
2154    {
2155        match Manifest::load_opt("Unlab.toml")? {
2156            Some(manifest) => Ok(manifest),
2157            None => Err(Error::Pkg(String::from("no manifest in current package"))), 
2158        }
2159    }
2160
2161    /// Saves the manifest of current package.
2162    pub fn save_manifest(manifest: &Manifest) -> Result<()>
2163    { manifest.save("Unlab.toml") }
2164    
2165    /// Resets the package manager.
2166    pub fn reset(&mut self)
2167    { self.pkgs.clear(); }
2168    
2169    /// Returns the path to the constraints.
2170    pub fn constraints_file(&self) -> PathBuf
2171    {
2172        let mut file = self.home_dir.clone();
2173        file.push("constraints.toml");
2174        file
2175    }
2176
2177    /// Returns the path to the custom sources.
2178    pub fn sources_file(&self) -> PathBuf
2179    {
2180        let mut file = self.home_dir.clone();
2181        file.push("sources.toml");
2182        file
2183    }
2184    
2185    /// Returns the path to the variable directory in the work directory.
2186    pub fn work_var_dir(&self) -> PathBuf
2187    {
2188        let mut dir = self.work_dir.clone();
2189        dir.push("var");
2190        dir
2191    }    
2192
2193    /// Returns the path to the temporary directory in the work directory.
2194    pub fn work_tmp_dir(&self) -> PathBuf
2195    {
2196        let mut dir = self.work_dir.clone();
2197        dir.push("tmp");
2198        dir
2199    }    
2200    
2201    /// Returns the path to the information directory.
2202    pub fn info_dir(&self) -> PathBuf
2203    {
2204        let mut dir = self.work_var_dir();
2205        dir.push("info");
2206        dir
2207    }
2208
2209    /// Returns the path to the information directory while pre-installing.
2210    pub fn new_part_info_dir(&self) -> PathBuf
2211    {
2212        let mut dir = self.work_var_dir();
2213        dir.push("info.new.part");
2214        dir
2215    }
2216    
2217    /// Returns the path to the information directory while installing.
2218    pub fn new_info_dir(&self) -> PathBuf
2219    {
2220        let mut dir = self.work_var_dir();
2221        dir.push("info.new");
2222        dir
2223    }
2224
2225    /// Returns the path to the information directory for the specified package.
2226    pub fn pkg_info_dir(&self, name: &PkgName) -> PathBuf
2227    {
2228        let mut dir = self.info_dir();
2229        dir.push(name.to_path_buf());
2230        dir
2231    }
2232
2233    /// Returns the path to the information directory while pre-installing for the specified
2234    /// package.
2235    pub fn pkg_new_part_info_dir(&self, name: &PkgName) -> PathBuf
2236    {
2237        let mut dir = self.new_part_info_dir();
2238        dir.push(name.to_path_buf());
2239        dir
2240    }
2241    
2242    /// Returns the path to the information directory while installing for the specified package.
2243    pub fn pkg_new_info_dir(&self, name: &PkgName) -> PathBuf
2244    {
2245        let mut dir = self.new_info_dir();
2246        dir.push(name.to_path_buf());
2247        dir
2248    }
2249    
2250    /// Returns the path to the documentation directory in the temporary directory for the
2251    /// specified package.
2252    pub fn pkg_tmp_doc_dir(&self, name: &PkgName, version: &Version) -> PathBuf
2253    {
2254        let mut dir = self.work_tmp_dir();
2255        dir.push(name.to_path_buf());
2256        dir.push(format!("{}", version));
2257        dir.push("doc");
2258        dir
2259    }
2260    
2261    /// Creates a source for the specified package.
2262    pub fn create_source(&self, name: &PkgName) -> Result<Box<dyn Source + Send + Sync>>
2263    {
2264        match self.sources.get(name) {
2265            Some(src_info) => {
2266                match src_info {
2267                    SrcInfo::Renamed(old_name) => {
2268                        for src_factory in &self.src_factories {
2269                            match src_factory.create(name.clone(), Some(old_name.clone()), self.home_dir.clone(), self.work_dir.clone(), self.printer.clone()) {
2270                                Some(src) => return Ok(src),
2271                                None => (),
2272                            }
2273                        }
2274                        Err(Error::PkgName(name.clone(), String::from("unrecognized source for renamed package")))
2275                    },
2276                    SrcInfo::Versions(version_src_infos) => Ok(Box::new(CustomSrc::new(name.clone(), self.home_dir.clone(), self.work_dir.clone(), version_src_infos.clone(), self.printer.clone()))),
2277                }
2278            },
2279            None => {
2280                for src_factory in &self.src_factories {
2281                    match src_factory.create(name.clone(), None, self.home_dir.clone(), self.work_dir.clone(), self.printer.clone()) {
2282                        Some(src) => return Ok(src),
2283                        None => (),
2284                    }
2285                }
2286                Err(Error::PkgName(name.clone(), String::from("unrecognized source for package")))
2287            },
2288        }
2289    }
2290    
2291    fn has_bucket(&self, bucket_name: &str) -> Result<bool>
2292    {
2293        let tx = db_tx(&self.pkg_db, false)?;
2294        match tx.get_bucket(bucket_name) {
2295            Ok(_) => Ok(true),
2296            Err(jammdb::Error::BucketMissing) => Ok(false),
2297            Err(err) => Err(Error::Jammdb(Box::new(err))),
2298        }
2299    }
2300
2301    fn remove_bucket(&self, bucket_name: &str) -> Result<()>
2302    {
2303        let tx = db_tx(&self.pkg_db, true)?;
2304        match tx.delete_bucket(bucket_name) {
2305            Ok(()) => (),
2306            Err(jammdb::Error::BucketMissing) => (),
2307            Err(err) => return Err(Error::Jammdb(Box::new(err))),
2308        }
2309        tx_commit(tx)?;
2310        Ok(())
2311    }
2312    
2313    fn pkg_versions_for_bucket(&self, bucket_name: &str) -> Result<Vec<(PkgName, Version)>>
2314    {
2315        let tx = db_tx(&self.pkg_db, false)?;
2316        match tx.get_bucket(bucket_name) {
2317            Ok(version_bucket) => {
2318                let mut pairs: Vec<(PkgName, Version)> = Vec::new();
2319                for data in version_bucket.cursor() {
2320                    let name = match String::from_utf8(data.kv().key().to_vec()) {
2321                        Ok(s) => PkgName::parse(s.as_str())?,
2322                        Err(_) => return Err(Error::Pkg(format!("invalid package name data"))),
2323                    };
2324                    let version = match String::from_utf8(data.kv().value().to_vec()) {
2325                        Ok(s) => Version::parse(s.as_str())?,
2326                        Err(_) => return Err(Error::Pkg(format!("invalid version data"))),
2327                    };
2328                    pairs.push((name, version));
2329                }
2330                Ok(pairs)
2331            },
2332            Err(jammdb::Error::BucketMissing) => Ok(Vec::new()),
2333            Err(err) => Err(Error::Jammdb(Box::new(err))),
2334        }
2335    }
2336
2337    fn pkg_versions_for_bucket_in<F>(&self, bucket_name: &str, mut f: F) -> Result<()>
2338        where F: FnMut(&PkgName, &Version) -> Result<()>
2339    {
2340        let tx = db_tx(&self.pkg_db, false)?;
2341        match tx.get_bucket(bucket_name) {
2342            Ok(version_bucket) => {
2343                for data in version_bucket.cursor() {
2344                    let name = match String::from_utf8(data.kv().key().to_vec()) {
2345                        Ok(s) => PkgName::parse(s.as_str())?,
2346                        Err(_) => return Err(Error::Pkg(format!("invalid package name data"))),
2347                    };
2348                    let version = match String::from_utf8(data.kv().value().to_vec()) {
2349                        Ok(s) => Version::parse(s.as_str())?,
2350                        Err(_) => return Err(Error::Pkg(format!("invalid version data"))),
2351                    };
2352                    f(&name, &version)?;
2353                }
2354                Ok(())
2355            },
2356            Err(jammdb::Error::BucketMissing) => Ok(()),
2357            Err(err) => Err(Error::Jammdb(Box::new(err))),
2358        }
2359    }
2360    
2361    fn pkg_version_for_bucket(&self, bucket_name: &str, name: &PkgName) -> Result<Option<Version>>
2362    {
2363        let tx = db_tx(&self.pkg_db, false)?;
2364        match tx.get_bucket(bucket_name) {
2365            Ok(version_bucket) => {
2366                match version_bucket.get(name.name()) {
2367                    Some(data) => {
2368                        match String::from_utf8(data.kv().value().to_vec()) {
2369                            Ok(s) => Ok(Some(Version::parse(s.as_str())?)),
2370                            Err(_) => Err(Error::Pkg(format!("invalid version data"))),
2371                        }
2372                    },
2373                    None => Ok(None),
2374                }
2375            },
2376            Err(jammdb::Error::BucketMissing) => Ok(None),
2377            Err(err) => Err(Error::Jammdb(Box::new(err))),
2378        }
2379    }
2380
2381    fn add_pkg_version_for_bucket(&self, bucket_name: &str, name: &PkgName, version: &Version) -> Result<()>
2382    {
2383        let tx = db_tx(&self.pkg_db, true)?;
2384        let version_bucket = tx_get_or_create_bucket(&tx, bucket_name)?;
2385        bucket_put(&version_bucket, name.name(), format!("{}", version))?;
2386        tx_commit(tx)?;
2387        Ok(())
2388    }
2389    
2390    fn move_pkg_versions_for_buckets(&self, src_bucket_name: &str, dst_bucket_name: &str) -> Result<()>
2391    { 
2392        let tx = db_tx(&self.pkg_db, true)?;
2393        {
2394            let src_version_bucket = match tx.get_bucket(src_bucket_name) {
2395                Ok(tmp_src_version_bucket) => tmp_src_version_bucket,
2396                Err(jammdb::Error::BucketMissing) => return Ok(()),
2397                Err(err) => return Err(Error::Jammdb(Box::new(err))),
2398            };
2399            let dst_version_bucket = tx_get_or_create_bucket(&tx, dst_bucket_name)?;
2400            for data in src_version_bucket.cursor() {
2401                bucket_put(&dst_version_bucket, data.kv().key().to_vec(), data.kv().value().to_vec())?;
2402            }
2403        }
2404        tx_delete_bucket(&tx, src_bucket_name)?;
2405        tx_commit(tx)?;
2406        Ok(())
2407    }
2408
2409    fn pkg_names_for_bucket(&self, bucket_name: &str) -> Result<Vec<PkgName>>
2410    {
2411        let tx = db_tx(&self.pkg_db, false)?;
2412        match tx.get_bucket(bucket_name) {
2413            Ok(version_bucket) => {
2414                let mut names: Vec<PkgName> = Vec::new();
2415                for data in version_bucket.cursor() {
2416                    let name = match String::from_utf8(data.kv().key().to_vec()) {
2417                        Ok(s) => PkgName::parse(s.as_str())?,
2418                        Err(_) => return Err(Error::Pkg(format!("invalid package name data"))),
2419                    };
2420                    names.push(name);
2421                }
2422                Ok(names)
2423            },
2424            Err(jammdb::Error::BucketMissing) => Ok(Vec::new()),
2425            Err(err) => Err(Error::Jammdb(Box::new(err))),
2426        }
2427    }
2428
2429    fn has_pkg_names_for_bucket(&self, bucket_name: &str, name: &PkgName) -> Result<bool>
2430    {
2431        let tx = db_tx(&self.pkg_db, false)?;
2432        match tx.get_bucket(bucket_name) {
2433            Ok(name_bucket) => {
2434                match name_bucket.get(name.name()) {
2435                    Some(_) => Ok(true),
2436                    None => Ok(false),
2437                }
2438            },
2439            Err(jammdb::Error::BucketMissing) => Ok(false),
2440            Err(err) => Err(Error::Jammdb(Box::new(err))),
2441        }
2442    }
2443    
2444    fn add_pkg_names_for_bucket(&self, bucket_name: &str, name: &PkgName) -> Result<()>
2445    {
2446        let tx = db_tx(&self.pkg_db, true)?;
2447        let name_bucket = tx_get_or_create_bucket(&tx, bucket_name)?;
2448        bucket_put(&name_bucket, name.name(), "t")?;
2449        tx_commit(tx)?;
2450        Ok(())
2451    }
2452
2453    fn add_pkg_names_for_bucket_and_removing(&self, bucket_name: &str, names: &[PkgName]) -> Result<()>
2454    {
2455        let tx = db_tx(&self.pkg_db, true)?;
2456        let name_bucket = tx_get_or_create_bucket(&tx, bucket_name)?;
2457        for name in names {
2458            let mut dependents_file = self.pkg_info_dir(&name);
2459            dependents_file.push("dependents.toml");
2460            let dependents = load_opt_version_reqs(dependents_file)?;
2461            match dependents {
2462                Some(dependents) => {
2463                    if dependents.is_empty() {
2464                        bucket_put(&name_bucket, name.name(), "t")?;
2465                    } else {
2466                        return Err(Error::PkgName(name.clone(), String::from("can't remove package")));
2467                    }
2468                },
2469                None => return Err(Error::PkgName(name.clone(), String::from("package isn't installed"))),
2470            }
2471        }
2472        tx_commit(tx)?;
2473        Ok(())
2474    }    
2475
2476    fn add_pkg_names_for_buckets_and_autoremoving(&self, bucket_name: &str, version_bucket_name: &str, visiteds: &HashSet<PkgName>) -> Result<()>
2477    {
2478        let tx = db_tx(&self.pkg_db, true)?;
2479        {
2480            let version_bucket = match tx.get_bucket(version_bucket_name) {
2481                Ok(tmp_version_bucket) => tmp_version_bucket,
2482                Err(jammdb::Error::BucketMissing) => return Ok(()),
2483                Err(err) => return Err(Error::Jammdb(Box::new(err))),
2484            };
2485            let name_bucket = tx_get_or_create_bucket(&tx, bucket_name)?;
2486            for data in version_bucket.cursor() {
2487                let name = match String::from_utf8(data.kv().key().to_vec()) {
2488                    Ok(s) => PkgName::parse(s.as_str())?,
2489                    Err(_) => return Err(Error::Pkg(format!("invalid package name data"))),
2490                };
2491                if !visiteds.contains(&name) {
2492                    bucket_put(&name_bucket, data.kv().key().to_vec(), "t")?;
2493                }
2494            }
2495        }
2496        tx_commit(tx)?;
2497        Ok(())
2498    }    
2499    
2500    fn remove_pkg_versions_for_buckets(&self, removal_bucket_name: &str, bucket_name: &str) -> Result<()>
2501    { 
2502        let tx = db_tx(&self.pkg_db, true)?;
2503        {
2504            let removal_bucket = match tx.get_bucket(removal_bucket_name) {
2505                Ok(tmp_removal_bucket) => tmp_removal_bucket,
2506                Err(jammdb::Error::BucketMissing) => return Ok(()),
2507                Err(err) => return Err(Error::Jammdb(Box::new(err))),
2508            };
2509            let version_bucket = tx_get_or_create_bucket(&tx, bucket_name)?;
2510            for data in removal_bucket.cursor() {
2511                match version_bucket.delete(data.kv().key()) {
2512                    Ok(_) => (),
2513                    Err(err) => return Err(Error::Jammdb(Box::new(err))),
2514                }
2515            }
2516        }
2517        tx_delete_bucket(&tx, removal_bucket_name)?;
2518        tx_commit(tx)?;
2519        Ok(())
2520    }
2521    
2522    /// Returns the package versions.
2523    pub fn pkg_versions(&self) -> Result<Vec<(PkgName, Version)>>
2524    { self.pkg_versions_for_bucket("versions") }
2525
2526    /// Calls the function for each package version.
2527    pub fn pkg_versions_in<F>(&self, f: F) -> Result<()>
2528        where F: FnMut(&PkgName, &Version) -> Result<()>
2529    { self.pkg_versions_for_bucket_in("versions", f) }
2530
2531    /// Returns the package version if the package is installed, otherwise `None`.
2532    pub fn pkg_version(&self, name: &PkgName) -> Result<Option<Version>>
2533    { self.pkg_version_for_bucket("versions", name) }
2534    
2535    /// Returns the package manifest if the package is installed, otherwise `None`.
2536    pub fn pkg_manifest(&self, name: &PkgName) -> Result<Option<Manifest>>
2537    {
2538        let mut manifest_file = self.pkg_info_dir(name);
2539        manifest_file.push("manifest.toml");
2540        Manifest::load_opt(manifest_file)
2541    }
2542
2543    /// Returns the package dependents if the package is installed, otherwise `None`.
2544    pub fn pkg_dependents(&self, name: &PkgName) -> Result<Option<HashMap<PkgName, VersionReq>>>
2545    {
2546        let mut dependents_file = self.pkg_info_dir(name);
2547        dependents_file.push("dependents.toml");
2548        load_opt_version_reqs(dependents_file)
2549    }
2550
2551    /// Returns the package paths if the package is installed, otherwise `None`.
2552    pub fn pkg_paths(&self, name: &PkgName) -> Result<Option<Paths>>
2553    {
2554        let mut paths_file = self.pkg_info_dir(name);
2555        paths_file.push("paths.toml");
2556        Paths::load_opt(paths_file)
2557    }    
2558        
2559    fn io_res_remove_dirs_for_cleaning(&self) -> io::Result<()>
2560    {
2561        recursively_remove(self.work_tmp_dir(), true)?;
2562        recursively_remove(self.new_part_info_dir(), true)?;
2563        Ok(())
2564    }
2565    
2566    fn clean_after_error(&self) -> Result<()>
2567    {
2568        self.printer.print_cleaning_after_error(false);
2569        self.remove_bucket("new_versions")?;
2570        self.remove_bucket("pkgs_to_remove")?;
2571        self.remove_bucket("pkgs_to_change")?;
2572        match self.io_res_remove_dirs_for_cleaning() {
2573            Ok(()) => (),
2574            Err(err) => return Err(Error::Io(err)),
2575        }
2576        self.printer.print_cleaning_after_error(true);
2577        Ok(())
2578    }
2579
2580    fn new_pkg_version_for_pre_installing(&mut self, name: &PkgName) -> Result<Option<Version>>
2581    {
2582        let is_new_version_from_bucket = match self.pkgs.get_mut(name) {
2583            Some(pkg) => {
2584                let tmp_is_new_version_from_bucket = pkg.has_new_version_from_bucket;
2585                pkg.has_new_version_from_bucket = true;
2586                tmp_is_new_version_from_bucket
2587            },
2588            None => true,
2589        };
2590        if is_new_version_from_bucket {
2591            self.pkg_version_for_bucket("new_versions", name)
2592        } else {
2593            Ok(None)
2594        }
2595    }
2596    
2597    fn prepare_new_infos_for_pre_installing_without_reset(&mut self, name: &PkgName, visiteds: &mut HashSet<PkgName>, is_update: bool, is_force: bool) -> Result<()>
2598    {
2599        if visiteds.contains(name) {
2600            return Ok(());
2601        }
2602        let res = dfs(name, visiteds, self, |name, data| {
2603                let pkg = match data.pkgs.get(name) {
2604                    Some(tmp_pkg) if !tmp_pkg.is_added_by_dependent => tmp_pkg.clone(),
2605                    _ => {
2606                        let mut src = data.create_source(name)?;
2607                        let old_version = data.pkg_version_for_bucket("versions", name)?;
2608                        let new_version_from_bucket = data.new_pkg_version_for_pre_installing(name)?;
2609                        let new_version = match &new_version_from_bucket {
2610                            Some(tmp_new_version) => Some(tmp_new_version.clone()),
2611                            None => {
2612                                if is_update {
2613                                    src.update()?;
2614                                }
2615                                let versions = src.versions()?;
2616                                let old_dependants = if old_version.is_some() {
2617                                    let mut old_dependents_file = data.pkg_info_dir(name);
2618                                    old_dependents_file.push("dependents.toml");
2619                                    load_version_reqs(old_dependents_file)?
2620                                } else {
2621                                    HashMap::new()
2622                                };
2623                                let mut tmp_new_version: Option<Version> = None; 
2624                                for old_version_req in old_dependants.values() {
2625                                    let max_version = max_pkg_version(&versions, Some(old_version_req), data.constraints.get(name), data.locks.get(name));
2626                                    match &max_version {
2627                                        Some(max_version) => {
2628                                            match &tmp_new_version {
2629                                                Some(tmp_new_version) => {
2630                                                    if tmp_new_version != max_version {
2631                                                        return Err(Error::PkgName(name.clone(), format!("version requirements indicate two different package versions: {}, {}", tmp_new_version, max_version)));
2632                                                    }
2633                                                },
2634                                                None => tmp_new_version = Some(max_version.clone()),
2635                                            }
2636                                        },
2637                                        None => return Err(Error::PkgName(name.clone(), String::from("each package version isn't matched to version requirement"))),
2638                                    }
2639                                }
2640                                match tmp_new_version {
2641                                    Some(tmp_new_version) => Some(tmp_new_version),
2642                                    None => max_pkg_version(&versions, None, data.constraints.get(name), data.locks.get(name)),
2643                                }
2644                            },
2645                        };
2646                        match &new_version {
2647                            Some(new_version) => {
2648                                src.set_current_version(new_version.clone());
2649                                if new_version_from_bucket.is_none() {
2650                                    data.add_pkg_version_for_bucket("new_versions", name, &new_version)?;
2651                                }
2652                                let dir = if is_force || old_version.as_ref().map(|ov| ov != new_version).unwrap_or(true) {
2653                                    Some(PathBuf::from(src.dir()?))
2654                                } else {
2655                                    None
2656                                };
2657                                data.pkgs.insert(name.clone(), Pkg::new_with_copying(dir, data.pkg_info_dir(name), data.pkg_new_part_info_dir(name))?);
2658                                data.pkgs.get(name).unwrap().clone()
2659                            },
2660                            None => return Err(Error::PkgName(name.clone(), String::from("each package version isn't matched to version requirement"))),
2661                        }
2662                    },
2663                };
2664                let manifest = pkg.manifest()?;
2665                match manifest.package.unlab_gpu_version {
2666                    Some(version_req) => {
2667                        let version = Version::parse(env!("CARGO_PKG_VERSION"))?;
2668                        if !version_req.matches(&version) {
2669                            return Err(Error::PkgName(name.clone(), format!("unlab-gpu version {} isn't matched to version requirement {}", version, version_req)));
2670                        }
2671                    },
2672                    None => (),
2673                }
2674                match &manifest.dependencies {
2675                    Some(deps) => {
2676                        for (dep_name, dep_version_req) in deps {
2677                            let mut dep_src = data.create_source(dep_name)?;
2678                            if is_update {
2679                                dep_src.update()?;
2680                            }
2681                            let versions = dep_src.versions()?;
2682                            let max_version = max_pkg_version(&versions, Some(dep_version_req), data.constraints.get(dep_name), data.locks.get(dep_name));
2683                            match &max_version {
2684                                Some(max_version) => {
2685                                    let dep_new_version_from_bucket = data.new_pkg_version_for_pre_installing(dep_name)?;
2686                                    match &dep_new_version_from_bucket {
2687                                        Some(dep_new_version_from_bucket) => {
2688                                            if dep_new_version_from_bucket != max_version {
2689                                                return Err(Error::PkgName(dep_name.clone(), format!("version requirements indicate two different package versions: {}, {}", dep_new_version_from_bucket, max_version)));
2690                                            }
2691                                        },
2692                                        None => data.add_pkg_version_for_bucket("new_versions", dep_name, max_version)?,
2693                                    }
2694                                },
2695                                None => return Err(Error::PkgName(dep_name.clone(), String::from("each package version isn't matched to version requirement"))),
2696                            }
2697                        }
2698                        Ok(deps.keys().map(|dn| dn.clone()).collect())
2699                    },
2700                    None => Ok(Vec::new()),
2701                }
2702        }, |name, data| {
2703                let pkg = match data.pkgs.get(name) {
2704                    Some(tmp_pkg) => tmp_pkg.clone(),
2705                    None => return Err(Error::PkgName(name.clone(), String::from("no package"))),
2706                };
2707                if pkg.is_to_install()? {
2708                    let old_manifest = pkg.old_manifest()?;
2709                    match old_manifest {
2710                        Some(old_manifest) => {
2711                            match &old_manifest.dependencies {
2712                                Some(old_deps) => {
2713                                    for old_dep_name in old_deps.keys() {
2714                                        if data.pkg_version_for_bucket("new_versions", old_dep_name)?.is_none() {
2715                                            match data.pkg_version_for_bucket("versions", old_dep_name)? {
2716                                                Some(version) => {
2717                                                    data.add_pkg_version_for_bucket("new_versions", old_dep_name, &version)?;
2718                                                    data.pkgs.insert(old_dep_name.clone(), Pkg::new_with_copying_and_flags(None, data.pkg_info_dir(old_dep_name), data.pkg_new_part_info_dir(old_dep_name), true, false)?);
2719                                                },
2720                                                None => return Err(Error::PkgName(old_dep_name.clone(), String::from("no package version"))),
2721                                            }
2722                                        }
2723                                        match data.pkgs.get(old_dep_name) {
2724                                            Some(old_dep_pkg) => {
2725                                                let mut depentents = old_dep_pkg.dependents()?;
2726                                                depentents.remove(name);
2727                                                old_dep_pkg.save_dependents(&depentents)?;
2728                                            },
2729                                            None => return Err(Error::PkgName(old_dep_name.clone(), String::from("no package"))),
2730                                        }
2731                                    }
2732                                },
2733                                None => (),
2734                            }
2735                        },
2736                        None => (),
2737                    }
2738                    let manifest = pkg.manifest()?;
2739                    match &manifest.dependencies {
2740                        Some(deps) => {
2741                            for (dep_name, dep_version_req) in deps {
2742                                match data.pkgs.get(dep_name) {
2743                                    Some(dep_pkg) => {
2744                                        let mut depentents = dep_pkg.dependents()?;
2745                                        depentents.insert(name.clone(), dep_version_req.clone());
2746                                        dep_pkg.save_dependents(&depentents)?;
2747                                    },
2748                                    None => return Err(Error::PkgName(dep_name.clone(), String::from("no package"))),
2749                                }
2750                            }
2751                        },
2752                        None => (),
2753                    }
2754                }
2755                Ok(())
2756        })?;
2757        match res {
2758            DfsResult::Success => Ok(()),
2759            DfsResult::Cycle(names) => Err(Error::PkgDepCycle(names)),
2760        }
2761    }
2762
2763    fn prepare_new_infos_for_pre_installing(&mut self, name: &PkgName, visiteds: &mut HashSet<PkgName>, is_update: bool, is_force: bool) -> Result<()>
2764    {
2765        let res = self.prepare_new_infos_for_pre_installing_without_reset(name, visiteds, is_update, is_force);
2766        match res {
2767            Ok(()) => Ok(()),
2768            Err(err) => {
2769                self.pkgs.clear();
2770                self.clean_after_error()?;
2771                Err(err)
2772            },
2773        }
2774    }
2775    
2776    fn check_dependent_version_reqs(&self) -> Result<()>
2777    {
2778        self.printer.print_checking_dependent_version_reqs(false);
2779        let new_versions = self.pkg_versions_for_bucket("new_versions")?;
2780        for (name, new_version) in &new_versions {
2781            match self.pkgs.get(name) {
2782                Some(pkg) => {
2783                    let mut src = self.create_source(name)?;
2784                    let versions = src.versions()?;
2785                    let dependents = pkg.dependents()?;
2786                    for version_req in dependents.values() {
2787                        let max_version = max_pkg_version(&versions, Some(version_req), self.constraints.get(name), self.locks.get(name));
2788                        match &max_version {
2789                            Some(max_version) => {
2790                                if new_version != max_version {
2791                                    return Err(Error::PkgName(name.clone(), format!("version requirements indicate two different package versions: {}, {}", new_version, max_version)));
2792                                }
2793                            },
2794                            None => return Err(Error::PkgName(name.clone(), String::from("each package version isn't matched to version requirement"))),
2795                        }
2796                    }
2797                },
2798                None => return Err(Error::PkgName(name.clone(), String::from("no package"))),
2799            }
2800        }
2801        self.printer.print_checking_dependent_version_reqs(true);
2802        Ok(())
2803    }
2804
2805    fn pkg_is_to_install_for_pre_install(&self, name: &PkgName) -> Result<bool>
2806    {
2807        let mut manifest_file = self.pkg_new_part_info_dir(name);
2808        manifest_file.push("manifest.toml");
2809        match fs::metadata(manifest_file) {
2810            Ok(_) => Ok(true),
2811            Err(err) if err.kind() == ErrorKind::NotFound => Ok(false),
2812            Err(err) => Err(Error::Io(err)),
2813        }
2814    }
2815        
2816    fn search_path_conflicts(&self) -> Result<()>
2817    {
2818        self.printer.print_searching_path_conflicts(false);
2819        check_dir(self.bin_dir.as_path(), "bin isn't directory")?;
2820        check_dir(self.lib_dir.as_path(), "lib isn't directory")?;
2821        check_dir(self.doc_dir.as_path(), "doc isn't directory")?;
2822        let new_versions = self.pkg_versions_for_bucket("new_versions")?;
2823        let mut ignored_bin_paths: HashSet<PathBuf> = HashSet::new();
2824        let mut ignored_lib_paths: HashSet<PathBuf> = HashSet::new();
2825        for (name, _) in &new_versions {
2826            if self.pkg_is_to_install_for_pre_install(name)? {
2827                let mut old_paths_file = self.pkg_info_dir(name);
2828                old_paths_file.push("paths.toml");
2829                match Paths::load_opt(old_paths_file)? {
2830                    Some(paths) => {
2831                        for bin_path in &paths.bin {
2832                            ignored_bin_paths.insert(PathBuf::from(bin_path));
2833                        }
2834                        for lib_path in &paths.lib {
2835                            ignored_lib_paths.insert(PathBuf::from(lib_path));
2836                        }
2837                    },
2838                    None => (),
2839                }
2840            }
2841        }
2842        for (name, new_version) in &new_versions {
2843            if self.pkg_is_to_install_for_pre_install(name)? {
2844                let mut src = self.create_source(name)?;
2845                src.set_current_version(new_version.clone());
2846                let mut pkg_bin_dir = PathBuf::from(src.dir()?);
2847                pkg_bin_dir.push("bin");
2848                check_dir_for_pkg(pkg_bin_dir.as_path(), name, "bin in package isn't directory")?;
2849                let bin_paths = match conflicts(pkg_bin_dir, self.bin_dir.as_path(), &ignored_bin_paths, Some(1)) {
2850                    Ok((conflict_paths, paths)) => {
2851                        if conflict_paths.is_empty() {
2852                            paths
2853                        } else {
2854                            return Err(Error::PkgPathConflicts(name.clone(), None, conflict_paths, PkgPathConflict::Bin));
2855                        }
2856                    },
2857                    Err(err) => return Err(Error::Io(err)),
2858                };
2859                let mut pkg_lib_dir = PathBuf::from(src.dir()?);
2860                pkg_lib_dir.push("lib");
2861                check_dir_for_pkg(pkg_lib_dir.as_path(), name, "lib in package isn't directory")?;
2862                let lib_paths = match conflicts(pkg_lib_dir, self.lib_dir.as_path(), &ignored_lib_paths, Some(2)) {
2863                    Ok((conflict_paths, paths)) => {
2864                        if conflict_paths.is_empty() {
2865                            paths
2866                        } else {
2867                            return Err(Error::PkgPathConflicts(name.clone(), None, conflict_paths, PkgPathConflict::Lib));
2868                        }
2869                    },
2870                    Err(err) => return Err(Error::Io(err)),
2871                };
2872                let mut bin: Vec<String> = Vec::new();
2873                for bin_path in &bin_paths {
2874                    match bin_path.to_str() {
2875                        Some(s) => bin.push(String::from(s)),
2876                        None => return Err(Error::PkgName(name.clone(), String::from("bin path contains invalid UTF-8 character"))),
2877                    }
2878                }
2879                let mut lib: Vec<String> = Vec::new();
2880                for lib_path in &lib_paths {
2881                    match lib_path.to_str() {
2882                        Some(s) => lib.push(String::from(s)),
2883                        None => return Err(Error::PkgName(name.clone(), String::from("lib path contains invalid UTF-8 character"))),
2884                    }
2885                }
2886                let paths = Paths::new(bin, lib);
2887                let mut paths_file = self.pkg_new_part_info_dir(name);
2888                paths_file.push("paths.toml");
2889                paths.save(paths_file)?;
2890            }
2891        }
2892        for (i, (name, new_version)) in new_versions.iter().enumerate() {
2893            for (name2, new_version2) in &new_versions[(i + 1)..] {
2894                if self.pkg_is_to_install_for_pre_install(name)? && self.pkg_is_to_install_for_pre_install(name2)? {
2895                    let mut src = self.create_source(name)?;
2896                    src.set_current_version(new_version.clone());
2897                    let mut src2 = self.create_source(name2)?;
2898                    src2.set_current_version(new_version2.clone());
2899                    let mut pkg_bin_dir = PathBuf::from(src.dir()?);
2900                    pkg_bin_dir.push("bin");
2901                    let mut pkg_bin_dir2 = PathBuf::from(src2.dir()?);
2902                    pkg_bin_dir2.push("bin");
2903                    match conflicts(pkg_bin_dir, pkg_bin_dir2, &HashSet::new(), Some(1)) {
2904                        Ok((conflict_paths, _)) => {
2905                            if !conflict_paths.is_empty() {
2906                                return Err(Error::PkgPathConflicts(name.clone(), Some(name2.clone()), conflict_paths, PkgPathConflict::Bin));
2907                            }
2908                        },
2909                        Err(err) => return Err(Error::Io(err)),
2910                    }
2911                    let mut pkg_lib_dir = PathBuf::from(src.dir()?);
2912                    pkg_lib_dir.push("lib");
2913                    let mut pkg_lib_dir2 = PathBuf::from(src2.dir()?);
2914                    pkg_lib_dir2.push("lib");
2915                    match conflicts(pkg_lib_dir, pkg_lib_dir2, &HashSet::new(), Some(2)) {
2916                        Ok((conflict_paths, _)) => {
2917                            if !conflict_paths.is_empty() {
2918                                return Err(Error::PkgPathConflicts(name.clone(), Some(name2.clone()), conflict_paths, PkgPathConflict::Lib));
2919                            }
2920                        },
2921                        Err(err) => return Err(Error::Io(err)),
2922                    }
2923                }
2924            }
2925        }
2926        self.printer.print_searching_path_conflicts(true);
2927        Ok(())
2928    }
2929
2930    fn generate_pkg_doc(&self, name: &PkgName, new_version: &Version) -> Result<()>
2931    {
2932        if self.pkg_is_to_install_for_pre_install(name)? {
2933            self.printer.print_documenting_pkg(name, false);
2934            let mut src = self.create_source(name)?;
2935            src.set_current_version(new_version.clone());
2936            let doc_dir = self.pkg_tmp_doc_dir(name, &new_version);
2937            let mut paths_file = self.pkg_new_part_info_dir(name);
2938            paths_file.push("paths.toml");
2939            let paths = Paths::load(paths_file)?;
2940            let mut pkg_lib_dir = PathBuf::from(src.dir()?);
2941            pkg_lib_dir.push("lib");
2942            for path in &paths.lib {
2943                let mut lib_doc_dir = doc_dir.clone();
2944                lib_doc_dir.push(path);
2945                match create_dir_all(lib_doc_dir.as_path()) {
2946                    Ok(()) => (),
2947                    Err(err) => return Err(Error::Io(err)),
2948                }
2949                generate_doc(pkg_lib_dir.as_path(), doc_dir.as_path(), path)?;
2950            }
2951            self.printer.print_documenting_pkg(name, true);
2952        }
2953        Ok(())
2954    }
2955    
2956    fn generate_docs(&self) -> Result<()>
2957    {
2958        let new_versions = self.pkg_versions_for_bucket("new_versions")?;
2959        for (name, new_version) in &new_versions {
2960            self.generate_pkg_doc(name, new_version)?;
2961        }
2962        Ok(())
2963    }
2964    
2965    fn check_new_infos_and_generate_docs_for_pre_installing_without_reset(&self, is_doc: bool) -> Result<()>
2966    {
2967        self.check_dependent_version_reqs()?;
2968        self.search_path_conflicts()?;
2969        if is_doc {
2970            self.generate_docs()?;
2971        }
2972        match rename(self.new_part_info_dir(), self.new_info_dir()) {
2973           Ok(()) => Ok(()),
2974           Err(err) if err.kind() == ErrorKind::NotFound => Ok(()),
2975           Err(err) => Err(Error::Io(err)),
2976        }
2977    }
2978
2979    fn check_new_infos_and_generate_docs_for_pre_installing(&mut self, is_doc: bool) -> Result<()>
2980    {
2981        let res = self.check_new_infos_and_generate_docs_for_pre_installing_without_reset(is_doc);
2982        self.pkgs.clear();
2983        match res {
2984            Ok(()) => Ok(()),
2985            Err(err) => {
2986                self.clean_after_error()?;
2987                Err(err)
2988            },
2989        }
2990    }
2991    
2992    fn prepare_new_infos_for_pre_removing_without_reset(&mut self) -> Result<()>
2993    {
2994        let names = self.pkg_names_for_bucket("pkgs_to_remove")?;
2995        for name in &names {
2996            let pkg = Pkg::new_without_copying(self.pkg_info_dir(name));
2997            let manifest = pkg.manifest()?;
2998            match &manifest.dependencies {
2999                Some(deps) => {
3000                    for dep_name in deps.keys() {
3001                        if !self.has_pkg_names_for_bucket("pkgs_to_change", dep_name)? {
3002                            if self.pkg_version_for_bucket("versions", dep_name)?.is_some() {
3003                                self.add_pkg_names_for_bucket("pkgs_to_change", dep_name)?;
3004                                self.pkgs.insert(dep_name.clone(), Pkg::new_with_copying_and_flags(None, self.pkg_info_dir(dep_name), self.pkg_new_part_info_dir(dep_name), true, false)?);
3005                            } else {
3006                                return Err(Error::PkgName(dep_name.clone(), String::from("no package version")));
3007                            }
3008                        }
3009                        match self.pkgs.get(dep_name) {
3010                            Some(dep_pkg) => {
3011                                let mut depentents = dep_pkg.dependents()?;
3012                                depentents.remove(name);
3013                                dep_pkg.save_dependents(&depentents)?;
3014                            },
3015                            None => return Err(Error::PkgName(dep_name.clone(), String::from("no package"))),
3016                        }
3017                    }
3018                },
3019                None => (),
3020            }
3021        }
3022        Ok(())
3023    }
3024
3025    fn prepare_new_infos_for_pre_removing(&mut self) -> Result<()>
3026    {
3027        let res = self.prepare_new_infos_for_pre_removing_without_reset();
3028        self.pkgs.clear();
3029        match res {
3030            Ok(()) => {
3031                match rename(self.new_part_info_dir(), self.new_info_dir()) {
3032                    Ok(()) => Ok(()),
3033                    Err(err) if err.kind() == ErrorKind::NotFound => Ok(()),
3034                    Err(err) => Err(Error::Io(err)),
3035                }
3036            },
3037            Err(err) => {
3038                self.clean_after_error()?;
3039                Err(err)
3040            },
3041        }
3042    }
3043    
3044    fn io_res_install_pkg(&self, name: &PkgName, new_version: &Version, dir: &Path, paths: &Paths, is_doc: bool) -> io::Result<()>
3045    {
3046        let mut src_bin_dir = PathBuf::from(dir);
3047        src_bin_dir.push("bin");
3048        let dst_bin_dir = self.bin_dir.clone();
3049        let bin_paths: Vec<PathBuf> = paths.bin.iter().map(|s| PathBuf::from(s)).collect();
3050        recursively_copy_paths_in_dir(src_bin_dir, dst_bin_dir, bin_paths.as_slice())?;
3051        let mut src_lib_dir = PathBuf::from(dir);
3052        src_lib_dir.push("lib");
3053        let dst_lib_dir = self.lib_dir.clone();
3054        let lib_paths: Vec<PathBuf> = paths.lib.iter().map(|s| PathBuf::from(s)).collect();
3055        recursively_copy_paths_in_dir(src_lib_dir, dst_lib_dir, lib_paths.as_slice())?;
3056        if is_doc {
3057            let src_doc_dir = self.pkg_tmp_doc_dir(name, new_version);
3058            let dst_doc_dir = self.doc_dir.clone();
3059            recursively_copy_paths_in_dir(src_doc_dir, dst_doc_dir, lib_paths.as_slice())?;
3060        }
3061        create_dir_all(self.pkg_info_dir(name))?;
3062        let mut src_manifest_file = self.pkg_new_info_dir(name);
3063        src_manifest_file.push("manifest.toml");
3064        let mut dst_manifest_file = self.pkg_info_dir(name);
3065        dst_manifest_file.push("manifest.toml");
3066        copy(src_manifest_file, dst_manifest_file)?;
3067        let mut src_dependents_file = self.pkg_new_info_dir(name);
3068        src_dependents_file.push("dependents.toml");
3069        let mut dst_dependents_file = self.pkg_info_dir(name);
3070        dst_dependents_file.push("dependents.toml");
3071        copy(src_dependents_file, dst_dependents_file)?;
3072        let mut src_paths_file = self.pkg_new_info_dir(name);
3073        src_paths_file.push("paths.toml");
3074        let mut dst_paths_file = self.pkg_info_dir(name);
3075        dst_paths_file.push("paths.toml");
3076        rename(src_paths_file, dst_paths_file)?;
3077        Ok(())
3078    }
3079
3080    fn io_res_copy_dependents_file(&self, name: &PkgName) -> io::Result<()>
3081    {
3082        create_dir_all(self.pkg_info_dir(name))?;
3083        let mut src_dependents_file = self.pkg_new_info_dir(name);
3084        src_dependents_file.push("dependents.toml");
3085        let mut dst_dependents_file = self.pkg_info_dir(name);
3086        dst_dependents_file.push("dependents.toml");
3087        match copy(src_dependents_file, dst_dependents_file) {
3088            Ok(_) => Ok(()),
3089            Err(err) if err.kind() == ErrorKind::NotFound => Ok(()),
3090            Err(err) => Err(err),
3091        }
3092    }
3093    
3094    fn install_pkg(&self, name: &PkgName, new_version: &Version, is_doc: bool) -> Result<()>
3095    {
3096        let mut paths_file = self.pkg_new_info_dir(name);
3097        paths_file.push("paths.toml");
3098        match Paths::load(paths_file) {
3099            Ok(paths) => {
3100                self.printer.print_installing_pkg(name, false);
3101                let mut src = self.create_source(name)?;
3102                src.set_current_version(new_version.clone());
3103                match self.io_res_install_pkg(name, new_version, src.dir()?, &paths, is_doc) {
3104                    Ok(()) => (),
3105                    Err(err) => return Err(Error::Io(err)),
3106                }
3107                self.printer.print_installing_pkg(name, true);
3108                Ok(())
3109            },
3110            Err(Error::Io(io_err)) if io_err.kind() == ErrorKind::NotFound => {
3111                match self.io_res_copy_dependents_file(name) {
3112                    Ok(()) => Ok(()),
3113                    Err(err) => Err(Error::Io(err)),
3114                }
3115            },
3116            Err(err) => Err(err),
3117        }
3118    }
3119    
3120    fn change_pkg(&self, name: &PkgName) -> Result<()>
3121    {
3122        match self.io_res_copy_dependents_file(name) {
3123            Ok(()) => Ok(()),
3124            Err(err) => Err(Error::Io(err)),
3125        }
3126    }
3127    
3128    fn io_res_remove_pkg(&self, name: &PkgName, paths: &Paths) -> io::Result<()>
3129    {
3130        let bin_dir = self.bin_dir.clone();
3131        let bin_paths: Vec<PathBuf> = paths.bin.iter().map(|s| PathBuf::from(s)).collect();
3132        recursively_remove_paths_in_dir(bin_dir, bin_paths.as_slice(), true)?;
3133        let lib_dir = self.lib_dir.clone();
3134        let lib_paths: Vec<PathBuf> = paths.lib.iter().map(|s| PathBuf::from(s)).collect();
3135        recursively_remove_paths_in_dir(lib_dir, lib_paths.as_slice(), true)?;
3136        let doc_dir = self.doc_dir.clone();
3137        recursively_remove_paths_in_dir(doc_dir, lib_paths.as_slice(), true)?;
3138        let mut manifest_file = self.pkg_info_dir(name);
3139        manifest_file.push("manifest.toml");
3140        recursively_remove(manifest_file, true)?;
3141        let mut dependents_file = self.pkg_info_dir(name);
3142        dependents_file.push("dependents.toml");
3143        recursively_remove(dependents_file, true)?;
3144        let mut paths_file = self.pkg_info_dir(name);
3145        paths_file.push("paths.toml");
3146        recursively_remove(paths_file, true)?;
3147        let mut tmp_suffix_path_buf = name.to_path_buf();
3148        tmp_suffix_path_buf.pop();
3149        while tmp_suffix_path_buf != PathBuf::from("") {
3150            let mut dir_path_buf = self.info_dir();
3151            dir_path_buf.push(tmp_suffix_path_buf.as_path());
3152            match remove_dir(dir_path_buf.as_path()) {
3153                Ok(()) => (),
3154                Err(_) => break,
3155            }
3156            tmp_suffix_path_buf.pop();
3157        }
3158        Ok(())
3159    }
3160
3161    fn remove_pkg(&self, name: &PkgName) -> Result<()>
3162    {
3163        let mut paths_file = self.pkg_info_dir(name);
3164        paths_file.push("paths.toml");
3165        match Paths::load(paths_file) {
3166            Ok(paths) => {
3167                self.printer.print_removing_pkg(name, false);
3168                match self.io_res_remove_pkg(name, &paths) {
3169                    Ok(()) => (),
3170                    Err(err) => return Err(Error::Io(err)),
3171                }
3172                self.printer.print_removing_pkg(name, true);
3173                Ok(())
3174            },
3175            Err(Error::Io(io_err)) if io_err.kind() == ErrorKind::NotFound => Ok(()),
3176            Err(err) => Err(err),
3177        }
3178    }
3179
3180    fn pkg_is_to_install(&self, name: &PkgName) -> Result<bool>
3181    {
3182        let mut paths_file = self.pkg_new_info_dir(name);
3183        paths_file.push("paths.toml");
3184        match fs::metadata(paths_file) {
3185            Ok(_) => Ok(true),
3186            Err(err) if err.kind() == ErrorKind::NotFound => Ok(false),
3187            Err(err) => Err(Error::Io(err)),
3188        }
3189    }
3190
3191    fn install_pkgs(&self, is_doc: bool) -> Result<()>
3192    {
3193        let new_versions = self.pkg_versions_for_bucket("new_versions")?;
3194        for (name, _) in &new_versions {
3195            if self.pkg_is_to_install(name)? {
3196                self.remove_pkg(name)?;
3197            }
3198        }
3199        for (name, new_version) in &new_versions {
3200            self.install_pkg(name, new_version, is_doc)?;
3201        }
3202        self.printer.print_cleaning_after_install(false);
3203        match recursively_remove(self.work_tmp_dir(), true) {
3204            Ok(()) => (),
3205            Err(err) => return Err(Error::Io(err)),
3206        }
3207        self.move_pkg_versions_for_buckets("new_versions", "versions")?;
3208        match recursively_remove(self.new_info_dir(), true) {
3209            Ok(()) => (),
3210            Err(err) => return Err(Error::Io(err)),
3211        }
3212        self.printer.print_cleaning_after_install(true);
3213        Ok(())
3214    }
3215
3216    fn change_pkgs(&self) -> Result<()>
3217    {
3218        let names = self.pkg_names_for_bucket("pkgs_to_change")?;
3219        for name in &names {
3220            self.change_pkg(name)?;
3221        }
3222        self.remove_bucket("pkgs_to_change")?;
3223        self.printer.print_cleaning_before_removal(false);
3224        match recursively_remove(self.new_info_dir(), true) {
3225            Ok(()) => (),
3226            Err(err) => return Err(Error::Io(err)),
3227        }
3228        self.printer.print_cleaning_before_removal(true);
3229        Ok(())
3230    }
3231    
3232    fn remove_pkgs(&self) -> Result<()>
3233    {
3234        let names = self.pkg_names_for_bucket("pkgs_to_remove")?;
3235        for name in &names {
3236            self.remove_pkg(name)?;
3237        }
3238        self.remove_pkg_versions_for_buckets("pkgs_to_remove", "versions")
3239    }
3240    
3241    /// Updates the versions of packages.
3242    pub fn update(&self, names: &[PkgName]) -> Result<()>
3243    {
3244        self.printer.print_updating();
3245        for name in names {
3246            let mut src = self.create_source(name)?;
3247            src.update()?;
3248        }
3249        Ok(())
3250    }
3251    
3252    /// Installs the specified packages with depedencies.
3253    ///
3254    /// This method overwrites the versions of packages if the update flag is set, otherwise
3255    /// the versions of the packages aren't updated. If the force flag is set, the packages with
3256    /// the dependencies are reinstalled. The documentations are installed for the packages if
3257    /// the documentation is set, otherwise the documentation aren't installed.
3258    pub fn install(&mut self, names: &[PkgName], is_update: bool, is_force: bool, is_doc: bool) -> Result<()>
3259    {
3260        self.printer.print_pre_installing();
3261        let mut visiteds: HashSet<PkgName> = HashSet::new();
3262        for name in names {
3263            self.prepare_new_infos_for_pre_installing(name, &mut visiteds, is_update, is_force)?;
3264        }
3265        self.check_new_infos_and_generate_docs_for_pre_installing(is_doc)?;
3266        self.printer.print_installing();
3267        self.install_pkgs(is_doc)?;
3268        Ok(())
3269    }
3270    
3271    /// Installs the dependencies for the current package.
3272    ///
3273    /// The unused packages are automatically removed from the work directory. See also
3274    /// [install](Self::install).
3275    pub fn install_deps(&mut self, is_update: bool, is_force: bool, is_doc: bool) -> Result<()>
3276    {
3277        self.printer.print_pre_installing();
3278        let mut visiteds: HashSet<PkgName> = HashSet::new();
3279        let current_pkg = Pkg::new();
3280        let manifest = current_pkg.manifest()?;
3281        let start_name = manifest.package.name.clone();
3282        self.constraints = manifest.constraints.map(|cs| cs.clone()).unwrap_or(Arc::new(HashMap::new()));
3283        self.sources = manifest.sources.map(|ss| ss.clone()).unwrap_or(Arc::new(HashMap::new()));
3284        self.pkgs.insert(start_name.clone(), current_pkg);
3285        self.prepare_new_infos_for_pre_installing(&start_name, &mut visiteds, is_update, is_force)?;
3286        self.add_pkg_names_for_buckets_and_autoremoving("pkgs_to_remove", "versions", &visiteds)?;
3287        self.check_new_infos_and_generate_docs_for_pre_installing(is_doc)?;
3288        self.printer.print_installing();
3289        self.install_pkgs(is_doc)?;
3290        self.printer.print_removing();
3291        self.remove_pkgs()?;
3292        Ok(())
3293    }
3294    
3295    /// Removes the specified packages.
3296    pub fn remove(&mut self, names: &[PkgName]) -> Result<()>
3297    {
3298        self.printer.print_pre_removing();
3299        self.add_pkg_names_for_bucket_and_removing("pkgs_to_remove", names)?;
3300        self.prepare_new_infos_for_pre_removing()?;
3301        self.printer.print_removing();
3302        self.change_pkgs()?;
3303        self.remove_pkgs()?;
3304        Ok(())
3305    }
3306    
3307    /// Checks whether the preparation to the last operation or the last operations was
3308    /// interrupted.
3309    ///
3310    /// If the preparation to the last operation or the last operation was interrupted, this
3311    /// method returns an error with the appropriate message.
3312    pub fn check_last_op(&self, are_deps: bool) -> Result<()>
3313    {
3314        let is_new_part_info_dir = match fs::metadata(self.new_part_info_dir()) {
3315            Ok(_) => true,
3316            Err(err) if err.kind() == ErrorKind::NotFound => false,
3317            Err(err) => return Err(Error::Io(err)),
3318        };
3319        if is_new_part_info_dir {
3320            if are_deps {
3321                return Err(Error::Pkg(String::from("Preparation to last operation was interrupted. Please call command 'unlab-pkg clean-deps' to clean after preparation.")));
3322            } else {
3323                return Err(Error::Pkg(String::from("Preparation to last operation was interrupted. Please call command 'unlab-pkg clean' to clean after preparation.")));
3324            }
3325        }
3326        let is_new_info_dir = match fs::metadata(self.new_info_dir()) {
3327            Ok(_) => true,
3328            Err(err) if err.kind() == ErrorKind::NotFound => false,
3329            Err(err) => return Err(Error::Io(err)),
3330        };
3331        if (is_new_info_dir && self.has_bucket("new_versions")?) || is_new_info_dir || self.has_bucket("pkgs_to_remove")? {
3332            if are_deps {
3333                return Err(Error::Pkg(String::from("Last operation was interrupted. Please call command 'unlab-pkg continue-deps' to complete last operation.")));
3334            } else {
3335                return Err(Error::Pkg(String::from("Last operation was interrupted. Please call command 'unlab-pkg continue' to complete last operation.")));
3336            }
3337        }
3338        Ok(())
3339    }
3340
3341    /// Continues the interrupted last operation.
3342    pub fn cont(&self, is_doc: bool, are_deps: bool) -> Result<()>
3343    {
3344        let is_new_part_info_dir = match fs::metadata(self.new_part_info_dir()) {
3345            Ok(_) => true,
3346            Err(err) if err.kind() == ErrorKind::NotFound => false,
3347            Err(err) => return Err(Error::Io(err)),
3348        };
3349        if is_new_part_info_dir {
3350            return Ok(());
3351        }
3352        let is_new_info_dir = match fs::metadata(self.new_info_dir()) {
3353            Ok(_) => true,
3354            Err(err) if err.kind() == ErrorKind::NotFound => false,
3355            Err(err) => return Err(Error::Io(err)),
3356        };
3357        if is_new_info_dir && !self.has_bucket("pkgs_to_remove")? {
3358            self.printer.print_installing();
3359            self.install_pkgs(is_doc)?;
3360        } else if is_new_info_dir && (are_deps || !self.has_bucket("pkgs_to_remove")?) {
3361            self.printer.print_installing();
3362            self.printer.print_cleaning_after_install(false);
3363            match recursively_remove(self.new_info_dir(), true) {
3364                Ok(()) => (),
3365                Err(err) => return Err(Error::Io(err)),
3366            }
3367            self.printer.print_cleaning_after_install(true);
3368        }
3369        if self.has_bucket("pkgs_to_remove")? {
3370            self.printer.print_removing();
3371            if !are_deps {
3372                if is_new_info_dir && self.has_bucket("pkgs_to_change")? {
3373                    self.change_pkgs()?;
3374                } else if is_new_info_dir {
3375                    self.printer.print_cleaning_before_removal(false);
3376                    match recursively_remove(self.new_info_dir(), true) {
3377                        Ok(()) => (),
3378                        Err(err) => return Err(Error::Io(err)),
3379                    }
3380                    self.printer.print_cleaning_before_removal(true);
3381                }
3382            }
3383            self.remove_pkgs()?;
3384        }
3385        Ok(())
3386    }
3387
3388    /// Cleans after the interrupted preparation to the last operation.
3389    pub fn clean(&self) -> Result<()>
3390    {
3391        let is_new_part_info_dir = match fs::metadata(self.new_part_info_dir()) {
3392            Ok(_) => true,
3393            Err(err) if err.kind() == ErrorKind::NotFound => false,
3394            Err(err) => return Err(Error::Io(err)),
3395        };
3396        if is_new_part_info_dir {
3397            self.printer.print_cleaning(false);
3398            self.remove_bucket("new_versions")?;
3399            self.remove_bucket("pkgs_to_remove")?;
3400            self.remove_bucket("pkgs_to_change")?;
3401            match self.io_res_remove_dirs_for_cleaning() {
3402                Ok(()) => (),
3403                Err(err) => return Err(Error::Io(err)),
3404            }
3405            self.printer.print_cleaning(true);
3406        }
3407        Ok(())
3408    }
3409    
3410    /// Updates the versions of all packages.
3411    pub fn update_all(&self) -> Result<()>
3412    {
3413        let mut names: Vec<PkgName> = Vec::new();
3414        self.pkg_versions_in(|name, _| {
3415                names.push(name.clone());
3416                Ok(())
3417        })?;
3418        self.update(names.as_slice())
3419    }
3420
3421    /// Reinstalls all packages.
3422    ///
3423    /// See [install](Self::install).
3424    pub fn install_all(&mut self, is_update: bool, is_force: bool, is_doc: bool) -> Result<()>
3425    {
3426        let mut names: Vec<PkgName> = Vec::new();
3427        self.pkg_versions_in(|name, _| {
3428                let dependents = self.pkg_dependents(name)?;
3429                if dependents.map(|ds| ds.is_empty()).unwrap_or(true) {
3430                    names.push(name.clone());
3431                }
3432                Ok(())
3433        })?;
3434        self.install(names.as_slice(), is_update, is_force, is_doc)
3435    }
3436    
3437    fn io_res_remove_pkg_doc(&self, doc_paths: &DocPaths) -> io::Result<()>
3438    {
3439        let doc_paths: Vec<PathBuf> = doc_paths.doc.iter().map(|s| PathBuf::from(s)).collect();
3440        recursively_remove_paths_in_dir(self.doc_dir.as_path(), doc_paths.as_slice(), true)?;
3441        let mut doc_paths_file = self.work_dir.clone();
3442        doc_paths_file.push("doc-paths.toml");
3443        recursively_remove(doc_paths_file, true)?;
3444        Ok(())
3445    }
3446
3447    /// Generates a documentation for the current package.
3448    pub fn generate_doc(&self) -> Result<()>
3449    {
3450        self.printer.print_documenting();
3451        let name = Self::manifest()?.package.name;
3452        let mut doc_paths_file = self.work_var_dir();
3453        doc_paths_file.push("doc-paths.toml");
3454        match DocPaths::load(doc_paths_file) {
3455            Ok(doc_paths) => {
3456                self.printer.print_removing_pkg_doc(&name, false);
3457                match self.io_res_remove_pkg_doc(&doc_paths) {
3458                    Ok(()) => (),
3459                    Err(err) => return Err(Error::Io(err)),
3460                }
3461                self.printer.print_removing_pkg_doc(&name, true);
3462            },
3463            Err(Error::Io(io_err)) if io_err.kind() == ErrorKind::NotFound => (),
3464            Err(err) => return Err(err),
3465        }
3466        {
3467            self.printer.print_searching_path_conflicts(false);
3468            let pkg_lib_dir = PathBuf::from("lib");
3469            check_dir_for_pkg(pkg_lib_dir.as_path(), &name, "lib in package isn't directory")?;
3470            let lib_paths = match conflicts(pkg_lib_dir, self.doc_dir.as_path(), &HashSet::new(), Some(2)) {
3471                Ok((conflict_paths, paths)) => {
3472                    if conflict_paths.is_empty() {
3473                        paths
3474                    } else {
3475                        return Err(Error::PkgPathConflicts(name.clone(), None, conflict_paths, PkgPathConflict::Doc));
3476                    }
3477                },
3478                Err(err) => return Err(Error::Io(err)),
3479            };
3480            let mut doc: Vec<String> = Vec::new();
3481            for lib_path in &lib_paths {
3482                match lib_path.to_str() {
3483                    Some(s) => doc.push(String::from(s)),
3484                    None => return Err(Error::PkgName(name.clone(), String::from("lib path contains invalid UTF-8 character"))),
3485                }
3486            }
3487            let doc_paths = DocPaths::new(doc);
3488            let mut doc_paths_file = self.work_var_dir();
3489            doc_paths_file.push("doc-paths.toml");
3490            doc_paths.save(doc_paths_file)?;
3491            self.printer.print_searching_path_conflicts(true);
3492        }
3493        {
3494            self.printer.print_documenting_pkg(&name, false);
3495            let mut doc_paths_file = self.work_var_dir();
3496            doc_paths_file.push("doc-paths.toml");
3497            let doc_paths = DocPaths::load(doc_paths_file)?;
3498            let pkg_lib_dir = PathBuf::from("lib");
3499            for path in &doc_paths.doc {
3500                let mut lib_doc_dir = self.doc_dir.clone();
3501                lib_doc_dir.push(path);
3502                match create_dir_all(lib_doc_dir.as_path()) {
3503                    Ok(()) => (),
3504                    Err(err) => return Err(Error::Io(err)),
3505                }
3506                generate_doc(pkg_lib_dir.as_path(), self.doc_dir.as_path(), path)?;
3507            }
3508            self.printer.print_documenting_pkg(&name, true);
3509        }
3510        Ok(())
3511    }
3512    
3513    /// Generates a documentation of the standard built-in functions.
3514    pub fn generate_std_doc(&self) -> Result<()>
3515    {
3516        self.printer.print_documenting();
3517        let name = PkgName::new(String::from("std/root"));
3518        let mut doc_path = PathBuf::from("std");
3519        doc_path.push("root");
3520        let mut lib_doc_dir = self.doc_dir.clone();
3521        lib_doc_dir.push(doc_path.as_path());
3522        match fs::metadata(lib_doc_dir.as_path()) {
3523            Ok(_) => {
3524                self.printer.print_removing_pkg_doc(&name, false);
3525                match recursively_remove_paths_in_dir(self.doc_dir.as_path(), &[doc_path.clone()], true) {
3526                    Ok(()) => (),
3527                    Err(err) => return Err(Error::Io(err)),
3528                }
3529                self.printer.print_removing_pkg_doc(&name, true);
3530            },
3531            Err(err) if err.kind() == ErrorKind::NotFound => (),
3532            Err(err) => return Err(Error::Io(err)),
3533        }
3534        {
3535            self.printer.print_documenting_pkg(&name, false);
3536            match create_dir_all(lib_doc_dir.as_path()) {
3537                Ok(()) => (),
3538                Err(err) => return Err(Error::Io(err)),
3539            }
3540            let mut sig_root_mod: ModNode<Sig, ()> = ModNode::new(());
3541            let mut doc_root_mod: ModNode<String, Option<String>> = ModNode::new(None);
3542            add_std_builtin_fun_doc(&mut sig_root_mod, &mut doc_root_mod);
3543            let doc_tree = DocTree::new(Arc::new(RwLock::new(sig_root_mod)), Arc::new(RwLock::new(doc_root_mod)));
3544            let doc_gen = DocGen::new(self.doc_dir.clone(), doc_path);
3545            doc_gen.generate(&doc_tree)?;
3546            self.printer.print_documenting_pkg(&name, true);
3547        }
3548        Ok(())
3549    }
3550}
3551
3552#[cfg(test)]
3553mod tests;