View Javadoc

1   /*
2   Karma core - Core of the Karma application
3   Copyright (C) 2004  Toolforge <www.toolforge.nl>
4   
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9   
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  Lesser General Public License for more details.
14  
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19  package nl.toolforge.karma.core.vc.cvsimpl;
20  
21  import nl.toolforge.karma.core.KarmaRuntimeException;
22  import nl.toolforge.karma.core.Patch;
23  import nl.toolforge.karma.core.Version;
24  import nl.toolforge.karma.core.module.Module;
25  import nl.toolforge.karma.core.vc.DevelopmentLine;
26  import nl.toolforge.karma.core.vc.ModuleStatus;
27  import nl.toolforge.karma.core.vc.PatchLine;
28  import nl.toolforge.karma.core.vc.model.MainLine;
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.netbeans.lib.cvsclient.admin.Entry;
32  import org.netbeans.lib.cvsclient.admin.StandardAdminHandler;
33  import org.netbeans.lib.cvsclient.command.log.LogInformation;
34  
35  import java.io.IOException;
36  import java.util.ArrayList;
37  import java.util.Collection;
38  import java.util.Collections;
39  import java.util.Iterator;
40  import java.util.List;
41  import java.util.regex.Matcher;
42  import java.util.regex.Pattern;
43  import java.util.regex.PatternSyntaxException;
44  
45  /***
46   * @author D.A. Smedes
47   * @version $Id: CVSModuleStatus.java,v 1.11 2004/11/16 22:31:57 asmedes Exp $
48   */
49  public class CVSModuleStatus implements ModuleStatus {
50  
51    private static final Log logger = LogFactory.getLog(Utils.class);
52  
53    private boolean existsInRepository = false;
54  
55    private List matchingList = null;
56  
57    private Module module = null;
58    private LogInformation logInfo = null;
59    private boolean connectionFailure = false;
60    private boolean authenticationFailure = false;
61    private boolean internalError = false;
62  
63    /***
64     * Creates a ModuleStatus instance with the LogInformation object that was generated by the <code>cvs log</code>
65     * command.
66     *
67     * @param module The module.
68     * @param logInfo A Netbeans LogInformation object.
69     */
70    public CVSModuleStatus(Module module, LogInformation logInfo) {
71      this.module = module;
72      setLogInformation(logInfo);
73    }
74  
75    public CVSModuleStatus(Module module) {
76      this.module = module;
77    }
78  
79    public void setLogInformation(Object logInfo) {
80      this.logInfo = (LogInformation) logInfo;
81      matchingList = collectVersions(module);
82    }
83  
84    /***
85     * Returns a Version instance representing the next possible version (major or patch) for the module.
86     *
87     * @return
88     */
89    public Version getNextVersion() {
90  
91      if (matchingList.size() == 0) {
92  
93        // If the module is in a ReleaseManifest and has a PatchLine already, we can savely
94        // return the initial patch level for the module.
95        //
96        // todo hmm (see sourceforge issue 1019628). Not totally convinced. What if the module doesn't have a patchline ?
97        // todo there is something to this logic.
98  
99        if (module.hasPatchLine()) {
100         return module.getVersion().createPatch(Patch.INITIAL_PATCH);
101       }
102 
103       return null;
104     }
105 
106     Version nextVersion = null;
107 
108     try {
109       nextVersion = (Version) ((Version) matchingList.get(matchingList.size() - 1)).clone();
110     } catch (CloneNotSupportedException e) {
111       throw new KarmaRuntimeException(e.getMessage(), e);
112     }
113 
114     nextVersion.increase();
115 
116     return nextVersion;
117   }
118 
119   public Version getNextMajorVersion() {
120     if (matchingList.size() == 0) {
121       return null;
122     }
123 
124     Version nextVersion = null;
125 
126     try {
127       nextVersion = (Version) ((Version) matchingList.get(matchingList.size() - 1)).clone();
128     } catch (CloneNotSupportedException e) {
129       throw new KarmaRuntimeException(e.getMessage(), e);
130     }
131 
132     nextVersion.increaseMajor();
133 
134     return nextVersion;
135   }
136 
137   /***
138    * The latest promoted version of the module in the version control system for the branch.
139    *
140    * @return
141    */
142   public Version getLastVersion() {
143 
144     if (matchingList.size() == 0) {
145 
146       if (module.hasPatchLine()) {
147         return module.getVersion();
148       } else {
149         return null;
150       }
151     }
152     return (Version) matchingList.get(matchingList.size() - 1);
153   }
154 
155   /***
156    * Gets the local version of the module, which is determined by parsing the <code>CVS/Entries</code> file.
157    *
158    * @return The version of the local checkout or <code>null</code> when the HEAD of the developmentline is local.
159    * @throws CVSException
160    */
161   public Version getLocalVersion() throws CVSException {
162     logger.debug("Retrieving local version for module: "+module.getName());
163     StandardAdminHandler handler = new StandardAdminHandler();
164     Version localVersion = null;
165 
166     try {
167       Entry[] entries = handler.getEntriesAsArray(module.getBaseDir());
168 
169       Entry moduleDescriptor = null;
170 
171       int i = 0;
172       while (i < entries.length) {
173         if (entries[i].getName().equals(Module.MODULE_DESCRIPTOR)) {
174           moduleDescriptor = entries[i];
175           break;
176         }
177         i++;
178       }
179       try {
180 
181         if (moduleDescriptor == null || moduleDescriptor.getTag() == null || moduleDescriptor.getTag().matches(DevelopmentLine.DEVELOPMENT_LINE_PATTERN_STRING)) {
182           logger.debug("We're on the head. Return null.");
183           // We have the HEAD of a DevelopmentLine.
184           //
185           return null;
186         }
187         if (moduleDescriptor.getTag().startsWith(PatchLine.NAME_PREFIX)) {
188           localVersion = new Patch(moduleDescriptor.getTag().substring(moduleDescriptor.getTag().indexOf("_") + 1));
189           logger.debug("PatchLine. Return "+localVersion);
190         } else {
191           localVersion = new Version(moduleDescriptor.getTag().substring(moduleDescriptor.getTag().indexOf("_") + 1));
192           logger.debug("MainLine. Return "+localVersion);
193         }
194 
195       } catch (Exception e) {
196         throw new CVSException(CVSException.LOCAL_MODULE_ERROR, new Object[]{module.getName()});
197       }
198 
199     } catch (IOException e) {
200       throw new CVSException(CVSException.LOCAL_MODULE_ERROR, new Object[]{module.getName()});
201     }
202     return localVersion;
203   }
204 
205   public void setExistsInRepository(boolean exists) {
206     existsInRepository = exists;
207   }
208 
209   public boolean existsInRepository() {
210     return existsInRepository;
211   }
212 
213   private List collectVersions(Module module) {
214 
215     if (logInfo == null) {
216       return new ArrayList();
217     }
218 
219     // Step 1 : get all symbolicnames that apply to the correct pattern
220     //
221     //
222     List matchingList = new ArrayList();
223 
224     Collection currentVersions = logInfo.getAllSymbolicNames();
225 
226     Pattern pattern = null;
227 
228     if (module.hasPatchLine()) {
229 
230       // We are working on the PatchLine of a module.
231       //
232       pattern = Pattern.compile(((PatchLine) module.getPatchLine()).getMatchingPattern());
233     } else {
234       // We are doing MAINLINE development.
235       //
236       pattern = Pattern.compile(MainLine.NAME_PREFIX.concat("_").concat(Version.VERSION_PATTERN_STRING));
237     }
238 
239     // Collect all applicable symbolic names.
240     //
241     for (Iterator it = currentVersions.iterator(); it.hasNext();) {
242 
243       String s = ((LogInformation.SymName) it.next()).getName();
244 
245       Matcher matcher = pattern.matcher(s);
246       if (matcher.matches()) {
247 
248         try {
249           if (module.hasPatchLine()) {
250             matchingList.add(new Patch(s.substring(s.lastIndexOf("_") + 1)));
251           } else {
252             matchingList.add(new Version(s.substring(s.lastIndexOf("_") + 1)));
253           }
254         } catch (PatternSyntaxException p) {
255           // Ignore, just no match ...
256         }
257       }
258     }
259 
260     // Step 2 : Sort them, so the last one is on top.
261     //
262     Collections.sort(matchingList);
263 
264     return matchingList;
265   }
266 
267   public boolean connectionFailure() {
268     return connectionFailure;
269   }
270 
271   public boolean authenticationFailure() {
272     return authenticationFailure;
273   }
274 
275   public boolean internalError() {
276     return internalError;
277   }
278 
279   /***
280    * Sets the indication that a connection failure to the remote CVS repository has occurred.
281    */
282   public void setConnnectionFailure() {
283     connectionFailure = true;
284   }
285 
286   public void setAuthenticationFailure() {
287     authenticationFailure = true;
288   }
289 
290   public void setInternalError() {
291     internalError = true;
292   }
293 }