001
014
015 package com.liferay.portal.tools;
016
017 import com.liferay.portal.kernel.util.FileUtil;
018 import com.liferay.portal.kernel.util.GetterUtil;
019 import com.liferay.portal.kernel.util.NumericalStringComparator;
020 import com.liferay.portal.kernel.util.OSDetector;
021 import com.liferay.portal.kernel.util.PropertiesUtil;
022 import com.liferay.portal.kernel.util.StringBundler;
023 import com.liferay.portal.kernel.util.StringPool;
024 import com.liferay.portal.kernel.util.StringUtil;
025 import com.liferay.portal.kernel.util.Validator;
026 import com.liferay.portal.util.InitUtil;
027
028 import java.io.File;
029
030 import java.util.Arrays;
031 import java.util.Properties;
032 import java.util.Set;
033 import java.util.TreeSet;
034
035 import org.apache.tools.ant.DirectoryScanner;
036
037
040 public class PluginsSummaryBuilder {
041
042 public static void main(String[] args) {
043 InitUtil.initWithSpring();
044
045 File pluginsDir = new File(System.getProperty("plugins.dir"));
046
047 new PluginsSummaryBuilder(pluginsDir);
048 }
049
050 public PluginsSummaryBuilder(File pluginsDir) {
051 try {
052 _pluginsDir = pluginsDir;
053
054 _createPluginsSummary();
055 }
056 catch (Exception e) {
057 e.printStackTrace();
058 }
059 }
060
061 private void _createPluginsSummary() throws Exception {
062 DirectoryScanner directoryScanner = new DirectoryScanner();
063
064 directoryScanner.setBasedir(_pluginsDir);
065 directoryScanner.setExcludes(
066 new String[] {"**\\tmp\\**", "**\\tools\\**"});
067 directoryScanner.setIncludes(
068 new String[] {
069 "**\\liferay-plugin-package.properties"
070 });
071
072 directoryScanner.scan();
073
074 String[] fileNames = directoryScanner.getIncludedFiles();
075
076 Arrays.sort(fileNames);
077
078 _createPluginsSummary(fileNames);
079 }
080
081 private void _createPluginsSummary(String[] fileNames) throws Exception {
082 StringBundler sb = new StringBundler();
083
084 sb.append("<plugins-summary>\n");
085
086 for (String fileName : fileNames) {
087 fileName = StringUtil.replace(
088 fileName, StringPool.BACK_SLASH, StringPool.SLASH);
089
090 _createPluginSummary(sb, fileName);
091 }
092
093 for (String author : _distinctAuthors) {
094 sb.append("\t<author>");
095 sb.append(author);
096 sb.append("</author>\n");
097 }
098
099 for (String license : _distinctLicenses) {
100 sb.append("\t<license>");
101 sb.append(license);
102 sb.append("</license>\n");
103 }
104
105 sb.append("</plugins-summary>");
106
107 FileUtil.write(_pluginsDir + "/summary.xml", sb.toString());
108 }
109
110 private void _createPluginSummary(StringBundler sb, String fileName)
111 throws Exception {
112
113 String content = FileUtil.read(fileName);
114
115 int x = fileName.indexOf(StringPool.SLASH);
116
117 String type = fileName.substring(0, x);
118
119 if (type.endsWith("s")) {
120 type = type.substring(0, type.length() - 1);
121 }
122
123 x = fileName.indexOf(StringPool.SLASH, x) + 1;
124
125 int y = fileName.indexOf(StringPool.SLASH, x);
126
127 String artifactId = fileName.substring(x, y);
128
129 Properties properties = PropertiesUtil.load(content);
130
131 String name = _readProperty(properties, "name");
132 String tags = _readProperty(properties, "tags");
133 String shortDescription = _readProperty(
134 properties, "short-description");
135 String longDescription = _readProperty(properties, "long-description");
136 String changeLog = _readProperty(properties, "change-log");
137 String pageURL = _readProperty(properties, "page-url");
138 String author = _readProperty(properties, "author");
139 String licenses = _readProperty(properties, "licenses");
140 String liferayVersions = _readProperty(properties, "liferay-versions");
141
142 _distinctAuthors.add(author);
143 _distinctLicenses.add(licenses);
144
145 sb.append("\t<plugin>\n");
146
147 _writeElement(sb, "artifact-id", artifactId, 2);
148 _writeElement(sb, "name", name, 2);
149 _writeElement(sb, "type", type, 2);
150 _writeElement(sb, "tags", tags, 2);
151 _writeElement(sb, "short-description", shortDescription, 2);
152 _writeElement(sb, "long-description", longDescription, 2);
153 _writeElement(sb, "change-log", changeLog, 2);
154 _writeElement(sb, "page-url", pageURL, 2);
155 _writeElement(sb, "author", author, 2);
156 _writeElement(sb, "licenses", licenses, 2);
157 _writeElement(sb, "liferay-versions", liferayVersions, 2);
158
159 sb.append("\t\t<releng>\n");
160 sb.append(_readReleng(fileName, properties));
161 sb.append("\t\t</releng>\n");
162 sb.append("\t</plugin>\n");
163 }
164
165 private Set<String> _extractTicketIds(File pluginDir, String range)
166 throws Exception {
167
168 Set<String> ticketIds = new TreeSet<String>(
169 new NumericalStringComparator()
170 );
171
172 Runtime runtime = Runtime.getRuntime();
173
174 String command = "git log " + range + " .";
175
176 if (OSDetector.isWindows()) {
177 command = "cmd /c " + command;
178 }
179
180 Process process = runtime.exec(command, null, pluginDir);
181
182 String content = StringUtil.read(process.getInputStream());
183
184 content = StringUtil.replace(content, "\n", " ");
185
186 for (String ticketIdPrefix : _TICKET_ID_PREFIXES) {
187 int x = 0;
188
189 while (true) {
190 x = content.indexOf(ticketIdPrefix + "-", x);
191
192 if (x == -1) {
193 break;
194 }
195
196 int y = x + ticketIdPrefix.length() + 1;
197
198 while (true) {
199 if ((y + 1) > content.length()) {
200 break;
201 }
202
203 if (Character.isDigit(content.charAt(y))) {
204 y++;
205 }
206 else {
207 break;
208 }
209 }
210
211 String ticketId = content.substring(x, y);
212
213 ticketIds.add(ticketId);
214
215 x = y;
216 }
217 }
218
219 return ticketIds;
220 }
221
222 private String _getChangeLogEntry(
223 int changeLogVersion, String range, String ticketIdsString) {
224
225 StringBundler sb = new StringBundler(8);
226
227 if (changeLogVersion > 1) {
228 sb.append("\n\n");
229 }
230
231 sb.append("#\n");
232 sb.append("# Module Incremental Version ");
233 sb.append(changeLogVersion);
234 sb.append("\n#\n");
235 sb.append(range);
236 sb.append("=");
237 sb.append(ticketIdsString);
238
239 return sb.toString();
240 }
241
242 private String _readProperty(Properties properties, String key) {
243 return GetterUtil.getString(properties.getProperty(key));
244 }
245
246 private String _readReleng(
247 String fileName, Properties pluginPackageProperties)
248 throws Exception {
249
250 int x = fileName.indexOf("WEB-INF");
251
252 String relativeWebInfDirName = fileName.substring(0, x + 8);
253
254 String fullWebInfDirName =
255 _pluginsDir + StringPool.SLASH + relativeWebInfDirName;
256
257 String relengPropertiesFileName =
258 fullWebInfDirName + "liferay-releng.properties";
259
260 Properties relengProperties = null;
261
262 if (FileUtil.exists(relengPropertiesFileName)) {
263 String relengPropertiesContent = FileUtil.read(
264 relengPropertiesFileName);
265
266 relengProperties = PropertiesUtil.load(relengPropertiesContent);
267 }
268 else {
269 relengProperties = new Properties();
270 }
271
272 String relengPropertiesContent = _updateRelengPropertiesFile(
273 relengPropertiesFileName, relengProperties);
274
275 relengProperties = PropertiesUtil.load(relengPropertiesContent);
276
277 StringBundler sb = new StringBundler();
278
279 _writeElement(sb, "bundle", relengProperties, 3);
280 _writeElement(sb, "category", relengProperties, 3);
281 _writeElement(sb, "demo-url", relengProperties, 3);
282 _writeElement(sb, "dependent-apps", relengProperties, 3);
283
284 if (FileUtil.exists(fullWebInfDirName + "releng/icons/90x90.png")) {
285 _writeElement(
286 sb, "icon", relativeWebInfDirName + "releng/icons/90x90.png",
287 3);
288 }
289
290 _writeElement(sb, "labs", relengProperties, 3);
291 _writeElement(sb, "marketplace", relengProperties, 3);
292 _writeElement(sb, "public", relengProperties, 3);
293
294 String fullScreenshotsDirName =
295 fullWebInfDirName + "releng/screenshots/";
296 String relativeScreenshotsDirName =
297 relativeWebInfDirName + "releng/screenshots/";
298
299 if (FileUtil.exists(fullScreenshotsDirName)) {
300 String[] screenshotsFileNames = FileUtil.listFiles(
301 fullScreenshotsDirName);
302
303 Arrays.sort(screenshotsFileNames);
304
305 for (String screenshotsFileName : screenshotsFileNames) {
306 if (screenshotsFileName.equals("Thumbs.db") ||
307 screenshotsFileName.endsWith(".png")) {
308
309 FileUtil.delete(
310 fullScreenshotsDirName + screenshotsFileName);
311 }
312
313 if (!screenshotsFileName.endsWith(".jpg")) {
314 continue;
315 }
316
317 _writeElement(
318 sb, "screenshot",
319 relativeScreenshotsDirName + screenshotsFileName, 3);
320 }
321 }
322
323 _writeElement(sb, "support-url", relengProperties, 3);
324 _writeElement(sb, "supported", relengProperties, 3);
325
326 File relengChangeLogFile = new File(
327 fullWebInfDirName + "liferay-releng.changelog");
328
329 if (GetterUtil.getBoolean(
330 relengProperties.getProperty("marketplace"))) {
331
332 _updateRelengChangeLogFile(
333 pluginPackageProperties, relengChangeLogFile, relengProperties);
334 }
335 else {
336 relengChangeLogFile.delete();
337 }
338
339 return sb.toString();
340 }
341
342 private void _updateRelengChangeLogFile(
343 Properties pluginPackageProperties, File relengChangeLogFile,
344 Properties relengProperties)
345 throws Exception {
346
347 StringBundler sb = new StringBundler();
348
349 int changeLogVersion = 0;
350
351 int moduleIncrementalVersion = GetterUtil.getInteger(
352 pluginPackageProperties.getProperty("module-incremental-version"));
353
354 if (!relengChangeLogFile.exists()) {
355 FileUtil.write(relengChangeLogFile, "HEAD=");
356 }
357
358 String relengChangeLogContent = FileUtil.read(relengChangeLogFile);
359
360 String[] relengChangeLogEntries = StringUtil.split(
361 relengChangeLogContent, "\n");
362
363 for (int i = 0; i < relengChangeLogEntries.length; i++) {
364 String relengChangeLogEntry = relengChangeLogEntries[i];
365
366 if (Validator.isNull(relengChangeLogEntry) ||
367 relengChangeLogEntry.startsWith("#")) {
368
369 continue;
370 }
371
372 String[] relengChangeLogEntryParts = StringUtil.split(
373 relengChangeLogEntry, "=");
374
375 String range = relengChangeLogEntryParts[0];
376
377 if (range.equals("HEAD")) {
378 changeLogVersion++;
379
380 sb.append(
381 _getChangeLogEntry(
382 changeLogVersion, range, StringPool.BLANK));
383
384 continue;
385 }
386
387 File webInfDir = relengChangeLogFile.getParentFile();
388
389 File docrootDir = webInfDir.getParentFile();
390
391 File pluginDir = docrootDir.getParentFile();
392
393 Set<String> ticketIds = _extractTicketIds(pluginDir, range);
394
395 String[] dependentApps = StringUtil.split(
396 relengProperties.getProperty("dependent-apps"));
397
398 for (String dependentApp : dependentApps) {
399 dependentApp = dependentApp.trim();
400
401 String dependentAppDirName = null;
402
403 if (dependentApp.endsWith("-hook")) {
404 dependentAppDirName = "hooks";
405 }
406 else if (dependentApp.endsWith("-layouttpl")) {
407 dependentAppDirName = "layouttpl";
408 }
409 else if (dependentApp.endsWith("-portlet")) {
410 dependentAppDirName = "portlets";
411 }
412 else if (dependentApp.endsWith("-theme")) {
413 dependentAppDirName = "themes";
414 }
415 else if (dependentApp.endsWith("-web")) {
416 dependentAppDirName = "webs";
417 }
418
419 File dependentAppDir = new File(
420 _pluginsDir, dependentAppDirName + "/" + dependentApp);
421
422 if (!dependentAppDir.exists()) {
423 throw new RuntimeException(
424 dependentAppDir + " does not exist");
425 }
426
427 ticketIds.addAll(_extractTicketIds(dependentAppDir, range));
428 }
429
430 String ticketIdsString = StringUtil.merge(
431 ticketIds.toArray(new String[ticketIds.size()]), " ");
432
433 changeLogVersion++;
434
435 sb.append(
436 _getChangeLogEntry(changeLogVersion, range, ticketIdsString));
437 }
438
439 if (moduleIncrementalVersion != changeLogVersion) {
440 File pluginPackagePropertiesFile = new File(
441 relengChangeLogFile.getParentFile(),
442 "liferay-plugin-package.properties");
443
444 String pluginPackagePropertiesContent = FileUtil.read(
445 pluginPackagePropertiesFile);
446
447 pluginPackagePropertiesContent = StringUtil.replace(
448 pluginPackagePropertiesContent,
449 "module-incremental-version=" + moduleIncrementalVersion,
450 "module-incremental-version=" + changeLogVersion);
451
452 FileUtil.write(
453 pluginPackagePropertiesFile, pluginPackagePropertiesContent);
454 }
455
456 FileUtil.write(relengChangeLogFile, sb.toString());
457 }
458
459 private String _updateRelengPropertiesFile(
460 String relengPropertiesFileName, Properties relengProperties)
461 throws Exception {
462
463 StringBundler sb = new StringBundler();
464
465 _writeProperty(sb, relengProperties, "bundle", "false");
466 _writeProperty(sb, relengProperties, "category", "");
467 _writeProperty(sb, relengProperties, "demo-url", "");
468 _writeProperty(sb, relengProperties, "dependent-apps", "");
469 _writeProperty(sb, relengProperties, "labs", "true");
470 _writeProperty(sb, relengProperties, "marketplace", "false");
471 _writeProperty(sb, relengProperties, "public", "true");
472 _writeProperty(sb, relengProperties, "support-url", "");
473 _writeProperty(sb, relengProperties, "supported", "false");
474
475 String relengPropertiesContent = sb.toString();
476
477 FileUtil.write(relengPropertiesFileName, relengPropertiesContent);
478
479 return relengPropertiesContent;
480 }
481
482 private void _writeElement(
483 StringBundler sb, String name, Properties properties, int tabsCount) {
484
485 _writeElement(sb, name, _readProperty(properties, name), tabsCount);
486 }
487
488 private void _writeElement(
489 StringBundler sb, String name, String value, int tabsCount) {
490
491 for (int i = 0; i < tabsCount; i++) {
492 sb.append("\t");
493 }
494
495 sb.append("<");
496 sb.append(name);
497 sb.append("><![CDATA[");
498 sb.append(value);
499 sb.append("]]></");
500 sb.append(name);
501 sb.append(">\n");
502 }
503
504 private void _writeProperty(
505 StringBundler sb, Properties properties, String key,
506 String defaultValue) {
507
508 String value = GetterUtil.getString(
509 properties.getProperty(key), defaultValue);
510
511 if (sb.length() > 0) {
512 sb.append(StringPool.NEW_LINE);
513 }
514
515 sb.append(key);
516 sb.append(StringPool.EQUAL);
517 sb.append(value);
518 }
519
520 private static final String[] _TICKET_ID_PREFIXES = {"LPS", "SOS"};
521
522 private Set<String> _distinctAuthors = new TreeSet<String>();
523 private Set<String> _distinctLicenses = new TreeSet<String>();
524 private File _pluginsDir;
525
526 }