001    /**
002     * Copyright (c) 2000-2013 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.ListUtil;
019    import com.liferay.portal.kernel.util.StringBundler;
020    import com.liferay.portal.kernel.util.StringUtil;
021    import com.liferay.portal.kernel.util.Validator;
022    import com.liferay.portal.util.FileImpl;
023    
024    import java.io.File;
025    import java.io.IOException;
026    import java.io.InputStream;
027    import java.io.InputStreamReader;
028    
029    import java.util.ArrayList;
030    import java.util.Collections;
031    import java.util.Iterator;
032    import java.util.List;
033    
034    /**
035     * @author Brian Wing Shun Chan
036     */
037    public class PluginsGitSvnSyncer {
038    
039            public static void main(String[] args) {
040                    String gitPluginsDirName = System.getProperty("git.plugins.dir");
041                    String svnPluginsDirName = System.getProperty("svn.plugins.dir");
042                    String syncTo = System.getProperty("sync.to");
043    
044                    new PluginsGitSvnSyncer(gitPluginsDirName, svnPluginsDirName, syncTo);
045            }
046    
047            public PluginsGitSvnSyncer(
048                    String gitPluginsDirName, String svnPluginsDirName, String syncTo) {
049    
050                    try {
051                            if (!gitPluginsDirName.endsWith("/")) {
052                                    gitPluginsDirName = gitPluginsDirName + "/";
053                            }
054    
055                            if (!svnPluginsDirName.endsWith("/")) {
056                                    svnPluginsDirName = svnPluginsDirName + "/";
057                            }
058    
059                            if (syncTo.equals("git")) {
060                                    _updateGitIgnores(svnPluginsDirName, gitPluginsDirName);
061                            }
062                            else if (syncTo.equals("svn")) {
063                                    _updateSvnIgnores(gitPluginsDirName, svnPluginsDirName);
064                            }
065                    }
066                    catch (Exception e) {
067                            e.printStackTrace();
068                    }
069            }
070    
071            private String[] _exec(String cmd) throws Exception {
072                    Runtime runtime = Runtime.getRuntime();
073    
074                    Process process = runtime.exec(cmd);
075    
076                    String[] stdout = _getExecOutput(process.getInputStream());
077                    String[] stderr = _getExecOutput(process.getErrorStream());
078    
079                    if (stderr.length > 0) {
080                            StringBundler sb = new StringBundler(stderr.length * 3 + 3);
081    
082                            sb.append("Received errors in executing '");
083                            sb.append(cmd);
084                            sb.append("'\n");
085    
086                            for (String err : stderr) {
087                                    sb.append("\t");
088                                    sb.append(err);
089                                    sb.append("\n");
090                            }
091    
092                            throw new Exception(sb.toString());
093                    }
094    
095                    return stdout;
096            }
097    
098            private String[] _getExecOutput(InputStream is) throws IOException {
099                    List<String> list = new ArrayList<String>();
100    
101                    UnsyncBufferedReader unsyncBufferedReader = null;
102    
103                    try {
104                            unsyncBufferedReader = new UnsyncBufferedReader(
105                                    new InputStreamReader(is));
106    
107                            String line = unsyncBufferedReader.readLine();
108    
109                            while (line != null) {
110                                    line = line.trim();
111    
112                                    if (Validator.isNotNull(line)) {
113                                            list.add(line);
114                                    }
115    
116                                    line = unsyncBufferedReader.readLine();
117                            }
118                    }
119                    finally {
120                            if (unsyncBufferedReader != null) {
121                                    try {
122                                            unsyncBufferedReader.close();
123                                    }
124                                    catch (Exception e) {
125                                    }
126                            }
127                    }
128    
129                    return list.toArray(new String[list.size()]);
130            }
131    
132            private void _updateGitIgnores(String srcDirName, String destDirName)
133                    throws Exception {
134    
135                    for (String pluginType : _PLUGIN_TYPES) {
136                            String[] dirNames = _fileUtil.listDirs(srcDirName + pluginType);
137    
138                            for (String dirName : dirNames) {
139                                    if (dirName.equals(".svn")) {
140                                            continue;
141                                    }
142    
143                                    for (String pluginDirName : _PLUGIN_DIR_NAMES) {
144                                            _updateGitIgnores(
145                                                    srcDirName + pluginType + "/",
146                                                    destDirName + pluginType + "/",
147                                                    dirName + pluginDirName + "/");
148                                    }
149                            }
150                    }
151            }
152    
153            private void _updateGitIgnores(
154                            String srcDirName, String destDirName, String dirName)
155                    throws Exception {
156    
157                    File gitIgnoreFile = new File(destDirName + dirName + ".gitignore");
158    
159                    if (!_fileUtil.exists(srcDirName + dirName + ".svn")) {
160                            _fileUtil.delete(gitIgnoreFile);
161    
162                            return;
163                    }
164    
165                    List<String> ignores = null;
166    
167                    if (!dirName.contains("/docroot/")) {
168                            ignores = Collections.emptyList();
169                    }
170                    else {
171                            ignores = ListUtil.fromArray(
172                                    _exec(_SVN_GET_IGNORES + srcDirName + dirName));
173                    }
174    
175                    Collections.sort(ignores);
176    
177                    Iterator<String> itr = ignores.iterator();
178    
179                    while (itr.hasNext()) {
180                            String ignore = itr.next();
181    
182                            if (ignore.equals("classes")) {
183                                    itr.remove();
184                            }
185                    }
186    
187                    if (!ignores.isEmpty()) {
188                            String[] ignoresArray = ignores.toArray(new String[ignores.size()]);
189    
190                            for (int i = 0; i < ignoresArray.length; i++) {
191                                    String ignore = ignoresArray[i];
192    
193                                    if (Validator.isNotNull(ignore) && !ignore.startsWith("/")) {
194                                            ignoresArray[i] = "/" + ignore;
195                                    }
196                            }
197    
198                            _fileUtil.write(
199                                    destDirName + dirName + ".gitignore",
200                                    StringUtil.merge(ignoresArray, "\n"));
201                    }
202                    else {
203                            _fileUtil.delete(gitIgnoreFile);
204                    }
205            }
206    
207            private void _updateSvnIgnores(String srcDirName, String destDirName)
208                    throws Exception {
209    
210                    for (String pluginType : _PLUGIN_TYPES) {
211                            String[] dirNames = _fileUtil.listDirs(srcDirName + pluginType);
212    
213                            for (String dirName : dirNames) {
214                                    for (String pluginDirName : _PLUGIN_DIR_NAMES) {
215                                            _updateSvnIgnores(
216                                                    srcDirName + pluginType + "/",
217                                                    destDirName + pluginType + "/",
218                                                    dirName + pluginDirName + "/");
219                                    }
220                            }
221                    }
222            }
223    
224            private void _updateSvnIgnores(
225                            String srcDirName, String destDirName, String dirName)
226                    throws Exception {
227    
228                    if (!_fileUtil.exists(destDirName + dirName)) {
229                            return;
230                    }
231    
232                    File gitIgnoreFile = new File(srcDirName + dirName + ".gitignore");
233                    File svnDir = new File(destDirName + dirName + ".svn");
234    
235                    if (gitIgnoreFile.exists() && !svnDir.exists()) {
236                            System.out.println(
237                                    "Invalid SVN directory " + destDirName + dirName);
238    
239                            return;
240                    }
241    
242                    List<String> ignores = null;
243    
244                    if (!dirName.contains("/docroot")) {
245                            ignores = new ArrayList<String>();
246    
247                            ignores.add("bin");
248                            ignores.add("classes");
249                            ignores.add("tmp");
250                    }
251                    else {
252                            ignores = ListUtil.fromFile(gitIgnoreFile);
253    
254                            for (int i = 0; i < ignores.size(); i++) {
255                                    String ignore = ignores.get(i);
256    
257                                    if (ignore.startsWith("/")) {
258                                            ignore = ignore.substring(1);
259                                    }
260    
261                                    ignores.set(i, ignore);
262                            }
263    
264                            if (dirName.endsWith("/docroot/WEB-INF/")) {
265                                    if (!ignores.contains("classes")) {
266                                            ignores.add("classes");
267                                    }
268                            }
269                    }
270    
271                    Collections.sort(ignores);
272    
273                    if (ignores.isEmpty() && !svnDir.exists()) {
274                            return;
275                    }
276    
277                    if (ignores.isEmpty()) {
278                            try {
279                                    _exec(_SVN_DEL_IGNORES + destDirName + dirName);
280                            }
281                            catch (Exception e) {
282                                    String message = e.getMessage();
283    
284                                    if (!message.contains(
285                                                    "svn: Attempting to delete nonexistent property " +
286                                                            "'svn:ignore'")) {
287    
288                                            throw e;
289                                    }
290                            }
291    
292                            return;
293                    }
294    
295                    File tempFile = File.createTempFile("svn-ignores-", null, null);
296    
297                    try {
298                            String[] ignoresArray = ignores.toArray(new String[ignores.size()]);
299    
300                            _fileUtil.write(tempFile, StringUtil.merge(ignoresArray, "\n"));
301    
302                            _exec(
303                                    _SVN_SET_IGNORES + "-F \"" + tempFile.getCanonicalPath() +
304                                            "\" \"" + destDirName + dirName + "\"");
305                    }
306                    finally {
307                            _fileUtil.delete(tempFile);
308                    }
309            }
310    
311            private static final String[] _PLUGIN_DIR_NAMES = {
312                    "", "/docroot", "/docroot/WEB-INF", "/docroot/WEB-INF/lib",
313                    "/docroot/WEB-INF/tld"
314            };
315    
316            private static final String[] _PLUGIN_TYPES = {
317                    "clients", "ext", "hooks", "layouttpl", "portlets", "themes", "webs"
318            };
319    
320            private static final String _SVN_DEL_IGNORES = "svn propdel svn:ignore ";
321    
322            private static final String _SVN_GET_IGNORES = "svn propget svn:ignore ";
323    
324            private static final String _SVN_SET_IGNORES = "svn propset svn:ignore ";
325    
326            private static FileImpl _fileUtil = FileImpl.getInstance();
327    
328    }