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