fix(updater): use all base library paths (#206)
This commit is contained in:
+1
-1
@@ -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 = "
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
@@ -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',
|
||||
);
|
||||
|
||||
@@ -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
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user