1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
use crate::config::{Architecture, OsType, PackageType, VmConfig};
use anyhow::{Context, Result};
use once_cell::sync::Lazy;
use regex::Regex;
use std::path::{Path, PathBuf};
static VERSION_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(r"\d{4}\.\d+(-beta\d+)?(-dev)?-([0-9a-z])+").unwrap());
#[derive(Debug, Clone)]
pub struct Manifest {
pub app_package_path: PathBuf,
pub app_package_to_upgrade_from_path: Option<PathBuf>,
pub ui_e2e_tests_path: Option<PathBuf>,
}
/// Obtain app packages and their filenames
/// If it's a path, use the path.
/// If it corresponds to a file in packages/, use that package.
/// TODO: If it's a git tag or rev, download it.
pub fn get_app_manifest(
config: &VmConfig,
app_package: String,
app_package_to_upgrade_from: Option<String>,
package_folder: Option<PathBuf>,
) -> Result<Manifest> {
let package_type = (config.os_type, config.package_type, config.architecture);
let app_package_path = find_app(&app_package, false, package_type, package_folder.as_ref())?;
log::info!("App package: {}", app_package_path.display());
let app_package_to_upgrade_from_path = app_package_to_upgrade_from
.map(|app| find_app(&app, false, package_type, package_folder.as_ref()))
.transpose()?;
log::info!("App package to upgrade from: {app_package_to_upgrade_from_path:?}");
let capture = VERSION_REGEX
.captures(app_package_path.to_str().unwrap())
.with_context(|| format!("Cannot parse version: {}", app_package_path.display()))?
.get(0)
.map(|c| c.as_str())
.expect("Could not parse version from package name: {app_package}");
let ui_e2e_tests_path = find_app(capture, true, package_type, package_folder.as_ref()).ok();
log::info!("GUI e2e test binary: {ui_e2e_tests_path:?}");
Ok(Manifest {
app_package_path,
app_package_to_upgrade_from_path,
ui_e2e_tests_path,
})
}
fn find_app(
app: &str,
e2e_bin: bool,
package_type: (OsType, Option<PackageType>, Option<Architecture>),
package_folder: Option<&PathBuf>,
) -> Result<PathBuf> {
// If it's a path, use that path
let app_path = Path::new(app);
if app_path.is_file() {
// TODO: Copy to packages?
return Ok(app_path.to_path_buf());
}
let mut app = app.to_owned();
app.make_ascii_lowercase();
let current_dir = std::env::current_dir().expect("Unable to get current directory");
let packages_dir = package_folder.unwrap_or(¤t_dir);
std::fs::create_dir_all(packages_dir)?;
let dir = std::fs::read_dir(packages_dir.clone()).context("Failed to list packages")?;
dir
.filter_map(|entry| entry.ok())
.map(|entry| entry.path())
.filter(|entry| entry.is_file())
.filter(|path| {
e2e_bin ||
path
.extension()
.map(|m_ext| m_ext.eq_ignore_ascii_case(get_ext(package_type)))
.unwrap_or(false)
}) // Filter out irrelevant platforms
.map(|path| {
let u8_path = path.as_os_str().to_string_lossy().to_ascii_lowercase();
(path, u8_path)
})
.filter(|(_path, u8_path)| !(e2e_bin ^ u8_path.contains("app-e2e-tests"))) // Skip non-UI-e2e binaries or vice versa
.filter(|(_path, u8_path)| !e2e_bin || u8_path.contains(get_os_name(package_type))) // Filter out irrelevant platforms
.filter(|(_path, u8_path)| {
let linux = e2e_bin || package_type.0 == OsType::Linux;
let matching_ident = package_type.2.map(|arch| arch.get_identifiers().iter().any(|id| u8_path.contains(id))).unwrap_or(true);
// Skip for non-Linux, because there's only one package
!linux || matching_ident
}) // Skip file if it doesn't match the architecture
.find(|(_path, u8_path)| u8_path.contains(&app)) // Find match
.map(|(path, _)| path).context(if e2e_bin {
format!(
"Could not find UI/e2e test for package: {app}.\n\
Expecting a binary named like `app-e2e-tests-{app}_ARCH` to exist in {package_dir}/\n\
Example ARCH: `amd64-unknown-linux-gnu`, `x86_64-unknown-linux-gnu`",
package_dir = packages_dir.display()
)
} else {
format!("Could not find package for app: {app}")
})
}
fn get_ext(package_type: (OsType, Option<PackageType>, Option<Architecture>)) -> &'static str {
match package_type.0 {
OsType::Windows => "exe",
OsType::Macos => "pkg",
OsType::Linux => match package_type.1.expect("must specify package type") {
PackageType::Deb => "deb",
PackageType::Rpm => "rpm",
},
}
}
fn get_os_name(package_type: (OsType, Option<PackageType>, Option<Architecture>)) -> &'static str {
match package_type.0 {
OsType::Windows => "windows",
OsType::Macos => "apple",
OsType::Linux => "linux",
}
}
|