refactor(updater): conform to new backend interfaces (#90)

This commit is contained in:
Felix Angelov
2023-03-17 13:00:35 -05:00
committed by GitHub
parent 1cf8aa9662
commit e91f2dbaac
14 changed files with 102 additions and 133 deletions
+11 -10
View File
@@ -1,38 +1,39 @@
name: Dart Package Workflow
description: Build and test your Dart packages.
inputs:
concurrency:
required: false
type: number
default: 4
default: "4"
description: The value of the concurrency flag (-j) used when running tests
coverage_excludes:
required: false
type: string
default: ""
description: Globs to exclude from coverage
dart_sdk:
required: false
type: string
default: "stable"
description: "The dart sdk version to use"
working_directory:
required: false
type: string
default: "."
description: The working directory for this workflow
min_coverage:
required: false
type: number
default: 100
default: "100"
description: The minimum coverage percentage value
analyze_directories:
required: false
type: string
default: "lib test"
description: Directories to analyze
report_on:
required: false
type: string
default: "lib"
description: Directories to report on when collecting coverage
platform:
required: false
type: string
default: "vm"
description: Platform to use when running tests
runs:
using: "composite"
+21
View File
@@ -0,0 +1,21 @@
name: Rust Crate Workflow
description: Build and test your Rust crate
inputs:
working_directory:
required: false
default: "."
description: The working directory for this workflow.
runs:
using: "composite"
steps:
- name: Build
working-directory: ${{ inputs.working_directory }}
shell: ${{ inputs.shell }}
run: cargo build --verbose
- name: Test
working-directory: ${{ inputs.working_directory }}
shell: ${{ inputs.shell }}
run: cargo test --verbose
+38 -6
View File
@@ -17,7 +17,8 @@ jobs:
pull-requests: read
outputs:
needs_build: ${{ steps.needs_build.outputs.changes }}
needs_dart_build: ${{ steps.needs_dart_build.outputs.changes }}
needs_rust_build: ${{ steps.needs_rust_build.outputs.changes }}
needs_verify: ${{ steps.needs_verify.outputs.changes }}
name: 👀 Detect Changes
@@ -28,7 +29,7 @@ jobs:
- uses: dorny/paths-filter@v2
name: Build Detection
id: needs_build
id: needs_dart_build
with:
filters: |
shorebird_cli:
@@ -42,6 +43,15 @@ jobs:
- ./.github/actions/dart_package
- packages/shorebird_code_push_protocol/**
- uses: dorny/paths-filter@v2
name: Build Detection
id: needs_rust_build
with:
filters: |
updater:
- ./.github/actions/rust
- updater/**
- uses: dorny/paths-filter@v2
name: Verify Detection
id: needs_verify
@@ -51,13 +61,13 @@ jobs:
- ./.github/actions/dart_package
- packages/shorebird_cli/**
build_packages:
build_dart_packages:
needs: changes
if: ${{ needs.changes.outputs.needs_build != '[]' }}
if: ${{ needs.changes.outputs.needs_dart_build != '[]' }}
strategy:
matrix:
package: ${{ fromJSON(needs.changes.outputs.needs_build) }}
package: ${{ fromJSON(needs.changes.outputs.needs_dart_build) }}
runs-on: ubuntu-latest
@@ -72,6 +82,27 @@ jobs:
with:
working_directory: packages/${{ matrix.package }}
build_rust_crates:
needs: changes
if: ${{ needs.changes.outputs.needs_rust_build != '[]' }}
strategy:
matrix:
crate: ${{ fromJSON(needs.changes.outputs.needs_rust_build) }}
runs-on: ubuntu-latest
name: 🦀 Build ${{ matrix.crate }}
steps:
- name: 📚 Git Checkout
uses: actions/checkout@v3
- name: 🦀 Build ${{ matrix.package }}
uses: ./.github/actions/rust_crate
with:
working_directory: ${{ matrix.crate }}
verify_packages:
needs: changes
if: ${{ needs.changes.outputs.needs_verify != '[]' }}
@@ -94,7 +125,8 @@ jobs:
working_directory: packages/${{ matrix.package }}
ci:
needs: [semantic_pull_request, build_packages, verify_packages]
needs:
[semantic_pull_request, build_dart_packages, build_rust_crates, verify_packages]
if: ${{ always() }}
runs-on: ubuntu-latest
@@ -1,4 +1,3 @@
export 'app.dart';
export 'patch.dart';
export 'patch_artifact.dart';
export 'user.dart';
@@ -1,33 +0,0 @@
import 'package:json_annotation/json_annotation.dart';
part 'patch_artifact.g.dart';
/// {@template patch_artifact}
/// A patch artifact represents the contents of an update (patch) for a specific
/// platform and architecture.
/// {@endtemplate}
@JsonSerializable()
class PatchArtifact {
/// {@macro patch_PatchArtifact}
const PatchArtifact({
required this.patchNumber,
required this.downloadUrl,
required this.hash,
});
/// Converts a Map<String, dynamic> to an [PatchArtifact]
factory PatchArtifact.fromJson(Map<String, dynamic> json) =>
_$PatchArtifactFromJson(json);
/// Converts an [PatchArtifact] to a Map<String, dynamic>
Map<String, dynamic> toJson() => _$PatchArtifactToJson(this);
/// The patch number associated with the artifact.
final int patchNumber;
/// The URL of the artifact.
final String downloadUrl;
/// The hash of the artifact.
final String hash;
}
@@ -1,34 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: implicit_dynamic_parameter, require_trailing_commas, cast_nullable_to_non_nullable, lines_longer_than_80_chars
part of 'patch_artifact.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
PatchArtifact _$PatchArtifactFromJson(Map<String, dynamic> json) =>
$checkedCreate(
'PatchArtifact',
json,
($checkedConvert) {
final val = PatchArtifact(
patchNumber: $checkedConvert('patch_number', (v) => v as int),
downloadUrl: $checkedConvert('download_url', (v) => v as String),
hash: $checkedConvert('hash', (v) => v as String),
);
return val;
},
fieldKeyMap: const {
'patchNumber': 'patch_number',
'downloadUrl': 'download_url'
},
);
Map<String, dynamic> _$PatchArtifactToJson(PatchArtifact instance) =>
<String, dynamic>{
'patch_number': instance.patchNumber,
'download_url': instance.downloadUrl,
'hash': instance.hash,
};
@@ -1,18 +0,0 @@
import 'package:shorebird_code_push_protocol/shorebird_code_push_protocol.dart';
import 'package:test/test.dart';
void main() {
group('PatchArtifact', () {
test('can be (de)serialized', () {
const patchArtifact = PatchArtifact(
patchNumber: 1,
downloadUrl: 'https://example.com',
hash: '#',
);
expect(
PatchArtifact.fromJson(patchArtifact.toJson()).toJson(),
equals(patchArtifact.toJson()),
);
});
});
}
+2 -2
View File
@@ -21,7 +21,7 @@ fn main() {
let config = updater::AppConfig {
cache_dir: "updater_cache".to_owned(),
base_version: "0.1.0".to_owned(),
release_version: "0.1.0".to_owned(),
original_libapp_path: "libapp.so".to_owned(),
vm_path: "libflutter.so".to_owned(),
};
@@ -50,7 +50,7 @@ base_url: http://localhost:8000
match version {
Some(v) => {
println!("path: {:?}", v.path);
println!("version: {:?}", v.version);
println!("number: {:?}", v.number);
}
None => {
println!("None");
+2 -2
View File
@@ -21,10 +21,10 @@
*/
typedef struct AppParameters {
/**
* base_version, required. Named version of the app, off of which updates
* release_version, required. Named version of the app, off of which updates
* are based. Can be either a version number or a hash.
*/
const char *base_version;
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
+8 -7
View File
@@ -14,9 +14,9 @@ use crate::updater;
/// NOTE: If this struct is changed all language bindings must be updated.
#[repr(C)]
pub struct AppParameters {
/// base_version, required. Named version of the app, off of which updates
/// release_version, required. Named version of the app, off of which updates
/// are based. Can be either a version number or a hash.
pub base_version: *const libc::c_char,
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
@@ -43,7 +43,7 @@ fn app_config_from_c(c_params: *const AppParameters) -> updater::AppConfig {
updater::AppConfig {
cache_dir: to_rust(c_params_ref.cache_dir),
base_version: to_rust(c_params_ref.base_version),
release_version: to_rust(c_params_ref.release_version),
original_libapp_path: to_rust(c_params_ref.original_libapp_path),
vm_path: to_rust(c_params_ref.vm_path),
}
@@ -67,13 +67,14 @@ pub extern "C" fn shorebird_init(c_params: *const AppParameters, c_yaml: *const
}
/// Return the active version of the app, or NULL if there is no active version.
// TODO: This should probably be renamed to `shorebird_active_patch_number`.
#[no_mangle]
pub extern "C" fn shorebird_active_version() -> *mut c_char {
let version = updater::active_patch();
match version {
let patch = updater::active_patch();
match patch {
Some(v) => {
let c_version = CString::new(v.version).unwrap();
c_version.into_raw()
let c_patch = CString::new(v.number.to_string()).unwrap();
c_patch.into_raw()
}
None => std::ptr::null_mut(),
}
+11 -11
View File
@@ -11,15 +11,15 @@ use crate::network::{download_file_to_path, PatchCheckResponse};
#[derive(PartialEq, Debug)]
pub struct PatchInfo {
pub path: String,
pub version: String,
pub number: usize,
}
#[derive(Deserialize, Serialize, Default, Clone)]
struct Slot {
/// Path to the slot directory.
path: String,
/// Version of the patch in this slot.
patch_version: String,
/// Patch number for the patch in this slot.
patch_number: usize,
}
// This struct is public, as callers can have a handle to it, but modifying
@@ -27,10 +27,10 @@ struct Slot {
#[derive(Deserialize, Serialize)]
pub struct UpdaterState {
/// List of patches that failed to boot. We will never attempt these again.
failed_patches: Vec<String>,
failed_patches: Vec<usize>,
/// List of patches that successfully booted. We will never rollback past
/// one of these for this device.
successful_patches: Vec<String>,
successful_patches: Vec<usize>,
/// Currently selected slot.
current_slot_index: usize,
/// List of slots.
@@ -51,11 +51,11 @@ impl Default for UpdaterState {
impl UpdaterState {
pub fn is_known_good_patch(&self, patch: &PatchInfo) -> bool {
self.successful_patches.iter().any(|v| v == &patch.version)
self.successful_patches.iter().any(|v| v == &patch.number)
}
pub fn is_known_bad_patch(&self, patch: &PatchInfo) -> bool {
self.failed_patches.iter().any(|v| v == &patch.version)
self.failed_patches.iter().any(|v| v == &patch.number)
}
pub fn mark_patch_as_bad(&mut self, patch: &PatchInfo) {
@@ -67,7 +67,7 @@ impl UpdaterState {
if self.is_known_bad_patch(patch) {
return;
}
self.failed_patches.push(patch.version.clone());
self.failed_patches.push(patch.number.clone());
}
pub fn mark_patch_as_good(&mut self, patch: &PatchInfo) {
@@ -79,7 +79,7 @@ impl UpdaterState {
if self.is_known_good_patch(patch) {
return;
}
self.successful_patches.push(patch.version.clone());
self.successful_patches.push(patch.number.clone());
}
pub fn load(cache_dir: &str) -> anyhow::Result<Self> {
@@ -111,7 +111,7 @@ impl UpdaterState {
// Otherwise return the version info from the current slot.
return Some(PatchInfo {
path: slot.path.clone(),
version: slot.patch_version.clone(),
number: slot.patch_number.clone(),
});
}
@@ -180,7 +180,7 @@ fn download_into_slot(
slot_index,
Slot {
path: path.to_str().unwrap().to_string(),
patch_version: patch.version.clone(),
patch_number: patch.number.clone(),
},
);
state.save(cache_dir)?;
+3 -3
View File
@@ -38,7 +38,7 @@ pub struct ResolvedConfig {
pub cache_dir: String,
pub channel: String,
pub app_id: String,
pub base_version: String,
pub release_version: String,
pub original_libapp_path: String,
pub vm_path: String,
pub base_url: String,
@@ -51,7 +51,7 @@ impl ResolvedConfig {
cache_dir: String::new(),
channel: String::new(),
app_id: String::new(),
base_version: String::new(),
release_version: String::new(),
original_libapp_path: String::new(),
vm_path: String::new(),
base_url: String::new(),
@@ -77,7 +77,7 @@ pub fn set_config(config: AppConfig, yaml: YamlConfig) {
.to_owned();
lock.cache_dir = config.cache_dir.to_string();
lock.app_id = yaml.app_id.to_string();
lock.base_version = config.base_version.to_string();
lock.release_version = config.release_version.to_string();
lock.original_libapp_path = config.original_libapp_path.to_string();
lock.vm_path = config.vm_path.to_string();
lock.is_initialized = true;
+3 -3
View File
@@ -17,7 +17,7 @@ fn patches_check_url(base_url: &str) -> String {
#[derive(Debug, Deserialize)]
pub struct Patch {
pub version: String,
pub number: usize,
pub hash: String,
pub download_url: String,
}
@@ -40,9 +40,9 @@ pub fn send_patch_check_request(
let mut body = HashMap::new();
body.insert("app_id", config.app_id.clone());
body.insert("channel", config.channel.clone());
body.insert("base_version", config.base_version.clone());
body.insert("release_version", config.release_version.clone());
if let Some(patch) = patch {
body.insert("patch_version", patch.version);
body.insert("patch_number", patch.number.to_string());
}
body.insert("platform", current_platform().to_string());
body.insert("arch", current_arch().to_string());
+3 -3
View File
@@ -52,7 +52,7 @@ impl Display for UpdateError {
// but making &str from CStr* is a bit of a pain.
pub struct AppConfig {
pub cache_dir: String,
pub base_version: String,
pub release_version: String,
pub original_libapp_path: String,
pub vm_path: String,
}
@@ -168,7 +168,7 @@ mod tests {
crate::init(
crate::AppConfig {
cache_dir: cache_dir.clone(),
base_version: "1.0.0".to_string(),
release_version: "1.0.0".to_string(),
original_libapp_path: "original_libapp_path".to_string(),
vm_path: "vm_path".to_string(),
},
@@ -185,7 +185,7 @@ mod tests {
crate::init(
crate::AppConfig {
cache_dir: cache_dir.clone(),
base_version: "1.0.0".to_string(),
release_version: "1.0.0".to_string(),
original_libapp_path: "original_libapp_path".to_string(),
vm_path: "vm_path".to_string(),
},