1 37 38 package net.sourceforge.cruisecontrol.labelincrementers; 39 40 import java.io.BufferedReader ; 41 import java.io.File ; 42 import java.io.IOException ; 43 import java.io.InputStream ; 44 import java.io.InputStreamReader ; 45 import java.util.ArrayList ; 46 import java.util.List ; 47 import java.util.StringTokenizer ; 48 49 import net.sourceforge.cruisecontrol.CruiseControlException; 50 import net.sourceforge.cruisecontrol.LabelIncrementer; 51 import net.sourceforge.cruisecontrol.util.Commandline; 52 import net.sourceforge.cruisecontrol.util.StreamPumper; 53 import net.sourceforge.cruisecontrol.util.ValidationHelper; 54 55 import org.apache.log4j.Logger; 56 import org.apache.tools.ant.BuildException; 57 import org.apache.tools.ant.Project; 58 import org.apache.tools.ant.taskdefs.Delete; 59 import org.apache.tools.ant.types.FileSet; 60 import org.apache.tools.ant.types.PatternSet.NameEntry; 61 import org.jdom.Element; 62 63 70 public class P4ChangelistLabelIncrementer implements LabelIncrementer { 71 72 private static final Logger LOG = 73 Logger.getLogger(P4ChangelistLabelIncrementer.class); 74 private static final String CHANGELIST_PREFIX = "@"; 75 private static final String REVISION_PREFIX = "#"; 76 private static final String RECURSE_U = "/..."; 77 private static final String RECURSE_W = "\\..."; 78 79 private String p4Port; 80 private String p4Client; 81 private String p4User; 82 private String p4View; 83 private String p4Passwd; 84 85 private boolean clean = false; 86 private boolean delete = false; 87 private boolean sync = true; 88 89 private int baseChangelist = -1; 90 91 98 public String incrementLabel(String oldLabel, Element buildLog) { 99 String label = null; 100 try { 101 validate(); 102 103 boolean delTree = delete; 107 boolean cleanP4 = delTree || clean; 108 boolean syncP4 = cleanP4 || sync; 109 110 if (cleanP4) { 111 LOG.info("Cleaning Perforce clientspec " + p4Client); 112 syncTo(REVISION_PREFIX + 0); 113 } 114 if (delTree) { 115 deleteView(); 116 } 117 118 label = getDefaultLabel(); 119 120 if (syncP4) { 121 syncTo(CHANGELIST_PREFIX + label); 122 } 123 } catch (CruiseControlException cce) { 124 LOG.warn("Couldn't run expected tasks", cce); 125 } 126 127 return label; 128 } 129 130 public boolean isPreBuildIncrementer() { 131 return true; 133 } 134 135 140 public boolean isValidLabel(String label) { 141 try { 142 Integer.parseInt(label); 143 return true; 144 } catch (NumberFormatException e) { 145 return false; 146 } 147 } 148 149 153 public String getDefaultLabel() { 154 if (baseChangelist > 0) { 155 return Integer.toString(baseChangelist); 156 } 157 159 try { 160 validate(); 161 162 return getCurrentChangelist(); 163 } catch (CruiseControlException cce) { 164 cce.printStackTrace(); 165 LOG.fatal("Problem accessing Perforce changelist", cce); 166 throw new IllegalStateException ( 167 "Problem accessing Perforce changelist"); 168 } 169 } 170 171 173 181 public void setChangelist(int syncChange) { 182 baseChangelist = syncChange; 183 } 184 185 186 187 public void setPort(String p4Port) { 188 this.p4Port = p4Port; 189 } 190 191 public void setClient(String p4Client) { 192 this.p4Client = p4Client; 193 } 194 195 public void setUser(String p4User) { 196 this.p4User = p4User; 197 } 198 199 public void setView(String p4View) { 200 this.p4View = p4View; 201 } 202 203 public void setPasswd(String p4Passwd) { 204 this.p4Passwd = p4Passwd; 205 } 206 207 213 public void setNoSync(boolean b) { 214 this.sync = !b; 215 } 216 217 223 public void setClean(boolean b) { 224 this.clean = b; 225 } 226 227 228 235 public void setDelete(boolean b) { 236 this.delete = b; 237 } 238 239 240 public void validate() throws CruiseControlException { 241 ValidationHelper.assertIsSet(p4View, "view", this.getClass()); 242 ValidationHelper.assertNotEmpty(p4View, "view", this.getClass()); 243 ValidationHelper.assertNotEmpty(p4Client, "client", this.getClass()); 244 ValidationHelper.assertNotEmpty(p4Port, "port", this.getClass()); 245 ValidationHelper.assertNotEmpty(p4User, "user", this.getClass()); 246 ValidationHelper.assertNotEmpty(p4Passwd, "passwd", this.getClass()); 247 } 248 249 250 251 protected String getCurrentChangelist() 252 throws CruiseControlException { 253 Commandline cmd = buildBaseP4Command(); 254 cmd.createArgument().setValue("changes"); 255 cmd.createArgument().setValue("-m1"); 256 cmd.createArgument().setValue("-ssubmitted"); 257 258 ParseChangelistNumbers pcn = new ParseChangelistNumbers(); 259 runP4Cmd(cmd, pcn); 260 261 String [] changes = pcn.getChangelistNumbers(); 262 if (changes != null && changes.length == 1) { 263 return changes[0]; 264 } else { 265 throw new CruiseControlException( 266 "Could not discover the changelist"); 267 } 268 } 269 270 271 protected void syncTo(String viewArg) throws CruiseControlException { 272 Commandline cmd = buildBaseP4Command(); 273 cmd.createArgument().setValue("sync"); 274 cmd.createArgument().setValue(p4View + viewArg); 275 276 runP4Cmd(cmd, new P4CmdParserAdapter()); 277 } 278 279 280 protected void deleteView() throws CruiseControlException { 281 try { 284 Project p = createProject(); 285 FileSet fs = getWhereView(p); 286 Delete d = createDelete(p); 287 d.setProject(p); 288 d.setVerbose(true); 289 d.addFileset(fs); 290 d.execute(); 291 } catch (BuildException be) { 292 throw new CruiseControlException(be.getMessage(), be); 293 } 294 } 295 296 297 304 protected FileSet getWhereView(Project p) throws CruiseControlException { 305 String view = p4View; 306 if (view == null) { 307 view = "//..."; 308 } 309 if (!view.endsWith(RECURSE_U) && !view.endsWith(RECURSE_W)) { 310 LOG.debug("view [" + view + "] isn't recursive."); 313 return null; 314 } 315 Commandline cmd = buildBaseP4Command(); 316 cmd.createArgument().setValue("where"); 317 cmd.createArgument().setValue(view); 318 319 ParseOutputParam pop = new ParseOutputParam(""); 320 runP4Cmd(cmd, pop); 321 String [] values = pop.getValues(); 322 if (values == null || values.length <= 0) { 323 LOG.debug("Didn't find any files for view"); 324 return null; 325 } 326 FileSet fs = createFileSet(p); 327 328 fs.setDir(new File ("/")); 330 int count = 0; 331 332 for (int i = 0; i < values.length; ++i) { 333 337 String s = values[i]; 342 if (!s.endsWith(RECURSE_U) && !s.endsWith(RECURSE_W)) { 344 continue; 345 } 346 347 String [] tokens = new String [3]; 348 int pos = 0; 349 for (int j = 0; j < 3; ++j) { 350 StringBuffer sb = new StringBuffer (); 351 boolean neot = true; 352 while (neot) { 353 if (pos >= s.length()) { 354 break; 355 } 356 int q1 = s.indexOf('\'', pos); 357 int q2 = s.indexOf('"', pos); 358 int sp = s.indexOf(' ', pos); 359 if (q1 >= 0 && (q1 < q2 || q2 < 0) && (q1 < sp || sp < 0)) { 360 sb.append(s.substring(pos, q1)); 361 pos = q1 + 1; 362 } else 363 if (q2 >= 0 && (q2 < q1 || q1 < 0) && (q2 < sp || sp < 0)) { 364 sb.append(s.substring(pos, q2)); 365 pos = q2 + 1; 366 } else 367 if (sp >= 0) { 368 String sub = s.substring(pos, sp); 370 pos = sp + 1; 371 sb.append(sub); 372 if (sub.endsWith(RECURSE_U) || sub.endsWith(RECURSE_W)) { 373 neot = false; 374 } else { 375 sb.append(' '); 377 } 378 } else { 379 sb.append(s.substring(pos)); 380 neot = false; 381 } 382 } 383 tokens[j] = new String (sb).trim(); 384 } 385 if (tokens[0] != null && tokens[1] != null && tokens[2] != null 386 && (tokens[2].endsWith(RECURSE_U) 387 || tokens[2].endsWith(RECURSE_W))) { 388 String f = tokens[2].substring(0, 391 tokens[2].length() - RECURSE_W.length()) 392 + File.separator + "**"; 393 if (tokens[0].startsWith("-//")) { 395 NameEntry ne = fs.createExclude(); 396 ne.setName(f); 397 } else { 398 NameEntry ne = fs.createInclude(); 399 ne.setName(f); 400 } 401 ++count; 402 } 403 } 404 if (count > 0) { 405 return fs; 406 } else { 407 LOG.debug("no files in view to delete"); 408 return null; 409 } 410 } 411 412 413 protected Project createProject() { 414 Project p = new Project(); 415 p.init(); 416 return p; 417 } 418 419 420 protected Delete createDelete(Project p) throws CruiseControlException { 421 Object o = p.createTask("delete"); 422 if (o == null || !(o instanceof Delete)) { 423 LOG.info("Could not find <delete> task in Ant. Defaulting to basic constructor."); 427 Delete d = new Delete(); 428 d.setProject(p); 429 o = d; 430 } 431 return (Delete) o; 432 } 433 434 435 protected FileSet createFileSet(Project p) throws CruiseControlException { 436 Object o = p.createDataType("fileset"); 437 if (o == null || !(o instanceof FileSet)) { 438 LOG.info("Could not find <fileset> type in Ant. Defaulting to basic constructor."); 442 FileSet fs = new FileSet(); 443 fs.setProject(p); 444 o = fs; 445 } 446 return (FileSet) o; 447 } 448 449 450 protected Commandline buildBaseP4Command() { 451 Commandline commandLine = new Commandline(); 452 commandLine.setExecutable("p4"); 453 commandLine.createArgument().setValue("-s"); 454 455 if (p4Client != null) { 456 commandLine.createArgument().setValue("-c"); 457 commandLine.createArgument().setValue(p4Client); 458 } 459 460 if (p4Port != null) { 461 commandLine.createArgument().setValue("-p"); 462 commandLine.createArgument().setValue(p4Port); 463 } 464 465 if (p4User != null) { 466 commandLine.createArgument().setValue("-u"); 467 commandLine.createArgument().setValue(p4User); 468 } 469 470 if (p4Passwd != null) { 471 commandLine.createArgument().setValue("-P"); 472 commandLine.createArgument().setValue(p4Passwd); 473 } 474 return commandLine; 475 } 476 477 478 protected void runP4Cmd(Commandline cmd, P4CmdParser parser) 479 throws CruiseControlException { 480 try { 481 LOG.info("Executing commandline [" + cmd + "]"); 482 Process p = Runtime.getRuntime().exec(cmd.getCommandline()); 483 484 try { 485 new Thread (new StreamPumper(p.getErrorStream())).start(); 486 487 InputStream p4Stream = p.getInputStream(); 488 parseStream(p4Stream, parser); 489 } finally { 490 p.waitFor(); 491 p.getInputStream().close(); 492 p.getOutputStream().close(); 493 p.getErrorStream().close(); 494 } 495 } catch (IOException e) { 496 throw new CruiseControlException("Problem trying to execute command line process", e); 497 } catch (InterruptedException e) { 498 throw new CruiseControlException("Problem trying to execute command line process", e); 499 } 500 } 501 502 protected void parseStream(InputStream stream, P4CmdParser parser) 503 throws IOException { 504 String line; 505 BufferedReader reader = new BufferedReader ( 506 new InputStreamReader (stream)); 507 while ((line = reader.readLine()) != null) { 508 if (line.startsWith("error:")) { 509 throw new IOException ( 510 "Error reading P4 stream: P4 says: " + line); 511 } else if (line.startsWith("exit: 0")) { 512 System.err.println("p4cmd: Found exit 0"); 513 break; 514 } else if (line.startsWith("exit:")) { 515 System.err.println("p4cmd: Found exit " + line); 517 throw new IOException ( 518 "Error reading P4 stream: P4 says: " + line); 519 } else if (line.startsWith("warning:")) { 520 parser.warning(line.substring(8)); 521 } else if (line.startsWith("info:") 522 || line.startsWith("info1:")) { 523 parser.info(line.substring(5)); 524 } else if (line.startsWith("text:")) { 525 parser.text(line.substring(5)); 526 } 527 } 528 if (line == null) { 529 throw new IOException ( 530 "Error reading P4 stream: Unexpected EOF reached"); 531 } 532 } 533 534 protected static interface P4CmdParser { 535 public void warning(String msg); 536 public void info(String msg); 537 public void text(String msg); 538 } 539 540 protected static class P4CmdParserAdapter implements P4CmdParser { 541 public void warning(String msg) { 542 } 544 public void info(String msg) { 545 } 547 public void text(String msg) { 548 } 550 } 551 552 protected static class ParseChangelistNumbers extends P4CmdParserAdapter { 553 private ArrayList changelists = new ArrayList (); 554 public void info(String msg) { 555 StringTokenizer st = new StringTokenizer (msg); 556 st.nextToken(); changelists.add(st.nextToken()); 558 } 559 560 public String [] getChangelistNumbers() { 561 String [] changelistNumbers = new String [ 0 ]; 562 return (String []) changelists.toArray(changelistNumbers); 563 } 564 } 565 566 protected static class ParseOutputParam extends P4CmdParserAdapter { 567 public ParseOutputParam(String paramName) { 568 this.paramName = paramName; 569 } 570 private final String paramName; 571 private List values = new ArrayList (); 572 public void info(final String msg) { 573 String m = msg.trim(); 574 if (m.startsWith(paramName)) { 575 String m2 = m.substring(paramName.length()).trim(); 576 values.add(m2); 577 } 578 } 579 580 public String [] getValues() { 581 String [] v = new String [ 0 ]; 582 return (String []) values.toArray(v); 583 } 584 } 585 } 586 | Popular Tags |