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    { Manifest::load("Unlab.toml") }
2155
2156    /// Saves the manifest of current package.
2157    pub fn save_manifest(manifest: &Manifest) -> Result<()>
2158    { manifest.save("Unlab.toml") }
2159    
2160    /// Resets the package manager.
2161    pub fn reset(&mut self)
2162    { self.pkgs.clear(); }
2163    
2164    /// Returns the path to the constraints.
2165    pub fn constraints_file(&self) -> PathBuf
2166    {
2167        let mut file = self.home_dir.clone();
2168        file.push("constraints.toml");
2169        file
2170    }
2171
2172    /// Returns the path to the custom sources.
2173    pub fn sources_file(&self) -> PathBuf
2174    {
2175        let mut file = self.home_dir.clone();
2176        file.push("sources.toml");
2177        file
2178    }
2179    
2180    /// Returns the path to the variable directory in the work directory.
2181    pub fn work_var_dir(&self) -> PathBuf
2182    {
2183        let mut dir = self.work_dir.clone();
2184        dir.push("var");
2185        dir
2186    }    
2187
2188    /// Returns the path to the temporary directory in the work directory.
2189    pub fn work_tmp_dir(&self) -> PathBuf
2190    {
2191        let mut dir = self.work_dir.clone();
2192        dir.push("tmp");
2193        dir
2194    }    
2195    
2196    /// Returns the path to the information directory.
2197    pub fn info_dir(&self) -> PathBuf
2198    {
2199        let mut dir = self.work_var_dir();
2200        dir.push("info");
2201        dir
2202    }
2203
2204    /// Returns the path to the information directory while pre-installing.
2205    pub fn new_part_info_dir(&self) -> PathBuf
2206    {
2207        let mut dir = self.work_var_dir();
2208        dir.push("info.new.part");
2209        dir
2210    }
2211    
2212    /// Returns the path to the information directory while installing.
2213    pub fn new_info_dir(&self) -> PathBuf
2214    {
2215        let mut dir = self.work_var_dir();
2216        dir.push("info.new");
2217        dir
2218    }
2219
2220    /// Returns the path to the information directory for the specified package.
2221    pub fn pkg_info_dir(&self, name: &PkgName) -> PathBuf
2222    {
2223        let mut dir = self.info_dir();
2224        dir.push(name.to_path_buf());
2225        dir
2226    }
2227
2228    /// Returns the path to the information directory while pre-installing for the specified
2229    /// package.
2230    pub fn pkg_new_part_info_dir(&self, name: &PkgName) -> PathBuf
2231    {
2232        let mut dir = self.new_part_info_dir();
2233        dir.push(name.to_path_buf());
2234        dir
2235    }
2236    
2237    /// Returns the path to the information directory while installing for the specified package.
2238    pub fn pkg_new_info_dir(&self, name: &PkgName) -> PathBuf
2239    {
2240        let mut dir = self.new_info_dir();
2241        dir.push(name.to_path_buf());
2242        dir
2243    }
2244    
2245    /// Returns the path to the documentation directory in the temporary directory for the
2246    /// specified package.
2247    pub fn pkg_tmp_doc_dir(&self, name: &PkgName, version: &Version) -> PathBuf
2248    {
2249        let mut dir = self.work_tmp_dir();
2250        dir.push(name.to_path_buf());
2251        dir.push(format!("{}", version));
2252        dir.push("doc");
2253        dir
2254    }
2255    
2256    /// Creates a source for the specified package.
2257    pub fn create_source(&self, name: &PkgName) -> Result<Box<dyn Source + Send + Sync>>
2258    {
2259        match self.sources.get(name) {
2260            Some(src_info) => {
2261                match src_info {
2262                    SrcInfo::Renamed(old_name) => {
2263                        for src_factory in &self.src_factories {
2264                            match src_factory.create(name.clone(), Some(old_name.clone()), self.home_dir.clone(), self.work_dir.clone(), self.printer.clone()) {
2265                                Some(src) => return Ok(src),
2266                                None => (),
2267                            }
2268                        }
2269                        Err(Error::PkgName(name.clone(), String::from("unrecognized source for renamed package")))
2270                    },
2271                    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()))),
2272                }
2273            },
2274            None => {
2275                for src_factory in &self.src_factories {
2276                    match src_factory.create(name.clone(), None, self.home_dir.clone(), self.work_dir.clone(), self.printer.clone()) {
2277                        Some(src) => return Ok(src),
2278                        None => (),
2279                    }
2280                }
2281                Err(Error::PkgName(name.clone(), String::from("unrecognized source for package")))
2282            },
2283        }
2284    }
2285    
2286    fn has_bucket(&self, bucket_name: &str) -> Result<bool>
2287    {
2288        let tx = db_tx(&self.pkg_db, false)?;
2289        match tx.get_bucket(bucket_name) {
2290            Ok(_) => Ok(true),
2291            Err(jammdb::Error::BucketMissing) => Ok(false),
2292            Err(err) => Err(Error::Jammdb(Box::new(err))),
2293        }
2294    }
2295
2296    fn remove_bucket(&self, bucket_name: &str) -> Result<()>
2297    {
2298        let tx = db_tx(&self.pkg_db, true)?;
2299        match tx.delete_bucket(bucket_name) {
2300            Ok(()) => (),
2301            Err(jammdb::Error::BucketMissing) => (),
2302            Err(err) => return Err(Error::Jammdb(Box::new(err))),
2303        }
2304        tx_commit(tx)?;
2305        Ok(())
2306    }
2307    
2308    fn pkg_versions_for_bucket(&self, bucket_name: &str) -> Result<Vec<(PkgName, Version)>>
2309    {
2310        let tx = db_tx(&self.pkg_db, false)?;
2311        match tx.get_bucket(bucket_name) {
2312            Ok(version_bucket) => {
2313                let mut pairs: Vec<(PkgName, Version)> = Vec::new();
2314                for data in version_bucket.cursor() {
2315                    let name = match String::from_utf8(data.kv().key().to_vec()) {
2316                        Ok(s) => PkgName::parse(s.as_str())?,
2317                        Err(_) => return Err(Error::Pkg(format!("invalid package name data"))),
2318                    };
2319                    let version = match String::from_utf8(data.kv().value().to_vec()) {
2320                        Ok(s) => Version::parse(s.as_str())?,
2321                        Err(_) => return Err(Error::Pkg(format!("invalid version data"))),
2322                    };
2323                    pairs.push((name, version));
2324                }
2325                Ok(pairs)
2326            },
2327            Err(jammdb::Error::BucketMissing) => Ok(Vec::new()),
2328            Err(err) => Err(Error::Jammdb(Box::new(err))),
2329        }
2330    }
2331
2332    fn pkg_versions_for_bucket_in<F>(&self, bucket_name: &str, mut f: F) -> Result<()>
2333        where F: FnMut(&PkgName, &Version) -> Result<()>
2334    {
2335        let tx = db_tx(&self.pkg_db, false)?;
2336        match tx.get_bucket(bucket_name) {
2337            Ok(version_bucket) => {
2338                for data in version_bucket.cursor() {
2339                    let name = match String::from_utf8(data.kv().key().to_vec()) {
2340                        Ok(s) => PkgName::parse(s.as_str())?,
2341                        Err(_) => return Err(Error::Pkg(format!("invalid package name data"))),
2342                    };
2343                    let version = match String::from_utf8(data.kv().value().to_vec()) {
2344                        Ok(s) => Version::parse(s.as_str())?,
2345                        Err(_) => return Err(Error::Pkg(format!("invalid version data"))),
2346                    };
2347                    f(&name, &version)?;
2348                }
2349                Ok(())
2350            },
2351            Err(jammdb::Error::BucketMissing) => Ok(()),
2352            Err(err) => Err(Error::Jammdb(Box::new(err))),
2353        }
2354    }
2355    
2356    fn pkg_version_for_bucket(&self, bucket_name: &str, name: &PkgName) -> Result<Option<Version>>
2357    {
2358        let tx = db_tx(&self.pkg_db, false)?;
2359        match tx.get_bucket(bucket_name) {
2360            Ok(version_bucket) => {
2361                match version_bucket.get(name.name()) {
2362                    Some(data) => {
2363                        match String::from_utf8(data.kv().value().to_vec()) {
2364                            Ok(s) => Ok(Some(Version::parse(s.as_str())?)),
2365                            Err(_) => Err(Error::Pkg(format!("invalid version data"))),
2366                        }
2367                    },
2368                    None => Ok(None),
2369                }
2370            },
2371            Err(jammdb::Error::BucketMissing) => Ok(None),
2372            Err(err) => Err(Error::Jammdb(Box::new(err))),
2373        }
2374    }
2375
2376    fn add_pkg_version_for_bucket(&self, bucket_name: &str, name: &PkgName, version: &Version) -> Result<()>
2377    {
2378        let tx = db_tx(&self.pkg_db, true)?;
2379        let version_bucket = tx_get_or_create_bucket(&tx, bucket_name)?;
2380        bucket_put(&version_bucket, name.name(), format!("{}", version))?;
2381        tx_commit(tx)?;
2382        Ok(())
2383    }
2384    
2385    fn move_pkg_versions_for_buckets(&self, src_bucket_name: &str, dst_bucket_name: &str) -> Result<()>
2386    { 
2387        let tx = db_tx(&self.pkg_db, true)?;
2388        {
2389            let src_version_bucket = match tx.get_bucket(src_bucket_name) {
2390                Ok(tmp_src_version_bucket) => tmp_src_version_bucket,
2391                Err(jammdb::Error::BucketMissing) => return Ok(()),
2392                Err(err) => return Err(Error::Jammdb(Box::new(err))),
2393            };
2394            let dst_version_bucket = tx_get_or_create_bucket(&tx, dst_bucket_name)?;
2395            for data in src_version_bucket.cursor() {
2396                bucket_put(&dst_version_bucket, data.kv().key().to_vec(), data.kv().value().to_vec())?;
2397            }
2398        }
2399        tx_delete_bucket(&tx, src_bucket_name)?;
2400        tx_commit(tx)?;
2401        Ok(())
2402    }
2403
2404    fn pkg_names_for_bucket(&self, bucket_name: &str) -> Result<Vec<PkgName>>
2405    {
2406        let tx = db_tx(&self.pkg_db, false)?;
2407        match tx.get_bucket(bucket_name) {
2408            Ok(version_bucket) => {
2409                let mut names: Vec<PkgName> = Vec::new();
2410                for data in version_bucket.cursor() {
2411                    let name = match String::from_utf8(data.kv().key().to_vec()) {
2412                        Ok(s) => PkgName::parse(s.as_str())?,
2413                        Err(_) => return Err(Error::Pkg(format!("invalid package name data"))),
2414                    };
2415                    names.push(name);
2416                }
2417                Ok(names)
2418            },
2419            Err(jammdb::Error::BucketMissing) => Ok(Vec::new()),
2420            Err(err) => Err(Error::Jammdb(Box::new(err))),
2421        }
2422    }
2423
2424    fn has_pkg_names_for_bucket(&self, bucket_name: &str, name: &PkgName) -> Result<bool>
2425    {
2426        let tx = db_tx(&self.pkg_db, false)?;
2427        match tx.get_bucket(bucket_name) {
2428            Ok(name_bucket) => {
2429                match name_bucket.get(name.name()) {
2430                    Some(_) => Ok(true),
2431                    None => Ok(false),
2432                }
2433            },
2434            Err(jammdb::Error::BucketMissing) => Ok(false),
2435            Err(err) => Err(Error::Jammdb(Box::new(err))),
2436        }
2437    }
2438    
2439    fn add_pkg_names_for_bucket(&self, bucket_name: &str, name: &PkgName) -> Result<()>
2440    {
2441        let tx = db_tx(&self.pkg_db, true)?;
2442        let name_bucket = tx_get_or_create_bucket(&tx, bucket_name)?;
2443        bucket_put(&name_bucket, name.name(), "t")?;
2444        tx_commit(tx)?;
2445        Ok(())
2446    }
2447
2448    fn add_pkg_names_for_bucket_and_removing(&self, bucket_name: &str, names: &[PkgName]) -> Result<()>
2449    {
2450        let tx = db_tx(&self.pkg_db, true)?;
2451        let name_bucket = tx_get_or_create_bucket(&tx, bucket_name)?;
2452        for name in names {
2453            let mut dependents_file = self.pkg_info_dir(&name);
2454            dependents_file.push("dependents.toml");
2455            let dependents = load_opt_version_reqs(dependents_file)?;
2456            match dependents {
2457                Some(dependents) => {
2458                    if dependents.is_empty() {
2459                        bucket_put(&name_bucket, name.name(), "t")?;
2460                    } else {
2461                        return Err(Error::PkgName(name.clone(), String::from("can't remove package")));
2462                    }
2463                },
2464                None => return Err(Error::PkgName(name.clone(), String::from("package isn't installed"))),
2465            }
2466        }
2467        tx_commit(tx)?;
2468        Ok(())
2469    }    
2470
2471    fn add_pkg_names_for_buckets_and_autoremoving(&self, bucket_name: &str, version_bucket_name: &str, visiteds: &HashSet<PkgName>) -> Result<()>
2472    {
2473        let tx = db_tx(&self.pkg_db, true)?;
2474        {
2475            let version_bucket = match tx.get_bucket(version_bucket_name) {
2476                Ok(tmp_version_bucket) => tmp_version_bucket,
2477                Err(jammdb::Error::BucketMissing) => return Ok(()),
2478                Err(err) => return Err(Error::Jammdb(Box::new(err))),
2479            };
2480            let name_bucket = tx_get_or_create_bucket(&tx, bucket_name)?;
2481            for data in version_bucket.cursor() {
2482                let name = match String::from_utf8(data.kv().key().to_vec()) {
2483                    Ok(s) => PkgName::parse(s.as_str())?,
2484                    Err(_) => return Err(Error::Pkg(format!("invalid package name data"))),
2485                };
2486                if !visiteds.contains(&name) {
2487                    bucket_put(&name_bucket, data.kv().key().to_vec(), "t")?;
2488                }
2489            }
2490        }
2491        tx_commit(tx)?;
2492        Ok(())
2493    }    
2494    
2495    fn remove_pkg_versions_for_buckets(&self, removal_bucket_name: &str, bucket_name: &str) -> Result<()>
2496    { 
2497        let tx = db_tx(&self.pkg_db, true)?;
2498        {
2499            let removal_bucket = match tx.get_bucket(removal_bucket_name) {
2500                Ok(tmp_removal_bucket) => tmp_removal_bucket,
2501                Err(jammdb::Error::BucketMissing) => return Ok(()),
2502                Err(err) => return Err(Error::Jammdb(Box::new(err))),
2503            };
2504            let version_bucket = tx_get_or_create_bucket(&tx, bucket_name)?;
2505            for data in removal_bucket.cursor() {
2506                match version_bucket.delete(data.kv().key()) {
2507                    Ok(_) => (),
2508                    Err(err) => return Err(Error::Jammdb(Box::new(err))),
2509                }
2510            }
2511        }
2512        tx_delete_bucket(&tx, removal_bucket_name)?;
2513        tx_commit(tx)?;
2514        Ok(())
2515    }
2516    
2517    /// Returns the package versions.
2518    pub fn pkg_versions(&self) -> Result<Vec<(PkgName, Version)>>
2519    { self.pkg_versions_for_bucket("versions") }
2520
2521    /// Calls the function for each package version.
2522    pub fn pkg_versions_in<F>(&self, f: F) -> Result<()>
2523        where F: FnMut(&PkgName, &Version) -> Result<()>
2524    { self.pkg_versions_for_bucket_in("versions", f) }
2525
2526    /// Returns the package version if the package is installed, otherwise `None`.
2527    pub fn pkg_version(&self, name: &PkgName) -> Result<Option<Version>>
2528    { self.pkg_version_for_bucket("versions", name) }
2529    
2530    /// Returns the package manifest if the package is installed, otherwise `None`.
2531    pub fn pkg_manifest(&self, name: &PkgName) -> Result<Option<Manifest>>
2532    {
2533        let mut manifest_file = self.pkg_info_dir(name);
2534        manifest_file.push("manifest.toml");
2535        Manifest::load_opt(manifest_file)
2536    }
2537
2538    /// Returns the package dependents if the package is installed, otherwise `None`.
2539    pub fn pkg_dependents(&self, name: &PkgName) -> Result<Option<HashMap<PkgName, VersionReq>>>
2540    {
2541        let mut dependents_file = self.pkg_info_dir(name);
2542        dependents_file.push("dependents.toml");
2543        load_opt_version_reqs(dependents_file)
2544    }
2545
2546    /// Returns the package paths if the package is installed, otherwise `None`.
2547    pub fn pkg_paths(&self, name: &PkgName) -> Result<Option<Paths>>
2548    {
2549        let mut paths_file = self.pkg_info_dir(name);
2550        paths_file.push("paths.toml");
2551        Paths::load_opt(paths_file)
2552    }    
2553        
2554    fn io_res_remove_dirs_for_cleaning(&self) -> io::Result<()>
2555    {
2556        recursively_remove(self.work_tmp_dir(), true)?;
2557        recursively_remove(self.new_part_info_dir(), true)?;
2558        Ok(())
2559    }
2560    
2561    fn clean_after_error(&self) -> Result<()>
2562    {
2563        self.printer.print_cleaning_after_error(false);
2564        self.remove_bucket("new_versions")?;
2565        self.remove_bucket("pkgs_to_remove")?;
2566        self.remove_bucket("pkgs_to_change")?;
2567        match self.io_res_remove_dirs_for_cleaning() {
2568            Ok(()) => (),
2569            Err(err) => return Err(Error::Io(err)),
2570        }
2571        self.printer.print_cleaning_after_error(true);
2572        Ok(())
2573    }
2574
2575    fn new_pkg_version_for_pre_installing(&mut self, name: &PkgName) -> Result<Option<Version>>
2576    {
2577        let is_new_version_from_bucket = match self.pkgs.get_mut(name) {
2578            Some(pkg) => {
2579                let tmp_is_new_version_from_bucket = pkg.has_new_version_from_bucket;
2580                pkg.has_new_version_from_bucket = true;
2581                tmp_is_new_version_from_bucket
2582            },
2583            None => true,
2584        };
2585        if is_new_version_from_bucket {
2586            self.pkg_version_for_bucket("new_versions", name)
2587        } else {
2588            Ok(None)
2589        }
2590    }
2591    
2592    fn prepare_new_infos_for_pre_installing_without_reset(&mut self, name: &PkgName, visiteds: &mut HashSet<PkgName>, is_update: bool, is_force: bool) -> Result<()>
2593    {
2594        if visiteds.contains(name) {
2595            return Ok(());
2596        }
2597        let res = dfs(name, visiteds, self, |name, data| {
2598                let pkg = match data.pkgs.get(name) {
2599                    Some(tmp_pkg) if !tmp_pkg.is_added_by_dependent => tmp_pkg.clone(),
2600                    _ => {
2601                        let mut src = data.create_source(name)?;
2602                        let old_version = data.pkg_version_for_bucket("versions", name)?;
2603                        let new_version_from_bucket = data.new_pkg_version_for_pre_installing(name)?;
2604                        let new_version = match &new_version_from_bucket {
2605                            Some(tmp_new_version) => Some(tmp_new_version.clone()),
2606                            None => {
2607                                if is_update {
2608                                    src.update()?;
2609                                }
2610                                let versions = src.versions()?;
2611                                let old_dependants = if old_version.is_some() {
2612                                    let mut old_dependents_file = data.pkg_info_dir(name);
2613                                    old_dependents_file.push("dependents.toml");
2614                                    load_version_reqs(old_dependents_file)?
2615                                } else {
2616                                    HashMap::new()
2617                                };
2618                                let mut tmp_new_version: Option<Version> = None; 
2619                                for old_version_req in old_dependants.values() {
2620                                    let max_version = max_pkg_version(&versions, Some(old_version_req), data.constraints.get(name), data.locks.get(name));
2621                                    match &max_version {
2622                                        Some(max_version) => {
2623                                            match &tmp_new_version {
2624                                                Some(tmp_new_version) => {
2625                                                    if tmp_new_version != max_version {
2626                                                        return Err(Error::PkgName(name.clone(), format!("version requirements indicate two different package versions: {}, {}", tmp_new_version, max_version)));
2627                                                    }
2628                                                },
2629                                                None => tmp_new_version = Some(max_version.clone()),
2630                                            }
2631                                        },
2632                                        None => return Err(Error::PkgName(name.clone(), String::from("each package version isn't matched to version requirement"))),
2633                                    }
2634                                }
2635                                match tmp_new_version {
2636                                    Some(tmp_new_version) => Some(tmp_new_version),
2637                                    None => max_pkg_version(&versions, None, data.constraints.get(name), data.locks.get(name)),
2638                                }
2639                            },
2640                        };
2641                        match &new_version {
2642                            Some(new_version) => {
2643                                src.set_current_version(new_version.clone());
2644                                if new_version_from_bucket.is_none() {
2645                                    data.add_pkg_version_for_bucket("new_versions", name, &new_version)?;
2646                                }
2647                                let dir = if is_force || old_version.as_ref().map(|ov| ov != new_version).unwrap_or(true) {
2648                                    Some(PathBuf::from(src.dir()?))
2649                                } else {
2650                                    None
2651                                };
2652                                data.pkgs.insert(name.clone(), Pkg::new_with_copying(dir, data.pkg_info_dir(name), data.pkg_new_part_info_dir(name))?);
2653                                data.pkgs.get(name).unwrap().clone()
2654                            },
2655                            None => return Err(Error::PkgName(name.clone(), String::from("each package version isn't matched to version requirement"))),
2656                        }
2657                    },
2658                };
2659                let manifest = pkg.manifest()?;
2660                match manifest.package.unlab_gpu_version {
2661                    Some(version_req) => {
2662                        let version = Version::parse(env!("CARGO_PKG_VERSION"))?;
2663                        if !version_req.matches(&version) {
2664                            return Err(Error::PkgName(name.clone(), format!("unlab-gpu version {} isn't matched to version requirement {}", version, version_req)));
2665                        }
2666                    },
2667                    None => (),
2668                }
2669                match &manifest.dependencies {
2670                    Some(deps) => {
2671                        for (dep_name, dep_version_req) in deps {
2672                            let mut dep_src = data.create_source(dep_name)?;
2673                            if is_update {
2674                                dep_src.update()?;
2675                            }
2676                            let versions = dep_src.versions()?;
2677                            let max_version = max_pkg_version(&versions, Some(dep_version_req), data.constraints.get(dep_name), data.locks.get(dep_name));
2678                            match &max_version {
2679                                Some(max_version) => {
2680                                    let dep_new_version_from_bucket = data.new_pkg_version_for_pre_installing(dep_name)?;
2681                                    match &dep_new_version_from_bucket {
2682                                        Some(dep_new_version_from_bucket) => {
2683                                            if dep_new_version_from_bucket != max_version {
2684                                                return Err(Error::PkgName(dep_name.clone(), format!("version requirements indicate two different package versions: {}, {}", dep_new_version_from_bucket, max_version)));
2685                                            }
2686                                        },
2687                                        None => data.add_pkg_version_for_bucket("new_versions", dep_name, max_version)?,
2688                                    }
2689                                },
2690                                None => return Err(Error::PkgName(dep_name.clone(), String::from("each package version isn't matched to version requirement"))),
2691                            }
2692                        }
2693                        Ok(deps.keys().map(|dn| dn.clone()).collect())
2694                    },
2695                    None => Ok(Vec::new()),
2696                }
2697        }, |name, data| {
2698                let pkg = match data.pkgs.get(name) {
2699                    Some(tmp_pkg) => tmp_pkg.clone(),
2700                    None => return Err(Error::PkgName(name.clone(), String::from("no package"))),
2701                };
2702                if pkg.is_to_install()? {
2703                    let old_manifest = pkg.old_manifest()?;
2704                    match old_manifest {
2705                        Some(old_manifest) => {
2706                            match &old_manifest.dependencies {
2707                                Some(old_deps) => {
2708                                    for old_dep_name in old_deps.keys() {
2709                                        if data.pkg_version_for_bucket("new_versions", old_dep_name)?.is_none() {
2710                                            match data.pkg_version_for_bucket("versions", old_dep_name)? {
2711                                                Some(version) => {
2712                                                    data.add_pkg_version_for_bucket("new_versions", old_dep_name, &version)?;
2713                                                    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)?);
2714                                                },
2715                                                None => return Err(Error::PkgName(old_dep_name.clone(), String::from("no package version"))),
2716                                            }
2717                                        }
2718                                        match data.pkgs.get(old_dep_name) {
2719                                            Some(old_dep_pkg) => {
2720                                                let mut depentents = old_dep_pkg.dependents()?;
2721                                                depentents.remove(name);
2722                                                old_dep_pkg.save_dependents(&depentents)?;
2723                                            },
2724                                            None => return Err(Error::PkgName(old_dep_name.clone(), String::from("no package"))),
2725                                        }
2726                                    }
2727                                },
2728                                None => (),
2729                            }
2730                        },
2731                        None => (),
2732                    }
2733                    let manifest = pkg.manifest()?;
2734                    match &manifest.dependencies {
2735                        Some(deps) => {
2736                            for (dep_name, dep_version_req) in deps {
2737                                match data.pkgs.get(dep_name) {
2738                                    Some(dep_pkg) => {
2739                                        let mut depentents = dep_pkg.dependents()?;
2740                                        depentents.insert(name.clone(), dep_version_req.clone());
2741                                        dep_pkg.save_dependents(&depentents)?;
2742                                    },
2743                                    None => return Err(Error::PkgName(dep_name.clone(), String::from("no package"))),
2744                                }
2745                            }
2746                        },
2747                        None => (),
2748                    }
2749                }
2750                Ok(())
2751        })?;
2752        match res {
2753            DfsResult::Success => Ok(()),
2754            DfsResult::Cycle(names) => Err(Error::PkgDepCycle(names)),
2755        }
2756    }
2757
2758    fn prepare_new_infos_for_pre_installing(&mut self, name: &PkgName, visiteds: &mut HashSet<PkgName>, is_update: bool, is_force: bool) -> Result<()>
2759    {
2760        let res = self.prepare_new_infos_for_pre_installing_without_reset(name, visiteds, is_update, is_force);
2761        match res {
2762            Ok(()) => Ok(()),
2763            Err(err) => {
2764                self.pkgs.clear();
2765                self.clean_after_error()?;
2766                Err(err)
2767            },
2768        }
2769    }
2770    
2771    fn check_dependent_version_reqs(&self) -> Result<()>
2772    {
2773        self.printer.print_checking_dependent_version_reqs(false);
2774        let new_versions = self.pkg_versions_for_bucket("new_versions")?;
2775        for (name, new_version) in &new_versions {
2776            match self.pkgs.get(name) {
2777                Some(pkg) => {
2778                    let mut src = self.create_source(name)?;
2779                    let versions = src.versions()?;
2780                    let dependents = pkg.dependents()?;
2781                    for version_req in dependents.values() {
2782                        let max_version = max_pkg_version(&versions, Some(version_req), self.constraints.get(name), self.locks.get(name));
2783                        match &max_version {
2784                            Some(max_version) => {
2785                                if new_version != max_version {
2786                                    return Err(Error::PkgName(name.clone(), format!("version requirements indicate two different package versions: {}, {}", new_version, max_version)));
2787                                }
2788                            },
2789                            None => return Err(Error::PkgName(name.clone(), String::from("each package version isn't matched to version requirement"))),
2790                        }
2791                    }
2792                },
2793                None => return Err(Error::PkgName(name.clone(), String::from("no package"))),
2794            }
2795        }
2796        self.printer.print_checking_dependent_version_reqs(true);
2797        Ok(())
2798    }
2799
2800    fn pkg_is_to_install_for_pre_install(&self, name: &PkgName) -> Result<bool>
2801    {
2802        let mut manifest_file = self.pkg_new_part_info_dir(name);
2803        manifest_file.push("manifest.toml");
2804        match fs::metadata(manifest_file) {
2805            Ok(_) => Ok(true),
2806            Err(err) if err.kind() == ErrorKind::NotFound => Ok(false),
2807            Err(err) => Err(Error::Io(err)),
2808        }
2809    }
2810        
2811    fn search_path_conflicts(&self) -> Result<()>
2812    {
2813        self.printer.print_searching_path_conflicts(false);
2814        check_dir(self.bin_dir.as_path(), "bin isn't directory")?;
2815        check_dir(self.lib_dir.as_path(), "lib isn't directory")?;
2816        check_dir(self.doc_dir.as_path(), "doc isn't directory")?;
2817        let new_versions = self.pkg_versions_for_bucket("new_versions")?;
2818        let mut ignored_bin_paths: HashSet<PathBuf> = HashSet::new();
2819        let mut ignored_lib_paths: HashSet<PathBuf> = HashSet::new();
2820        for (name, _) in &new_versions {
2821            if self.pkg_is_to_install_for_pre_install(name)? {
2822                let mut old_paths_file = self.pkg_info_dir(name);
2823                old_paths_file.push("paths.toml");
2824                match Paths::load_opt(old_paths_file)? {
2825                    Some(paths) => {
2826                        for bin_path in &paths.bin {
2827                            ignored_bin_paths.insert(PathBuf::from(bin_path));
2828                        }
2829                        for lib_path in &paths.lib {
2830                            ignored_lib_paths.insert(PathBuf::from(lib_path));
2831                        }
2832                    },
2833                    None => (),
2834                }
2835            }
2836        }
2837        for (name, new_version) in &new_versions {
2838            if self.pkg_is_to_install_for_pre_install(name)? {
2839                let mut src = self.create_source(name)?;
2840                src.set_current_version(new_version.clone());
2841                let mut pkg_bin_dir = PathBuf::from(src.dir()?);
2842                pkg_bin_dir.push("bin");
2843                check_dir_for_pkg(pkg_bin_dir.as_path(), name, "bin in package isn't directory")?;
2844                let bin_paths = match conflicts(pkg_bin_dir, self.bin_dir.as_path(), &ignored_bin_paths, Some(1)) {
2845                    Ok((conflict_paths, paths)) => {
2846                        if conflict_paths.is_empty() {
2847                            paths
2848                        } else {
2849                            return Err(Error::PkgPathConflicts(name.clone(), None, conflict_paths, PkgPathConflict::Bin));
2850                        }
2851                    },
2852                    Err(err) => return Err(Error::Io(err)),
2853                };
2854                let mut pkg_lib_dir = PathBuf::from(src.dir()?);
2855                pkg_lib_dir.push("lib");
2856                check_dir_for_pkg(pkg_lib_dir.as_path(), name, "lib in package isn't directory")?;
2857                let lib_paths = match conflicts(pkg_lib_dir, self.lib_dir.as_path(), &ignored_lib_paths, Some(2)) {
2858                    Ok((conflict_paths, paths)) => {
2859                        if conflict_paths.is_empty() {
2860                            paths
2861                        } else {
2862                            return Err(Error::PkgPathConflicts(name.clone(), None, conflict_paths, PkgPathConflict::Lib));
2863                        }
2864                    },
2865                    Err(err) => return Err(Error::Io(err)),
2866                };
2867                let mut bin: Vec<String> = Vec::new();
2868                for bin_path in &bin_paths {
2869                    match bin_path.to_str() {
2870                        Some(s) => bin.push(String::from(s)),
2871                        None => return Err(Error::PkgName(name.clone(), String::from("bin path contains invalid UTF-8 character"))),
2872                    }
2873                }
2874                let mut lib: Vec<String> = Vec::new();
2875                for lib_path in &lib_paths {
2876                    match lib_path.to_str() {
2877                        Some(s) => lib.push(String::from(s)),
2878                        None => return Err(Error::PkgName(name.clone(), String::from("lib path contains invalid UTF-8 character"))),
2879                    }
2880                }
2881                let paths = Paths::new(bin, lib);
2882                let mut paths_file = self.pkg_new_part_info_dir(name);
2883                paths_file.push("paths.toml");
2884                paths.save(paths_file)?;
2885            }
2886        }
2887        for (i, (name, new_version)) in new_versions.iter().enumerate() {
2888            for (name2, new_version2) in &new_versions[(i + 1)..] {
2889                if self.pkg_is_to_install_for_pre_install(name)? && self.pkg_is_to_install_for_pre_install(name2)? {
2890                    let mut src = self.create_source(name)?;
2891                    src.set_current_version(new_version.clone());
2892                    let mut src2 = self.create_source(name2)?;
2893                    src2.set_current_version(new_version2.clone());
2894                    let mut pkg_bin_dir = PathBuf::from(src.dir()?);
2895                    pkg_bin_dir.push("bin");
2896                    let mut pkg_bin_dir2 = PathBuf::from(src2.dir()?);
2897                    pkg_bin_dir2.push("bin");
2898                    match conflicts(pkg_bin_dir, pkg_bin_dir2, &HashSet::new(), Some(1)) {
2899                        Ok((conflict_paths, _)) => {
2900                            if !conflict_paths.is_empty() {
2901                                return Err(Error::PkgPathConflicts(name.clone(), Some(name2.clone()), conflict_paths, PkgPathConflict::Bin));
2902                            }
2903                        },
2904                        Err(err) => return Err(Error::Io(err)),
2905                    }
2906                    let mut pkg_lib_dir = PathBuf::from(src.dir()?);
2907                    pkg_lib_dir.push("lib");
2908                    let mut pkg_lib_dir2 = PathBuf::from(src2.dir()?);
2909                    pkg_lib_dir2.push("lib");
2910                    match conflicts(pkg_lib_dir, pkg_lib_dir2, &HashSet::new(), Some(2)) {
2911                        Ok((conflict_paths, _)) => {
2912                            if !conflict_paths.is_empty() {
2913                                return Err(Error::PkgPathConflicts(name.clone(), Some(name2.clone()), conflict_paths, PkgPathConflict::Lib));
2914                            }
2915                        },
2916                        Err(err) => return Err(Error::Io(err)),
2917                    }
2918                }
2919            }
2920        }
2921        self.printer.print_searching_path_conflicts(true);
2922        Ok(())
2923    }
2924
2925    fn generate_pkg_doc(&self, name: &PkgName, new_version: &Version) -> Result<()>
2926    {
2927        if self.pkg_is_to_install_for_pre_install(name)? {
2928            self.printer.print_documenting_pkg(name, false);
2929            let mut src = self.create_source(name)?;
2930            src.set_current_version(new_version.clone());
2931            let doc_dir = self.pkg_tmp_doc_dir(name, &new_version);
2932            let mut paths_file = self.pkg_new_part_info_dir(name);
2933            paths_file.push("paths.toml");
2934            let paths = Paths::load(paths_file)?;
2935            let mut pkg_lib_dir = PathBuf::from(src.dir()?);
2936            pkg_lib_dir.push("lib");
2937            for path in &paths.lib {
2938                let mut lib_doc_dir = doc_dir.clone();
2939                lib_doc_dir.push(path);
2940                match create_dir_all(lib_doc_dir.as_path()) {
2941                    Ok(()) => (),
2942                    Err(err) => return Err(Error::Io(err)),
2943                }
2944                generate_doc(pkg_lib_dir.as_path(), doc_dir.as_path(), path)?;
2945            }
2946            self.printer.print_documenting_pkg(name, true);
2947        }
2948        Ok(())
2949    }
2950    
2951    fn generate_docs(&self) -> Result<()>
2952    {
2953        let new_versions = self.pkg_versions_for_bucket("new_versions")?;
2954        for (name, new_version) in &new_versions {
2955            self.generate_pkg_doc(name, new_version)?;
2956        }
2957        Ok(())
2958    }
2959    
2960    fn check_new_infos_and_generate_docs_for_pre_installing_without_reset(&self, is_doc: bool) -> Result<()>
2961    {
2962        self.check_dependent_version_reqs()?;
2963        self.search_path_conflicts()?;
2964        if is_doc {
2965            self.generate_docs()?;
2966        }
2967        match rename(self.new_part_info_dir(), self.new_info_dir()) {
2968           Ok(()) => Ok(()),
2969           Err(err) if err.kind() == ErrorKind::NotFound => Ok(()),
2970           Err(err) => Err(Error::Io(err)),
2971        }
2972    }
2973
2974    fn check_new_infos_and_generate_docs_for_pre_installing(&mut self, is_doc: bool) -> Result<()>
2975    {
2976        let res = self.check_new_infos_and_generate_docs_for_pre_installing_without_reset(is_doc);
2977        self.pkgs.clear();
2978        match res {
2979            Ok(()) => Ok(()),
2980            Err(err) => {
2981                self.clean_after_error()?;
2982                Err(err)
2983            },
2984        }
2985    }
2986    
2987    fn prepare_new_infos_for_pre_removing_without_reset(&mut self) -> Result<()>
2988    {
2989        let names = self.pkg_names_for_bucket("pkgs_to_remove")?;
2990        for name in &names {
2991            let pkg = Pkg::new_without_copying(self.pkg_info_dir(name));
2992            let manifest = pkg.manifest()?;
2993            match &manifest.dependencies {
2994                Some(deps) => {
2995                    for dep_name in deps.keys() {
2996                        if !self.has_pkg_names_for_bucket("pkgs_to_change", dep_name)? {
2997                            if self.pkg_version_for_bucket("versions", dep_name)?.is_some() {
2998                                self.add_pkg_names_for_bucket("pkgs_to_change", dep_name)?;
2999                                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)?);
3000                            } else {
3001                                return Err(Error::PkgName(dep_name.clone(), String::from("no package version")));
3002                            }
3003                        }
3004                        match self.pkgs.get(dep_name) {
3005                            Some(dep_pkg) => {
3006                                let mut depentents = dep_pkg.dependents()?;
3007                                depentents.remove(name);
3008                                dep_pkg.save_dependents(&depentents)?;
3009                            },
3010                            None => return Err(Error::PkgName(dep_name.clone(), String::from("no package"))),
3011                        }
3012                    }
3013                },
3014                None => (),
3015            }
3016        }
3017        Ok(())
3018    }
3019
3020    fn prepare_new_infos_for_pre_removing(&mut self) -> Result<()>
3021    {
3022        let res = self.prepare_new_infos_for_pre_removing_without_reset();
3023        self.pkgs.clear();
3024        match res {
3025            Ok(()) => {
3026                match rename(self.new_part_info_dir(), self.new_info_dir()) {
3027                    Ok(()) => Ok(()),
3028                    Err(err) if err.kind() == ErrorKind::NotFound => Ok(()),
3029                    Err(err) => Err(Error::Io(err)),
3030                }
3031            },
3032            Err(err) => {
3033                self.clean_after_error()?;
3034                Err(err)
3035            },
3036        }
3037    }
3038    
3039    fn io_res_install_pkg(&self, name: &PkgName, new_version: &Version, dir: &Path, paths: &Paths, is_doc: bool) -> io::Result<()>
3040    {
3041        let mut src_bin_dir = PathBuf::from(dir);
3042        src_bin_dir.push("bin");
3043        let dst_bin_dir = self.bin_dir.clone();
3044        let bin_paths: Vec<PathBuf> = paths.bin.iter().map(|s| PathBuf::from(s)).collect();
3045        recursively_copy_paths_in_dir(src_bin_dir, dst_bin_dir, bin_paths.as_slice())?;
3046        let mut src_lib_dir = PathBuf::from(dir);
3047        src_lib_dir.push("lib");
3048        let dst_lib_dir = self.lib_dir.clone();
3049        let lib_paths: Vec<PathBuf> = paths.lib.iter().map(|s| PathBuf::from(s)).collect();
3050        recursively_copy_paths_in_dir(src_lib_dir, dst_lib_dir, lib_paths.as_slice())?;
3051        if is_doc {
3052            let src_doc_dir = self.pkg_tmp_doc_dir(name, new_version);
3053            let dst_doc_dir = self.doc_dir.clone();
3054            recursively_copy_paths_in_dir(src_doc_dir, dst_doc_dir, lib_paths.as_slice())?;
3055        }
3056        create_dir_all(self.pkg_info_dir(name))?;
3057        let mut src_manifest_file = self.pkg_new_info_dir(name);
3058        src_manifest_file.push("manifest.toml");
3059        let mut dst_manifest_file = self.pkg_info_dir(name);
3060        dst_manifest_file.push("manifest.toml");
3061        copy(src_manifest_file, dst_manifest_file)?;
3062        let mut src_dependents_file = self.pkg_new_info_dir(name);
3063        src_dependents_file.push("dependents.toml");
3064        let mut dst_dependents_file = self.pkg_info_dir(name);
3065        dst_dependents_file.push("dependents.toml");
3066        copy(src_dependents_file, dst_dependents_file)?;
3067        let mut src_paths_file = self.pkg_new_info_dir(name);
3068        src_paths_file.push("paths.toml");
3069        let mut dst_paths_file = self.pkg_info_dir(name);
3070        dst_paths_file.push("paths.toml");
3071        rename(src_paths_file, dst_paths_file)?;
3072        Ok(())
3073    }
3074
3075    fn io_res_copy_dependents_file(&self, name: &PkgName) -> io::Result<()>
3076    {
3077        create_dir_all(self.pkg_info_dir(name))?;
3078        let mut src_dependents_file = self.pkg_new_info_dir(name);
3079        src_dependents_file.push("dependents.toml");
3080        let mut dst_dependents_file = self.pkg_info_dir(name);
3081        dst_dependents_file.push("dependents.toml");
3082        match copy(src_dependents_file, dst_dependents_file) {
3083            Ok(_) => Ok(()),
3084            Err(err) if err.kind() == ErrorKind::NotFound => Ok(()),
3085            Err(err) => Err(err),
3086        }
3087    }
3088    
3089    fn install_pkg(&self, name: &PkgName, new_version: &Version, is_doc: bool) -> Result<()>
3090    {
3091        let mut paths_file = self.pkg_new_info_dir(name);
3092        paths_file.push("paths.toml");
3093        match Paths::load(paths_file) {
3094            Ok(paths) => {
3095                self.printer.print_installing_pkg(name, false);
3096                let mut src = self.create_source(name)?;
3097                src.set_current_version(new_version.clone());
3098                match self.io_res_install_pkg(name, new_version, src.dir()?, &paths, is_doc) {
3099                    Ok(()) => (),
3100                    Err(err) => return Err(Error::Io(err)),
3101                }
3102                self.printer.print_installing_pkg(name, true);
3103                Ok(())
3104            },
3105            Err(Error::Io(io_err)) if io_err.kind() == ErrorKind::NotFound => {
3106                match self.io_res_copy_dependents_file(name) {
3107                    Ok(()) => Ok(()),
3108                    Err(err) => Err(Error::Io(err)),
3109                }
3110            },
3111            Err(err) => Err(err),
3112        }
3113    }
3114    
3115    fn change_pkg(&self, name: &PkgName) -> Result<()>
3116    {
3117        match self.io_res_copy_dependents_file(name) {
3118            Ok(()) => Ok(()),
3119            Err(err) => Err(Error::Io(err)),
3120        }
3121    }
3122    
3123    fn io_res_remove_pkg(&self, name: &PkgName, paths: &Paths) -> io::Result<()>
3124    {
3125        let bin_dir = self.bin_dir.clone();
3126        let bin_paths: Vec<PathBuf> = paths.bin.iter().map(|s| PathBuf::from(s)).collect();
3127        recursively_remove_paths_in_dir(bin_dir, bin_paths.as_slice(), true)?;
3128        let lib_dir = self.lib_dir.clone();
3129        let lib_paths: Vec<PathBuf> = paths.lib.iter().map(|s| PathBuf::from(s)).collect();
3130        recursively_remove_paths_in_dir(lib_dir, lib_paths.as_slice(), true)?;
3131        let doc_dir = self.doc_dir.clone();
3132        recursively_remove_paths_in_dir(doc_dir, lib_paths.as_slice(), true)?;
3133        let mut manifest_file = self.pkg_info_dir(name);
3134        manifest_file.push("manifest.toml");
3135        recursively_remove(manifest_file, true)?;
3136        let mut dependents_file = self.pkg_info_dir(name);
3137        dependents_file.push("dependents.toml");
3138        recursively_remove(dependents_file, true)?;
3139        let mut paths_file = self.pkg_info_dir(name);
3140        paths_file.push("paths.toml");
3141        recursively_remove(paths_file, true)?;
3142        let mut tmp_suffix_path_buf = name.to_path_buf();
3143        tmp_suffix_path_buf.pop();
3144        while tmp_suffix_path_buf != PathBuf::from("") {
3145            let mut dir_path_buf = self.info_dir();
3146            dir_path_buf.push(tmp_suffix_path_buf.as_path());
3147            match remove_dir(dir_path_buf.as_path()) {
3148                Ok(()) => (),
3149                Err(_) => break,
3150            }
3151            tmp_suffix_path_buf.pop();
3152        }
3153        Ok(())
3154    }
3155
3156    fn remove_pkg(&self, name: &PkgName) -> Result<()>
3157    {
3158        let mut paths_file = self.pkg_info_dir(name);
3159        paths_file.push("paths.toml");
3160        match Paths::load(paths_file) {
3161            Ok(paths) => {
3162                self.printer.print_removing_pkg(name, false);
3163                match self.io_res_remove_pkg(name, &paths) {
3164                    Ok(()) => (),
3165                    Err(err) => return Err(Error::Io(err)),
3166                }
3167                self.printer.print_removing_pkg(name, true);
3168                Ok(())
3169            },
3170            Err(Error::Io(io_err)) if io_err.kind() == ErrorKind::NotFound => Ok(()),
3171            Err(err) => Err(err),
3172        }
3173    }
3174
3175    fn pkg_is_to_install(&self, name: &PkgName) -> Result<bool>
3176    {
3177        let mut paths_file = self.pkg_new_info_dir(name);
3178        paths_file.push("paths.toml");
3179        match fs::metadata(paths_file) {
3180            Ok(_) => Ok(true),
3181            Err(err) if err.kind() == ErrorKind::NotFound => Ok(false),
3182            Err(err) => Err(Error::Io(err)),
3183        }
3184    }
3185
3186    fn install_pkgs(&self, is_doc: bool) -> Result<()>
3187    {
3188        let new_versions = self.pkg_versions_for_bucket("new_versions")?;
3189        for (name, _) in &new_versions {
3190            if self.pkg_is_to_install(name)? {
3191                self.remove_pkg(name)?;
3192            }
3193        }
3194        for (name, new_version) in &new_versions {
3195            self.install_pkg(name, new_version, is_doc)?;
3196        }
3197        self.printer.print_cleaning_after_install(false);
3198        match recursively_remove(self.work_tmp_dir(), true) {
3199            Ok(()) => (),
3200            Err(err) => return Err(Error::Io(err)),
3201        }
3202        self.move_pkg_versions_for_buckets("new_versions", "versions")?;
3203        match recursively_remove(self.new_info_dir(), true) {
3204            Ok(()) => (),
3205            Err(err) => return Err(Error::Io(err)),
3206        }
3207        self.printer.print_cleaning_after_install(true);
3208        Ok(())
3209    }
3210
3211    fn change_pkgs(&self) -> Result<()>
3212    {
3213        let names = self.pkg_names_for_bucket("pkgs_to_change")?;
3214        for name in &names {
3215            self.change_pkg(name)?;
3216        }
3217        self.remove_bucket("pkgs_to_change")?;
3218        self.printer.print_cleaning_before_removal(false);
3219        match recursively_remove(self.new_info_dir(), true) {
3220            Ok(()) => (),
3221            Err(err) => return Err(Error::Io(err)),
3222        }
3223        self.printer.print_cleaning_before_removal(true);
3224        Ok(())
3225    }
3226    
3227    fn remove_pkgs(&self) -> Result<()>
3228    {
3229        let names = self.pkg_names_for_bucket("pkgs_to_remove")?;
3230        for name in &names {
3231            self.remove_pkg(name)?;
3232        }
3233        self.remove_pkg_versions_for_buckets("pkgs_to_remove", "versions")
3234    }
3235    
3236    /// Updates the versions of packages.
3237    pub fn update(&self, names: &[PkgName]) -> Result<()>
3238    {
3239        self.printer.print_updating();
3240        for name in names {
3241            let mut src = self.create_source(name)?;
3242            src.update()?;
3243        }
3244        Ok(())
3245    }
3246    
3247    /// Installs the specified packages with depedencies.
3248    ///
3249    /// This method overwrites the versions of packages if the update flag is set, otherwise
3250    /// the versions of the packages aren't updated. If the force flag is set, the packages with
3251    /// the dependencies are reinstalled. The documentations are installed for the packages if
3252    /// the documentation is set, otherwise the documentation aren't installed.
3253    pub fn install(&mut self, names: &[PkgName], is_update: bool, is_force: bool, is_doc: bool) -> Result<()>
3254    {
3255        self.printer.print_pre_installing();
3256        let mut visiteds: HashSet<PkgName> = HashSet::new();
3257        for name in names {
3258            self.prepare_new_infos_for_pre_installing(name, &mut visiteds, is_update, is_force)?;
3259        }
3260        self.check_new_infos_and_generate_docs_for_pre_installing(is_doc)?;
3261        self.printer.print_installing();
3262        self.install_pkgs(is_doc)?;
3263        Ok(())
3264    }
3265    
3266    /// Installs the dependencies for the current package.
3267    ///
3268    /// The unused packages are automatically removed from the work directory. See also
3269    /// [install](Self::install).
3270    pub fn install_deps(&mut self, is_update: bool, is_force: bool, is_doc: bool) -> Result<()>
3271    {
3272        self.printer.print_pre_installing();
3273        let mut visiteds: HashSet<PkgName> = HashSet::new();
3274        let current_pkg = Pkg::new();
3275        let manifest = current_pkg.manifest()?;
3276        let start_name = manifest.package.name.clone();
3277        self.constraints = manifest.constraints.map(|cs| cs.clone()).unwrap_or(Arc::new(HashMap::new()));
3278        self.sources = manifest.sources.map(|ss| ss.clone()).unwrap_or(Arc::new(HashMap::new()));
3279        self.pkgs.insert(start_name.clone(), current_pkg);
3280        self.prepare_new_infos_for_pre_installing(&start_name, &mut visiteds, is_update, is_force)?;
3281        self.add_pkg_names_for_buckets_and_autoremoving("pkgs_to_remove", "versions", &visiteds)?;
3282        self.check_new_infos_and_generate_docs_for_pre_installing(is_doc)?;
3283        self.printer.print_installing();
3284        self.install_pkgs(is_doc)?;
3285        self.printer.print_removing();
3286        self.remove_pkgs()?;
3287        Ok(())
3288    }
3289    
3290    /// Removes the specified packages.
3291    pub fn remove(&mut self, names: &[PkgName]) -> Result<()>
3292    {
3293        self.printer.print_pre_removing();
3294        self.add_pkg_names_for_bucket_and_removing("pkgs_to_remove", names)?;
3295        self.prepare_new_infos_for_pre_removing()?;
3296        self.printer.print_removing();
3297        self.change_pkgs()?;
3298        self.remove_pkgs()?;
3299        Ok(())
3300    }
3301    
3302    /// Checks whether the preparation to the last operation or the last operations was
3303    /// interrupted.
3304    ///
3305    /// If the preparation to the last operation or the last operation was interrupted, this
3306    /// method returns an error with the appropriate message.
3307    pub fn check_last_op(&self, are_deps: bool) -> Result<()>
3308    {
3309        let is_new_part_info_dir = match fs::metadata(self.new_part_info_dir()) {
3310            Ok(_) => true,
3311            Err(err) if err.kind() == ErrorKind::NotFound => false,
3312            Err(err) => return Err(Error::Io(err)),
3313        };
3314        if is_new_part_info_dir {
3315            if are_deps {
3316                return Err(Error::Pkg(String::from("Preparation to last operation was interrupted. Please call command 'unlab-pkg clean-deps' to clean after preparation.")));
3317            } else {
3318                return Err(Error::Pkg(String::from("Preparation to last operation was interrupted. Please call command 'unlab-pkg clean' to clean after preparation.")));
3319            }
3320        }
3321        let is_new_info_dir = match fs::metadata(self.new_info_dir()) {
3322            Ok(_) => true,
3323            Err(err) if err.kind() == ErrorKind::NotFound => false,
3324            Err(err) => return Err(Error::Io(err)),
3325        };
3326        if (is_new_info_dir && self.has_bucket("new_versions")?) || is_new_info_dir || self.has_bucket("pkgs_to_remove")? {
3327            if are_deps {
3328                return Err(Error::Pkg(String::from("Last operation was interrupted. Please call command 'unlab-pkg continue-deps' to complete last operation.")));
3329            } else {
3330                return Err(Error::Pkg(String::from("Last operation was interrupted. Please call command 'unlab-pkg continue' to complete last operation.")));
3331            }
3332        }
3333        Ok(())
3334    }
3335
3336    /// Continues the interrupted last operation.
3337    pub fn cont(&self, is_doc: bool, are_deps: bool) -> Result<()>
3338    {
3339        let is_new_part_info_dir = match fs::metadata(self.new_part_info_dir()) {
3340            Ok(_) => true,
3341            Err(err) if err.kind() == ErrorKind::NotFound => false,
3342            Err(err) => return Err(Error::Io(err)),
3343        };
3344        if is_new_part_info_dir {
3345            return Ok(());
3346        }
3347        let is_new_info_dir = match fs::metadata(self.new_info_dir()) {
3348            Ok(_) => true,
3349            Err(err) if err.kind() == ErrorKind::NotFound => false,
3350            Err(err) => return Err(Error::Io(err)),
3351        };
3352        if is_new_info_dir && !self.has_bucket("pkgs_to_remove")? {
3353            self.printer.print_installing();
3354            self.install_pkgs(is_doc)?;
3355        } else if is_new_info_dir && (are_deps || !self.has_bucket("pkgs_to_remove")?) {
3356            self.printer.print_installing();
3357            self.printer.print_cleaning_after_install(false);
3358            match recursively_remove(self.new_info_dir(), true) {
3359                Ok(()) => (),
3360                Err(err) => return Err(Error::Io(err)),
3361            }
3362            self.printer.print_cleaning_after_install(true);
3363        }
3364        if self.has_bucket("pkgs_to_remove")? {
3365            self.printer.print_removing();
3366            if !are_deps {
3367                if is_new_info_dir && self.has_bucket("pkgs_to_change")? {
3368                    self.change_pkgs()?;
3369                } else if is_new_info_dir {
3370                    self.printer.print_cleaning_before_removal(false);
3371                    match recursively_remove(self.new_info_dir(), true) {
3372                        Ok(()) => (),
3373                        Err(err) => return Err(Error::Io(err)),
3374                    }
3375                    self.printer.print_cleaning_before_removal(true);
3376                }
3377            }
3378            self.remove_pkgs()?;
3379        }
3380        Ok(())
3381    }
3382
3383    /// Cleans after the interrupted preparation to the last operation.
3384    pub fn clean(&self) -> Result<()>
3385    {
3386        let is_new_part_info_dir = match fs::metadata(self.new_part_info_dir()) {
3387            Ok(_) => true,
3388            Err(err) if err.kind() == ErrorKind::NotFound => false,
3389            Err(err) => return Err(Error::Io(err)),
3390        };
3391        if is_new_part_info_dir {
3392            self.printer.print_cleaning(false);
3393            self.remove_bucket("new_versions")?;
3394            self.remove_bucket("pkgs_to_remove")?;
3395            self.remove_bucket("pkgs_to_change")?;
3396            match self.io_res_remove_dirs_for_cleaning() {
3397                Ok(()) => (),
3398                Err(err) => return Err(Error::Io(err)),
3399            }
3400            self.printer.print_cleaning(true);
3401        }
3402        Ok(())
3403    }
3404    
3405    /// Updates the versions of all packages.
3406    pub fn update_all(&self) -> Result<()>
3407    {
3408        let mut names: Vec<PkgName> = Vec::new();
3409        self.pkg_versions_in(|name, _| {
3410                names.push(name.clone());
3411                Ok(())
3412        })?;
3413        self.update(names.as_slice())
3414    }
3415
3416    /// Reinstalls all packages.
3417    ///
3418    /// See [install](Self::install).
3419    pub fn install_all(&mut self, is_update: bool, is_force: bool, is_doc: bool) -> Result<()>
3420    {
3421        let mut names: Vec<PkgName> = Vec::new();
3422        self.pkg_versions_in(|name, _| {
3423                let dependents = self.pkg_dependents(name)?;
3424                if dependents.map(|ds| ds.is_empty()).unwrap_or(true) {
3425                    names.push(name.clone());
3426                }
3427                Ok(())
3428        })?;
3429        self.install(names.as_slice(), is_update, is_force, is_doc)
3430    }
3431    
3432    fn io_res_remove_pkg_doc(&self, doc_paths: &DocPaths) -> io::Result<()>
3433    {
3434        let doc_paths: Vec<PathBuf> = doc_paths.doc.iter().map(|s| PathBuf::from(s)).collect();
3435        recursively_remove_paths_in_dir(self.doc_dir.as_path(), doc_paths.as_slice(), true)?;
3436        let mut doc_paths_file = self.work_dir.clone();
3437        doc_paths_file.push("doc-paths.toml");
3438        recursively_remove(doc_paths_file, true)?;
3439        Ok(())
3440    }
3441
3442    /// Generates a documentation for the current package.
3443    pub fn generate_doc(&self) -> Result<()>
3444    {
3445        self.printer.print_documenting();
3446        let name = Self::manifest()?.package.name;
3447        let mut doc_paths_file = self.work_var_dir();
3448        doc_paths_file.push("doc-paths.toml");
3449        match DocPaths::load(doc_paths_file) {
3450            Ok(doc_paths) => {
3451                self.printer.print_removing_pkg_doc(&name, false);
3452                match self.io_res_remove_pkg_doc(&doc_paths) {
3453                    Ok(()) => (),
3454                    Err(err) => return Err(Error::Io(err)),
3455                }
3456                self.printer.print_removing_pkg_doc(&name, true);
3457            },
3458            Err(Error::Io(io_err)) if io_err.kind() == ErrorKind::NotFound => (),
3459            Err(err) => return Err(err),
3460        }
3461        {
3462            self.printer.print_searching_path_conflicts(false);
3463            let pkg_lib_dir = PathBuf::from("lib");
3464            check_dir_for_pkg(pkg_lib_dir.as_path(), &name, "lib in package isn't directory")?;
3465            let lib_paths = match conflicts(pkg_lib_dir, self.doc_dir.as_path(), &HashSet::new(), Some(2)) {
3466                Ok((conflict_paths, paths)) => {
3467                    if conflict_paths.is_empty() {
3468                        paths
3469                    } else {
3470                        return Err(Error::PkgPathConflicts(name.clone(), None, conflict_paths, PkgPathConflict::Doc));
3471                    }
3472                },
3473                Err(err) => return Err(Error::Io(err)),
3474            };
3475            let mut doc: Vec<String> = Vec::new();
3476            for lib_path in &lib_paths {
3477                match lib_path.to_str() {
3478                    Some(s) => doc.push(String::from(s)),
3479                    None => return Err(Error::PkgName(name.clone(), String::from("lib path contains invalid UTF-8 character"))),
3480                }
3481            }
3482            let doc_paths = DocPaths::new(doc);
3483            let mut doc_paths_file = self.work_var_dir();
3484            doc_paths_file.push("doc-paths.toml");
3485            doc_paths.save(doc_paths_file)?;
3486            self.printer.print_searching_path_conflicts(true);
3487        }
3488        {
3489            self.printer.print_documenting_pkg(&name, false);
3490            let mut doc_paths_file = self.work_var_dir();
3491            doc_paths_file.push("doc-paths.toml");
3492            let doc_paths = DocPaths::load(doc_paths_file)?;
3493            let pkg_lib_dir = PathBuf::from("lib");
3494            for path in &doc_paths.doc {
3495                let mut lib_doc_dir = self.doc_dir.clone();
3496                lib_doc_dir.push(path);
3497                match create_dir_all(lib_doc_dir.as_path()) {
3498                    Ok(()) => (),
3499                    Err(err) => return Err(Error::Io(err)),
3500                }
3501                generate_doc(pkg_lib_dir.as_path(), self.doc_dir.as_path(), path)?;
3502            }
3503            self.printer.print_documenting_pkg(&name, true);
3504        }
3505        Ok(())
3506    }
3507    
3508    /// Generates a documentation of the standard built-in functions.
3509    pub fn generate_std_doc(&self) -> Result<()>
3510    {
3511        self.printer.print_documenting();
3512        let name = PkgName::new(String::from("std/root"));
3513        let mut doc_path = PathBuf::from("std");
3514        doc_path.push("root");
3515        let mut lib_doc_dir = self.doc_dir.clone();
3516        lib_doc_dir.push(doc_path.as_path());
3517        match fs::metadata(lib_doc_dir.as_path()) {
3518            Ok(_) => {
3519                self.printer.print_removing_pkg_doc(&name, false);
3520                match recursively_remove_paths_in_dir(self.doc_dir.as_path(), &[doc_path.clone()], true) {
3521                    Ok(()) => (),
3522                    Err(err) => return Err(Error::Io(err)),
3523                }
3524                self.printer.print_removing_pkg_doc(&name, true);
3525            },
3526            Err(err) if err.kind() == ErrorKind::NotFound => (),
3527            Err(err) => return Err(Error::Io(err)),
3528        }
3529        {
3530            self.printer.print_documenting_pkg(&name, false);
3531            match create_dir_all(lib_doc_dir.as_path()) {
3532                Ok(()) => (),
3533                Err(err) => return Err(Error::Io(err)),
3534            }
3535            let mut sig_root_mod: ModNode<Sig, ()> = ModNode::new(());
3536            let mut doc_root_mod: ModNode<String, Option<String>> = ModNode::new(None);
3537            add_std_builtin_fun_doc(&mut sig_root_mod, &mut doc_root_mod);
3538            let doc_tree = DocTree::new(Arc::new(RwLock::new(sig_root_mod)), Arc::new(RwLock::new(doc_root_mod)));
3539            let doc_gen = DocGen::new(self.doc_dir.clone(), doc_path);
3540            doc_gen.generate(&doc_tree)?;
3541            self.printer.print_documenting_pkg(&name, true);
3542        }
3543        Ok(())
3544    }
3545}
3546
3547#[cfg(test)]
3548mod tests;