import 'dart:convert'; import 'dart:io'; import 'package:oto/cli/commands/command_base.dart'; import 'package:oto/oto/application.dart'; class CommandValidateCli extends CommandBase { final Future Function(String) _printString; CommandValidateCli({Future Function(String)? printString}) : _printString = printString ?? ((value) async { stdout.writeln(value); }); @override String get name => 'validate'; @override String get usage => '[arguments]'; @override String getDescription() => 'Validate the pipeline yaml file structure and semantics without executing it.'; @override Map> get arguments => { '-f {file path}': ['Validate the yaml file without executing it.'], '--json': ['Output validation result as structured JSON format.'], }; @override bool shouldPrintExecuteLog(List parameters) { return !parameters.contains('--json'); } @override bool shouldExecuteWithoutParameters() => false; @override Future execute(List parameters) async { String? filePath; bool isJson = false; for (int i = 0; i < parameters.length; i++) { final param = parameters[i]; if (param == '--json') { isJson = true; } else if (param.startsWith('-f')) { if (param == '-f') { if (i + 1 < parameters.length) { filePath = parameters[++i]; } else { throw Exception('Missing value for -f'); } } else { filePath = param.substring(2); } } else if (param.startsWith('--file=')) { filePath = param.substring('--file='.length); } else if (param == '--file') { if (i + 1 < parameters.length) { filePath = parameters[++i]; } else { throw Exception('Missing value for --file'); } } else { throw Exception('Unknown option: $param'); } } if (filePath == null) { throw Exception('Missing required option: -f {file path}'); } final file = File(filePath); YamlValidationResult result; if (!file.existsSync()) { result = YamlValidationResult.failure( phase: 'Read YAML file', message: 'There are no files in path "$filePath"', exitCode: 10, ); } else { try { final content = file.readAsStringSync(); result = Application.validateYamlContent(content); } catch (e) { result = YamlValidationResult.failure( phase: 'Read YAML file', message: e.toString(), exitCode: 10, ); } } exitCode = result.exitCode; if (isJson) { final jsonMap = result.toJson(); await _printString(const JsonEncoder.withIndent(' ').convert(jsonMap)); } else { if (result.valid) { await _printString('Valid YAML.'); } else { await _printString('Invalid YAML: [${result.phase}] ${result.message}'); } } } }