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.cmd.impl;
20  
21  import nl.toolforge.karma.core.cmd.Command;
22  import nl.toolforge.karma.core.cmd.CommandDescriptor;
23  import nl.toolforge.karma.core.cmd.CommandException;
24  import nl.toolforge.karma.core.cmd.CommandFactory;
25  import nl.toolforge.karma.core.cmd.CommandLoadException;
26  import nl.toolforge.karma.core.cmd.CommandResponse;
27  import nl.toolforge.karma.core.cmd.CompositeCommand;
28  import nl.toolforge.karma.core.cmd.event.ErrorEvent;
29  import nl.toolforge.karma.core.cmd.event.MessageEvent;
30  import nl.toolforge.karma.core.cmd.event.SimpleMessage;
31  import nl.toolforge.karma.core.location.LocationException;
32  import nl.toolforge.karma.core.manifest.Manifest;
33  import nl.toolforge.karma.core.manifest.ManifestException;
34  import nl.toolforge.karma.core.manifest.ManifestFactory;
35  import nl.toolforge.karma.core.manifest.ManifestLoader;
36  import nl.toolforge.karma.core.module.Module;
37  import nl.toolforge.karma.core.vc.AuthenticationException;
38  import nl.toolforge.karma.core.vc.ModuleStatus;
39  import nl.toolforge.karma.core.vc.VersionControlException;
40  import nl.toolforge.karma.core.vc.cvsimpl.Utils;
41  import nl.toolforge.karma.core.vc.cvsimpl.threads.CVSLogThread;
42  import nl.toolforge.karma.core.vc.threads.ParallelRunner;
43  import org.apache.commons.logging.Log;
44  import org.apache.commons.logging.LogFactory;
45  
46  import java.io.File;
47  import java.io.FileWriter;
48  import java.io.IOException;
49  import java.util.Iterator;
50  import java.util.Map;
51  
52  /***
53   * Creates a release manifest, based on the current (development) manifest, by checking all the latest versions
54   * of modules and adding them
55   *
56   * @author D.A. Smedes
57   * @version $Id: CreateRelease.java,v 1.26 2004/11/10 23:53:08 asmedes Exp $
58   */
59  public class CreateRelease extends CompositeCommand {
60  
61    private static final Log logger = LogFactory.getLog(CreateRelease.class);
62  
63    private CommandResponse commandResponse = new CommandResponse();
64  
65    public CreateRelease(CommandDescriptor descriptor) {
66      super(descriptor);
67    }
68  
69    public void execute() throws CommandException {
70  
71      String manifestName = getCommandLine().getOptionValue("d");
72  
73      Manifest releaseManifest = null;
74  
75      if (manifestName == null) {
76  
77        // The option '-d' is optional, so we use the current manifest
78        //
79        if (!getContext().isManifestLoaded()) {
80          throw new CommandException(ManifestException.NO_ACTIVE_MANIFEST);
81        }
82  
83        releaseManifest = getContext().getCurrentManifest();
84  
85      } else {
86  
87        try {
88          ManifestFactory factory = new ManifestFactory();
89          ManifestLoader loader = new ManifestLoader(getWorkingContext());
90          releaseManifest = factory.create(getWorkingContext(), loader.load(manifestName));
91        } catch (ManifestException e) {
92          throw new CommandException(e.getErrorCode(), e.getMessageArguments());
93        } catch (LocationException e) {
94          throw new CommandException(e.getErrorCode(), e.getMessageArguments());
95        }
96      }
97  
98      String releaseName = getCommandLine().getOptionValue("r");
99  
100     File releaseManifestFile = new File(getWorkingContext().getConfiguration().getManifestStore().getModule().getBaseDir(), releaseName + ".xml");
101 
102     if (releaseManifestFile.exists()) {
103       if (!getCommandLine().hasOption("o")) {
104         throw new CommandException(
105             ManifestException.DUPLICATE_MANIFEST_FILE,
106             new Object[] {releaseName, getWorkingContext().getConfiguration().getManifestStore().getModule().getBaseDir().getPath()}
107         );
108       }
109     }
110 
111     // todo are there any rules for file-names (manifest names ...).
112     //
113 
114     SimpleMessage message = new SimpleMessage(getFrontendMessages().getString("message.CREATE_RELEASE_STARTED"), new Object[]{releaseName});
115     commandResponse.addEvent(new MessageEvent(this, message));
116 
117     // Checking manifest
118     //
119 
120     ParallelRunner runner = new ParallelRunner(releaseManifest, CVSLogThread.class);
121     runner.execute(100); // Blocks ...
122 
123     Map statusOverview = runner.retrieveResults();
124 
125     Map modules = releaseManifest.getAllModules();
126 
127     for (Iterator i = modules.values().iterator(); i.hasNext();) {
128 
129       Module module = (Module) i.next();
130       ModuleStatus moduleStatus = (ModuleStatus) statusOverview.get(module);
131 
132       if (moduleStatus.connectionFailure()) {
133 
134         getCommandResponse().addEvent(new ErrorEvent(this, LocationException.CONNECTION_EXCEPTION));
135         message = new SimpleMessage(getFrontendMessages().getString("message.CREATE_RELEASE_FAILED"));
136         getCommandResponse().addEvent(new MessageEvent(this, message));
137 
138         return;
139       }
140       if (!moduleStatus.existsInRepository()) {
141 
142         getCommandResponse().addEvent(new ErrorEvent(this, VersionControlException.MODULE_NOT_IN_REPOSITORY, new Object[]{module.getName()}));
143 
144         // todo message implies an error, should be an error code.
145         message = new SimpleMessage(getFrontendMessages().getString("message.CREATE_RELEASE_FAILED"));
146         getCommandResponse().addEvent(new MessageEvent(this, message));
147         return;
148       }
149     }
150 
151 
152     // Ok, ww're ready to go now. Let's collect the latest versions of modules.
153     //
154 
155     StringBuffer buffer = new StringBuffer();
156     buffer.append("<?xml version=\"1.0\"?>\n");
157 
158     buffer.append("<manifest type=\"release\" version=\"1-0\">\n");
159 
160     buffer.append("  <modules>\n");
161 
162     for (Iterator i = modules.values().iterator(); i.hasNext();) {
163 
164       // todo NEED AN ADDITIONAL method in Manifest : getDevelopmentManifests() ...
165 
166       Module module = (Module) i.next();
167 
168       if (getContext().getCurrentManifest().getState(module).equals(Module.WORKING)) {
169         throw new CommandException(CommandException.MODULE_CANNOT_BE_WORKING_FOR_RELEASE_MANIFEST, new Object[]{module.getName()});
170       }
171 
172       buffer.append(getModule(module, getCommandLine().hasOption("u")));
173     }
174 
175     buffer.append("  </modules>\n");
176 
177     buffer.append("</manifest>\n");
178 
179     FileWriter writer = null;
180     try {
181       // Write the manifest to the manifest store.
182       //
183       writer = new FileWriter(releaseManifestFile);
184 
185       writer.write(buffer.toString());
186       writer.flush();
187     } catch (IOException e) {
188       e.printStackTrace();
189     } finally {
190       try {
191         writer.close();
192       } catch (IOException e) {
193         logger.error(e);
194       }
195     }
196 
197     boolean store = getCommandLine().hasOption("s");
198 
199     if (store) {
200       try {
201         getWorkingContext().getConfiguration().getManifestStore().commit(releaseName);
202 
203         message = new SimpleMessage(getFrontendMessages().getString("message.RELEASE_COMMITTED"), new Object[]{releaseName});
204         commandResponse.addEvent(new MessageEvent(this, message));
205 
206       } catch (AuthenticationException e) {
207         logger.error(e);
208         throw new CommandException(e, e.getErrorCode(), e.getMessageArguments());
209       } catch (VersionControlException e) {
210         logger.error(e);
211         throw new CommandException(e, e.getErrorCode(), e.getMessageArguments());
212       }
213     } else {
214       message = new SimpleMessage(getFrontendMessages().getString("message.RELEASE_NOT_COMMITTED"), new Object[]{releaseName});
215       commandResponse.addEvent(new MessageEvent(this, message));
216     }
217 
218     message = new SimpleMessage(getFrontendMessages().getString("message.CREATE_RELEASE_FINISHED"), new Object[]{releaseName});
219     commandResponse.addEvent(new MessageEvent(this, message));
220 
221     boolean loadManifest = getCommandLine().hasOption("l");
222 
223     if (loadManifest) {
224 
225       Command command = null;
226       try {
227         command = CommandFactory.getInstance().getCommand("select-manifest -m ".concat(releaseName));
228       } catch (CommandLoadException e) {
229         throw new CommandException(e.getErrorCode(), e.getMessageArguments());
230       }
231       command.registerCommandResponseListener(this);
232       getContext().execute(command);
233     }
234 
235     // todo The included manifests of type 'development' should be release as well.
236   }
237 
238   public CommandResponse getCommandResponse() {
239     return commandResponse;
240   }
241 
242   private String getModule(Module module, boolean useRemote) throws CommandException {
243 
244     String n;
245     String v;
246     String l;
247 
248     n = "\"" + module.getName() + "\"";
249     l = module.getLocation().getId();
250 
251     if (module.hasVersion()) {
252 
253       v = module.getVersion().getVersionNumber();
254 
255     } else {
256 
257       try {
258         if (useRemote) {
259           v = Utils.getLastVersion(module).getVersionNumber();
260         } else {
261           v = Utils.getLocalVersion(module).getVersionNumber();
262         }
263       } catch (VersionControlException e) {
264         throw new CommandException(e.getErrorCode(), e.getMessageArguments());
265       }
266     }
267 
268     return "    <module name=" + n + " version=\"" + v + "\" location=\"" + l + "\"/>\n";
269 
270   }
271 
272 }