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