001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.tools;
016    
017    import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
018    import com.liferay.portal.kernel.util.FileUtil;
019    import com.liferay.portal.kernel.util.GetterUtil;
020    import com.liferay.portal.kernel.util.ListUtil;
021    import com.liferay.portal.kernel.util.StringBundler;
022    import com.liferay.portal.kernel.util.StringPool;
023    import com.liferay.portal.kernel.util.StringUtil;
024    import com.liferay.portal.kernel.util.Validator;
025    import com.liferay.portal.util.InitUtil;
026    
027    import java.io.File;
028    import java.io.FileInputStream;
029    import java.io.IOException;
030    import java.io.InputStream;
031    import java.io.InputStreamReader;
032    
033    import java.util.ArrayList;
034    import java.util.Arrays;
035    import java.util.List;
036    import java.util.Properties;
037    
038    import org.apache.oro.io.GlobFilenameFilter;
039    import org.apache.tools.ant.DirectoryScanner;
040    
041    /**
042     * @author Alexander Chow
043     * @author Brian Wing Shun Chan
044     */
045    public class PluginsEnvironmentBuilder {
046    
047            public static void main(String[] args) throws Exception {
048                    InitUtil.initWithSpring();
049    
050                    File dir = new File(System.getProperty("plugins.env.dir"));
051                    boolean svn = GetterUtil.getBoolean(
052                            System.getProperty("plugins.env.svn"));
053                    boolean eclipse = GetterUtil.getBoolean(
054                            System.getProperty("plugins.env.eclipse"));
055    
056                    new PluginsEnvironmentBuilder(dir, svn, eclipse);
057            }
058    
059            public PluginsEnvironmentBuilder(File dir, boolean svn, boolean eclipse) {
060                    try {
061                            _svn = svn;
062    
063                            DirectoryScanner ds = new DirectoryScanner();
064    
065                            ds.setBasedir(dir);
066                            ds.setIncludes(
067                                    new String[] {
068                                            "**\\liferay-plugin-package.properties",
069                                    });
070    
071                            ds.scan();
072    
073                            String dirName = dir.getCanonicalPath();
074    
075                            String[] fileNames = ds.getIncludedFiles();
076    
077                            for (String fileName : fileNames) {
078                                    File propertiesFile = new File(dirName + "/" + fileName);
079                                    File libDir = new File(propertiesFile.getParent() + "/lib");
080                                    File projectDir = new File(
081                                            propertiesFile.getParent() + "/../..");
082    
083                                    Properties properties = new Properties();
084    
085                                    properties.load(new FileInputStream(propertiesFile));
086    
087                                    String[] dependencyJars = StringUtil.split(
088                                            properties.getProperty(
089                                                    "portal-dependency-jars",
090                                                    properties.getProperty("portal.dependency.jars")));
091    
092                                    if (svn) {
093                                            List<String> jars = ListUtil.toList(dependencyJars);
094    
095                                            jars.add("commons-logging.jar");
096                                            jars.add("log4j.jar");
097                                            jars.add("util-bridges.jar");
098                                            jars.add("util-java.jar");
099                                            jars.add("util-taglib.jar");
100    
101                                            jars = ListUtil.sort(jars);
102    
103                                            updateLibIgnores(
104                                                    libDir, jars.toArray(new String[jars.size()]));
105                                    }
106    
107                                    if (eclipse) {
108                                            updateEclipseFiles(libDir, projectDir, dependencyJars);
109                                    }
110                            }
111                    }
112                    catch (Exception e) {
113                            e.printStackTrace();
114                    }
115            }
116    
117            public void updateEclipseFiles(
118                            File libDir, File projectDir, String[] dependencyJars)
119                    throws Exception {
120    
121                    String libDirPath = libDir.getPath();
122    
123                    libDirPath = StringUtil.replace(
124                            libDirPath, StringPool.BACK_SLASH, StringPool.SLASH);
125    
126                    String projectDirName = projectDir.getCanonicalPath();
127                    String projectName = StringUtil.extractLast(
128                            projectDirName, File.separator);
129    
130                    boolean javaProject = false;
131    
132                    if (FileUtil.exists(projectDirName + "/docroot/WEB-INF/src")) {
133                            javaProject = true;
134                    }
135    
136                    // .project
137    
138                    StringBundler sb = new StringBundler(17);
139    
140                    sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
141                    sb.append("<projectDescription>\n");
142                    sb.append("\t<name>");
143                    sb.append(projectName);
144                    sb.append("</name>\n");
145                    sb.append("\t<comment></comment>\n");
146                    sb.append("\t<projects></projects>\n");
147                    sb.append("\t<buildSpec>\n");
148    
149                    if (javaProject) {
150                            sb.append("\t\t<buildCommand>\n");
151                            sb.append("\t\t\t<name>org.eclipse.jdt.core.javabuilder</name>\n");
152                            sb.append("\t\t\t<arguments></arguments>\n");
153                            sb.append("\t\t</buildCommand>\n");
154                    }
155    
156                    sb.append("\t</buildSpec>\n");
157                    sb.append("\t<natures>\n");
158    
159                    if (javaProject) {
160                            sb.append("\t\t<nature>org.eclipse.jdt.core.javanature</nature>\n");
161                    }
162    
163                    sb.append("\t</natures>\n");
164                    sb.append("</projectDescription>");
165    
166                    File projectFile = new File(projectDirName + "/.project");
167    
168                    System.out.println("Updating " + projectFile);
169    
170                    FileUtil.write(projectFile, sb.toString());
171    
172                    // .classpath
173    
174                    File classpathFile = null;
175    
176                    if (javaProject) {
177                            List<String> portalJars = ListUtil.toList(dependencyJars);
178    
179                            portalJars.add("commons-logging.jar");
180                            portalJars.add("log4j.jar");
181    
182                            portalJars = ListUtil.sort(portalJars);
183    
184                            String[] customJarsArray = libDir.list(
185                                    new GlobFilenameFilter("*.jar"));
186    
187                            List<String> customJars = null;
188    
189                            if (customJarsArray != null) {
190                                    customJars = ListUtil.toList(customJarsArray);
191    
192                                    customJars = ListUtil.sort(customJars);
193    
194                                    for (String jar : portalJars) {
195                                            customJars.remove(jar);
196                                    }
197    
198                                    customJars.remove(projectName + "-service.jar");
199                                    customJars.remove("util-bridges.jar");
200                                    customJars.remove("util-java.jar");
201                                    customJars.remove("util-taglib.jar");
202                            }
203                            else {
204                                    customJars = new ArrayList<String>();
205                            }
206    
207                            sb = new StringBundler();
208    
209                            sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
210                            sb.append("<classpath>\n");
211    
212                            if (FileUtil.exists(projectDirName + "/docroot/WEB-INF/service")) {
213                                    sb.append("\t<classpathentry excluding=\"**/.svn/**|.svn/\" ");
214                                    sb.append("kind=\"src\" path=\"docroot/WEB-INF/service\" />\n");
215                            }
216    
217                            sb.append("\t<classpathentry excluding=\"**/.svn/**|.svn/\" ");
218                            sb.append("kind=\"src\" path=\"docroot/WEB-INF/src\" />\n");
219                            sb.append("\t<classpathentry kind=\"src\" path=\"/portal\" />\n");
220                            sb.append("\t<classpathentry kind=\"con\" ");
221                            sb.append("path=\"org.eclipse.jdt.launching.JRE_CONTAINER\" />\n");
222    
223                            if (FileUtil.exists(projectDirName + "/docroot/WEB-INF/test")) {
224                                    sb.append("\t<classpathentry excluding=\"**/.svn/**|.svn/\" ");
225                                    sb.append("kind=\"src\" path=\"docroot/WEB-INF/test\" />\n");
226                            }
227    
228                            _addClasspathEntry(sb, "/portal/lib/development/activation.jar");
229                            _addClasspathEntry(sb, "/portal/lib/development/annotations.jar");
230                            _addClasspathEntry(sb, "/portal/lib/development/jsp-api.jar");
231                            _addClasspathEntry(sb, "/portal/lib/development/mail.jar");
232                            _addClasspathEntry(sb, "/portal/lib/development/servlet-api.jar");
233                            _addClasspathEntry(sb, "/portal/lib/global/portlet.jar");
234    
235                            for (String jar : portalJars) {
236                                    _addClasspathEntry(sb, "/portal/lib/portal/" + jar);
237                            }
238    
239                            _addClasspathEntry(sb, "/portal/portal-service/portal-service.jar");
240                            _addClasspathEntry(sb, "/portal/util-bridges/util-bridges.jar");
241                            _addClasspathEntry(sb, "/portal/util-java/util-java.jar");
242                            _addClasspathEntry(sb, "/portal/util-taglib/util-taglib.jar");
243    
244                            for (String jar : customJars) {
245                                    if (libDirPath.contains("/tmp/WEB-INF/lib")) {
246                                            _addClasspathEntry(sb, "tmp/WEB-INF/lib/" + jar);
247                                    }
248                                    else {
249                                            _addClasspathEntry(sb, "docroot/WEB-INF/lib/" + jar);
250                                    }
251                            }
252    
253                            sb.append("\t<classpathentry kind=\"output\" path=\"bin\" />\n");
254                            sb.append("</classpath>");
255    
256                            classpathFile = new File(projectDirName + "/.classpath");
257    
258                            System.out.println("Updating " + classpathFile);
259    
260                            FileUtil.write(classpathFile, sb.toString());
261                    }
262    
263                    // SVN
264    
265                    if (_svn) {
266                            String projectFileName = "\"" + projectFile + "\"";
267    
268                            try {
269                                    _exec(_SVN_INFO + projectFileName);
270                            }
271                            catch (Exception e) {
272                                    _exec(_SVN_ADD + projectFileName);
273                            }
274    
275                            if (javaProject) {
276                                    String classpathFileName = "\"" + classpathFile + "\"";
277    
278                                    try {
279                                            _exec(_SVN_INFO + classpathFileName);
280                                    }
281                                    catch (Exception e) {
282                                            _exec(_SVN_ADD + classpathFileName);
283                                    }
284                            }
285    
286                            File tempFile = File.createTempFile("svn-ignores-", null, null);
287    
288                            try {
289                                    FileUtil.write(tempFile, "bin\ntmp");
290    
291                                    _exec(
292                                            _SVN_SET_IGNORES + "-F \"" + tempFile.getCanonicalPath() +
293                                                    "\" \"" + projectDirName + "\"");
294                            }
295                            finally {
296                                    FileUtil.delete(tempFile);
297                            }
298                    }
299            }
300    
301            public void updateLibIgnores(File libDir, String[] jars) throws Exception {
302                    if (!_isSVNDir(libDir)) {
303                            return;
304                    }
305    
306                    File tempFile = null;
307    
308                    try {
309                            String libDirName = "\"" + libDir.getCanonicalPath() + "\"";
310    
311                            String[] oldIgnores = _exec(_SVN_GET_IGNORES + libDirName);
312    
313                            Arrays.sort(oldIgnores);
314    
315                            if (Arrays.equals(oldIgnores, jars)) {
316                                    return;
317                            }
318    
319                            tempFile = File.createTempFile("svn-ignores-", null, null);
320    
321                            _exec(_SVN_DEL_IGNORES + libDirName);
322    
323                            if (jars.length == 0) {
324                                    FileUtil.write(tempFile, StringPool.BLANK);
325                            }
326                            else {
327                                    StringBundler sb = new StringBundler(jars.length * 2);
328    
329                                    for (String jar : jars) {
330                                            sb.append(jar);
331                                            sb.append("\n");
332                                    }
333    
334                                    FileUtil.write(tempFile, sb.toString());
335                            }
336    
337                            _exec(
338                                    _SVN_SET_IGNORES + "-F \"" + tempFile.getCanonicalPath() +
339                                            "\" \"" + libDirName + "\"");
340    
341                            String[] newIgnores = _exec(
342                                    _SVN_GET_IGNORES + "\"" + libDirName + "\"");
343    
344                            if (newIgnores.length > 0) {
345                                    Arrays.sort(newIgnores);
346                            }
347                    }
348                    finally {
349                            if (tempFile != null) {
350                                    FileUtil.delete(tempFile);
351                            }
352                    }
353            }
354    
355            private void _addClasspathEntry(StringBundler sb, String jar)
356                    throws Exception {
357    
358                    sb.append("\t<classpathentry kind=\"lib\" path=\"");
359                    sb.append(jar);
360                    sb.append("\" />\n");
361            }
362    
363            private String[] _exec(String cmd) throws Exception {
364                    Process process = Runtime.getRuntime().exec(cmd);
365    
366                    String[] stdout = _getExecOutput(process.getInputStream());
367                    String[] stderr = _getExecOutput(process.getErrorStream());
368    
369                    if (stderr.length > 0) {
370                            StringBundler sb = new StringBundler(stderr.length * 3 + 3);
371    
372                            sb.append("Received errors in executing '");
373                            sb.append(cmd);
374                            sb.append("'\n");
375    
376                            for (String err : stderr) {
377                                    sb.append("\t");
378                                    sb.append(err);
379                                    sb.append("\n");
380                            }
381    
382                            throw new Exception(sb.toString());
383                    }
384    
385                    return stdout;
386            }
387    
388            private String[] _getExecOutput(InputStream is) throws IOException {
389                    List<String> list = new ArrayList<String>();
390    
391                    UnsyncBufferedReader unsyncBufferedReader = null;
392    
393                    try {
394                            unsyncBufferedReader = new UnsyncBufferedReader(
395                                    new InputStreamReader(is));
396    
397                            String line = unsyncBufferedReader.readLine();
398    
399                            while (line != null) {
400                                    line = line.trim();
401    
402                                    if (Validator.isNotNull(line)) {
403                                            list.add(line);
404                                    }
405    
406                                    line = unsyncBufferedReader.readLine();
407                            }
408                    }
409                    finally {
410                            if (unsyncBufferedReader != null) {
411                                    try {
412                                            unsyncBufferedReader.close();
413                                    }
414                                    catch (Exception e) {
415                                    }
416                            }
417                    }
418    
419                    return list.toArray(new String[] {});
420            }
421    
422            private boolean _isSVNDir(File libDir) {
423                    if (!libDir.exists()) {
424                            return false;
425                    }
426    
427                    try {
428                            _exec(_SVN_INFO + "\"" + libDir + "\"");
429                    }
430                    catch (Exception e) {
431                            return false;
432                    }
433    
434                    return true;
435            }
436    
437            private static final String _SVN_ADD = "svn add ";
438    
439            private static final String _SVN_DEL_IGNORES = "svn propdel svn:ignore ";
440    
441            private static final String _SVN_GET_IGNORES = "svn propget svn:ignore ";
442    
443            private static final String _SVN_INFO = "svn info ";
444    
445            private static final String _SVN_SET_IGNORES = "svn propset svn:ignore ";
446    
447            private boolean _svn;
448    
449    }