pkg/
lib.rs

1//#![cfg_attr(target_os = "redox", feature(io_error_more))]
2
3use std::{cell::RefCell, cmp::Ordering, fs, path::Path, rc::Rc};
4
5use backend::pkgar_backend::PkgarBackend;
6use backend::Backend;
7use net_backend::{DefaultNetBackend, DownloadBackend};
8use package_list::PackageList;
9use repo_manager::RepoManager;
10
11pub use backend::Error;
12pub use callback::Callback;
13pub use package::{Package, PackageInfo, PackageName};
14
15pub mod backend;
16pub mod callback;
17pub mod net_backend;
18pub mod package;
19mod package_list;
20mod repo_manager;
21mod sorensen;
22
23pub struct Library {
24    package_list: PackageList,
25    backend: Box<dyn Backend>,
26}
27
28const DOWNLOAD_PATH: &str = "/tmp/pkg_dowload/";
29
30// make them not relative
31const PACKAGES_PATH: &str = "etc/pkg/packages.toml";
32
33impl Library {
34    pub fn new<P: AsRef<Path>>(
35        install_path: P,
36        target: &str,
37        callback: Rc<RefCell<dyn Callback>>,
38    ) -> Result<Self, Error> {
39        let install_path = install_path.as_ref();
40
41        let download_backend = DefaultNetBackend::new()?;
42
43        let mut repo_manager = RepoManager {
44            remotes: Vec::new(),
45            download_path: DOWNLOAD_PATH.into(),
46            download_backend: Box::new(download_backend.clone()),
47            callback: callback.clone(),
48        };
49
50        {
51            let repos_path = install_path.join("etc/pkg.d");
52            let mut repo_files = Vec::new();
53            for entry_res in fs::read_dir(&repos_path)? {
54                let entry = entry_res?;
55                let path = entry.path();
56                if path.is_file() {
57                    repo_files.push(path);
58                }
59            }
60            repo_files.sort();
61            for repo_file in repo_files {
62                let data = fs::read_to_string(repo_file)?;
63                for line in data.lines() {
64                    if !line.starts_with('#') {
65                        repo_manager.add_remote(line.trim(), target)?;
66                    }
67                }
68            }
69        }
70
71        let backend = PkgarBackend::new(install_path, repo_manager)?;
72
73        Ok(Library {
74            package_list: PackageList::default(),
75            backend: Box::new(backend),
76        })
77    }
78
79    pub fn get_installed_packages(&self) -> Result<Vec<PackageName>, Error> {
80        self.backend.get_installed_packages()
81    }
82
83    pub fn install(&mut self, packages: Vec<PackageName>) -> Result<(), Error> {
84        for package_name in packages {
85            self.package_list.install.push(package_name);
86        }
87
88        Ok(())
89    }
90
91    pub fn uninstall(&mut self, packages: Vec<PackageName>) -> Result<(), Error> {
92        for package_name in packages {
93            if self.get_installed_packages()?.contains(&package_name) {
94                self.package_list.uninstall.push(package_name);
95            }
96        }
97
98        Ok(())
99    }
100
101    /// if packages is empty then update all installed packages
102    pub fn update(&mut self, packages: Vec<PackageName>) -> Result<(), Error> {
103        let installed_packages = self.get_installed_packages()?;
104        if packages.is_empty() {
105            for package_name in &installed_packages {
106                self.package_list.install.push(package_name.clone());
107            }
108        } else {
109            for package_name in packages {
110                if installed_packages.contains(&package_name) {
111                    self.package_list.install.push(package_name);
112                }
113            }
114        }
115
116        Ok(())
117    }
118
119    pub fn get_all_package_names(&mut self) -> Result<Vec<PackageName>, Error> {
120        let repository = self.backend.get_repository_detail()?;
121        let list = repository
122            .packages
123            .keys()
124            .cloned()
125            .fold(Vec::new(), |mut acc, x| {
126                match PackageName::new(x) {
127                    Ok(name) => {
128                        acc.push(name);
129                    }
130                    Err(_) => {}
131                };
132                acc
133            });
134        Ok(list)
135    }
136
137    pub fn search(&mut self, package: &str) -> Result<Vec<(PackageName, f64)>, Error> {
138        let names = self.get_all_package_names()?;
139
140        let mut result = vec![];
141
142        for name in names {
143            let mut rank = 0.0;
144
145            let dst = sorensen::distance(
146                package.to_lowercase().as_bytes(),
147                name.as_str().to_lowercase().as_bytes(),
148            );
149
150            if dst >= 0.2 {
151                rank += dst;
152            }
153
154            if name.as_str().contains(package) {
155                rank += 0.01;
156            }
157
158            if rank > 0.0 {
159                result.push((name, rank));
160            }
161        }
162
163        // this is hard to read
164        result.as_mut_slice().sort_by(|a, b| {
165            let check1 = b.1.partial_cmp(&a.1);
166            if check1 == Some(Ordering::Equal) {
167                a.0.cmp(&b.0)
168            } else {
169                check1.unwrap_or(Ordering::Equal)
170            }
171        });
172
173        Ok(result)
174    }
175
176    pub fn apply(&mut self) -> Result<(), Error> {
177        for package in self.package_list.uninstall.iter() {
178            self.backend.uninstall(package.clone())?;
179        }
180
181        let install = self.with_dependecies(&self.package_list.install.clone())?;
182
183        for package in install.into_iter() {
184            if self.backend.get_installed_packages()?.contains(&package) {
185                self.backend.upgrade(package)?;
186            } else {
187                self.backend.install(package)?;
188            }
189        }
190
191        self.package_list = Default::default();
192        Ok(())
193    }
194
195    pub fn with_dependecies(
196        &mut self,
197        packages: &Vec<PackageName>,
198    ) -> Result<Vec<PackageName>, Error> {
199        let mut list = vec![];
200        for package in packages {
201            self.get_dependecies_recursive(package, &mut list)?;
202        }
203
204        Ok(list)
205    }
206
207    fn get_dependecies_recursive(
208        &mut self,
209        package_name: &PackageName,
210        list: &mut Vec<PackageName>,
211    ) -> Result<(), Error> {
212        let package = self.backend.get_package_detail(package_name)?;
213        for dep in &package.depends {
214            let package = self.backend.get_package_detail(dep)?;
215
216            if list.contains(&package.name) {
217                continue;
218            }
219
220            list.push(package.name.clone());
221            self.get_dependecies_recursive(package_name, list)?;
222        }
223        list.push(package.name);
224        Ok(())
225    }
226
227    pub fn info(&mut self, package: PackageName) -> Result<PackageInfo, Error> {
228        let installed = self.backend.get_installed_packages()?.contains(&package);
229        let package = self.backend.get_package_detail(&package)?;
230
231        Ok(PackageInfo {
232            installed,
233            version: package.version,
234            target: package.target,
235            // this can be implemented
236            download_size: "not implemented".to_string(),
237            depends: package.depends,
238        })
239    }
240}