fix(updater): use all base library paths (#206)

This commit is contained in:
Felix Angelov
2023-03-31 12:44:12 -05:00
committed by GitHub
parent d541d466a8
commit 60a931f0d9
8 changed files with 108 additions and 25 deletions
+1 -1
View File
@@ -22,7 +22,7 @@ fn main() {
let config = updater::AppConfig {
cache_dir: "updater_cache".to_owned(),
release_version: "0.1.0".to_owned(),
original_libapp_path: "libapp.so".to_owned(),
original_libapp_paths: vec!["libapp.so".to_owned()],
vm_path: "libflutter.so".to_owned(),
};
let yaml_str = "
+17 -4
View File
@@ -16,7 +16,10 @@ class AppParameters extends ffi.Struct {
// ignore: non_constant_identifier_names
external ffi.Pointer<Utf8> update_url;
// ignore: non_constant_identifier_names
external ffi.Pointer<Utf8> original_libapp_path;
external ffi.Pointer<ffi.Pointer<Utf8>> original_libapp_paths;
@ffi.Int8()
// ignore: non_constant_identifier_names
external int original_libapp_paths_size;
// ignore: non_constant_identifier_names
external ffi.Pointer<Utf8> vm_path;
// ignore: non_constant_identifier_names
@@ -27,7 +30,7 @@ class AppParameters extends ffi.Struct {
required String version,
required String channel,
required String? updateUrl,
required String libappPath,
required List<String> libappPaths,
required String libflutterPath,
required String cacheDir,
}) {
@@ -38,7 +41,13 @@ class AppParameters extends ffi.Struct {
if (updateUrl != null) {
config.ref.update_url = updateUrl.toNativeUtf8();
}
config.ref.original_libapp_path = libappPath.toNativeUtf8();
config.ref.original_libapp_paths = calloc<ffi.Pointer<Utf8>>(
libappPaths.length,
);
for (var i = 0; i < libappPaths.length; i++) {
config.ref.original_libapp_paths[i] = libappPaths[i].toNativeUtf8();
}
config.ref.vm_path = libflutterPath.toNativeUtf8();
config.ref.cache_dir = cacheDir.toNativeUtf8();
return config;
@@ -49,7 +58,11 @@ class AppParameters extends ffi.Struct {
calloc.free(config.ref.base_version);
calloc.free(config.ref.channel);
calloc.free(config.ref.update_url);
calloc.free(config.ref.original_libapp_path);
// Free all paths in original_libapp_path.
for (var i = 0; i < config.ref.original_libapp_paths_size; i++) {
calloc.free(config.ref.original_libapp_paths[i]);
}
calloc.free(config.ref.original_libapp_paths);
calloc.free(config.ref.vm_path);
calloc.free(config.ref.cache_dir);
calloc.free(config);
+2 -2
View File
@@ -54,7 +54,7 @@ class Updater {
required String version,
required String channel,
required String? updateUrl,
required String baseLibraryPath,
required List<String> baseLibraryPaths,
required String vmPath,
required String cacheDir,
}) {
@@ -63,7 +63,7 @@ class Updater {
version: version,
channel: channel,
updateUrl: updateUrl,
libappPath: baseLibraryPath,
libappPaths: baseLibraryPaths,
libflutterPath: vmPath,
cacheDir: cacheDir,
);
+1 -1
View File
@@ -14,7 +14,7 @@ void main(List<String> args) async {
version: '1.0.0',
channel: 'stable',
updateUrl: null,
baseLibraryPath: 'libapp.so',
baseLibraryPaths: ['libapp.so'],
vmPath: Platform.executable,
cacheDir: 'updater_cache',
);
+7 -4
View File
@@ -26,11 +26,14 @@ typedef struct AppParameters {
*/
const char *release_version;
/**
* Path to the original aot library, required. For Flutter apps this
* is the path to the bundled libapp.so. May be used for compression
* downloaded artifacts.
* Array of paths to the original aot library, required. For Flutter apps
* these are the paths to the bundled libapp.so. May be used for compression downloaded artifacts.
*/
const char *original_libapp_path;
const char *const *original_libapp_paths;
/**
* Length of the original_libapp_paths array.
*/
int original_libapp_paths_size;
/**
* Path to the app's libflutter.so, required. May be used for ensuring
* downloaded artifacts are compatible with the Flutter/Dart versions
+19 -5
View File
@@ -18,10 +18,12 @@ pub struct AppParameters {
/// are based. Can be either a version number or a hash.
pub release_version: *const libc::c_char,
/// Path to the original aot library, required. For Flutter apps this
/// is the path to the bundled libapp.so. May be used for compression
/// downloaded artifacts.
pub original_libapp_path: *const libc::c_char,
/// Array of paths to the original aot library, required. For Flutter apps
/// these are the paths to the bundled libapp.so. May be used for compression downloaded artifacts.
pub original_libapp_paths: *const *const libc::c_char,
/// Length of the original_libapp_paths array.
pub original_libapp_paths_size: libc::c_int,
/// Path to the app's libflutter.so, required. May be used for ensuring
/// downloaded artifacts are compatible with the Flutter/Dart versions
@@ -38,13 +40,25 @@ fn to_rust(c_string: *const libc::c_char) -> String {
unsafe { CStr::from_ptr(c_string).to_str().unwrap() }.to_string()
}
fn to_rust_vector(c_array: *const *const libc::c_char, size: libc::c_int) -> Vec<String> {
let mut result = Vec::new();
for i in 0..size {
let c_string = unsafe { *c_array.offset(i as isize) };
result.push(to_rust(c_string));
}
result
}
fn app_config_from_c(c_params: *const AppParameters) -> updater::AppConfig {
let c_params_ref = unsafe { &*c_params };
updater::AppConfig {
cache_dir: to_rust(c_params_ref.cache_dir),
release_version: to_rust(c_params_ref.release_version),
original_libapp_path: to_rust(c_params_ref.original_libapp_path),
original_libapp_paths: to_rust_vector(
c_params_ref.original_libapp_paths,
c_params_ref.original_libapp_paths_size,
),
vm_path: to_rust(c_params_ref.vm_path),
}
}
+3 -3
View File
@@ -40,7 +40,7 @@ pub struct ResolvedConfig {
pub channel: String,
pub app_id: String,
pub release_version: String,
pub original_libapp_path: String,
pub original_libapp_paths: Vec<String>,
pub vm_path: String,
pub base_url: String,
}
@@ -54,7 +54,7 @@ impl ResolvedConfig {
channel: String::new(),
app_id: String::new(),
release_version: String::new(),
original_libapp_path: String::new(),
original_libapp_paths: Vec::new(),
vm_path: String::new(),
base_url: String::new(),
}
@@ -83,7 +83,7 @@ pub fn set_config(config: AppConfig, yaml: YamlConfig) {
lock.download_dir = cache_path.to_str().unwrap().to_string();
lock.app_id = yaml.app_id.to_string();
lock.release_version = config.release_version.to_string();
lock.original_libapp_path = config.original_libapp_path.to_string();
lock.original_libapp_paths = config.original_libapp_paths;
lock.vm_path = config.vm_path.to_string();
lock.is_initialized = true;
info!("Updater configured with: {:?}", lock);
+58 -5
View File
@@ -58,7 +58,7 @@ impl Display for UpdateError {
pub struct AppConfig {
pub cache_dir: String,
pub release_version: String,
pub original_libapp_path: String,
pub original_libapp_paths: Vec<String>,
pub vm_path: String,
}
@@ -145,8 +145,7 @@ fn update_internal(config: &ResolvedConfig) -> anyhow::Result<UpdateStatus> {
let download_path = download_dir.join(patch.number.to_string());
download_to_path(&patch.download_url, &download_path)?;
// Inflate the patch from a diff.
let base_path = PathBuf::from(&config.original_libapp_path);
let base_path = get_base_path(&config.original_libapp_paths)?;
let output_path = download_dir.join(format!("{}.full", patch.number.to_string()));
inflate(&download_path, &base_path, &output_path)?;
@@ -169,6 +168,17 @@ fn update_internal(config: &ResolvedConfig) -> anyhow::Result<UpdateStatus> {
return Ok(UpdateStatus::UpdateInstalled);
}
fn get_base_path(original_lib_app_paths: &Vec<String>) -> anyhow::Result<PathBuf> {
// Iterate through the paths and find the first one that exists.
for path in original_lib_app_paths {
let path = PathBuf::from(path);
if path.exists() {
return Ok(path);
}
}
return Err(UpdateError::InvalidState("No base file found".to_string()).into());
}
fn inflate(patch_path: &Path, base_path: &Path, output_path: &Path) -> anyhow::Result<()> {
info!("Patch is compressed, inflating...");
use anyhow::Context;
@@ -275,7 +285,7 @@ mod tests {
crate::AppConfig {
cache_dir: cache_dir.clone(),
release_version: "1.0.0".to_string(),
original_libapp_path: "original_libapp_path".to_string(),
original_libapp_paths: vec!["original_libapp_path".to_string()],
vm_path: "vm_path".to_string(),
},
"app_id: 1234",
@@ -292,7 +302,7 @@ mod tests {
crate::AppConfig {
cache_dir: cache_dir.clone(),
release_version: "1.0.0".to_string(),
original_libapp_path: "original_libapp_path".to_string(),
original_libapp_paths: vec!["original_libapp_path".to_string()],
vm_path: "vm_path".to_string(),
},
"",
@@ -398,4 +408,47 @@ mod tests {
error = result.unwrap_err();
assert!(format!("{}", error).starts_with("Failed to open patch file:"));
}
#[test]
fn get_base_path_uses_correct_path() {
let tmp_dir = TempDir::new("example").unwrap();
let missing_file = tmp_dir.path().join("missing_file");
let existing_file = tmp_dir.path().join("existing_file");
std::fs::write(&existing_file, "hello world").unwrap();
// Should use first file since it exists.
let mut base_paths = vec![
existing_file.as_path().to_str().unwrap().to_string(),
missing_file.as_path().to_str().unwrap().to_string(),
];
let mut result = super::get_base_path(&base_paths);
assert_eq!(result.unwrap(), existing_file.as_path());
// Should skip first file since it is missing.
base_paths = vec![
missing_file.as_path().to_str().unwrap().to_string(),
existing_file.as_path().to_str().unwrap().to_string(),
];
result = super::get_base_path(&base_paths);
assert_eq!(result.unwrap(), existing_file.as_path());
// Should error since all files are missing.
base_paths = vec![
missing_file.as_path().to_str().unwrap().to_string(),
missing_file.as_path().to_str().unwrap().to_string(),
];
result = super::get_base_path(&base_paths);
let error = result.unwrap_err();
assert_eq!(
format!("{}", error),
"Invalid State: No base file found".to_string()
);
}
}