001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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[] {});
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                            _fileUtil.write(
191                                    destDirName + dirName + ".gitignore",
192                                    StringUtil.merge(ignoresArray, "\n"));
193                    }
194                    else {
195                            _fileUtil.delete(gitIgnoreFile);
196                    }
197            }
198    
199            private void _updateSvnIgnores(String srcDirName, String destDirName)
200                    throws Exception {
201    
202                    for (String pluginType : _PLUGIN_TYPES) {
203                            String[] dirNames = _fileUtil.listDirs(srcDirName + pluginType);
204    
205                            for (String dirName : dirNames) {
206                                    for (String pluginDirName : _PLUGIN_DIR_NAMES) {
207                                            _updateSvnIgnores(
208                                                    srcDirName + pluginType + "/",
209                                                    destDirName + pluginType + "/",
210                                                    dirName + pluginDirName + "/");
211                                    }
212                            }
213                    }
214            }
215    
216            private void _updateSvnIgnores(
217                            String srcDirName, String destDirName, String dirName)
218                    throws Exception {
219    
220                    if (!_fileUtil.exists(destDirName + dirName)) {
221                            return;
222                    }
223    
224                    File gitIgnoreFile = new File(srcDirName + dirName + ".gitignore");
225                    File svnDir = new File(destDirName + dirName + ".svn");
226    
227                    if (gitIgnoreFile.exists() && !svnDir.exists()) {
228                            System.out.println(
229                                    "Invalid SVN directory " + destDirName + dirName);
230    
231                            return;
232                    }
233    
234                    List<String> ignores = null;
235    
236                    if (!dirName.contains("/docroot")) {
237                            ignores = new ArrayList<String>();
238    
239                            ignores.add("bin");
240                            ignores.add("classes");
241                            ignores.add("tmp");
242                    }
243                    else {
244                            ignores = ListUtil.fromFile(gitIgnoreFile);
245    
246                            if (dirName.endsWith("/docroot/WEB-INF/")) {
247                                    if (!ignores.contains("classes")) {
248                                            ignores.add("classes");
249                                    }
250                            }
251                    }
252    
253                    Collections.sort(ignores);
254    
255                    if (ignores.isEmpty() && !svnDir.exists()) {
256                            return;
257                    }
258    
259                    if (ignores.isEmpty()) {
260                            try {
261                                    _exec(_SVN_DEL_IGNORES + destDirName + dirName);
262                            }
263                            catch (Exception e) {
264                                    String message = e.getMessage();
265    
266                                    if (!message.contains(
267                                                    "svn: Attempting to delete nonexistent property " +
268                                                            "'svn:ignore'")) {
269    
270                                            throw e;
271                                    }
272                            }
273    
274                            return;
275                    }
276    
277                    File tempFile = File.createTempFile("svn-ignores-", null, null);
278    
279                    try {
280                            String[] ignoresArray = ignores.toArray(
281                                    new String[ignores.size()]);
282    
283                            _fileUtil.write(tempFile, StringUtil.merge(ignoresArray, "\n"));
284    
285                            _exec(
286                                    _SVN_SET_IGNORES + "-F \"" + tempFile.getCanonicalPath() +
287                                            "\" \"" + destDirName + dirName + "\"");
288                    }
289                    finally {
290                            _fileUtil.delete(tempFile);
291                    }
292            }
293    
294            private static final String[] _PLUGIN_DIR_NAMES = {
295                    "", "/docroot", "/docroot/WEB-INF", "/docroot/WEB-INF/lib",
296                    "/docroot/WEB-INF/tld"
297            };
298    
299            private static final String[] _PLUGIN_TYPES = {
300                    "clients", "ext", "hooks", "layouttpl", "portlets", "themes", "webs"
301            };
302    
303            private static final String _SVN_DEL_IGNORES = "svn propdel svn:ignore ";
304    
305            private static final String _SVN_GET_IGNORES = "svn propget svn:ignore ";
306    
307            private static final String _SVN_SET_IGNORES = "svn propset svn:ignore ";
308    
309            private static FileImpl _fileUtil = FileImpl.getInstance();
310    
311    }