chore: Fix the rust build (#27)

This commit is contained in:
Eric Seidel
2023-03-06 15:06:31 -08:00
committed by GitHub
parent debc601066
commit c13091b721
21 changed files with 967 additions and 3 deletions
+17
View File
@@ -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
+2
View File
@@ -0,0 +1,2 @@
[workspace]
members = ["cli", "library"]
+38
View File
@@ -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
+128
View File
@@ -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
```
+10
View File
@@ -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" }
+61
View File
@@ -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<Commands>,
}
#[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 => {}
}
}
+3
View File
@@ -0,0 +1,3 @@
# https://dart.dev/guides/libraries/private-files
# Created by `dart pub`
.dart_tool/
+1
View File
@@ -0,0 +1 @@
Command line application to test ffi wrapping of updater library.
+30
View File
@@ -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
+129
View File
@@ -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<String> 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<void>('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<void> {
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<void> {
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<void> {
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<void> {
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<void> {
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);
}
}
+60
View File
@@ -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<Utf8> clientId, ffi.Pointer<Utf8> cacheDir);
typedef GetBool = bool Function(
ffi.Pointer<Utf8> clientId, ffi.Pointer<Utf8> cacheDir);
typedef _GetStringFunc = ffi.Pointer<Utf8> Function(
ffi.Pointer<Utf8> clientId, ffi.Pointer<Utf8> cacheDir);
typedef GetString = ffi.Pointer<Utf8> Function(
ffi.Pointer<Utf8> clientId, ffi.Pointer<Utf8> cacheDir);
typedef _GetVoidFunc = ffi.Void Function(
ffi.Pointer<Utf8> clientId, ffi.Pointer<Utf8> cacheDir);
typedef GetVoid = void Function(
ffi.Pointer<Utf8> clientId, ffi.Pointer<Utf8> cacheDir);
typedef _FreeStringFunc = ffi.Void Function(ffi.Pointer<Utf8> str);
typedef FreeString = void Function(ffi.Pointer<Utf8> 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');
}
}
+86
View File
@@ -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>(
T Function(ffi.Pointer<Utf8> clientId, ffi.Pointer<Utf8> 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<Utf8> cVersion = ffi.Pointer<Utf8>.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<Utf8> cVersion = ffi.Pointer<Utf8>.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);
}
});
}
}
+381
View File
@@ -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"
+16
View File
@@ -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
@@ -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