203 lines
5.8 KiB
Dart

// 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 <https://www.gnu.org/licenses/>.
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<void> 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!);
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<void> main(List<String> 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);
}