From a247893f08feb309d80644dc55eb975f518cd69d Mon Sep 17 00:00:00 2001 From: Nikhil Ishwara Date: Fri, 3 Nov 2023 13:43:19 +0400 Subject: [PATCH] Implented remove in pubm --- lib/pubm.dart | 5 +- lib/src/configuration.dart | 14 +- lib/src/pubspec_manage.dart | 352 +++++++++++++++++++++++++++++++----- 3 files changed, 310 insertions(+), 61 deletions(-) diff --git a/lib/pubm.dart b/lib/pubm.dart index 56b6c9a..1e563ae 100644 --- a/lib/pubm.dart +++ b/lib/pubm.dart @@ -30,9 +30,8 @@ class Pubm with PubspecManager { /// Register [Logger] and [Configuration] as singleton services void _setupSingletonServices(List args) { - GetIt.I.registerSingleton(args.contains('-v') - ? Logger.verbose() - : Logger.standard(ansi: Ansi(true))); + GetIt.I.registerSingleton( + args.contains('-v') ? Logger.verbose() : Logger.standard(ansi: Ansi(true))); GetIt.I.registerSingleton(Configuration(args)); } diff --git a/lib/src/configuration.dart b/lib/src/configuration.dart index a4456f5..1035efd 100644 --- a/lib/src/configuration.dart +++ b/lib/src/configuration.dart @@ -27,8 +27,7 @@ class Configuration { dynamic pubspec = await _getPubspec(); dynamic yaml = pubspec['pubm_config'] ?? YamlMap(); - final String? buildArgsConfig = - (_args['build-args'] ?? yaml['build_args'])?.toString(); + final String? buildArgsConfig = (_args['build-args'] ?? yaml['build_args'])?.toString(); if (buildArgsConfig != null && buildArgsConfig.isNotEmpty) { CommandLineConverter commandLineConverter = CommandLineConverter(); buildArgs = commandLineConverter.convert(buildArgsConfig); @@ -41,15 +40,13 @@ class Configuration { if (_args['help']) { _logger.stdout('Usage: pubm -f '); - _logger.stdout( - 'Usage: pubm -f -v (verbose) to enable verbose mode'); - _logger.stdout( - 'Usage: pubm -h to get the list of available commands and how to use'); + _logger.stdout('Usage: pubm -f -v (verbose) to enable verbose mode'); + _logger.stdout('Usage: pubm -h to get the list of available commands and how to use'); return false; } - flavor = _args['flavor']?.toString() ?? ''; + flavor = _args['flavor']?.toString() ?? 'test'; if (flavor.isEmpty) { exitCode = 2; _logger.stderr('Usage: dart manage.dart -f '.red); @@ -72,8 +69,7 @@ class Configuration { _logger.trace('parsing cli arguments'); ArgParser parser = ArgParser() - ..addOption('flavor', - abbr: 'f', help: 'flavor of YAML file (pubspec_/flavor/.yaml)') + ..addOption('flavor', abbr: 'f', help: 'flavor of YAML file (pubspec_/flavor/.yaml)') ..addOption('build-args') ..addFlag('help', negatable: false, abbr: 'h'); diff --git a/lib/src/pubspec_manage.dart b/lib/src/pubspec_manage.dart index fce3759..83f5865 100644 --- a/lib/src/pubspec_manage.dart +++ b/lib/src/pubspec_manage.dart @@ -17,6 +17,278 @@ mixin PubspecManager { Logger get logger; Configuration get config; + Future remove() async { + bool nameChanged = false; + if (!config.pubspecFlavorFile.existsSync()) { + logger.stderr('File does not exist: ${config.flavor}'.red); + return; + } + + // Read the YAML file + final String contents = config.pubspecFlavorFile.readAsStringSync(); + + // Parse the YAML contents + final dynamic yamlMap = loadYaml(contents); + final dynamic actualYamlMap = loadYaml(config.pubspecFile.readAsStringSync()); + + // Create a Pubspec object + final Pubspec actualPubspec = Pubspec.fromMap(actualYamlMap); + final Pubspec flavorPubspec = Pubspec.fromMap(yamlMap["remove"]); + + // Update the Pubspec object + final Map finalMap = actualPubspec.toMap(); + final Map map = flavorPubspec.toMap(); + + //Remove name if name exists in flavor + if (map.containsKey("name")) { + logger.trace('Updating name'); + nameChanged = true; + finalMap.remove("name"); + } + + ///Remove description if description exists in flavor + if (map.containsKey("description")) { + logger.trace('Delete description'); + finalMap.remove("description"); + } + + ///Remove version if version exists in flavor + if (map.containsKey("version")) { + logger.trace('Updating version'); + finalMap.remove("version"); + } + + ///Remove homepage if homepage exists in flavor + if (map.containsKey("homepage")) { + logger.trace('Updating homepage'); + finalMap.remove("homepage"); + } + + ///Remove repository if repository exists in flavor + if (map.containsKey("repository")) { + logger.trace('Updating repository'); + finalMap.remove("repository"); + } + + ///Remove issueTracker if issueTracker exists in flavor + if (map.containsKey("issueTracker")) { + logger.trace('Updating issueTracker'); + finalMap.remove("issueTracker"); + } + + ///Remove documentation if documentation exists in flavor + if (map.containsKey("documentation")) { + logger.trace('Deleting documentation'); + finalMap.remove("documentation"); + } + + ///Remove publish_to if publish_to exists in flavor + if (map.containsKey("publish_to")) { + logger.trace('Deleting publishTo'); + finalMap.remove("publish_to"); + } + + ///Remove environment if environment exists in flavor + if (map.containsKey("environment")) { + logger.trace('Deleting environment '); + finalMap.remove("environment"); + } + + ///Check if dependencies key exists if so then + ///Loop through all the dependencies and remove it. + if (map.containsKey("dependencies")) { + map['dependencies'].forEach((key, value) { + if (finalMap['dependencies'].containsKey(key)) { + logger.trace('Deleting dependency $key'); + finalMap['dependencies'].remove(key); + } + }); + if ((finalMap['dependencies'] as Map).isEmpty) { + finalMap.remove('dependencies'); + } + } + + ///Check if dev_dependencies key exists if so then + ///Loop through all the dev_dependencies and remove it. + if (map.containsKey("dev_dependencies")) { + map['dev_dependencies'].forEach((key, value) { + if (finalMap['dev_dependencies'].containsKey(key)) { + logger.trace('Deleting dev_dependencies $key'); + finalMap['dev_dependencies'].remove(key); + } + }); + if ((finalMap['dev_dependencies'] as Map).isEmpty) { + finalMap.remove('dev_dependencies'); + } + } + + ///Check if dependency_overrides key exists if so then + ///Loop through all the dependency_overrides and remove it. + if (map.containsKey("dependency_overrides")) { + map['dependency_overrides'].forEach((key, value) { + if (finalMap['dependency_overrides'].containsKey(key)) { + logger.trace('Deleting dependency_overrides $key'); + finalMap['dependency_overrides'].remove(key); + } + }); + if ((finalMap['dependency_overrides'] as Map).isEmpty) { + finalMap.remove('dependency_overrides'); + } + } + + if (finalMap.containsKey('dependencies')) { + logger.trace('Sorting dependencies'); + var sortedKeys = finalMap['dependencies'].keys.toList(growable: false) + ..sort((k1, k2) => k1.toString().compareTo(k2.toString())); + LinkedHashMap sortedMap = LinkedHashMap.fromIterable(sortedKeys, + key: (k) => k, value: (k) => finalMap['dependencies'][k]); + finalMap['dependencies'] = sortedMap; + } + + if (finalMap.containsKey('dev_dependencies')) { + logger.trace('Sorting dev_dependencies'); + var sortedDDKeys = finalMap['dev_dependencies'].keys.toList(growable: false) + ..sort((k1, k2) => k1.toString().compareTo(k2.toString())); + LinkedHashMap sortedDDMap = LinkedHashMap.fromIterable(sortedDDKeys, + key: (k) => k, value: (k) => finalMap['dev_dependencies'][k]); + finalMap['dev_dependencies'] = sortedDDMap; + } + + if (finalMap.containsKey('dependency_overrides')) { + logger.trace('Sorting dependency_overrides'); + var sortedDOKeys = finalMap['dependency_overrides'].keys.toList(growable: false) + ..sort((k1, k2) => k1.toString().compareTo(k2.toString())); + LinkedHashMap sortedDOMap = LinkedHashMap.fromIterable(sortedDOKeys, + key: (k) => k, value: (k) => finalMap['dependency_overrides'][k]); + finalMap['dependency_overrides'] = sortedDOMap; + } + + /// Other values which are not checked and might be from other plugins + if (DeepCollectionEquality().equals(flavorPubspec.others, actualPubspec.others)) { + logger.trace('Deleteing others values'); + + if (flavorPubspec.others != null) { + flavorPubspec.others!.forEach((key, value) { + if (finalMap.containsKey(key)) { + logger.trace('Deleting $key'); + finalMap.remove(key); + } + }); + } + } + + if (flavorPubspec.flutter != null) { + logger.trace('Deleting flutter values'); + + final flutter = actualPubspec.flutter?.toMap() ?? {}; + final flavorFlutter = flavorPubspec.flutter?.toMap() ?? {}; + //finalMap['flutter'] = flavorPubspec.flutter?.toMap(); + if (actualPubspec.flutter != null) { + if (flutter.containsKey('uses-material-design')) { + logger.trace('Deleting Flutter uses-material-design'); + flutter.remove('uses-material-design'); + } + if (flutter.containsKey('generate')) { + logger.trace('Deleting Flutter generate'); + flutter.remove('generate'); + } + + if (flavorFlutter.containsKey('assets')) { + logger.trace('Deleting Flutter Assets'); + final flavourAssets = flavorPubspec.flutter?.assets ?? []; + for (var item in flavourAssets) { + logger.trace('Deleting Flutter Assets $item'); + actualPubspec.flutter?.assets?.remove(item); + } + final assets = actualPubspec.flutter?.assets ?? []; + flutter['assets'] = assets.toList(); + } + + final finalFonts = actualPubspec.flutter?.fonts?.toList() ?? []; + + for (final Font dataI in actualPubspec.flutter?.fonts ?? []) { + for (final Font dataJ in flavorPubspec.flutter?.fonts ?? []) { + if (dataJ == dataI) { + finalFonts.remove(dataI); + } + } + } + + for (final Font dataI in finalFonts) { + for (final Font dataJ in flavorPubspec.flutter?.fonts ?? []) { + if (dataJ.family == dataI.family) { + for (FontsData item in dataJ.fonts ?? []) { + dataI.fonts?.removeWhere((element) => element == item); + } + } + } + } + var fonts = {}..addAll(finalFonts); + + flutter['fonts'] = fonts.toList().map((e) => e.toMap()).toList(); + + if (finalFonts.isEmpty) { + flutter.remove('fonts'); + } + // finalFonts.clear(); + } + + finalMap['flutter'] = flutter; + if (flutter.isEmpty) { + finalMap.remove('flutter'); + } + } + + final finalPubspec = Pubspec.fromMap(finalMap); + + /// Convert the `finalMap` to String with pubspec.yaml format + final String string = json2yaml( + finalPubspec.toMap(addComments: true), + yamlStyle: YamlStyle.pubspecYaml, + ); + + /// If any of the value contains # then it will be converted to "#" + /// ex: hexCode #FFFFFF will be converted to "#FFFFFF" + String replacedText = string.replaceAllMapped(RegExp("#(.*?)(?=\\s|\$)"), (Match m) { + return '"#${m.group(1)}"'; + }); + + /// This will replace the temp added comment string with # + /// [Constants.comment] -> "Pubspec Manager Comment:" will be replaced with "#" in the final pubspec.yaml + replacedText = replacedText + .replaceAllMapped(RegExp("${Constants.comment}\\d+: (.*?)(?=\\s|\$)"), (Match m) { + return '# ${m.group(1)}'; + }); + + /// Save the updated YAML to the file + logger.trace('Creating a backup of pubspec.yaml to backup_pubspec.yaml'); + config.backupPubspecFile.writeAsStringSync(config.pubspecFile.readAsStringSync()); + config.pubspecFile.writeAsStringSync(replacedText); + + logger.stdout('Merging of pubspec.yaml files completed successfully'.green); + + /// Error message when name is changed in the main pubspec.yaml from the flavor pubspec.yaml + if (nameChanged) { + logger.stderr( + 'The name is changed from ${actualPubspec.name} to ${flavorPubspec.name} (as the the one mentioned in the pubspec_${config.flavor}.yaml'); + logger.stderr('This would cause errors in the project.'); + logger.stderr('Fix for this would to refactor the places where the package name was used'); + logger.stderr( + "Refactor: import 'package:${actualPubspec.name}/ to import 'package:${flavorPubspec.name}/ "); + } + + await FlutterBuild().pubGet(); + } + + bool checkIfItsRemove(dynamic data) { + if (data is Map) { + Map result = data; + if (result.containsKey("remove")) { + return true; + } + } + return false; + } Future mergePubspec() async { bool nameChanged = false; @@ -30,8 +302,11 @@ mixin PubspecManager { // Parse the YAML contents final dynamic yamlMap = loadYaml(contents); - final dynamic actualYamlMap = - loadYaml(config.pubspecFile.readAsStringSync()); + final dynamic actualYamlMap = loadYaml(config.pubspecFile.readAsStringSync()); + if (checkIfItsRemove(yamlMap)) { + remove(); + return; + } // Create a Pubspec object final Pubspec actualPubspec = Pubspec.fromMap(actualYamlMap); @@ -83,15 +358,13 @@ mixin PubspecManager { } if (!PubspecChecker.checkIssueTracker(actualPubspec, flavorPubspec)) { - logger - .trace('Updating issueTracker from ${actualPubspec.issueTracker} to ' - '${flavorPubspec.issueTracker}'); + logger.trace('Updating issueTracker from ${actualPubspec.issueTracker} to ' + '${flavorPubspec.issueTracker}'); finalMap['issueTracker'] = flavorPubspec.issueTracker; } if (!PubspecChecker.checkDocumentation(actualPubspec, flavorPubspec)) { - logger.trace( - 'Updating documentation from ${actualPubspec.documentation} to ' + logger.trace('Updating documentation from ${actualPubspec.documentation} to ' '${flavorPubspec.documentation}'); finalMap['documentation'] = flavorPubspec.documentation; } @@ -111,9 +384,8 @@ mixin PubspecManager { finalMap['environment'] = env; } - var dependencyCheck = PubspecChecker.checkDependencies( - actualPubspec, flavorPubspec, - checkAll: true); + var dependencyCheck = + PubspecChecker.checkDependencies(actualPubspec, flavorPubspec, checkAll: true); if (!dependencyCheck.hasMatch) { if (dependencyCheck.update.isNotEmpty) { for (var element in dependencyCheck.update) { @@ -133,9 +405,8 @@ mixin PubspecManager { }; } - var devDependencyCheck = PubspecChecker.checkDevDependencies( - actualPubspec, flavorPubspec, - checkAll: true); + var devDependencyCheck = + PubspecChecker.checkDevDependencies(actualPubspec, flavorPubspec, checkAll: true); if (!devDependencyCheck.hasMatch) { if (devDependencyCheck.update.isNotEmpty) { @@ -151,15 +422,13 @@ mixin PubspecManager { } finalMap['dev_dependencies'] = { - if (finalMap['dev_dependencies'] != null) - ...finalMap['dev_dependencies'], + if (finalMap['dev_dependencies'] != null) ...finalMap['dev_dependencies'], if (map['dev_dependencies'] != null) ...map['dev_dependencies'], }; } - var dependencyOverrideCheck = PubspecChecker.checkDependencyOverride( - actualPubspec, flavorPubspec, - checkAll: true); + var dependencyOverrideCheck = + PubspecChecker.checkDependencyOverride(actualPubspec, flavorPubspec, checkAll: true); if (!dependencyOverrideCheck.hasMatch) { if (dependencyOverrideCheck.update.isNotEmpty) { @@ -175,8 +444,7 @@ mixin PubspecManager { } finalMap['dependency_overrides'] = { - if (finalMap['dependency_overrides'] != null) - ...finalMap['dependency_overrides'], + if (finalMap['dependency_overrides'] != null) ...finalMap['dependency_overrides'], if (map['dependency_overrides'] != null) ...map['dependency_overrides'], }; } @@ -192,9 +460,7 @@ mixin PubspecManager { if (finalMap.containsKey('dev_dependencies')) { logger.trace('Sorting dev_dependencies'); - var sortedDDKeys = finalMap['dev_dependencies'] - .keys - .toList(growable: false) + var sortedDDKeys = finalMap['dev_dependencies'].keys.toList(growable: false) ..sort((k1, k2) => k1.toString().compareTo(k2.toString())); LinkedHashMap sortedDDMap = LinkedHashMap.fromIterable(sortedDDKeys, key: (k) => k, value: (k) => finalMap['dev_dependencies'][k]); @@ -203,9 +469,7 @@ mixin PubspecManager { if (finalMap.containsKey('dependency_overrides')) { logger.trace('Sorting dependency_overrides'); - var sortedDOKeys = finalMap['dependency_overrides'] - .keys - .toList(growable: false) + var sortedDOKeys = finalMap['dependency_overrides'].keys.toList(growable: false) ..sort((k1, k2) => k1.toString().compareTo(k2.toString())); LinkedHashMap sortedDOMap = LinkedHashMap.fromIterable(sortedDOKeys, key: (k) => k, value: (k) => finalMap['dependency_overrides'][k]); @@ -213,8 +477,7 @@ mixin PubspecManager { } /// Other values which are not checked and might be from other plugins - if (!DeepCollectionEquality() - .equals(flavorPubspec.others, actualPubspec.others)) { + if (!DeepCollectionEquality().equals(flavorPubspec.others, actualPubspec.others)) { logger.trace('Updating others values'); Map others = {}; if (actualPubspec.others != null) { @@ -255,18 +518,15 @@ mixin PubspecManager { '${actualPubspec.flutter?.usesMaterialDesign} to ' '${flavorPubspec.flutter?.usesMaterialDesign}'); - flutter['uses-material-design'] = - flavorPubspec.flutter?.usesMaterialDesign ?? - actualPubspec.flutter?.usesMaterialDesign; + flutter['uses-material-design'] = flavorPubspec.flutter?.usesMaterialDesign ?? + actualPubspec.flutter?.usesMaterialDesign; } - if (actualPubspec.flutter?.generate != - flavorPubspec.flutter?.generate) { + if (actualPubspec.flutter?.generate != flavorPubspec.flutter?.generate) { logger.trace('Updating generate from ' '${actualPubspec.flutter?.generate} to ' '${flavorPubspec.flutter?.generate}'); - flutter['generate'] = flavorPubspec.flutter?.generate ?? - actualPubspec.flutter?.generate; + flutter['generate'] = flavorPubspec.flutter?.generate ?? actualPubspec.flutter?.generate; } final assets = actualPubspec.flutter?.assets ?? []; @@ -295,12 +555,9 @@ mixin PubspecManager { map['family'] = actualFont.family; final f = {}; - for (final FontsData data in [ - ...actualFont.fonts ?? [], - ...flavorFont.fonts ?? [] - ]) { - final d = flavorFont.fonts?.firstWhereOrNull( - (element) => element.weight == data.weight); + for (final FontsData data in [...actualFont.fonts ?? [], ...flavorFont.fonts ?? []]) { + final d = + flavorFont.fonts?.firstWhereOrNull((element) => element.weight == data.weight); if (d != null) { f.add(d); } else { @@ -335,22 +592,20 @@ mixin PubspecManager { /// If any of the value contains # then it will be converted to "#" /// ex: hexCode #FFFFFF will be converted to "#FFFFFF" - String replacedText = - string.replaceAllMapped(RegExp("#(.*?)(?=\\s|\$)"), (Match m) { + String replacedText = string.replaceAllMapped(RegExp("#(.*?)(?=\\s|\$)"), (Match m) { return '"#${m.group(1)}"'; }); /// This will replace the temp added comment string with # /// [Constants.comment] -> "Pubspec Manager Comment:" will be replaced with "#" in the final pubspec.yaml - replacedText = replacedText.replaceAllMapped( - RegExp("${Constants.comment}\\d+: (.*?)(?=\\s|\$)"), (Match m) { + replacedText = replacedText + .replaceAllMapped(RegExp("${Constants.comment}\\d+: (.*?)(?=\\s|\$)"), (Match m) { return '# ${m.group(1)}'; }); /// Save the updated YAML to the file logger.trace('Creating a backup of pubspec.yaml to backup_pubspec.yaml'); - config.backupPubspecFile - .writeAsStringSync(config.pubspecFile.readAsStringSync()); + config.backupPubspecFile.writeAsStringSync(config.pubspecFile.readAsStringSync()); config.pubspecFile.writeAsStringSync(replacedText); logger.stdout('Merging of pubspec.yaml files completed successfully'.green); @@ -360,8 +615,7 @@ mixin PubspecManager { logger.stderr( 'The name is changed from ${actualPubspec.name} to ${flavorPubspec.name} (as the the one mentioned in the pubspec_${config.flavor}.yaml'); logger.stderr('This would cause errors in the project.'); - logger.stderr( - 'Fix for this would to refactor the places where the package name was used'); + logger.stderr('Fix for this would to refactor the places where the package name was used'); logger.stderr( "Refactor: import 'package:${actualPubspec.name}/ to import 'package:${flavorPubspec.name}/ "); }