diff --git a/updater/.gitignore b/updater/.gitignore new file mode 100644 index 00000000..1aaec948 --- /dev/null +++ b/updater/.gitignore @@ -0,0 +1,17 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +# Cache directory from updater cli. +updater_cache \ No newline at end of file diff --git a/updater/Cargo.toml b/updater/Cargo.toml new file mode 100644 index 00000000..bcbfce6a --- /dev/null +++ b/updater/Cargo.toml @@ -0,0 +1,2 @@ +[workspace] +members = ["cli", "library"] \ No newline at end of file diff --git a/updater/README.md b/updater/README.md new file mode 100644 index 00000000..2002d7a0 --- /dev/null +++ b/updater/README.md @@ -0,0 +1,38 @@ +# Updater library + +This is the C/Rust side of the Shorebird code push system. This is built +in Rust with a C API for easy calling from other languages, most notably +for linking into libflutter.so. + +# Parts +* cli: Test the updater library via the Rust API (for development). +* dart_cli: Test ffi wrapping of updater library. +* library: The rust library that does the actual update work. + +# TODO: +* Remove all non-MVP code. +* Add an async API. +* Add support for "channels" (e.g. beta, stable, etc). +* Write tests for state management. +* Make state management/filesystem management atomic (and tested). +* Move updater values out of the params into post body? +* Support hashing values and check them? +* Add "validate" command to validate state. +* Write a mode that runs the updater first and then launches whatever is downloaded? +* Use cbindgen to generate the C api header file. + https://github.com/eqrion/cbindgen/blob/master/docs.md + + +# Rust +We use normal rust idioms (e.g. Result) inside the library and then bridge those +to C via an explicit stable C API (explicit enums, null pointers for optional +arguments, etc). The reason for this is that it lets the Rust code feel natural +and also gives us maximum flexibility in the future for exposing more in the C +API without having to refactor the internals of the library. + +## Notes +* https://github.com/RubberDuckEng/safe_wren has an example of building a rust library and exposing it with a C api. + +## Other update systems +* https://theupdateframework.io/ +* https://fuchsia.dev/fuchsia-src/concepts/packages/software_update_system diff --git a/updater/UPDATER_DEMO.md b/updater/UPDATER_DEMO.md new file mode 100644 index 00000000..7ea9c919 --- /dev/null +++ b/updater/UPDATER_DEMO.md @@ -0,0 +1,128 @@ +To replicate the updater demo, you'll need a copy of the Flutter Engine. + +These are _not_ how Shorebird will work, but this is what I hacked together +for the demo video. Writing these down so others can replicate if desired. + +# Building the updater library for Android + +The best way I found was to install: +https://github.com/bbqsrc/cargo-ndk + +``` +rustup install beta +cargo +beta install cargo-ndk +rustup +beta target add \ + aarch64-linux-android \ + armv7-linux-androideabi \ + x86_64-linux-android \ + i686-linux-android +cargo +beta ndk --target aarch64-linux-android build --release +``` + +# Setting up to build the Flutter Engine: + +https://github.com/flutter/flutter/wiki/Setting-up-the-Engine-development-environment +https://github.com/flutter/flutter/wiki/Compiling-the-engine + +I would consider building a clean engine first and testing that you have +that working before trying Shorebird's modified engine. + +The hacked up version of the engine used for my demo can be found here: +https://github.com/shorebirdtech/engine/tree/codepush + +# Symlink in the Rust binaries + +I symlinked the results of the rust build into the engine/src directory: + +``` +cd flutter +mkdir updater +cd updater +ln -s $HOME/Documents/GitHub/shorebird_private/shorebird/updater/library/include/updater.h +mkdir android_aarch64 +cd android_aarch64 +ln -s $HOME/Documents/GitHub/shorebird_private/shorebird/updater/target/aarch64-linux-android/release/libupdater.a +``` + +# Building Flutter Engine + +``` +./flutter/tools/gn --android --android-cpu arm64 --runtime-mode=release +ninja -C out/android_release_arm64 +``` + +The linking step for android_release_arm64 is _much_ longer than other platforms +we may need to use unopt or debug builds for faster iteration. + +I also add `&& say "done"` to the end of the ninja command so I know when it's +done (because it takes minutes). + +# Running the updater + +From updater_demo: + +``` +flutter run --local-engine-src-path $HOME/Documents/GitHub/engine/src --local-engine=android_release_arm64 --release +``` + +Only need to do that once, once it's installed on the phone then you don't +need `flutter run` anymore. + +# Building the replacement libraries + +For the demo I used "android.a" and "android.b" which were just copies of +libapp.so files which Flutter had built for me. + +Once you've built the Flutter app in the way you want it: + +``` +cp build/app/intermediates/stripped_native_libs/release/out/lib/arm64-v8a/libapp.so android.a +``` + +You could dig them out of the apk, but that intermediate directory should be +the correct file and is much easier. + +`flutter build apk -t lib/main_b.dart` should build the app in the way I used +in my demo (I built it with `flutter run` and modifying main.dart directly, but +that command should work too). + +# shorebird command line + +I hadn't yet modified `shorebird` to include the `publisher` functionality, +so I had this in my path: + +``` +#!/bin/bash +dart run $HOME/Documents/Github/shorebird_private/shorebird/updater/publisher/bin/publisher.dart publish $2 +``` + +The right solution is to remove the old shorebird functionality and integrate publisher. + +# Ports + +Because updater_server as running locally I also had to forward ports from my +host into the emulator: + +``` +adb reverse tcp:8080 tcp:8080 +``` + +# Running the updater_server + +In a separate terminal: + +``` +cd shorebird/updater/updater_server +dart run +``` + +# The demo + +The demo was then just launching the app on the emulator (manually) +and then using the `shorebird` command line to publish the new libraries +to change what code the app ran: + +``` +shorebird publish android.a +shorebird publish android.b +``` diff --git a/updater/cli/Cargo.toml b/updater/cli/Cargo.toml new file mode 100644 index 00000000..dff817fc --- /dev/null +++ b/updater/cli/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "cli" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = { version = "4.1.6", features = ["derive"] } +updater = { path = "../library" } \ No newline at end of file diff --git a/updater/cli/src/main.rs b/updater/cli/src/main.rs new file mode 100644 index 00000000..3d992ac8 --- /dev/null +++ b/updater/cli/src/main.rs @@ -0,0 +1,61 @@ +extern crate updater; + +use clap::{Parser, Subcommand}; + +#[derive(Parser)] +#[command(author, version, about, long_about = None, arg_required_else_help=true)] +struct Cli { + #[command(subcommand)] + command: Option, +} + +#[derive(Subcommand)] +enum Commands { + Check {}, + Current {}, + Update {}, +} + +fn main() { + let cli = Cli::parse(); + + let config = updater::AppConfig { + client_id: "demo".to_string(), + cache_dir: None, + // base_url: "http://localhost:8080", + // channel: "stable", + }; + + // You can check for the existence of subcommands, and if found use their + // matches just as you would the top level cmd + match &cli.command { + Some(Commands::Check {}) => { + let needs_update = updater::check_for_update(&config); + println!("Checking for update..."); + if needs_update { + println!("Update needed."); + } else { + println!("No update needed."); + } + } + Some(Commands::Current {}) => { + let version = updater::active_version(&config); + println!("Current version info:"); + match version { + Some(v) => { + println!("path: {:?}", v.path); + println!("hash: {:?}", v.hash); + println!("version: {:?}", v.version); + } + None => { + println!("None"); + } + } + } + Some(Commands::Update {}) => { + let status = updater::update(&config); + println!("Update: {}", status); + } + None => {} + } +} diff --git a/updater/dart_cli/.gitignore b/updater/dart_cli/.gitignore new file mode 100644 index 00000000..3a857904 --- /dev/null +++ b/updater/dart_cli/.gitignore @@ -0,0 +1,3 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ diff --git a/updater/dart_cli/README.md b/updater/dart_cli/README.md new file mode 100644 index 00000000..7fb92493 --- /dev/null +++ b/updater/dart_cli/README.md @@ -0,0 +1 @@ +Command line application to test ffi wrapping of updater library. \ No newline at end of file diff --git a/updater/dart_cli/analysis_options.yaml b/updater/dart_cli/analysis_options.yaml new file mode 100644 index 00000000..dee8927a --- /dev/null +++ b/updater/dart_cli/analysis_options.yaml @@ -0,0 +1,30 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +# linter: +# rules: +# - camel_case_types + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/updater/dart_cli/bin/dart_cli.dart b/updater/dart_cli/bin/dart_cli.dart new file mode 100644 index 00000000..533a780b --- /dev/null +++ b/updater/dart_cli/bin/dart_cli.dart @@ -0,0 +1,129 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:args/command_runner.dart'; +import 'package:dart_cli/updater.dart'; + +void main(List args) async { + // This might pass a path or flavor (debug/release) later. + Updater.loadLibrary(); + + var clientId = 'my-client-id'; + var cacheDir = 'updater_cache'; + var updater = Updater(clientId, cacheDir); + + final runner = CommandRunner('updater', 'Updater CLI') + ..addCommand(CheckForUpdate(updater)) + ..addCommand(PrintVersion(updater)) + ..addCommand(PrintPath(updater)) + ..addCommand(Update(updater)) + ..addCommand(Run(updater)); + await runner.run(args); +} + +class CheckForUpdate extends Command { + final Updater updater; + CheckForUpdate(this.updater); + + @override + final name = 'check'; + + @override + final description = 'Check for an update.'; + + @override + void run() { + var result = updater.checkForUpdate(); + if (result) { + print('Update available'); + } else { + print('No update available'); + } + } +} + +class PrintVersion extends Command { + final Updater updater; + PrintVersion(this.updater); + + @override + final name = 'version'; + + @override + final description = 'Print current installed version.'; + + @override + void run() { + print(updater.activeVersion()); + } +} + +class PrintPath extends Command { + final Updater updater; + PrintPath(this.updater); + + @override + final name = 'path'; + + @override + final description = 'Print current installed path.'; + + @override + void run() { + print(updater.activePath()); + } +} + +class Update extends Command { + final Updater updater; + Update(this.updater); + + @override + final name = 'update'; + + @override + final description = 'Update to the latest version.'; + + @override + void run() { + updater.update(); + } +} + +class Run extends Command { + final Updater updater; + Run(this.updater) { + argParser.addFlag('update', abbr: 'u', help: 'Update before running.'); + } + + @override + final name = 'run'; + + @override + final description = 'Run the active version.'; + + @override + void run() async { + // This is a basic demo of what this might look like. + // Real callers wouldn't likely do this from Dart as there is no need + // to have two copies of the Dart VM running. + + if (argResults!['update']) { + updater.update(); + } + + var path = updater.activePath(); + if (path == null) { + print('No active version (should run the bundled version)'); + return; + } + // Should this run update first? + print('Running $path'); + // Is there a portable way to just "exec" and replace the current process? + var process = await Process.start(Platform.executable, ['run', path]); + process.stdout.transform(utf8.decoder).forEach(stdout.write); + process.stderr.transform(utf8.decoder).forEach(stderr.write); + // TODO: Handle stdin. + exit(await process.exitCode); + } +} diff --git a/updater/dart_cli/lib/bindings.dart b/updater/dart_cli/lib/bindings.dart new file mode 100644 index 00000000..69ae67c1 --- /dev/null +++ b/updater/dart_cli/lib/bindings.dart @@ -0,0 +1,60 @@ +// This entire file could be easily autogenerated. + +import 'dart:ffi' as ffi; +import 'dart:io' show Directory, Platform; + +import 'package:ffi/ffi.dart'; +import 'package:path/path.dart' as path; + +typedef _GetBoolFunc = ffi.Bool Function( + ffi.Pointer clientId, ffi.Pointer cacheDir); +typedef GetBool = bool Function( + ffi.Pointer clientId, ffi.Pointer cacheDir); + +typedef _GetStringFunc = ffi.Pointer Function( + ffi.Pointer clientId, ffi.Pointer cacheDir); +typedef GetString = ffi.Pointer Function( + ffi.Pointer clientId, ffi.Pointer cacheDir); + +typedef _GetVoidFunc = ffi.Void Function( + ffi.Pointer clientId, ffi.Pointer cacheDir); +typedef GetVoid = void Function( + ffi.Pointer clientId, ffi.Pointer cacheDir); + +typedef _FreeStringFunc = ffi.Void Function(ffi.Pointer str); +typedef FreeString = void Function(ffi.Pointer str); + +class UpdaterBindings { + final ffi.DynamicLibrary _updater; + + late GetBool checkForUpdate; + late GetString activeVersion; + late GetString activePath; + late FreeString freeString; + late GetVoid update; + + static ffi.DynamicLibrary loadLibrary(String directory, String name) { + if (Platform.isMacOS) { + return ffi.DynamicLibrary.open(path.join(directory, 'lib$name.dylib')); + } + if (Platform.isWindows) { + return ffi.DynamicLibrary.open(path.join(directory, '$name.dll')); + } + // Assume everything else follows the Linux pattern. + return ffi.DynamicLibrary.open(path.join(directory, 'lib$name.so')); + } + + UpdaterBindings() + : _updater = loadLibrary( + path.join(Directory.current.path, 'target', 'debug'), "updater") { + checkForUpdate = + _updater.lookupFunction<_GetBoolFunc, GetBool>('check_for_update'); + activeVersion = + _updater.lookupFunction<_GetStringFunc, GetString>('active_version'); + activePath = + _updater.lookupFunction<_GetStringFunc, GetString>('active_path'); + freeString = + _updater.lookupFunction<_FreeStringFunc, FreeString>('free_string'); + update = _updater.lookupFunction<_GetVoidFunc, GetVoid>('update'); + } +} diff --git a/updater/dart_cli/lib/updater.dart b/updater/dart_cli/lib/updater.dart new file mode 100644 index 00000000..dfc7938c --- /dev/null +++ b/updater/dart_cli/lib/updater.dart @@ -0,0 +1,86 @@ +// This eventually moves to its own package. +import 'dart:ffi' as ffi; + +import 'package:ffi/ffi.dart'; + +import 'bindings.dart'; + +class Updater { + final String clientId; + final String cacheDir; + + Updater(this.clientId, this.cacheDir); + + static UpdaterBindings? _bindings; + + static loadLibrary() { + if (_bindings != null) { + throw Exception('Library already loaded.'); + } + _bindings = UpdaterBindings(); + } + + static UpdaterBindings get bindings { + if (_bindings == null) { + throw Exception('Must call loadLibrary() first.'); + } + return _bindings!; + } + + // Currently bindings passes context as two separate char*, if it ever + // uses a struct instead at least we only have one place to change. + T _callWithContext( + T Function(ffi.Pointer clientId, ffi.Pointer cacheDir) f) { + // Will this leak if the second toNativeUtf8 throws an exception? + var clientId = this.clientId.toNativeUtf8(); + var cacheDir = this.cacheDir.toNativeUtf8(); + try { + return f(clientId, cacheDir); + } finally { + calloc.free(clientId); + calloc.free(cacheDir); + } + } + + bool checkForUpdate() { + return _callWithContext(bindings.checkForUpdate); + } + + void update() { + return _callWithContext(bindings.update); + } + + String? activeVersion() { + return _callWithContext((clientId, cacheDir) { + ffi.Pointer cVersion = ffi.Pointer.fromAddress(0); + try { + cVersion = bindings.activeVersion(clientId, cacheDir); + if (cVersion.address == 0) { + return null; + } + return cVersion.toDartString(); + } finally { + // Can toDartString ever throw an exception, such that this finally + // block is necessary? + bindings.freeString(cVersion); + } + }); + } + + String? activePath() { + return _callWithContext((clientId, cacheDir) { + ffi.Pointer cVersion = ffi.Pointer.fromAddress(0); + try { + cVersion = bindings.activePath(clientId, cacheDir); + if (cVersion.address == 0) { + return null; + } + return cVersion.toDartString(); + } finally { + // Can toDartString ever throw an exception, such that this finally + // block is necessary? + bindings.freeString(cVersion); + } + }); + } +} diff --git a/updater/dart_cli/pubspec.lock b/updater/dart_cli/pubspec.lock new file mode 100644 index 00000000..a2bdb399 --- /dev/null +++ b/updater/dart_cli/pubspec.lock @@ -0,0 +1,381 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: "569ddca58d535e601dd1584afa117710abc999d036c0cd2c51777fb257df78e8" + url: "https://pub.dev" + source: hosted + version: "53.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "10927c4b7c7c88b1adbca278c3d5531db92e2f4b4abf04e2919a800af965f3f5" + url: "https://pub.dev" + source: hosted + version: "5.5.0" + args: + dependency: "direct main" + description: + name: args + sha256: "4cab82a83ffef80b262ddedf47a0a8e56ee6fbf7fe21e6e768b02792034dd440" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + async: + dependency: transitive + description: + name: async + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" + source: hosted + version: "2.10.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + url: "https://pub.dev" + source: hosted + version: "1.17.1" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + coverage: + dependency: transitive + description: + name: coverage + sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097" + url: "https://pub.dev" + source: hosted + version: "1.6.3" + crypto: + dependency: transitive + description: + name: crypto + sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + url: "https://pub.dev" + source: hosted + version: "3.0.2" + ffi: + dependency: "direct main" + description: + name: ffi + sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + glob: + dependency: transitive + description: + name: glob + sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + lints: + dependency: "direct dev" + description: + name: lints + sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + logging: + dependency: transitive + description: + name: logging + sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: c94db23593b89766cda57aab9ac311e3616cf87c6fa4e9749df032f66f30dcb8 + url: "https://pub.dev" + source: hosted + version: "0.12.14" + meta: + dependency: transitive + description: + name: meta + sha256: "12307e7f0605ce3da64cf0db90e5fcab0869f3ca03f76be6bb2991ce0a55e82b" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + mime: + dependency: transitive + description: + name: mime + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" + source: hosted + version: "1.0.4" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "8ebdbaa3b96d5285d068f80772390d27c21e1fa10fb2df6627b1b9415043608d" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: "direct main" + description: + name: path + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" + source: hosted + version: "1.8.3" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17" + url: "https://pub.dev" + source: hosted + version: "2.1.3" + shelf: + dependency: transitive + description: + name: shelf + sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c + url: "https://pub.dev" + source: hosted + version: "1.4.0" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: aef74dc9195746a384843102142ab65b6a4735bb3beea791e63527b88cc83306 + url: "https://pub.dev" + source: hosted + version: "3.0.1" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: e792b76b96a36d4a41b819da593aff4bdd413576b3ba6150df5d8d9996d2e74c + url: "https://pub.dev" + source: hosted + version: "1.1.1" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8 + url: "https://pub.dev" + source: hosted + version: "1.0.3" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + url: "https://pub.dev" + source: hosted + version: "0.10.12" + source_span: + dependency: transitive + description: + name: source_span + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" + source: hosted + version: "1.9.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test: + dependency: "direct dev" + description: + name: test + sha256: "5301f54eb6fe945daa99bc8df6ece3f88b5ceaa6f996f250efdaaf63e22886be" + url: "https://pub.dev" + source: hosted + version: "1.23.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "6182294da5abf431177fccc1ee02401f6df30f766bc6130a0852c6b6d7ee6b2d" + url: "https://pub.dev" + source: hosted + version: "0.4.18" + test_core: + dependency: transitive + description: + name: test_core + sha256: d2e9240594b409565524802b84b7b39341da36dd6fd8e1660b53ad928ec3e9af + url: "https://pub.dev" + source: hosted + version: "0.4.24" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: a4040e9852e56bf8a3c5a2e08a56f6facd76e75500cf2a922ce5d52394c4998a + url: "https://pub.dev" + source: hosted + version: "11.0.1" + watcher: + dependency: transitive + description: + name: watcher + sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b + url: "https://pub.dev" + source: hosted + version: "2.3.0" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" + url: "https://pub.dev" + source: hosted + version: "3.1.1" +sdks: + dart: ">=2.19.0 <3.0.0" diff --git a/updater/dart_cli/pubspec.yaml b/updater/dart_cli/pubspec.yaml new file mode 100644 index 00000000..548ee662 --- /dev/null +++ b/updater/dart_cli/pubspec.yaml @@ -0,0 +1,16 @@ +name: dart_cli +description: A sample command-line application. +version: 1.0.0 +# repository: https://github.com/my_org/my_repo + +environment: + sdk: ">=2.19.0 <4.0.0" + +dependencies: + args: ^2.4.0 + ffi: ^2.0.1 + path: ^1.8.3 + +dev_dependencies: + lints: ^2.0.0 + test: ^1.21.0 diff --git a/packages/shorebird_code_push_updater/.gitignore b/updater/library/.gitignore similarity index 100% rename from packages/shorebird_code_push_updater/.gitignore rename to updater/library/.gitignore diff --git a/packages/shorebird_code_push_updater/Cargo.toml b/updater/library/Cargo.toml similarity index 71% rename from packages/shorebird_code_push_updater/Cargo.toml rename to updater/library/Cargo.toml index e6782fe5..cf9707b9 100644 --- a/packages/shorebird_code_push_updater/Cargo.toml +++ b/updater/library/Cargo.toml @@ -1,13 +1,15 @@ [package] -name = "shorebird_code_push_updater" +name = "updater" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] -# Build a rust library (for testing with rust "cli" project) and a c library -crate-type = ["staticlib"] +# "lib" is used by the "cli" target for testing from Rust +# "cdylib" is used by the "dart_cli" target for testing from Dart +# "staticlib" is used by the engine build for linking into libflutter.so +crate-type = ["lib", "cdylib", "staticlib"] [dependencies] # Used for exposing C API diff --git a/packages/shorebird_code_push_updater/README.md b/updater/library/README.md similarity index 100% rename from packages/shorebird_code_push_updater/README.md rename to updater/library/README.md diff --git a/packages/shorebird_code_push_updater/include/updater.h b/updater/library/include/updater.h similarity index 100% rename from packages/shorebird_code_push_updater/include/updater.h rename to updater/library/include/updater.h diff --git a/packages/shorebird_code_push_updater/src/c_api.rs b/updater/library/src/c_api.rs similarity index 100% rename from packages/shorebird_code_push_updater/src/c_api.rs rename to updater/library/src/c_api.rs diff --git a/packages/shorebird_code_push_updater/src/lib.rs b/updater/library/src/lib.rs similarity index 100% rename from packages/shorebird_code_push_updater/src/lib.rs rename to updater/library/src/lib.rs diff --git a/packages/shorebird_code_push_updater/src/updater.rs b/updater/library/src/updater.rs similarity index 100% rename from packages/shorebird_code_push_updater/src/updater.rs rename to updater/library/src/updater.rs