1use 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
65pub const USER_AGENT_HTTP_HEADER: &'static str = concat!("User-Agent: Unlab-pkg/", env!("CARGO_PKG_VERSION"));
67
68pub trait Print
73{
74 fn print_updating(&self);
76
77 fn print_pre_installing(&self);
79
80 fn print_installing(&self);
82
83 fn print_pre_removing(&self);
85
86 fn print_removing(&self);
88
89 fn print_documenting(&self);
91
92 fn print_updating_pkg_versions(&self, name: &PkgName, is_done: bool);
94
95 fn print_downloading_pkg_file(&self, name: &PkgName, is_done: bool) -> Result<()>;
97
98 fn print_downloading_pkg_file_with_progress(&self, name: &PkgName, byte_count: f64, total_byte_count: f64) -> Result<()>;
100
101 fn print_extracting_pkg_file(&self, name: &PkgName, is_done: bool);
103
104 fn print_checking_dependent_version_reqs(&self, is_done: bool);
106
107 fn print_searching_path_conflicts(&self, is_done: bool);
109
110 fn print_documenting_pkg(&self, name: &PkgName, is_done: bool);
112
113 fn print_installing_pkg(&self, name: &PkgName, is_done: bool);
115
116 fn print_removing_pkg(&self, name: &PkgName, is_done: bool);
118
119 fn print_removing_pkg_doc(&self, name: &PkgName, is_done: bool);
121
122 fn print_cleaning_after_install(&self, is_done: bool);
124
125 fn print_cleaning_before_removal(&self, is_done: bool);
127
128 fn print_cleaning_after_error(&self, is_done: bool);
130
131 fn print_cleaning(&self, is_done: bool);
133
134 fn print_lf_for_error(&self);
136
137 fn eprint_error(&self, err: &Error);
139}
140
141#[derive(Copy, Clone, Debug)]
145pub struct EmptyPrinter;
146
147impl EmptyPrinter
148{
149 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#[derive(Debug)]
228pub struct StdPrinter
229{
230 byte_count: Mutex<f64>,
231 has_lf_for_error: AtomicBool,
232}
233
234impl StdPrinter
235{
236 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
455pub trait Source
462{
463 fn update(&mut self) -> Result<()>;
465
466 fn versions(&mut self) -> Result<&BTreeSet<Version>>;
468
469 fn set_current_version(&mut self, version: Version);
471
472 fn dir(&mut self) -> Result<&Path>;
474}
475
476pub trait SourceCreate
480{
481 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#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
490pub struct PkgName
491{
492 name: String,
493}
494
495impl PkgName
496{
497 pub fn new(name: String) -> Self
499 { PkgName { name, } }
500
501 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 pub fn name(&self) -> &str
520 { self.name.as_str() }
521
522 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#[derive(Clone, Debug, Serialize, Deserialize)]
568pub struct PkgInfo
569{
570 pub name: PkgName,
572 pub description: Option<String>,
574 pub authors: Option<Vec<String>>,
576 pub license: Option<String>,
578 #[serde(rename = "unlab-gpu-version")]
580 pub unlab_gpu_version: Option<VersionReq>,
581}
582
583#[derive(Clone, Debug, Serialize, Deserialize)]
585pub enum VersionSrcInfo
586{
587 #[serde(rename = "dir")]
589 Dir(String),
590 #[serde(rename = "file")]
592 File(String),
593 #[serde(rename = "url")]
595 Url(String),
596}
597
598#[derive(Clone, Debug, Serialize, Deserialize)]
600pub enum SrcInfo
601{
602 #[serde(rename = "renamed")]
604 Renamed(PkgName),
605 #[serde(rename = "versions")]
607 Versions(Arc<BTreeMap<Version, VersionSrcInfo>>),
608}
609
610#[derive(Clone, Debug, Serialize, Deserialize)]
616pub struct Manifest
617{
618 pub package: PkgInfo,
620 pub dependencies: Option<HashMap<PkgName, VersionReq>>,
622 pub constraints: Option<Arc<HashMap<PkgName, VersionReq>>>,
624 pub sources: Option<Arc<HashMap<PkgName, SrcInfo>>>,
626}
627
628impl Manifest
629{
630 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 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 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 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 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 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#[derive(Clone, Debug, Serialize, Deserialize)]
708pub struct Paths
709{
710 pub bin: Vec<String>,
712 pub lib: Vec<String>,
714}
715
716impl Paths
717{
718 pub fn new(bin: Vec<String>, lib: Vec<String>) -> Self
720 { Paths { bin, lib, } }
721
722 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 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 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 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 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#[derive(Clone, Debug, Serialize, Deserialize)]
782pub struct DocPaths
783{
784 pub doc: Vec<String>,
786}
787
788impl DocPaths
789{
790 pub fn new(doc: Vec<String>) -> Self
792 { DocPaths { doc, } }
793
794 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 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 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 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 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#[derive(Clone, Debug, Serialize, Deserialize)]
855pub struct Versions
856{
857 pub versions: BTreeSet<Version>,
859}
860
861impl Versions
862{
863 pub fn new(versions: BTreeSet<Version>) -> Self
865 { Versions { versions, } }
866
867 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 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 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 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 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#[derive(Clone, Debug, Serialize, Deserialize)]
928pub struct PkgConfig
929{
930 pub account: Option<String>,
932 pub domain: Option<String>,
934}
935
936impl PkgConfig
937{
938 pub fn new(account: Option<String>, domain: Option<String>) -> Self
940 { PkgConfig { account, domain, } }
941
942 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 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 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 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 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
1001pub 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
1016pub 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
1030pub 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
1039pub 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
1049pub 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
1060pub 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
1069pub 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
1084pub 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
1098pub 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
1107pub 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
1118pub 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
1129pub 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
1138pub 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
1153pub 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
1167pub 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
1176pub 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
1187pub 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
1198pub 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
1207pub 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
1220pub fn version_to_tag_name(version: &Version) -> String
1222{ format!("v{}", version) }
1223
1224pub 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
1232pub 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
1240pub 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
1248pub 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
1256pub 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
1264pub 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
1273pub 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
1282pub 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
1290pub 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
1321pub 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
1436pub 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
1491pub 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#[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 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 pub fn name(&self) -> &PkgName
1629 { &self.name }
1630
1631 pub fn home_dir(&self) -> &Path
1633 { self.home_dir.as_path() }
1634
1635 pub fn work_dir(&self) -> &Path
1637 { self.work_dir.as_path() }
1638
1639 pub fn version_src_infos(&self) -> &Arc<BTreeMap<Version, VersionSrcInfo>>
1641 { &self.version_src_infos }
1642
1643 pub fn printer(&self) -> &Arc<dyn Print + Send + Sync>
1645 { &self.printer }
1646
1647 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
1917pub 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#[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 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 pub fn home_dir(&self) -> &Path
2066 { self.home_dir.as_path() }
2067
2068 pub fn work_dir(&self) -> &Path
2070 { self.work_dir.as_path() }
2071
2072 pub fn bin_dir(&self) -> &Path
2074 { self.bin_dir.as_path() }
2075
2076 pub fn lib_dir(&self) -> &Path
2078 { self.lib_dir.as_path() }
2079
2080 pub fn doc_dir(&self) -> &Path
2082 { self.doc_dir.as_path() }
2083
2084 pub fn locks(&self) -> &HashMap<PkgName, Version>
2086 { &self.locks }
2087
2088 pub fn set_locks(&mut self, locks: HashMap<PkgName, Version>)
2090 { self.locks = locks; }
2091
2092 pub fn load_locks(&mut self) -> Result<()>
2094 {
2095 self.locks = load_versions_or_empty("Unlab.lock")?;
2096 Ok(())
2097 }
2098
2099 pub fn save_locks(&self) -> Result<()>
2101 { save_versions("Unlab.lock", &self.locks) }
2102
2103 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 pub fn constraints(&self) -> &Arc<HashMap<PkgName, VersionReq>>
2116 { &self.constraints }
2117
2118 pub fn set_constraints(&mut self, constraints: Arc<HashMap<PkgName, VersionReq>>)
2120 { self.constraints = constraints; }
2121
2122 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 pub fn sources(&self) -> &Arc<HashMap<PkgName, SrcInfo>>
2131 { &self.sources }
2132
2133 pub fn set_sources(&mut self, sources: Arc<HashMap<PkgName, SrcInfo>>)
2135 { self.sources = sources; }
2136
2137 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 pub fn src_factories(&self) -> &[Arc<dyn SourceCreate + Send + Sync>]
2146 { self.src_factories.as_slice() }
2147
2148 pub fn printer(&self) -> &Arc<dyn Print + Send + Sync>
2150 { &self.printer }
2151
2152 pub fn manifest() -> Result<Manifest>
2154 { Manifest::load("Unlab.toml") }
2155
2156 pub fn save_manifest(manifest: &Manifest) -> Result<()>
2158 { manifest.save("Unlab.toml") }
2159
2160 pub fn reset(&mut self)
2162 { self.pkgs.clear(); }
2163
2164 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 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 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 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 pub fn info_dir(&self) -> PathBuf
2198 {
2199 let mut dir = self.work_var_dir();
2200 dir.push("info");
2201 dir
2202 }
2203
2204 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 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 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 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 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 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 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 pub fn pkg_versions(&self) -> Result<Vec<(PkgName, Version)>>
2519 { self.pkg_versions_for_bucket("versions") }
2520
2521 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 pub fn pkg_version(&self, name: &PkgName) -> Result<Option<Version>>
2528 { self.pkg_version_for_bucket("versions", name) }
2529
2530 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 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 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 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 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 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 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 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 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 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 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 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 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 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;