1   /**
2    * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.tools;
24  
25  import com.liferay.portal.kernel.util.FileUtil;
26  import com.liferay.portal.kernel.util.GetterUtil;
27  import com.liferay.portal.kernel.util.ListUtil;
28  import com.liferay.portal.kernel.util.StringUtil;
29  import com.liferay.portal.kernel.util.Validator;
30  import com.liferay.portal.util.InitUtil;
31  
32  import java.io.BufferedReader;
33  import java.io.File;
34  import java.io.FileInputStream;
35  import java.io.IOException;
36  import java.io.InputStream;
37  import java.io.InputStreamReader;
38  
39  import java.util.ArrayList;
40  import java.util.Arrays;
41  import java.util.Collections;
42  import java.util.List;
43  import java.util.Properties;
44  
45  import org.apache.oro.io.GlobFilenameFilter;
46  import org.apache.tools.ant.DirectoryScanner;
47  
48  /**
49   * <a href="PluginsEnvironmentBuilder.java.html"><b><i>View Source</i></b></a>
50   *
51   * @author Alexander Chow
52   * @author Brian Wing Shun Chan
53   *
54   */
55  public class PluginsEnvironmentBuilder {
56  
57      public static void main(String[] args) throws Exception {
58          InitUtil.initWithSpring();
59  
60          File dir = new File(System.getProperty("plugins.env.dir"));
61          boolean svn = GetterUtil.getBoolean(
62              System.getProperty("plugins.env.svn"));
63          boolean eclipse = GetterUtil.getBoolean(
64              System.getProperty("plugins.env.eclipse"));
65  
66          new PluginsEnvironmentBuilder(dir, svn, eclipse);
67      }
68  
69      public PluginsEnvironmentBuilder(File dir, boolean svn, boolean eclipse) {
70          try {
71              _svn = svn;
72  
73              DirectoryScanner ds = new DirectoryScanner();
74  
75              ds.setBasedir(dir);
76              ds.setIncludes(
77                  new String[] {
78                      "**\\liferay-plugin-package.properties",
79                  });
80  
81              ds.scan();
82  
83              String dirName = dir.getCanonicalPath();
84  
85              String[] fileNames = ds.getIncludedFiles();
86  
87              for (String fileName : fileNames) {
88                  File propsFile = new File(dirName + "/" + fileName);
89                  File libDir = new File(propsFile.getParent() + "/lib");
90                  File projectDir = new File(propsFile.getParent() + "/../..");
91  
92                  Properties props = new Properties();
93  
94                  props.load(new FileInputStream(propsFile));
95  
96                  List<String> dependencyJars = ListUtil.toList(StringUtil.split(
97                      props.getProperty("portal.dependency.jars")));
98  
99                  if (svn) {
100                     List<String> jars = new ArrayList<String>(dependencyJars);
101 
102                     jars.add("commons-logging.jar");
103                     jars.add("log4j.jar");
104                     jars.add("util-bridges.jar");
105                     jars.add("util-java.jar");
106                     jars.add("util-taglib.jar");
107 
108                     Collections.sort(jars);
109 
110                     updateLibIgnores(
111                         libDir, jars.toArray(new String[jars.size()]));
112                 }
113 
114                 if (eclipse) {
115                     updateEclipseFiles(libDir, projectDir, dependencyJars);
116                 }
117             }
118         }
119         catch (Exception e) {
120             e.printStackTrace();
121         }
122     }
123 
124     public void updateEclipseFiles(
125             File libDir, File projectDir, List<String> dependencyJars)
126         throws Exception {
127 
128         String projectDirName = projectDir.getCanonicalPath();
129         String projectName = StringUtil.extractLast(
130             projectDirName, File.separator);
131 
132         // .project
133 
134         StringBuilder sb = new StringBuilder();
135 
136         sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
137         sb.append("<projectDescription>\n");
138         sb.append("\t<name>" + projectName + "</name>\n");
139         sb.append("\t<comment></comment>\n");
140         sb.append("\t<projects></projects>\n");
141         sb.append("\t<buildSpec>\n");
142         sb.append("\t\t<buildCommand>\n");
143         sb.append("\t\t\t<name>org.eclipse.jdt.core.javabuilder</name>\n");
144         sb.append("\t\t\t<arguments></arguments>\n");
145         sb.append("\t\t</buildCommand>\n");
146         sb.append("\t</buildSpec>\n");
147         sb.append("\t<natures>\n");
148         sb.append("\t\t<nature>org.eclipse.jdt.core.javanature</nature>\n");
149         sb.append("\t</natures>\n");
150         sb.append("</projectDescription>");
151 
152         File projectFile = new File(projectDirName + "/.project");
153 
154         System.out.println("Updating " + projectFile);
155 
156         FileUtil.write(projectFile, sb.toString());
157 
158         // .classpath
159 
160         List<String> portalJars = new ArrayList<String>(dependencyJars);
161 
162         portalJars.add("commons-logging.jar");
163         portalJars.add("log4j.jar");
164 
165         Collections.sort(portalJars);
166 
167         String[] customJarsArray = libDir.list(new GlobFilenameFilter("*.jar"));
168 
169         List<String> customJars = null;
170 
171         if (customJarsArray != null) {
172             customJars = ListUtil.toList(customJarsArray);
173 
174             Collections.sort(customJars);
175 
176             for (String jar : portalJars) {
177                 customJars.remove(jar);
178             }
179 
180             customJars.remove(projectName + "-service.jar");
181             customJars.remove("util-bridges.jar");
182             customJars.remove("util-java.jar");
183             customJars.remove("util-taglib.jar");
184         }
185         else {
186             customJars = new ArrayList<String>();
187         }
188 
189         sb = new StringBuilder();
190 
191         sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
192         sb.append("<classpath>\n");
193 
194         if (FileUtil.exists(projectDirName + "/docroot/WEB-INF/service")) {
195             sb.append("\t<classpathentry excluding=\"**/.svn/**|.svn/\" ");
196             sb.append("kind=\"src\" path=\"docroot/WEB-INF/service\" />\n");
197         }
198 
199         sb.append("\t<classpathentry excluding=\"**/.svn/**|.svn/\" ");
200         sb.append("kind=\"src\" path=\"docroot/WEB-INF/src\" />\n");
201         sb.append("\t<classpathentry kind=\"src\" path=\"/portal\" />\n");
202         sb.append("\t<classpathentry kind=\"con\" ");
203         sb.append("path=\"org.eclipse.jdt.launching.JRE_CONTAINER\" />\n");
204 
205         _addClasspathEntry(sb, "/portal/lib/development/activation.jar");
206         _addClasspathEntry(sb, "/portal/lib/development/jsp-api.jar");
207         _addClasspathEntry(sb, "/portal/lib/development/mail.jar");
208         _addClasspathEntry(sb, "/portal/lib/development/servlet-api.jar");
209         _addClasspathEntry(sb, "/portal/lib/global/annotations.jar");
210         _addClasspathEntry(sb, "/portal/lib/global/container.jar");
211         _addClasspathEntry(sb, "/portal/lib/global/portlet-container.jar");
212         _addClasspathEntry(sb, "/portal/lib/global/portlet.jar");
213 
214         for (String jar : portalJars) {
215             _addClasspathEntry(sb, "/portal/lib/portal/" + jar);
216         }
217 
218         _addClasspathEntry(sb, "/portal/portal-kernel/portal-kernel.jar");
219         _addClasspathEntry(sb, "/portal/portal-service/portal-service.jar");
220         _addClasspathEntry(sb, "/portal/util-bridges/util-bridges.jar");
221         _addClasspathEntry(sb, "/portal/util-java/util-java.jar");
222         _addClasspathEntry(sb, "/portal/util-taglib/util-taglib.jar");
223 
224         for (String jar : customJars) {
225             _addClasspathEntry(sb, "docroot/WEB-INF/lib/" + jar);
226         }
227 
228         sb.append("\t<classpathentry kind=\"output\" path=\"bin\" />\n");
229         sb.append("</classpath>");
230 
231         File classpathFile = new File(projectDirName + "/.classpath");
232 
233         System.out.println("Updating " + classpathFile);
234 
235         FileUtil.write(classpathFile, sb.toString());
236 
237         // SVN
238 
239         if (_svn) {
240             String projectFileName = "\"" + projectFile + "\"";
241 
242             try {
243                 _exec(_SVN_INFO + projectFileName);
244             }
245             catch (Exception e) {
246                 _exec(_SVN_ADD + projectFileName);
247             }
248 
249             String classpathFileName = "\"" + classpathFile + "\"";
250 
251             try {
252                 _exec(_SVN_INFO + classpathFileName);
253             }
254             catch (Exception e) {
255                 _exec(_SVN_ADD + classpathFileName);
256             }
257 
258             _exec(_SVN_SET_IGNORES + "bin \"" + projectDirName + "\"");
259         }
260     }
261 
262     public void updateLibIgnores(File libDir, String[] jars) throws Exception {
263         if (!_isSVNDir(libDir)) {
264             return;
265         }
266 
267         File tempFile = null;
268 
269         try {
270             String libDirName = "\"" + libDir.getCanonicalPath() + "\"";
271 
272             String[] oldIgnores = _exec(_SVN_GET_IGNORES + libDirName);
273 
274             Arrays.sort(oldIgnores);
275 
276             if (Arrays.equals(oldIgnores, jars)) {
277                 return;
278             }
279 
280             tempFile = File.createTempFile("svn-ignores-", null, null);
281 
282             _exec(_SVN_DEL_IGNORES + libDirName);
283 
284             StringBuilder sb = new StringBuilder();
285 
286             for (String jar : jars) {
287                 sb.append(jar + "\n");
288             }
289 
290             FileUtil.write(tempFile, sb.toString());
291 
292             _exec(
293                 _SVN_SET_IGNORES + "-F \"" + tempFile.getCanonicalPath() +
294                     "\" " + libDirName);
295 
296             String[] newIgnores = _exec(_SVN_GET_IGNORES + libDirName);
297 
298             if (newIgnores.length > 0) {
299                 Arrays.sort(newIgnores);
300             }
301         }
302         finally {
303             if (tempFile != null) {
304                 tempFile.delete();
305             }
306         }
307     }
308 
309     private void _addClasspathEntry(StringBuilder sb, String jar)
310         throws Exception {
311 
312         sb.append("\t<classpathentry kind=\"lib\" path=\"");
313         sb.append(jar);
314         sb.append("\" />\n");
315     }
316 
317     private String[] _exec(String cmd) throws Exception {
318         Process process = Runtime.getRuntime().exec(cmd);
319 
320         String[] stdout = _getExecOutput(process.getInputStream());
321         String[] stderr = _getExecOutput(process.getErrorStream());
322 
323         if (stderr.length > 0) {
324             StringBuilder sb = new StringBuilder();
325 
326             sb.append("Received errors in executing '" + cmd + "'\n");
327 
328             for (String err : stderr) {
329                 sb.append("\t" + err + "\n");
330             }
331 
332             throw new Exception(sb.toString());
333         }
334 
335         return stdout;
336     }
337 
338     private String[] _getExecOutput(InputStream is) throws IOException {
339         List<String> list = new ArrayList<String>();
340 
341         BufferedReader br = null;
342 
343         try {
344             br = new BufferedReader(new InputStreamReader(is));
345 
346             String line = br.readLine();
347 
348             while (line != null) {
349                 line = line.trim();
350 
351                 if (Validator.isNotNull(line)) {
352                     list.add(line);
353                 }
354 
355                 line = br.readLine();
356             }
357         }
358         finally {
359             if (br != null) {
360                 try {
361                     br.close();
362                 }
363                 catch (Exception e) {
364                 }
365             }
366         }
367 
368         return list.toArray(new String[] {});
369     }
370 
371     private boolean _isSVNDir(File libDir) {
372         if (!libDir.exists()) {
373             return false;
374         }
375 
376         try {
377             _exec(_SVN_INFO + "\"" + libDir + "\"");
378         }
379         catch (Exception e) {
380             return false;
381         }
382 
383         return true;
384     }
385 
386     private static final String _SVN_ADD = "svn add ";
387 
388     private static final String _SVN_DEL_IGNORES = "svn propdel svn:ignore ";
389 
390     private static final String _SVN_GET_IGNORES = "svn propget svn:ignore ";
391 
392     private static final String _SVN_INFO = "svn info ";
393 
394     private static final String _SVN_SET_IGNORES = "svn propset svn:ignore ";
395 
396     private boolean _svn;
397 
398 }