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};

61

use crate::{pacman, terminal_util};

2+

use crate::{reviewing, wrapped};

3+

use crate::{rua_files, tar_check};

745+

use core::cmp;

86

use directories::ProjectDirs;

7+

use fs_extra::dir::CopyOptions;

98

use 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;

1018

use std::fs;

11-12-

use std::collections::{HashMap, HashSet};

19+

use std::fs::ReadDir;

1320

use std::path::PathBuf;

14211522

pub fn install(targets: Vec<String>, dirs: &ProjectDirs, is_offline: bool, asdeps: bool) {

1623

let mut pacman_deps = HashSet::new();

1724

let mut aur_packages = HashMap::new();

1825

let alpm = pacman::create_alpm();

1926

for install_target in targets {

20-

wrapped::prefetch_aur(

27+

resolve_dependencies(

2128

&install_target,

22-

dirs,

2329

&mut pacman_deps,

2430

&mut aur_packages,

2531

0,

@@ -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));

3036

show_install_summary(&pacman_deps, &aur_packages);

3137

for 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);

3544

install_all(dirs, aur_packages, is_offline, asdeps);

@@ -53,7 +62,7 @@ fn show_install_summary(pacman_deps: &HashSet<String>, aur_packages: &HashMap<St

5362

);

5463

loop {

5564

eprint!("Proceed? [O]=ok, Ctrl-C=abort. ");

56-

let string = terminal_util::console_get_line();

65+

let string = terminal_util::read_line_lowercase();

5766

if string == "o" {

5867

break;

5968

}

@@ -66,83 +75,154 @@ fn install_all(dirs: &ProjectDirs, packages: HashMap<String, i32>, offline: bool

6675

for (depth, packages) in &packages.iter().group_by(|pair| *pair.1) {

6776

let packages: Vec<_> = packages.map(|pair| pair.0).collect();

6877

for 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

}

8695

for name in &packages {

8796

check_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);

92101

let read_dir_iterator = fs::read_dir(checked_tars).unwrap_or_else(|e| {

93102

panic!(

94103

"Failed to read 'checked_tars' directory for {}, {}",

95104

name, e

96105

)

97106

});

98107

for 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

}

109118110119

pub 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| {

128123

panic!(

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| {

143138

panic!(

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

}