source: other-projects/trunk/gs3-release-maker/apache-ant-1.6.5/src/main/org/apache/tools/ant/taskdefs/optional/pvcs/Pvcs.java@ 14627

Last change on this file since 14627 was 14627, checked in by oranfry, 17 years ago

initial import of the gs3-release-maker

File size: 21.6 KB
Line 
1/*
2 * Copyright 2001-2004 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17package org.apache.tools.ant.taskdefs.optional.pvcs;
18
19import java.io.BufferedReader;
20import java.io.BufferedWriter;
21import java.io.File;
22import java.io.FileNotFoundException;
23import java.io.FileOutputStream;
24import java.io.FileReader;
25import java.io.FileWriter;
26import java.io.IOException;
27import java.text.MessageFormat;
28import java.text.ParseException;
29import java.util.Enumeration;
30import java.util.Random;
31import java.util.Vector;
32import org.apache.tools.ant.BuildException;
33import org.apache.tools.ant.Project;
34import org.apache.tools.ant.taskdefs.Execute;
35import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
36import org.apache.tools.ant.taskdefs.LogOutputStream;
37import org.apache.tools.ant.taskdefs.LogStreamHandler;
38import org.apache.tools.ant.taskdefs.PumpStreamHandler;
39import org.apache.tools.ant.types.Commandline;
40
41/**
42 *
43 * Extracts the latest edition of the source code from a PVCS repository.
44 * PVCS is a version control system
45 * developed by <a href="http://www.merant.com/products/pvcs">Merant</a>.
46 * <br>
47 * Before using this tag, the user running ant must have access to the commands
48 * of PVCS (get and pcli) and must have access to the repository. Note that the way to specify
49 * the repository is platform dependent so use property to specify location of repository.
50 * <br>
51 * This version has been tested agains PVCS version 6.5 and 6.6 under Windows and Solaris.
52
53 *
54 * <b>19-04-2001</b> <p>The task now has a more robust
55 * parser. It allows for platform independant file paths
56 * and supports file names with <i>()</i>. Thanks to Erik Husby for
57 * bringing the bug to my attention.
58 *
59 * <b>27-04-2001</b> <p>UNC paths are now handled properly.
60 * Fix provided by Don Jeffery. He also added an <i>UpdateOnly</i> flag
61 * that, when true, conditions the PVCS get using the -U option to only
62 * update those files that have a modification time (in PVCS) that is newer
63 * than the existing workfile.
64 *
65 * <b>25-10-2002</b> <p>Added a revision attribute that currently is a
66 * synonym for label, but in a future release the behavior of the label
67 * attribute will change to use the -v option of GET. See bug #13847 for
68 * discussion.
69 *
70 */
71public class Pvcs extends org.apache.tools.ant.Task {
72 private String pvcsbin;
73 private String repository;
74 private String pvcsProject;
75 private Vector pvcsProjects;
76 private String workspace;
77 private String force;
78 private String promotiongroup;
79 private String label;
80 private String revision;
81 private boolean ignorerc;
82 private boolean updateOnly;
83 private String filenameFormat;
84 private String lineStart;
85 private String userId;
86 private String config;
87 /**
88 * Constant for the thing to execute
89 */
90 private static final String PCLI_EXE = "pcli";
91
92 /*
93 * Constant for the PCLI listversionedfiles recursive i a format "get" understands
94 */
95 // private static final String PCLI_LVF_ARGS = "lvf -z -aw";
96
97 /**
98 * Constant for the thing to execute
99 */
100 private static final String GET_EXE = "get";
101
102
103 protected int runCmd(Commandline cmd, ExecuteStreamHandler out) {
104 try {
105 Project aProj = getProject();
106 Execute exe = new Execute(out);
107 exe.setAntRun(aProj);
108 exe.setWorkingDirectory(aProj.getBaseDir());
109 exe.setCommandline(cmd.getCommandline());
110 return exe.execute();
111 } catch (java.io.IOException e) {
112 String msg = "Failed executing: " + cmd.toString()
113 + ". Exception: " + e.getMessage();
114 throw new BuildException(msg, getLocation());
115 }
116 }
117
118 private String getExecutable(String exe) {
119 StringBuffer correctedExe = new StringBuffer();
120 if (getPvcsbin() != null) {
121 if (pvcsbin.endsWith(File.separator)) {
122 correctedExe.append(pvcsbin);
123 } else {
124 correctedExe.append(pvcsbin).append(File.separator);
125 }
126 }
127 return correctedExe.append(exe).toString();
128 }
129
130 /**
131 * @exception org.apache.tools.ant.BuildException Something is stopping the build...
132 */
133 public void execute() throws org.apache.tools.ant.BuildException {
134 int result = 0;
135
136 if (repository == null || repository.trim().equals("")) {
137 throw new BuildException("Required argument repository not specified");
138 }
139
140 // Check workspace exists
141 // Launch PCLI listversionedfiles -z -aw
142 // Capture output
143 // build the command line from what we got the format is
144 Commandline commandLine = new Commandline();
145 commandLine.setExecutable(getExecutable(PCLI_EXE));
146
147 commandLine.createArgument().setValue("lvf");
148 commandLine.createArgument().setValue("-z");
149 commandLine.createArgument().setValue("-aw");
150 if (getWorkspace() != null) {
151 commandLine.createArgument().setValue("-sp" + getWorkspace());
152 }
153 commandLine.createArgument().setValue("-pr" + getRepository());
154
155 String uid = getUserId();
156
157 if (uid != null) {
158 commandLine.createArgument().setValue("-id" + uid);
159 }
160
161 // default pvcs project is "/"
162 if (getPvcsproject() == null && getPvcsprojects().isEmpty()) {
163 pvcsProject = "/";
164 }
165
166 if (getPvcsproject() != null) {
167 commandLine.createArgument().setValue(getPvcsproject());
168 }
169 if (!getPvcsprojects().isEmpty()) {
170 Enumeration e = getPvcsprojects().elements();
171 while (e.hasMoreElements()) {
172 String projectName = ((PvcsProject) e.nextElement()).getName();
173 if (projectName == null || (projectName.trim()).equals("")) {
174 throw new BuildException("name is a required attribute "
175 + "of pvcsproject");
176 }
177 commandLine.createArgument().setValue(projectName);
178 }
179 }
180
181 File tmp = null;
182 File tmp2 = null;
183 try {
184 Random rand = new Random(System.currentTimeMillis());
185 tmp = new File("pvcs_ant_" + rand.nextLong() + ".log");
186 FileOutputStream fos = new FileOutputStream(tmp);
187 tmp2 = new File("pvcs_ant_" + rand.nextLong() + ".log");
188 log(commandLine.describeCommand(), Project.MSG_VERBOSE);
189 try {
190 result = runCmd(commandLine,
191 new PumpStreamHandler(fos,
192 new LogOutputStream(this,
193 Project.MSG_WARN)));
194 } finally {
195 fos.close();
196 }
197
198 if (Execute.isFailure(result) && !ignorerc) {
199 String msg = "Failed executing: " + commandLine.toString();
200 throw new BuildException(msg, getLocation());
201 }
202
203 if (!tmp.exists()) {
204 throw new BuildException("Communication between ant and pvcs "
205 + "failed. No output generated from executing PVCS "
206 + "commandline interface \"pcli\" and \"get\"");
207 }
208
209 // Create folders in workspace
210 log("Creating folders", Project.MSG_INFO);
211 createFolders(tmp);
212
213 // Massage PCLI lvf output transforming '\' to '/' so get command works appropriately
214 massagePCLI(tmp, tmp2);
215
216 // Launch get on output captured from PCLI lvf
217 commandLine.clearArgs();
218 commandLine.setExecutable(getExecutable(GET_EXE));
219
220 if (getConfig() != null && getConfig().length() > 0) {
221 commandLine.createArgument().setValue("-c" + getConfig());
222 }
223
224 if (getForce() != null && getForce().equals("yes")) {
225 commandLine.createArgument().setValue("-Y");
226 } else {
227 commandLine.createArgument().setValue("-N");
228 }
229
230 if (getPromotiongroup() != null) {
231 commandLine.createArgument().setValue("-G"
232 + getPromotiongroup());
233 } else {
234 if (getLabel() != null) {
235 commandLine.createArgument().setValue("-r" + getLabel());
236 } else {
237 if (getRevision() != null) {
238 commandLine.createArgument().setValue("-r"
239 + getRevision());
240 }
241 }
242 }
243
244 if (updateOnly) {
245 commandLine.createArgument().setValue("-U");
246 }
247
248 commandLine.createArgument().setValue("@" + tmp2.getAbsolutePath());
249 log("Getting files", Project.MSG_INFO);
250 log("Executing " + commandLine.toString(), Project.MSG_VERBOSE);
251 result = runCmd(commandLine,
252 new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_WARN));
253 if (result != 0 && !ignorerc) {
254 String msg = "Failed executing: " + commandLine.toString()
255 + ". Return code was " + result;
256 throw new BuildException(msg, getLocation());
257 }
258
259 } catch (FileNotFoundException e) {
260 String msg = "Failed executing: " + commandLine.toString()
261 + ". Exception: " + e.getMessage();
262 throw new BuildException(msg, getLocation());
263 } catch (IOException e) {
264 String msg = "Failed executing: " + commandLine.toString()
265 + ". Exception: " + e.getMessage();
266 throw new BuildException(msg, getLocation());
267 } catch (ParseException e) {
268 String msg = "Failed executing: " + commandLine.toString()
269 + ". Exception: " + e.getMessage();
270 throw new BuildException(msg, getLocation());
271 } finally {
272 if (tmp != null) {
273 tmp.delete();
274 }
275 if (tmp2 != null) {
276 tmp2.delete();
277 }
278 }
279 }
280
281 /**
282 * Parses the file and creates the folders specified in the output section
283 */
284 private void createFolders(File file) throws IOException, ParseException {
285 BufferedReader in = null;
286 try {
287 in = new BufferedReader(new FileReader(file));
288 MessageFormat mf = new MessageFormat(getFilenameFormat());
289 String line = in.readLine();
290 while (line != null) {
291 log("Considering \"" + line + "\"", Project.MSG_VERBOSE);
292 if (line.startsWith("\"\\")
293 || line.startsWith("\"/")
294 || (line.length() > 3 && line.startsWith("\"")
295 && Character.isLetter(line.charAt(1))
296 && String.valueOf(line.charAt(2)).equals(":")
297 && String.valueOf(line.charAt(3)).equals("\\"))) {
298 Object[] objs = mf.parse(line);
299 String f = (String) objs[1];
300 // Extract the name of the directory from the filename
301 int index = f.lastIndexOf(File.separator);
302 if (index > -1) {
303 File dir = new File(f.substring(0, index));
304 if (!dir.exists()) {
305 log("Creating " + dir.getAbsolutePath(),
306 Project.MSG_VERBOSE);
307 if (dir.mkdirs()) {
308 log("Created " + dir.getAbsolutePath(),
309 Project.MSG_INFO);
310 } else {
311 log("Failed to create "
312 + dir.getAbsolutePath(),
313 Project.MSG_INFO);
314 }
315 } else {
316 log(dir.getAbsolutePath() + " exists. Skipping",
317 Project.MSG_VERBOSE);
318 }
319 } else {
320 log("File separator problem with " + line,
321 Project.MSG_WARN);
322 }
323 } else {
324 log("Skipped \"" + line + "\"", Project.MSG_VERBOSE);
325 }
326 line = in.readLine();
327 }
328 } finally {
329 if (in != null) {
330 in.close();
331 }
332 }
333 }
334
335
336 /**
337 * Simple hack to handle the PVCS command-line tools botch when
338 * handling UNC notation.
339 */
340 private void massagePCLI(File in, File out)
341 throws FileNotFoundException, IOException {
342 BufferedReader inReader = null;
343 BufferedWriter outWriter = null;
344 try {
345 inReader = new BufferedReader(new FileReader(in));
346 outWriter = new BufferedWriter(new FileWriter(out));
347 String s = null;
348 while ((s = inReader.readLine()) != null) {
349 String sNormal = s.replace('\\', '/');
350 outWriter.write(sNormal);
351 outWriter.newLine();
352 }
353 } finally {
354 if (inReader != null) {
355 inReader.close();
356 }
357 if (outWriter != null) {
358 outWriter.close();
359 }
360 }
361 }
362
363 /**
364 * Get network name of the PVCS repository
365 * @return String
366 */
367 public String getRepository() {
368 return repository;
369 }
370
371 /**
372 * The filenameFormat attribute defines a MessageFormat string used
373 * to parse the output of the pcli command. It defaults to
374 * <code>{0}-arc({1})</code>. Repositories where the archive
375 * extension is not -arc should set this.
376 */
377 public String getFilenameFormat() {
378 return filenameFormat;
379 }
380
381 /**
382 * The format of the folder names; optional.
383 * This must be in a format suitable for
384 * <code>java.text.MessageFormat</code>.
385 * Index 1 of the format will be used as the file name.
386 * Defaults to <code>{0}-arc({1})</code>
387 */
388 public void setFilenameFormat(String f) {
389 filenameFormat = f;
390 }
391
392 /**
393
394 * The lineStart attribute is used to parse the output of the pcli
395 * command. It defaults to <code>&quot;P:</code>. The parser already
396 * knows about / and \\, this property is useful in cases where the
397 * repository is accessed on a Windows platform via a drive letter
398 * mapping.
399 */
400 public String getLineStart() {
401 return lineStart;
402 }
403
404 /**
405 * What a valid return value from PVCS looks like
406 * when it describes a file. Defaults to <code>&quot;P:</code>.
407 * If you are not using an UNC name for your repository and the
408 * drive letter <code>P</code> is incorrect for your setup, you may
409 * need to change this value, UNC names will always be
410 * accepted.
411 */
412
413 public void setLineStart(String l) {
414 lineStart = l;
415 }
416
417 /**
418 * The network name of the PVCS repository; required.
419 * @param repo String
420 */
421 public void setRepository(String repo) {
422 repository = repo;
423 }
424
425 /**
426 * Get name of the project in the PVCS repository
427 * @return String
428 */
429 public String getPvcsproject() {
430 return pvcsProject;
431 }
432
433 /**
434 * The project within the PVCS repository to extract files from;
435 * optional, default &quot;/&quot;
436 * @param prj String
437 */
438 public void setPvcsproject(String prj) {
439 pvcsProject = prj;
440 }
441
442 /**
443 * Get name of the project in the PVCS repository
444 * @return Vector
445 */
446 public Vector getPvcsprojects() {
447 return pvcsProjects;
448 }
449
450 /**
451 * Get name of the workspace to store the retrieved files
452 * @return String
453 */
454 public String getWorkspace() {
455 return workspace;
456 }
457
458 /**
459 * Workspace to use; optional.
460 * By specifying a workspace, the files are extracted to that location.
461 * A PVCS workspace is a name for a location of the workfiles and
462 * isn't as such the location itself.
463 * You define the location for a workspace using the PVCS GUI clients.
464 * If this isn't specified the default workspace for the current user is used.
465 * @param ws String
466 */
467 public void setWorkspace(String ws) {
468 workspace = ws;
469 }
470
471 /**
472 * Get name of the PVCS bin directory
473 * @return String
474 */
475 public String getPvcsbin() {
476 return pvcsbin;
477 }
478
479 /**
480 * Specifies the location of the PVCS bin directory; optional if on the PATH.
481 * On some systems the PVCS executables <i>pcli</i>
482 * and <i>get</i> are not found in the PATH. In such cases this attribute
483 * should be set to the bin directory of the PVCS installation containing
484 * the executables mentioned before. If this attribute isn't specified the
485 * tag expects the executables to be found using the PATH environment variable.
486 * @param bin PVCS bin directory
487 * @todo use a File setter and resolve paths.
488 */
489 public void setPvcsbin(String bin) {
490 pvcsbin = bin;
491 }
492
493 /**
494 * Get value of force
495 * @return String
496 */
497 public String getForce() {
498 return force;
499 }
500
501 /**
502 * Specifies the value of the force argument; optional.
503 * If set to <i>yes</i> all files that exists and are
504 * writable are overwritten. Default <i>no</i> causes the files
505 * that are writable to be ignored. This stops the PVCS command
506 * <i>get</i> to stop asking questions!
507 * @todo make a boolean setter
508 * @param f String (yes/no)
509 */
510 public void setForce(String f) {
511 if (f != null && f.equalsIgnoreCase("yes")) {
512 force = "yes";
513 } else {
514 force = "no";
515 }
516 }
517
518 /**
519 * Get value of promotiongroup
520 * @return String
521 */
522 public String getPromotiongroup() {
523 return promotiongroup;
524 }
525
526 /**
527 * Specifies the name of the promotiongroup argument
528 * @param w String
529 */
530 public void setPromotiongroup(String w) {
531 promotiongroup = w;
532 }
533
534 /**
535 * Get value of label
536 * @return String
537 */
538 public String getLabel() {
539 return label;
540 }
541
542 /**
543 * Only files marked with this label are extracted; optional.
544 * @param l String
545 */
546 public void setLabel(String l) {
547 label = l;
548 }
549
550 /**
551 * Get value of revision
552 * @return String
553 */
554 public String getRevision() {
555 return revision;
556 }
557
558 /**
559 * Only files with this revision are extract; optional.
560 * @param r String
561 */
562 public void setRevision(String r) {
563 revision = r;
564 }
565
566 /**
567 * Get value of ignorereturncode
568 * @return String
569 */
570 public boolean getIgnoreReturnCode() {
571 return ignorerc;
572 }
573
574 /**
575 * If set to true the return value from executing the pvcs
576 * commands are ignored; optional, default false.
577 */
578 public void setIgnoreReturnCode(boolean b) {
579 ignorerc = b;
580 }
581
582 /**
583 * Specify a project within the PVCS repository to extract files from.
584 * @param p
585 */
586 public void addPvcsproject(PvcsProject p) {
587 pvcsProjects.addElement(p);
588 }
589
590 public boolean getUpdateOnly() {
591 return updateOnly;
592 }
593
594 /**
595 * If set to <i>true</i> files are fetched only if
596 * newer than existing local files; optional, default false.
597 */
598 public void setUpdateOnly(boolean l) {
599 updateOnly = l;
600 }
601
602 /**
603 * returns the path of the configuration file to be used
604 * @return the path of the config file
605 */
606 public String getConfig() {
607 return config;
608 }
609
610 /**
611 * Sets a configuration file other than the default to be used.
612 * These files have a .cfg extension and are often found in archive or pvcsprop folders.
613 * @param f config file - can be given absolute or relative to ant basedir
614 */
615 public void setConfig(File f) {
616 config = f.toString();
617 }
618
619
620 public String getUserId() {
621 return userId;
622 }
623
624 /**
625 * User ID; unused.
626 * @ant.attribute ignore="true"
627 */
628
629 public void setUserId(String u) {
630 userId = u;
631 }
632
633 /**
634 * Creates a Pvcs object
635 */
636 public Pvcs() {
637 super();
638 pvcsProject = null;
639 pvcsProjects = new Vector();
640 workspace = null;
641 repository = null;
642 pvcsbin = null;
643 force = null;
644 promotiongroup = null;
645 label = null;
646 ignorerc = false;
647 updateOnly = false;
648 lineStart = "\"P:";
649 filenameFormat = "{0}-arc({1})";
650 }
651}
652
Note: See TracBrowser for help on using the repository browser.