1use 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
30const 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 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 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 download_size: "not implemented".to_string(),
237 depends: package.depends,
238 })
239 }
240}