run method

Implementation

Future<CommandResult> run() async {
  var cmd = command.command;

  // TODO(mrgnhnt): we are source the env file for the command that could
  // create it... we should probably split that up
  if (command.envFile.isNotEmpty) {
    for (final file in command.envFile) {
      logger.detail('Sourcing env file $file');
      cmd = '. $file && $cmd';
    }
  }
  logger.detail('Setting directory to ${command.workingDirectory}');
  cmd = 'cd ${command.workingDirectory} && $cmd';

  var printOutput = showOutput;
  if (logger.level == Level.quiet) {
    printOutput = false;
  }

  logger.detail('''
--------- SCRIPT ---------
${command.command}
--------------------------
''');

  final runScript = bindings.runScript(cmd, showOutput: printOutput);

  CommandResult codeResult;
  final retryAfter = this.retryAfter;
  if (retryAfter == null) {
    logger.detail('Not retrying');
    final result = await runScript;

    codeResult = result;
  } else {
    logger.detail('Retrying command after $retryAfter');
    var hasExited = false;
    var attempt = 0;

    while (!hasExited && attempt < maxAttempts) {
      attempt++;

      final controller = StreamController<CommandResult?>();

      final wait = retryAfter + (retryAfter * (.1 * attempt));

      logger.detail('Waiting $wait before attempt $attempt');

      final timer = Timer(wait, () => controller.add(null));

      runScript.then(controller.add).ignore();

      final exitCode = await controller.stream.first;

      timer.cancel();

      if (exitCode == null) {
        continue;
      }

      codeResult = exitCode;
      hasExited = true;
    }

    logger.detail(
      'Native failed to exit after $maxAttempts attempts, '
      'running without retries',
    );

    final result = await runScript;

    codeResult = result;
  }

  logger.detail('Native exited with ${codeResult.exitCode}');

  return codeResult;
}