implement upstream diffs, implement shellcheck · vn971/rua@0459a8b
1-use crate::rua_dirs::CHECKED_TARS;
2-use crate::rua_dirs::REVIEWED_BUILD_DIR;
3-use crate::rua_dirs::TARGET_SUBDIR;
4-use crate::tar_check;
5-use crate::{aur_download, wrapped};
61use crate::{pacman, terminal_util};
2+use crate::{reviewing, wrapped};
3+use crate::{rua_files, tar_check};
745+use core::cmp;
86use directories::ProjectDirs;
7+use fs_extra::dir::CopyOptions;
98use itertools::Itertools;
9+use lazy_static::lazy_static;
10+use libalpm::Alpm;
11+use log::debug;
12+use log::info;
13+use log::trace;
14+use raur::Package;
15+use regex::Regex;
16+use std::collections::HashMap;
17+use std::collections::HashSet;
1018use std::fs;
11-12-use std::collections::{HashMap, HashSet};
19+use std::fs::ReadDir;
1320use std::path::PathBuf;
14211522pub fn install(targets: Vec<String>, dirs: &ProjectDirs, is_offline: bool, asdeps: bool) {
1623let mut pacman_deps = HashSet::new();
1724let mut aur_packages = HashMap::new();
1825let alpm = pacman::create_alpm();
1926for install_target in targets {
20-wrapped::prefetch_aur(
27+resolve_dependencies(
2128&install_target,
22- dirs,
2329&mut pacman_deps,
2430&mut aur_packages,
25310,
@@ -29,7 +35,10 @@ pub fn install(targets: Vec<String>, dirs: &ProjectDirs, is_offline: bool, asdep
2935 pacman_deps.retain(|name| !pacman::is_package_installed(&alpm, name));
3036show_install_summary(&pacman_deps, &aur_packages);
3137for name in aur_packages.keys() {
32- aur_download::review_repo(name, dirs);
38+let dir = rua_files::review_dir(dirs, name);
39+ fs::create_dir_all(&dir)
40+.unwrap_or_else(|err| panic!("Failed to create repository dir for {}, {}", name, err));
41+ reviewing::review_repo(&dir, name, dirs);
3342}
3443 pacman::ensure_pacman_packages_installed(pacman_deps);
3544install_all(dirs, aur_packages, is_offline, asdeps);
@@ -53,7 +62,7 @@ fn show_install_summary(pacman_deps: &HashSet<String>, aur_packages: &HashMap<St
5362);
5463loop {
5564eprint!("Proceed? [O]=ok, Ctrl-C=abort. ");
56-let string = terminal_util::console_get_line();
65+let string = terminal_util::read_line_lowercase();
5766if string == "o" {
5867break;
5968}
@@ -66,83 +75,154 @@ fn install_all(dirs: &ProjectDirs, packages: HashMap<String, i32>, offline: bool
6675for (depth, packages) in &packages.iter().group_by(|pair| *pair.1) {
6776let packages: Vec<_> = packages.map(|pair| pair.0).collect();
6877for name in &packages {
78+let review_dir = rua_files::review_dir(dirs, name);
79+let build_dir = rua_files::build_dir(dirs, name);
80+ rm_rf::force_remove_all(&build_dir, true).expect("Failed to remove old build dir");
81+ std::fs::create_dir_all(&build_dir).expect("Failed to create build dir");
82+ fs_extra::copy_items(
83+&vec![review_dir],
84+ rua_files::global_build_dir(dirs),
85+&CopyOptions::new(),
86+)
87+.expect("failed to copy reviewed dir to build dir");
88+ rm_rf::force_remove_all(build_dir.join(".git"), true).expect("Failed to remove .git");
6989 wrapped::build_directory(
70- dirs.cache_dir()
71-.join(&name)
72-.join(REVIEWED_BUILD_DIR)
73-.to_str()
74-.unwrap_or_else(|| {
75-panic!(
76-"{}:{} Failed to resolve build path for {}",
77- file!(),
78- line!(),
79- name
80-)
81-}),
90+&build_dir.to_str().expect("Non-UTF8 directory name"),
8291 dirs,
8392 offline,
8493);
8594}
8695for name in &packages {
8796check_tars_and_move(name, dirs);
8897}
89-let mut packages_to_install: Vec<(String, PathBuf)> = Vec::new();
90-for name in packages {
91-let checked_tars = dirs.cache_dir().join(name).join(CHECKED_TARS);
98+let mut files_to_install: Vec<(String, PathBuf)> = Vec::new();
99+for name in &packages {
100+let checked_tars = rua_files::checked_tars_dir(dirs, &name);
92101let read_dir_iterator = fs::read_dir(checked_tars).unwrap_or_else(|e| {
93102panic!(
94103"Failed to read 'checked_tars' directory for {}, {}",
95104 name, e
96105)
97106});
98107for file in read_dir_iterator {
99-packages_to_install.push((
100- name.to_owned(),
108+files_to_install.push((
109+ name.to_string(),
101110 file.expect("Failed to open file for tar_check analysis")
102111.path(),
103112));
104113}
105114}
106- pacman::ensure_aur_packages_installed(packages_to_install, asdeps || depth > 0);
115+ pacman::ensure_aur_packages_installed(files_to_install, asdeps || depth > 0);
107116}
108117}
109118110119pub fn check_tars_and_move(name: &str, dirs: &ProjectDirs) {
111-let build_target_dir = dirs
112-.cache_dir()
113-.join(name)
114-.join(REVIEWED_BUILD_DIR)
115-.join(TARGET_SUBDIR);
116-let checked_tars_dir = dirs.cache_dir().join(name).join(CHECKED_TARS);
117- rm_rf::force_remove_all(&checked_tars_dir, true).unwrap_or_else(|err| {
118-panic!(
119-"{}:{} Failed to clean checked tar files dir {:?}, {}",
120- file!(),
121- line!(),
122-CHECKED_TARS,
123- err,
124-)
125-});
126-let target_dir = fs::read_dir(&build_target_dir);
127-let target_dir = target_dir.unwrap_or_else(|err| {
120+debug!("{}:{} checking tars for package {}", file!(), line!(), name);
121+let build_dir = rua_files::build_dir(dirs, name);
122+let dir_items: ReadDir = build_dir.read_dir().unwrap_or_else(|err| {
128123panic!(
129-"target directory not found for package {}: {:?}. \
130- \nDoes the PKGBUILD respect the environment variable PKGDEST ?\
131- \n{}",
132- name, &build_target_dir, err,
124+"Failed to read directory contents for {:?}, {}",
125+&build_dir, err
133126)
134127});
135-for file in target_dir {
128+let checked_files = dir_items.flat_map(|file| {
136129 tar_check::tar_check(
137130&file
138131.expect("Failed to open file for tar_check analysis")
139132.path(),
140-);
141-}
142- fs::rename(&build_target_dir, &checked_tars_dir).unwrap_or_else(|e| {
133+)
134+});
135+debug!("all package (tar) files checked, moving them",);
136+let checked_tars_dir = rua_files::checked_tars_dir(dirs, name);
137+ rm_rf::force_remove_all(&checked_tars_dir, true).unwrap_or_else(|err| {
143138panic!(
144-"Failed to move {:?} (build artifacts) to {:?} for package {}, {}",
145-&build_target_dir, &checked_tars_dir, name, e,
139+"Failed to clean checked tar files dir {:?}, {}",
140+ checked_tars_dir, err,
146141)
147142});
143+ fs::create_dir_all(&checked_tars_dir).unwrap_or_else(|err| {
144+panic!(
145+"Failed to create checked_tars dir {:?}, {}",
146+&checked_tars_dir, err
147+);
148+});
149+150+for file in checked_files {
151+let file_name = file.file_name().expect("Failed to parse package tar name");
152+let file_name = file_name
153+.to_str()
154+.expect("Non-UTF8 characters in tar file name");
155+ fs::rename(&file, checked_tars_dir.join(file_name)).unwrap_or_else(|e| {
156+panic!(
157+"Failed to move {:?} (build artifact) to {:?}, {}",
158+&file, &checked_tars_dir, e,
159+)
160+});
161+}
162+}
163+164+/// Check that the package name is easy to work with in shell
165+fn check_package_name(name: &str) {
166+lazy_static! {
167+static ref NAME_REGEX: Regex = Regex::new(r"[a-zA-Z][a-zA-Z._-]*")
168+.unwrap_or_else(|_| panic!("{}:{} Failed to parse regexp", file!(), line!()));
169+}
170+if !NAME_REGEX.is_match(name) {
171+eprintln!("Unexpected package name {}", name);
172+ std::process::exit(1)
173+}
174+}
175+176+fn resolve_dependencies(
177+name: &str,
178+pacman_deps: &mut HashSet<String>,
179+aur_packages: &mut HashMap<String, i32>,
180+depth: i32,
181+alpm: &Alpm,
182+) {
183+check_package_name(&name);
184+if let Some(old_depth) = aur_packages.get(name) {
185+let old_depth = *old_depth;
186+ aur_packages.insert(name.to_owned(), cmp::max(depth + 1, old_depth));
187+info!("Skipping already resolved package {}", name);
188+} else {
189+ aur_packages.insert(name.to_owned(), depth);
190+let info = raur_info(&name);
191+let deps = info
192+.depends
193+.iter()
194+.chain(info.make_depends.iter())
195+.collect::<Vec<_>>();
196+for dep in deps.into_iter() {
197+if pacman::is_package_installed(alpm, &dep) {
198+// skip if already installed
199+} else if !pacman::is_package_installable(alpm, &dep) {
200+info!(
201+"{} depends on AUR package {}. Trying to resolve it...",
202+ name, &dep
203+);
204+resolve_dependencies(&dep, pacman_deps, aur_packages, depth + 1, alpm);
205+} else {
206+ pacman_deps.insert(dep.to_owned());
207+}
208+}
209+}
210+}
211+212+fn raur_info(pkg: &str) -> Package {
213+trace!(
214+"{}:{} Fetching AUR information for package {}",
215+ file!(),
216+ line!(),
217+ pkg
218+);
219+let info = raur::info(&[pkg]);
220+let info = info.unwrap_or_else(|e| panic!("Failed to fetch info for package {}, {}", &pkg, e));
221+match info.into_iter().next() {
222+Some(pkg) => pkg,
223+None => {
224+eprintln!("Package {} not found in AUR", pkg);
225+ std::process::exit(1)
226+}
227+}
148228}