This reverts commit f4db98b759.
This commit is contained in:
Vendored
+1
-1
@@ -15,5 +15,5 @@
|
|||||||
"reqwest",
|
"reqwest",
|
||||||
"tempdir",
|
"tempdir",
|
||||||
"vmcode"
|
"vmcode"
|
||||||
],
|
]
|
||||||
}
|
}
|
||||||
@@ -184,9 +184,6 @@ pub(crate) fn open_base_lib(apks_dir: &Path, lib_name: &str) -> anyhow::Result<C
|
|||||||
Ok(Cursor::new(buffer))
|
Ok(Cursor::new(buffer))
|
||||||
}
|
}
|
||||||
|
|
||||||
// On Android we don't use a direct path to libapp.so, but rather a data dir
|
|
||||||
// and a hard-coded name for the libapp file which we look up in the
|
|
||||||
// split APKs in that datadir. On other platforms we just use a path.
|
|
||||||
pub fn libapp_path_from_settings(original_libapp_paths: &[String]) -> Result<PathBuf, UpdateError> {
|
pub fn libapp_path_from_settings(original_libapp_paths: &[String]) -> Result<PathBuf, UpdateError> {
|
||||||
// FIXME: This makes the assumption that the last path provided is the full
|
// FIXME: This makes the assumption that the last path provided is the full
|
||||||
// path to the libapp.so file. This is true for the current engine, but
|
// path to the libapp.so file. This is true for the current engine, but
|
||||||
@@ -255,7 +255,6 @@ pub extern "C" fn shorebird_report_launch_success() {
|
|||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::network::{testing_set_network_hooks, PatchCheckResponse};
|
use crate::network::{testing_set_network_hooks, PatchCheckResponse};
|
||||||
use crate::platform;
|
|
||||||
use anyhow::Ok;
|
use anyhow::Ok;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
use tempdir::TempDir;
|
use tempdir::TempDir;
|
||||||
@@ -410,7 +409,7 @@ mod test {
|
|||||||
let options = zip::write::FileOptions::default()
|
let options = zip::write::FileOptions::default()
|
||||||
.compression_method(zip::CompressionMethod::Stored)
|
.compression_method(zip::CompressionMethod::Stored)
|
||||||
.unix_permissions(0o755);
|
.unix_permissions(0o755);
|
||||||
let app_path = platform::get_relative_lib_path("libapp.so");
|
let app_path = crate::android::get_relative_lib_path("libapp.so");
|
||||||
zip.start_file(app_path.to_str().unwrap(), options).unwrap();
|
zip.start_file(app_path.to_str().unwrap(), options).unwrap();
|
||||||
zip.write_all(libapp_contents).unwrap();
|
zip.write_all(libapp_contents).unwrap();
|
||||||
zip.finish().unwrap();
|
zip.finish().unwrap();
|
||||||
|
|||||||
+3
-1
@@ -11,11 +11,13 @@ mod config;
|
|||||||
mod events;
|
mod events;
|
||||||
mod logging;
|
mod logging;
|
||||||
mod network;
|
mod network;
|
||||||
mod platform;
|
|
||||||
mod updater;
|
mod updater;
|
||||||
mod updater_lock;
|
mod updater_lock;
|
||||||
mod yaml;
|
mod yaml;
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "android", test))]
|
||||||
|
mod android;
|
||||||
|
|
||||||
// Take all public items from the updater namespace and make them public.
|
// Take all public items from the updater namespace and make them public.
|
||||||
pub use self::updater::*;
|
pub use self::updater::*;
|
||||||
|
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
use std::{
|
|
||||||
fs::File,
|
|
||||||
io::{Cursor, Read},
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
};
|
|
||||||
|
|
||||||
use anyhow::Context;
|
|
||||||
|
|
||||||
use crate::UpdateError;
|
|
||||||
|
|
||||||
/// lib name is unused on iOS, it exists as a parameter here to match the signature of the
|
|
||||||
/// function on Android.
|
|
||||||
pub(crate) fn open_base_lib(app_dir: &Path, _lib_name: &str) -> anyhow::Result<Cursor<Vec<u8>>> {
|
|
||||||
let mut file =
|
|
||||||
File::open(app_dir).with_context(|| format!("Failed to open iOS app_dir {:?}", app_dir))?;
|
|
||||||
let mut buffer = Vec::new();
|
|
||||||
file.read_to_end(&mut buffer)
|
|
||||||
.with_context(|| format!("Failed to read iOS app_dir {:?}", app_dir))?;
|
|
||||||
Ok(Cursor::new(buffer))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn libapp_path_from_settings(original_libapp_paths: &[String]) -> Result<PathBuf, UpdateError> {
|
|
||||||
let first = original_libapp_paths
|
|
||||||
.first()
|
|
||||||
.ok_or(UpdateError::InvalidArgument(
|
|
||||||
"original_libapp_paths".to_string(),
|
|
||||||
"empty".to_string(),
|
|
||||||
));
|
|
||||||
first.map(PathBuf::from)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use std::{fs::File, path::PathBuf};
|
|
||||||
|
|
||||||
use tempdir::TempDir;
|
|
||||||
|
|
||||||
use crate::UpdateError;
|
|
||||||
|
|
||||||
use super::{libapp_path_from_settings, open_base_lib};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn opens_and_reads_app() {
|
|
||||||
let tmp_dir = TempDir::new("test").unwrap();
|
|
||||||
let path = tmp_dir.path().join("foo.txt");
|
|
||||||
File::create(&path).unwrap();
|
|
||||||
let result = open_base_lib(&path.to_path_buf(), "");
|
|
||||||
assert!(result.is_ok());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn returns_error_if_app_fails_to_open() {
|
|
||||||
let tmp_dir = TempDir::new("test").unwrap();
|
|
||||||
let path = tmp_dir.path().join("foo.txt");
|
|
||||||
let result = open_base_lib(&path.to_path_buf(), "");
|
|
||||||
assert!(result.is_err());
|
|
||||||
assert_eq!(
|
|
||||||
format!("{}", result.unwrap_err()),
|
|
||||||
format!("Failed to open iOS app_dir \"{}\"", path.to_str().unwrap()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(bryanoltman): we don't currently test read_to_end returning an Err
|
|
||||||
// result. We should do that, but I'm not sure how.
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn libapp_path_from_settings_returns_first_path() {
|
|
||||||
let path1 = "some/path/1".to_string();
|
|
||||||
let path2 = "some/path/2".to_string();
|
|
||||||
let path3 = "some/path/3".to_string();
|
|
||||||
let result = libapp_path_from_settings(&[path1.clone(), path2.clone(), path3.clone()]);
|
|
||||||
assert!(result.is_ok());
|
|
||||||
assert_eq!(result.unwrap(), PathBuf::from(path1));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn libapp_path_from_settings_returns_err_when_provided_slice_is_empty() {
|
|
||||||
let result = libapp_path_from_settings(&[]);
|
|
||||||
assert!(result.is_err());
|
|
||||||
assert_eq!(
|
|
||||||
result.unwrap_err(),
|
|
||||||
UpdateError::InvalidArgument("original_libapp_paths".to_string(), "empty".to_string(),)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#[cfg(any(target_os = "android", test))]
|
|
||||||
pub mod android;
|
|
||||||
#[cfg(any(target_os = "ios", test))]
|
|
||||||
pub mod ios;
|
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios", test)))]
|
|
||||||
pub mod unknown;
|
|
||||||
|
|
||||||
#[cfg(any(target_os = "android", test))]
|
|
||||||
pub use android::*;
|
|
||||||
#[cfg(target_os = "ios")]
|
|
||||||
pub use ios::*;
|
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios", test)))]
|
|
||||||
pub use unknown::*;
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
use crate::UpdateError;
|
|
||||||
use anyhow::bail;
|
|
||||||
use std::{
|
|
||||||
io::Cursor,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
};
|
|
||||||
|
|
||||||
const UNKNOWN_PLATFORM_ERR_MSG: &str = "Unknown platform";
|
|
||||||
|
|
||||||
pub fn open_base_lib(_app_dir: &Path, _lib_name: &str) -> anyhow::Result<Cursor<Vec<u8>>> {
|
|
||||||
bail!(UNKNOWN_PLATFORM_ERR_MSG)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn libapp_path_from_settings(
|
|
||||||
_original_libapp_paths: &[String],
|
|
||||||
) -> Result<PathBuf, UpdateError> {
|
|
||||||
Err(UpdateError::InvalidState(
|
|
||||||
UNKNOWN_PLATFORM_ERR_MSG.to_string(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
+44
-9
@@ -1,7 +1,8 @@
|
|||||||
// This file's job is to be the Rust API for the updater.
|
// This file's job is to be the Rust API for the updater.
|
||||||
|
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::fs::File;
|
use std::fs;
|
||||||
|
#[cfg(any(target_os = "android", test))]
|
||||||
use std::io::{Read, Seek};
|
use std::io::{Read, Seek};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
@@ -15,7 +16,6 @@ use crate::logging::init_logging;
|
|||||||
use crate::network::{
|
use crate::network::{
|
||||||
download_to_path, send_patch_check_request, NetworkHooks, PatchCheckResponse,
|
download_to_path, send_patch_check_request, NetworkHooks, PatchCheckResponse,
|
||||||
};
|
};
|
||||||
use crate::platform::{libapp_path_from_settings, open_base_lib};
|
|
||||||
use crate::updater_lock::{with_updater_thread_lock, UpdaterLockState};
|
use crate::updater_lock::{with_updater_thread_lock, UpdaterLockState};
|
||||||
use crate::yaml::YamlConfig;
|
use crate::yaml::YamlConfig;
|
||||||
|
|
||||||
@@ -84,12 +84,29 @@ pub struct AppConfig {
|
|||||||
pub original_libapp_paths: Vec<String>,
|
pub original_libapp_paths: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// On Android we don't use a direct path to libapp.so, but rather a data dir
|
||||||
|
// and a hard-coded name for the libapp file which we look up in the
|
||||||
|
// split APKs in that datadir. On other platforms we just use a path.
|
||||||
|
#[cfg(not(any(target_os = "android", test)))]
|
||||||
|
fn libapp_path_from_settings(original_libapp_paths: &[String]) -> Result<PathBuf, UpdateError> {
|
||||||
|
let first = original_libapp_paths
|
||||||
|
.first()
|
||||||
|
.ok_or(UpdateError::InvalidArgument(
|
||||||
|
"original_libapp_paths".to_string(),
|
||||||
|
"empty".to_string(),
|
||||||
|
));
|
||||||
|
first.map(PathBuf::from)
|
||||||
|
}
|
||||||
|
|
||||||
/// Initialize the updater library.
|
/// Initialize the updater library.
|
||||||
/// Takes a `AppConfig` struct and a yaml string.
|
/// Takes a `AppConfig` struct and a yaml string.
|
||||||
/// The yaml string is the contents of the `shorebird.yaml` file.
|
/// The yaml string is the contents of the `shorebird.yaml` file.
|
||||||
/// The `AppConfig` struct is information about the running app and where
|
/// The `AppConfig` struct is information about the running app and where
|
||||||
/// the updater should keep its cache.
|
/// the updater should keep its cache.
|
||||||
pub fn init(app_config: AppConfig, yaml: &str) -> Result<(), UpdateError> {
|
pub fn init(app_config: AppConfig, yaml: &str) -> Result<(), UpdateError> {
|
||||||
|
#[cfg(any(target_os = "android", test))]
|
||||||
|
use crate::android::libapp_path_from_settings;
|
||||||
|
|
||||||
init_logging();
|
init_logging();
|
||||||
let config = YamlConfig::from_yaml(yaml)
|
let config = YamlConfig::from_yaml(yaml)
|
||||||
.map_err(|err| UpdateError::InvalidArgument("yaml".to_string(), err.to_string()))?;
|
.map_err(|err| UpdateError::InvalidArgument("yaml".to_string(), err.to_string()))?;
|
||||||
@@ -127,7 +144,7 @@ fn check_hash(path: &Path, expected_string: &str) -> anyhow::Result<()> {
|
|||||||
// Based on guidance from:
|
// Based on guidance from:
|
||||||
// <https://github.com/RustCrypto/hashes#hashing-readable-objects>
|
// <https://github.com/RustCrypto/hashes#hashing-readable-objects>
|
||||||
|
|
||||||
let mut file = File::open(path)?;
|
let mut file = fs::File::open(path)?;
|
||||||
let mut hasher = Sha256::new();
|
let mut hasher = Sha256::new();
|
||||||
std::io::copy(&mut file, &mut hasher)?;
|
std::io::copy(&mut file, &mut hasher)?;
|
||||||
// Check that the length from copy is the same as the file size?
|
// Check that the length from copy is the same as the file size?
|
||||||
@@ -152,17 +169,32 @@ fn check_hash(path: &Path, expected_string: &str) -> anyhow::Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is just a place to put our terrible android hacks.
|
||||||
|
// And also avoid (for now) dealing with inflating patches on iOS.
|
||||||
|
#[cfg(any(target_os = "android", test))]
|
||||||
fn prepare_for_install(
|
fn prepare_for_install(
|
||||||
app_dir: &PathBuf,
|
config: &UpdateConfig,
|
||||||
download_path: &Path,
|
download_path: &Path,
|
||||||
output_path: &Path,
|
output_path: &Path,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
// We abuse `libapp_path` to actually be the path to the data dir for now.
|
// We abuse `libapp_path` to actually be the path to the data dir for now.
|
||||||
// This is an abuse because the variable name is `libapp_path`, but
|
// This is an abuse because the variable name is `libapp_path`, but
|
||||||
// we're making it point to a the `app_data` directory instead.
|
// we're making it point to a the `app_data` directory instead.
|
||||||
|
let app_dir = &config.libapp_path;
|
||||||
debug!("app_dir: {:?}", app_dir);
|
debug!("app_dir: {:?}", app_dir);
|
||||||
let base_release_artifact = open_base_lib(app_dir, "libapp.so")?;
|
let base_r = crate::android::open_base_lib(app_dir, "libapp.so")?;
|
||||||
inflate(download_path, base_release_artifact, output_path)
|
inflate(download_path, base_r, output_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "android", test)))]
|
||||||
|
fn prepare_for_install(
|
||||||
|
_config: &UpdateConfig,
|
||||||
|
download_path: &Path,
|
||||||
|
output_path: &Path,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
// On iOS we don't yet support compressed patches, just copy the file.
|
||||||
|
fs::copy(download_path, output_path)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_update_config() -> anyhow::Result<UpdateConfig> {
|
fn copy_update_config() -> anyhow::Result<UpdateConfig> {
|
||||||
@@ -233,7 +265,8 @@ fn update_internal(_: &UpdaterLockState) -> anyhow::Result<UpdateStatus> {
|
|||||||
download_to_path(&config.network_hooks, &patch.download_url, &download_path)?;
|
download_to_path(&config.network_hooks, &patch.download_url, &download_path)?;
|
||||||
|
|
||||||
let output_path = download_dir.join(format!("{}.full", patch.number));
|
let output_path = download_dir.join(format!("{}.full", patch.number));
|
||||||
prepare_for_install(&config.libapp_path, &download_path, &output_path)?;
|
// Should not pass config, rather should read necessary information earlier.
|
||||||
|
prepare_for_install(&config, &download_path, &output_path)?;
|
||||||
|
|
||||||
// Check the hash before moving into place.
|
// Check the hash before moving into place.
|
||||||
check_hash(&output_path, &patch.hash).context(format!(
|
check_hash(&output_path, &patch.hash).context(format!(
|
||||||
@@ -269,6 +302,7 @@ pub fn update() -> anyhow::Result<UpdateStatus> {
|
|||||||
|
|
||||||
/// Given a path to a patch file, and a base file, apply the patch to the base
|
/// Given a path to a patch file, and a base file, apply the patch to the base
|
||||||
/// and write the result to the output path.
|
/// and write the result to the output path.
|
||||||
|
#[cfg(any(target_os = "android", test))]
|
||||||
fn inflate<RS>(patch_path: &Path, base_r: RS, output_path: &Path) -> anyhow::Result<()>
|
fn inflate<RS>(patch_path: &Path, base_r: RS, output_path: &Path) -> anyhow::Result<()>
|
||||||
where
|
where
|
||||||
RS: Read + Seek,
|
RS: Read + Seek,
|
||||||
@@ -282,9 +316,10 @@ where
|
|||||||
// PipeReader/Writer errors instead of file open errors.
|
// PipeReader/Writer errors instead of file open errors.
|
||||||
debug!("Reading patch file: {:?}", patch_path);
|
debug!("Reading patch file: {:?}", patch_path);
|
||||||
let compressed_patch_r = BufReader::new(
|
let compressed_patch_r = BufReader::new(
|
||||||
File::open(patch_path).context(format!("Failed to open patch file: {:?}", patch_path))?,
|
fs::File::open(patch_path)
|
||||||
|
.context(format!("Failed to open patch file: {:?}", patch_path))?,
|
||||||
);
|
);
|
||||||
let output_file_w = File::create(output_path)?;
|
let output_file_w = fs::File::create(output_path)?;
|
||||||
|
|
||||||
// Set up a pipe to connect the writing from the decompression thread
|
// Set up a pipe to connect the writing from the decompression thread
|
||||||
// to the reading of the decompressed patch data on this thread.
|
// to the reading of the decompressed patch data on this thread.
|
||||||
|
|||||||
Reference in New Issue
Block a user