001 /*
002 * ----------------------------------------------------------------------
003 * Copyright (C) 2009 Enrique Lara (k957@68k.org)
004 *
005 * TinLizard is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public License
007 * as published by the Free Software Foundation; either version 3.0
008 * of the License, or (at your option) any later version.
009 *
010 * TinLizard is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013 * GNU Lesser General Public License for more details.
014 *
015 * You should have received a copy of the GNU Lesser General Public License
016 * along with TinLizard. If not, see http://www.gnu.org/licenses/.
017 * ----------------------------------------------------------------------
018 */
019 package tinlizard.dao.maven;
020
021 import tinlizard.dao.ScmDao;
022
023 import tinlizard.model.Codeline;
024
025 import tinlizard.util.Messages;
026
027 import java.io.File;
028 import java.io.FileInputStream;
029 import java.io.IOException;
030 import java.io.InputStream;
031 import java.util.Collection;
032 import java.util.Date;
033 import java.util.Iterator;
034 import java.util.List;
035
036 import org.apache.log4j.Logger;
037 import org.apache.maven.model.Model;
038 import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
039 import org.apache.maven.scm.ScmBranch;
040 import org.apache.maven.scm.ScmException;
041 import org.apache.maven.scm.ScmFile;
042 import org.apache.maven.scm.ScmFileSet;
043 import org.apache.maven.scm.ScmResult;
044 import org.apache.maven.scm.ScmVersion;
045 import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
046 import org.apache.maven.scm.command.checkout.CheckOutScmResult;
047 import org.apache.maven.scm.command.status.StatusScmResult;
048 import org.apache.maven.scm.manager.NoSuchScmProviderException;
049 import org.apache.maven.scm.manager.ScmManager;
050 import org.apache.maven.scm.provider.ScmProvider;
051 import org.apache.maven.scm.provider.cvslib.AbstractCvsScmProvider;
052 import org.apache.maven.scm.repository.ScmRepository;
053 import org.apache.maven.scm.repository.ScmRepositoryException;
054
055 import org.codehaus.plexus.util.FileUtils;
056 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
057
058 /**
059 * Maven API backed implementation of ScmDao.
060 */
061 public final class ScmDaoImpl implements ScmDao {
062 private static final Logger LOG = Logger.getLogger(ScmDaoImpl.class);
063 private ScmManager scmManager;
064 private String baseWorkingDirectory;
065
066 public String getBaseWorkingDirectory() {
067 return baseWorkingDirectory;
068 }
069
070 public void setBaseWorkingDirectory(final String baseWorkingDirectory) {
071 this.baseWorkingDirectory = baseWorkingDirectory;
072 }
073
074 public ScmManager getScmManager() {
075 return scmManager;
076 }
077
078 public void setScmManager(final ScmManager scmManager) {
079 this.scmManager = scmManager;
080 }
081
082 private String getWD(final Codeline pb) {
083 return baseWorkingDirectory + "/tinlizard/projects/" + pb.getProject().getId() + "/" + pb.getId();
084 }
085
086 public Model getPOM(final Codeline pb) {
087 File pomFile = getPOMFile(pb);
088 Model pom = null;
089
090 try {
091 pom = readPOM(pomFile);
092 } catch (Exception e) {
093 throw new RuntimeException(Messages.error_0001(), e);
094 }
095
096 return pom;
097 }
098
099 private File getPOMFile(final Codeline pb) {
100 File pomFile = new File(getWD(pb) + "/pom.xml");
101
102 if (!pomFile.exists()) {
103 CheckOutScmResult result = checkout(pb);
104
105 if (!result.isSuccess()) {
106 throw new RuntimeException(result.getProviderMessage());
107 }
108 }
109
110 return pomFile;
111 }
112
113 private Model readPOM(final File pomFile) throws IOException, XmlPullParserException {
114 MavenXpp3Reader pomReader = new MavenXpp3Reader();
115
116 InputStream is = new FileInputStream(pomFile);
117 Model model = pomReader.read(is);
118
119 return model;
120 }
121
122 private ScmRepository getScmRepository(final Codeline pb) throws ScmRepositoryException, NoSuchScmProviderException {
123 ScmRepository repository = scmManager.makeScmRepository(pb.getScmConnection());
124
125 return repository;
126 }
127
128 private ScmRepository getScmRepository(final Model pom) throws ScmRepositoryException, NoSuchScmProviderException {
129 return scmManager.makeScmRepository(pom.getScm().getConnection());
130 }
131
132 @SuppressWarnings("unchecked")
133 public boolean isValidSmUrl(final String scmUrl) {
134 List results = scmManager.validateScmRepository(scmUrl);
135
136 //XXX signal problems, how?
137 return results.isEmpty();
138 }
139
140 @SuppressWarnings("unchecked")
141 public ScmResult update(final Codeline pb) {
142 ScmResult result;
143 File workingDirectory = new File(getWD(pb));
144
145 try {
146 if (!workingDirectory.exists()) {
147 return checkout(pb);
148 }
149
150 ScmRepository scmRepository = getScmRepository(pb);
151 ScmProvider provider = scmManager.getProviderByRepository(scmRepository);
152
153 ScmVersion version = getVersion(pb);
154
155 ScmFileSet fileSet;
156
157 if (provider instanceof AbstractCvsScmProvider) {
158 //For CVS, get just the pom.xml.
159 scmRepository = scmManager.makeScmRepository(pb.getScmConnection() + "/pom.xml");
160
161 final List files = FileUtils.getFiles(workingDirectory, "pom.xml", provider.getScmSpecificFilename(), true);
162 fileSet = new ScmFileSet(workingDirectory, files);
163 } else {
164 final List files = FileUtils.getFiles(workingDirectory, null, provider.getScmSpecificFilename(), true);
165 fileSet = new ScmFileSet(workingDirectory, files);
166 }
167
168 result = scmManager.update(scmRepository, fileSet, version);
169 } catch (ScmException e) {
170 throw new RuntimeException(Messages.error_0007(workingDirectory), e);
171 } catch (IOException e) {
172 throw new RuntimeException(Messages.error_0008(workingDirectory), e);
173 }
174
175 return result;
176 }
177
178 @SuppressWarnings("unchecked")
179 private CheckOutScmResult checkout(final Codeline pb) {
180 CheckOutScmResult result = null;
181
182 try {
183 ScmRepository repository = getScmRepository(pb);
184 File workingDirectory = new File(getWD(pb));
185 ScmVersion version = getVersion(pb);
186
187 if (workingDirectory.exists()) {
188 try {
189 FileUtils.deleteDirectory(workingDirectory);
190 } catch (Exception e) {
191 throw new RuntimeException(Messages.error_0006(workingDirectory.getAbsolutePath()));
192 }
193
194 if (workingDirectory.exists()) {
195 throw new RuntimeException(Messages.error_0002(workingDirectory.getAbsolutePath()));
196 }
197 }
198
199 if (!workingDirectory.mkdirs()) {
200 throw new RuntimeException(Messages.error_0003(workingDirectory.getAbsolutePath()));
201 }
202
203 ScmProvider provider = scmManager.getProviderByRepository(repository);
204
205 ScmFileSet fileSet;
206
207 if (provider instanceof AbstractCvsScmProvider) {
208 //For CVS, get just the pom.xml.
209 fileSet = new ScmFileSet(workingDirectory, new File(workingDirectory, "pom.xml"));
210 } else {
211 fileSet = new ScmFileSet(workingDirectory);
212 }
213
214 result = scmManager.checkOut(repository, fileSet, version);
215
216 if (LOG.isTraceEnabled() && result.isSuccess()) {
217 List checkedOutFiles = result.getCheckedOutFiles();
218 LOG.trace("Checked out these files: ");
219
220 for (Iterator it = checkedOutFiles.iterator(); it.hasNext();) {
221 ScmFile file = (ScmFile) it.next();
222
223 LOG.trace(" " + file.getPath());
224 }
225 }
226 } catch (ScmException e) {
227 throw new RuntimeException(Messages.error_0005(), e);
228 }
229
230 return result;
231 }
232
233 private ScmVersion getVersion(final Codeline pb) {
234 ScmVersion version = null;
235
236 if (!pb.isMainLine()) {
237 version = new ScmBranch(pb.getName());
238 }
239
240 return version;
241 }
242
243 public void releaseFiles(final Codeline pb) {
244 try {
245 FileUtils.deleteDirectory(getWD(pb));
246 } catch (Exception e) {
247 LOG.error(Messages.error_0004(), e);
248 }
249 }
250
251 public void releaseFiles(final Collection<Codeline> codelines) {
252 for (Codeline pb : codelines) {
253 releaseFiles(pb);
254 }
255 }
256
257 public StatusScmResult getPOMStatus(final Codeline pb) {
258 StatusScmResult statusScmResult = null;
259
260 try {
261 File pomFile = getPOMFile(pb);
262 ScmRepository repository = getScmRepository(pb);
263 ScmFileSet fileSet = new ScmFileSet(pomFile);
264
265 statusScmResult = scmManager.status(repository, fileSet);
266 } catch (Exception e) {
267 LOG.error("Problems getting Pom Status.", e);
268 }
269
270 return statusScmResult;
271 }
272
273 public ChangeLogScmResult getChangeLogForNDaysAgo(final Codeline pb, final int numDays) {
274 return getChangeLog(pb, null, null, numDays);
275 }
276
277 public ChangeLogScmResult getChangeLog(final Codeline pb, final Date startDate, final Date endDate, final int numDays) {
278 ChangeLogScmResult rval = null;
279
280 try {
281 Model pom = getPOM(pb);
282 ScmRepository repository = getScmRepository(pom);
283
284 ScmFileSet fileSet = new ScmFileSet(new File(getWD(pb)));
285
286 ScmBranch codeline = new ScmBranch(pb.getName());
287 rval = scmManager.changeLog(repository, fileSet, startDate, endDate, numDays, codeline);
288 } catch (Exception e) {
289 throw new RuntimeException(Messages.error_0104(), e);
290 }
291
292 return rval;
293 }
294 }