sheller

Pub Version Dart Package Docs License: MIT Build Status

Ergonomic scripting in Dart. Utilities for interacting with shells and converting output to Dart types.

List<File> files = $("cd $dir && find . -maxdepth 1 -type f").lines();

Table of Contents

  1. Example
  2. Valid Conversion Types
  3. Custom Conversion Types
  4. Real Use Case - Protobuf Package Generation Script Example

Example

With Sheller you can esaily write sync or async Dart scripts that interact with the host platform on Linux, MacOs, or Windows.

import 'sheller/sync.dart';
// import 'sheller/async.dart'; // alternative

// Linux
void main() {
  // run process and print stdout to terminal
  print($("netstat")());
  // run process and convert to Dart type
  int number = $("echo 1")();
  assert(number == 1);
  // built in support for types like json
  String data ='{\\"id\\":1, \\"name\\":\\"lorem ipsum\\", \\"address\\":\\"dolor set amet\\"}';
  Map<String, dynamic> json = $('echo $data')();
  assert(json.entries.length == 3);
  // split by spaces then convert
  List<double> doubleList = $('echo 1  2   3').spaces();
  assert(doubleList.length == 3);
  // The class
  $ shellClassInstance = $("echo 1");
  int id = shellClassInstance.pid;
  int exitCode = shellClassInstance.exitCode;
  int convertedResult = shellClassInstance();
  assert(convertedResult == 1);
  // split by lines then convert
  List<File> files = $("find . -maxdepth 1 -type f").lines();
  // Writing to a file
  $("echo 1") > File("./temp");
  // Appending to a file
  $("echo 2") >> File("./temp");
}

Valid Conversion Types

Built in conversions for stdout of successful shells to

int
double
num
BigInt
String
bool // empty is false, non-empty is true.
Map<String, dynamic>
Object
FileSystemEntity
Directory
File
Link

Custom Conversion Types

Easily add your own custom conversion types. e.g.

class IntConverter extends Converter<String, int> {
  const IntConverter();

  @override
  int convert(String input) {
    int? result = int.tryParse(input);
    if (result == null) {
      throw ShellResultConversionException(int, input);
    }
    return result;
  }
}

ShellConfig.addConverter(const IntConverter());

Real Use Case - Protobuf Package Generation Script Example

void main() async {
  String osPathSeparator = path.separator;
  if(Directory.current.path.split(osPathSeparator).last != "generator") throw StateError("Launched from wrong current directory.");
  if(Directory("bin").listSync(recursive: true).length != 1) throw StateError("Directory not clean.");
  const protoFilesDir = "../../proto";
  const outputDir = "../generated";
  const outputSrcDir = "../generated/lib/src";
  if(Directory(outputDir).existsSync()){
    Directory(outputDir).deleteSync(recursive: true);
  }
  Directory(outputSrcDir).createSync(recursive: true);

  final protoFiles = Directory(protoFilesDir)
      .listSync()
      .whereType<File>()
      .where((file) => file.path.endsWith(".proto"))
      .map((file) => file.path)
      .toList();

  final command = "protoc -I=$protoFilesDir --dart_out=grpc:$outputSrcDir ${protoFiles.join(' ')}";
  print($(command)());

  // Contains desired pubspec.yaml
  const toCopyOver = "./to_copy_over";
  print($("cp -r $toCopyOver/* $outputDir")());

  final generateBarrelFileCommand = "cd $outputDir && dart pub run index_generator";
  print($(generateBarrelFileCommand)());
  print("Done.");
}

Libraries

async
Asynchronous ergonomic shell library for Dart.
sync
Synchronous ergonomic shell library for Dart.