Skip to content

Commit e8f6fc4

Browse files
authored
feat: add functionality to keep custom intellij modules (#949)
<!-- Thanks for contributing! Provide a description of your changes below and a general summary in the title Please look at the following checklist to ensure that your PR can be accepted quickly: --> As described in #589 intellij modules are overwritten at each `melos bootstrap`. The reason for this is that the whole modules.xml file isrecreated at every bootstrap. Closes #589 ## Description - Added xml dependency to read and parse the xml content of the modules.xml properly - Added a function to compare the modules inside the current modules.xml with the melos modules. Then merge them before recreating the modules.xml. ## Type of Change <!--- Put an `x` in all the boxes that apply: --> - [x] ✨ `feat` -- New feature (non-breaking change which adds functionality) - [ ] 🛠️ `fix` -- Bug fix (non-breaking change which fixes an issue) - [ ] ❌ `!` -- Breaking change (fix or feature that would cause existing functionality to change) - [ ] 🧹 `refactor` -- Code refactor - [ ] ✅ `ci` -- Build configuration change - [ ] 📝 `docs` -- Documentation - [ ] 🗑️ `chore` -- Chore
1 parent 1c3045f commit e8f6fc4

File tree

2 files changed

+70
-12
lines changed

2 files changed

+70
-12
lines changed

packages/melos/lib/src/common/intellij_project.dart

Lines changed: 69 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'dart:io';
22

33
import 'package:path/path.dart' as p;
4+
import 'package:xml/xml.dart' as xml;
45

56
import '../common/utils.dart' as utils;
67
import '../package.dart';
@@ -133,19 +134,27 @@ class IntellijProject {
133134
return template;
134135
}
135136

136-
String ideaModuleStringForName(String moduleName, {String? relativePath}) {
137+
xml.XmlElement ideaModuleElementForName(
138+
String moduleName, {
139+
String? relativePath,
140+
}) {
137141
var imlPath = relativePath != null
138142
? p.normalize('$relativePath/$moduleName.iml')
139143
: '$moduleName.iml';
144+
140145
// Use `/` instead of `\` no matter what platform is.
141146
imlPath = imlPath.replaceAll(r'\', '/');
142-
final module =
143-
'<module '
144-
'fileurl="file://\$PROJECT_DIR\$/$imlPath" '
145-
'filepath="\$PROJECT_DIR\$/$imlPath" '
146-
'/>';
147-
// Pad to preserve formatting on generated file.
148-
return module.padLeft(6);
147+
148+
return xml.XmlElement(
149+
xml.XmlName('module'),
150+
[
151+
xml.XmlAttribute(
152+
xml.XmlName('fileurl'),
153+
'file://\$PROJECT_DIR\$/$imlPath',
154+
),
155+
xml.XmlAttribute(xml.XmlName('filepath'), '\$PROJECT_DIR\$/$imlPath'),
156+
],
157+
);
149158
}
150159

151160
Future<void> forceWriteToFile(String filePath, String fileContents) async {
@@ -212,22 +221,70 @@ class IntellijProject {
212221
);
213222
}
214223

224+
Future<List<xml.XmlElement>> mergeExistingModules(
225+
List<xml.XmlElement> melosModules,
226+
) async {
227+
if (!fileExists(pathModulesXml)) return melosModules;
228+
229+
final text = await readTextFileAsync(pathModulesXml);
230+
try {
231+
final doc = xml.XmlDocument.parse(text);
232+
233+
String createNormalizedKey(xml.XmlElement e) {
234+
final v =
235+
e.getAttribute('filepath') ??
236+
e.getAttribute('filePath') ??
237+
e.getAttribute('fileurl') ??
238+
e.getAttribute('fileUrl');
239+
return (v ?? '')
240+
.trim()
241+
.replaceAll(r'\', '/')
242+
.replaceFirst(
243+
RegExp(r'^file://\$PROJECT_DIR\$/', caseSensitive: false),
244+
'',
245+
)
246+
.replaceFirst(
247+
RegExp(r'^\$PROJECT_DIR\$/', caseSensitive: false),
248+
'',
249+
);
250+
}
251+
252+
final seen = melosModules
253+
.map(createNormalizedKey)
254+
.where((s) => s.isNotEmpty)
255+
.toSet();
256+
257+
final extras = doc
258+
.findAllElements('module')
259+
.where(
260+
(m) => seen.add(createNormalizedKey(m)),
261+
)
262+
.map((m) => m.copy());
263+
264+
return [...melosModules.map((e) => e.copy()), ...extras];
265+
} catch (_) {
266+
return melosModules;
267+
}
268+
}
269+
215270
Future<void> writeModulesXml() async {
216-
final ideaModules = <String>[];
271+
final ideaModules = <xml.XmlElement>[];
272+
217273
for (final package in _workspace.filteredPackages.values) {
218274
ideaModules.add(
219-
ideaModuleStringForName(
275+
ideaModuleElementForName(
220276
packageModuleName(package),
221277
relativePath: package.pathRelativeToWorkspace,
222278
),
223279
);
224280
}
225-
ideaModules.add(ideaModuleStringForName(workspaceModuleName));
281+
ideaModules.add(ideaModuleElementForName(workspaceModuleName));
282+
final mergedModules = await mergeExistingModules(ideaModules);
226283
final ideaModulesXmlTemplate = await readFileTemplate('modules.xml');
227284
final generatedModulesXml = injectTemplateVariable(
228285
template: ideaModulesXmlTemplate,
229286
variableName: 'modules',
230-
variableValue: ideaModules.join('\n'),
287+
variableValue: mergedModules.join('\n'),
231288
);
232289
return forceWriteToFile(pathModulesXml, generatedModulesXml);
233290
}

packages/melos/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ dependencies:
4444
pub_updater: ^0.5.0
4545
pubspec_parse: ^1.5.0
4646
string_scanner: ^1.4.1
47+
xml: ^6.6.1
4748
yaml: ^3.1.3
4849
yaml_edit: ^2.2.2
4950

0 commit comments

Comments
 (0)