chore: Fix the rust build (#27)
This commit is contained in:
@@ -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
|
||||
@@ -0,0 +1,2 @@
|
||||
[workspace]
|
||||
members = ["cli", "library"]
|
||||
@@ -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
|
||||
@@ -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
|
||||
```
|
||||
@@ -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" }
|
||||
@@ -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 => {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# https://dart.dev/guides/libraries/private-files
|
||||
# Created by `dart pub`
|
||||
.dart_tool/
|
||||
@@ -0,0 +1 @@
|
||||
Command line application to test ffi wrapping of updater library.
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user