Skip to content

Commit

Permalink
Merge pull request #129 from cunarist/dart-command-message
Browse files Browse the repository at this point in the history
Dart command `message`
  • Loading branch information
temeddix authored Sep 1, 2023
2 parents 3fef3f3 + 42ca8f5 commit a39e76e
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 175 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,13 @@ jobs:
java-version: "11"
cache: "gradle"

- name: Fetch dependencies
- name: Fetch Flutter dependencies
working-directory: example/
run: flutter pub get

- name: Generate message files
working-directory: example/
run: cargo check
run: dart run rust_in_flutter message

- name: Build example Flutter app
if: matrix.target == 'linux'
Expand Down
46 changes: 13 additions & 33 deletions .github/workflows/formatting_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,38 +19,7 @@ concurrency:

jobs:
dart:
name: dart-code
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
submodules: true

- name: Setup Flutter SDK
uses: subosito/flutter-action@v2
with:
channel: "stable"

- name: Format Dart code
run: dart format .

- name: Verify changed files
id: verify-changed-files
uses: tj-actions/verify-changed-files@v16
with:
files: >
**/*
- name: Raise error if any of the files has changed
if: steps.verify-changed-files.outputs.files_changed == 'true'
run: |
echo "Changed files: ${{ steps.verify-changed-files.outputs.changed_files }}"
exit 1
rust:
name: rust-code
name: dart-and-rust-code
runs-on: ubuntu-latest

steps:
Expand All @@ -70,9 +39,20 @@ jobs:
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}

- name: Fetch Flutter dependencies
working-directory: example/
run: flutter pub get

- name: Generate message files
working-directory: example/
run: dart run rust_in_flutter message

- name: Install Clippy
run: rustup component add clippy

- name: Format Dart code
run: dart format .

- name: Format Rust code
run: cargo clippy --fix

Expand All @@ -90,7 +70,7 @@ jobs:
exit 1
config:
name: other-files
name: configuration-files
runs-on: ubuntu-latest

steps:
Expand Down
132 changes: 125 additions & 7 deletions bin/rust_in_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Future<void> main(List<String> args) async {
print("No operation is provided");
} else if (args[0] == "template") {
await _applyTemplate();
} else if (args[0] == "message") {
await _generateMessageCode();
} else if (args[0] == "wasm") {
if (args.contains("--release") || args.contains("-r")) {
await _buildWebassembly(isReleaseMode: true);
Expand All @@ -23,7 +25,7 @@ Future<void> main(List<String> args) async {
/// Creates new folders and files to an existing Flutter project folder.
Future<void> _applyTemplate() async {
// Get the path of the current project directory
final projectPath = Directory.current.path;
final flutterProjectPath = Directory.current.path;

// Get the package directory path
final packageConfig = await findPackageConfig(Directory.current);
Expand All @@ -37,7 +39,7 @@ Future<void> _applyTemplate() async {
final packagePath = package.root.toFilePath();

// Check if current folder is a Flutter project.
final mainFile = File('$projectPath/lib/main.dart');
final mainFile = File('$flutterProjectPath/lib/main.dart');
final isFlutterProject = await mainFile.exists();
if (!isFlutterProject) {
print("\nThis folder doesn't look like a Flutter project. Aborting...\n");
Expand All @@ -46,19 +48,19 @@ Future<void> _applyTemplate() async {

// Copy basic folders needed for Rust to work
final templateSource = Directory('$packagePath/example/native');
final templateDestination = Directory('$projectPath/native');
final templateDestination = Directory('$flutterProjectPath/native');
await _copyDirectory(templateSource, templateDestination);
final messagesSource = Directory('$packagePath/example/messages');
final messagesDestination = Directory('$projectPath/messages');
final messagesDestination = Directory('$flutterProjectPath/messages');
await _copyDirectory(messagesSource, messagesDestination);

// Copy `Cargo.toml`
final cargoSource = File('$packagePath/example/Cargo.toml');
final cargoDestination = File('$projectPath/Cargo.toml');
final cargoDestination = File('$flutterProjectPath/Cargo.toml');
await cargoSource.copy(cargoDestination.path);

// Create `.cargo/config.toml` file
final cargoConfigFile = File('$projectPath/.cargo/config.toml');
final cargoConfigFile = File('$flutterProjectPath/.cargo/config.toml');
if (!(await cargoConfigFile.exists())) {
await cargoConfigFile.create(recursive: true);
}
Expand All @@ -74,7 +76,7 @@ Future<void> _applyTemplate() async {
// Add some lines to `.gitignore`
final rustSectionTitle = '# Rust related';
final messageSectionTitle = '# Generated messages';
final gitignoreFile = File('$projectPath/.gitignore');
final gitignoreFile = File('$flutterProjectPath/.gitignore');
if (!(await gitignoreFile.exists())) {
await gitignoreFile.create(recursive: true);
}
Expand Down Expand Up @@ -288,3 +290,119 @@ Future<void> _runAdvancedCommand(
command, arguments, processOutput.join(''), exitCode);
}
}

Future<void> _generateMessageCode() async {
// Prepare paths.
final flutterProjectPath = Directory.current;
final protoPath = flutterProjectPath.uri.resolve('messages').toFilePath();
final rustOutputPath =
flutterProjectPath.uri.resolve('native/hub/src/messages').toFilePath();
final dartOutputPath =
flutterProjectPath.uri.resolve('lib/messages').toFilePath();
await Directory(rustOutputPath).create(recursive: true);
await _emptyDirectory(rustOutputPath);
await Directory(dartOutputPath).create(recursive: true);
await _emptyDirectory(dartOutputPath);

// Get the list of `.proto` files.
final Stream<FileSystemEntity> protoEntityStream =
Directory(protoPath).list();
final List<String> protoFilenames = [];
await for (final entity in protoEntityStream) {
if (entity is File) {
final String filename = entity.uri.pathSegments.last;
if (filename.endsWith('.proto')) {
protoFilenames.add(filename);
}
}
}

// Generate Rust message files.
print("Verifying `protoc-gen-prost` for Rust." +
" This might take a while if there are new updates to be installed.");
final cargoInstallCommand =
await Process.run('cargo', ['install', 'protoc-gen-prost']);
if (cargoInstallCommand.exitCode != 0) {
throw Exception('Cannot globally install `protoc-gen-prost` Rust crate');
}
final protocRustResult = await Process.run('protoc', [
'--proto_path=$protoPath',
'--prost_out=$rustOutputPath',
'--fatal_warnings',
...protoFilenames,
]);
if (protocRustResult.exitCode != 0) {
throw Exception('Could not compile `.proto` files into Rust');
}

// Generate `mod.rs` for `messages` module in Rust.
final Stream<FileSystemEntity> rustEntityStream =
Directory(rustOutputPath).list();
final List<FileSystemEntity> rustMessageFiles = [];
await for (final entity in rustEntityStream) {
if (entity is File) {
final String filename = entity.uri.pathSegments.last;
if (filename.endsWith('.rs') && filename != 'mod.rs') {
rustMessageFiles.add(entity);
}
}
}
final modRsLines = rustMessageFiles.map((file) async {
final fileName = file.uri.pathSegments.last;
final parts = fileName.split('.');
parts.removeLast(); // Remove the extension from the filename.
final fileNameWithoutExtension = parts.join('.');
return 'pub mod $fileNameWithoutExtension;';
});
final modRsContent = (await Future.wait(modRsLines)).join('\n');
await File('$rustOutputPath/mod.rs').writeAsString(modRsContent);

// Generate Dart message files.
print("Verifying `protoc_plugin` for Dart." +
" This might take a while if there are new updates to be installed.");
final pubGlobalActivateCommand =
await Process.run('dart', ['pub', 'global', 'activate', 'protoc_plugin']);
if (pubGlobalActivateCommand.exitCode != 0) {
throw Exception('Cannot globally install `protoc_plugin` Dart package');
}
final newEnvironment = Map<String, String>.from(Platform.environment);
final currentPathVariable = newEnvironment['PATH'];
final pubCacheBinPath = Platform.isWindows
? '${Platform.environment['LOCALAPPDATA']}\\Pub\\Cache\\bin'
: '${Platform.environment['HOME']}/.pub-cache/bin';
final pathSeparator = Platform.isWindows ? ';' : ':';
final newPathVariable = currentPathVariable != null
? '$currentPathVariable$pathSeparator$pubCacheBinPath'
: pubCacheBinPath;
newEnvironment['PATH'] = newPathVariable;
final protocDartResult = await Process.run(
'protoc',
[
'--proto_path=$protoPath',
'--dart_out=$dartOutputPath',
'--fatal_warnings',
...protoFilenames,
],
environment: newEnvironment,
);
if (protocDartResult.exitCode != 0) {
throw Exception('Could not compile `.proto` files into Dart');
}

// Notify that it's done
print("🎉 Message code in Dart and Rust is now ready! 🎉");
}

Future<void> _emptyDirectory(String directoryPath) async {
final directory = Directory(directoryPath);

if (await directory.exists()) {
await for (final entity in directory.list()) {
if (entity is File) {
await entity.delete();
} else if (entity is Directory) {
await entity.delete(recursive: true);
}
}
}
}
133 changes: 0 additions & 133 deletions example/native/hub/build.rs

This file was deleted.

0 comments on commit a39e76e

Please sign in to comment.