// ignore_for_file: public_member_api_docs, sort_constructors_first // Copyright (C) 2023 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . import 'dart:io'; import 'package:args/args.dart'; import 'package:brick_generator/core/file_system.dart'; import 'package:brick_generator/core/logger.dart'; import 'package:brick_generator/models/brick_config.dart'; import 'package:path/path.dart'; const _configurationFileName = 'brickgen.yaml'; const _masonConfigurationFileName = 'brick.yaml'; const _brickFolderName = '__brick__'; const _hooksFolderName = 'hooks'; const _helpOption = 'help'; const _verboseOption = 'verbose'; const _removeEmptyOption = 'remove-empty'; class Brickgen { final String brickPath; final String outputPath; final bool deleteEmptyFolders; late String configPath; late String hooksInputPath; String? toBrickifyPath; String? masonConfigPath; String? targetPath; String? hooksOutputPath; Brickgen({ required this.brickPath, required this.outputPath, required this.deleteEmptyFolders, }) { configPath = join(brickPath, _configurationFileName); hooksInputPath = join(brickPath, _hooksFolderName); } Future run() async { // Load config final config = BrickConfig.fromFile(configPath); Logger.debug('Read config: \n${config.toMason()}'); Logger.info('Config retrieved.'); // Define paths toBrickifyPath = FileSystem.joinExists( brickPath, config.brickgenConfig.pathToBrickify, ); Logger.debug('Define `toBrickifyPath`: $toBrickifyPath'); masonConfigPath = FileSystem.joinTouch( outputPath, config.name, _masonConfigurationFileName, ); Logger.debug('Define `masonConfigPath`: $masonConfigPath'); hooksOutputPath = FileSystem.joinRecreate( outputPath, config.name, _hooksFolderName, ); Logger.debug('Define `hooksOutputPath`: $hooksOutputPath'); targetPath = FileSystem.joinRecreate( outputPath, config.name, _brickFolderName, ); Logger.debug('Define `targetPath`: $targetPath'); // Check paths if (toBrickifyPath == null || targetPath == null || masonConfigPath == null || hooksOutputPath == null) { throw Exception('An error occures during path definition.'); } Logger.info('Paths defined.'); // Copy (and exclude from copy) project files await FileSystem.copyFolder( toBrickifyPath!, targetPath!, ignoreList: config.brickgenConfig.ignore, ); Logger.info('Project copied.'); // Take care of boolean mapping and boolean fs FileSystem.applyBooleanFileSystem(config, targetPath!); Logger.info('Boolean file system applied.'); // TODO(wyatt): generate hook to handle boolean mapping. // Convert compilable values -> variables (in files) FileSystem.convertCompilableVariablesInFolder(config, targetPath!); FileSystem.convertBooleanVariablesInFolder(config, targetPath!); Logger.info('Files content converted with variables.'); // Create `.gitkeep` in empty folders (to keep them in brick generation) // Or remove them (depending of --remove option) if (deleteEmptyFolders) { FileSystem.removeEmptyFolders(targetPath!); Logger.info('Empty folders removed.'); } else { FileSystem.createGitKeepInEmptyFolders(targetPath!); Logger.info('Empty folders marked as to keep.'); } // Convert compilable values -> variables (files/folder names) FileSystem.renameCompilableFilesInFolder(config, targetPath!); Logger.info('Files renamed with variables.'); // Clean empty folders created from copy/moves FileSystem.removeEmptyFolders(targetPath!); // Create Mason config FileSystem.writeFile(masonConfigPath!, config.toMason()); Logger.info('Mason `brick.yaml` generated.'); // Copy hooks await FileSystem.copyHooks(config, hooksInputPath, hooksOutputPath!); // Success! Logger.success('Brick template available at $targetPath'); } } Future main(List args) async { int exitCode = 0; final parser = ArgParser() ..addFlag( _helpOption, negatable: false, abbr: 'h', help: 'Show this help dialog', ) ..addFlag( _verboseOption, negatable: false, abbr: 'v', help: 'Show additional diagnostic info', ) ..addFlag( _removeEmptyOption, negatable: false, abbr: 'r', help: 'Remove empty folders (if not it creates ' '.gitkeep in each empty folders)', ); final argResults = parser.parse(args); if (argResults[_helpOption] as bool? ?? false) { Logger.info('Brickgen\n${parser.usage}'); exit(0); } if (argResults[_verboseOption] as bool? ?? false) { Logger.setVerbose(); } final paths = argResults.rest; if (paths.length < 2) { Logger.error('Please provide input and output paths.'); if (!(argResults[_helpOption] as bool? ?? false)) { Logger.info('Brickgen\n${parser.usage}'); } exitCode = 1; exit(exitCode); } final brickPath = paths[0]; final outputPath = paths[1]; await Brickgen( brickPath: brickPath, outputPath: outputPath, deleteEmptyFolders: argResults[_removeEmptyOption] as bool? ?? false, ).run(); exit(exitCode); }