1 37 package net.sourceforge.cruisecontrol.sourcecontrols; 38 39 import net.sourceforge.cruisecontrol.CruiseControlException; 40 import net.sourceforge.cruisecontrol.Modification; 41 import net.sourceforge.cruisecontrol.SourceControl; 42 import net.sourceforge.cruisecontrol.util.Commandline; 43 import net.sourceforge.cruisecontrol.util.ValidationHelper; 44 45 import org.apache.log4j.Level; 46 import org.apache.log4j.Logger; 47 48 import java.io.BufferedReader ; 49 import java.io.File ; 50 import java.io.FileReader ; 51 import java.io.IOException ; 52 import java.text.ParseException ; 53 import java.text.SimpleDateFormat ; 54 import java.util.ArrayList ; 55 import java.util.Date ; 56 import java.util.Hashtable ; 57 import java.util.Iterator ; 58 import java.util.List ; 59 import java.util.Locale ; 60 import java.util.Map ; 61 62 70 public class Vss implements SourceControl { 71 72 private static final Logger LOG = Logger.getLogger(Vss.class); 73 74 private SimpleDateFormat vssDateTimeFormat; 75 private String ssDir; 76 private String vssPath; 77 private String serverPath; 78 private String login; 79 private String dateFormat; 80 private String timeFormat; 81 private Hashtable properties = new Hashtable (); 82 private String property; 83 private String propertyOnDelete; 84 85 public Vss() { 86 dateFormat = "MM/dd/yy"; 87 timeFormat = "hh:mma"; 88 constructVssDateTimeFormat(); 89 } 90 91 96 public void setVsspath(String vsspath) { 97 this.vssPath = "$" + vsspath; 98 } 99 100 105 public void setSsDir(String ssdir) { 106 this.ssDir = ssdir; 107 } 108 109 114 public void setServerPath(String dirWithSrcsafeIni) { 115 serverPath = dirWithSrcsafeIni; 116 } 117 118 123 public void setLogin(String usernameCommaPassword) { 124 login = usernameCommaPassword; 125 } 126 127 133 public void setProperty(String propertyName) { 134 property = propertyName; 135 } 136 137 142 public void setPropertyOnDelete(String propertyName) { 143 propertyOnDelete = propertyName; 144 } 145 146 154 public void setDateFormat(String format) { 155 dateFormat = format; 156 constructVssDateTimeFormat(); 157 } 158 159 167 public void setTimeFormat(String format) { 168 timeFormat = format; 169 constructVssDateTimeFormat(); 170 } 171 172 public Map getProperties() { 173 return properties; 174 } 175 176 public void validate() throws CruiseControlException { 177 ValidationHelper.assertIsSet(vssPath, "vsspath", this.getClass()); 178 ValidationHelper.assertIsSet(login, "login", this.getClass()); 179 } 180 181 189 public List getModifications(Date lastBuild, Date now) { 190 ArrayList modifications = new ArrayList (); 191 192 String [] env = VSSHelper.loadVSSEnvironment(serverPath); 193 LOG.info("Vss: getting modifications for " + vssPath); 194 195 try { 196 Process p = Runtime.getRuntime().exec(getCommandLine(lastBuild, now), env); 197 p.waitFor(); 198 p.getInputStream().close(); 199 p.getOutputStream().close(); 200 p.getErrorStream().close(); 201 202 parseTempFile(modifications); 203 } catch (IOException e) { 204 LOG.equals(e); 205 throw new RuntimeException (e.getMessage()); 206 } catch (CruiseControlException e) { 207 LOG.equals(e); 208 throw new RuntimeException (e.getMessage()); 209 } catch (InterruptedException e) { 210 LOG.equals(e); 211 throw new RuntimeException (e.getMessage()); 212 } 213 214 if (property != null && modifications.size() > 0) { 215 properties.put(property, "true"); 216 } 217 218 return modifications; 219 } 220 221 private void parseTempFile(ArrayList modifications) throws IOException { 222 Level loggingLevel = LOG.getEffectiveLevel(); 223 if (Level.DEBUG.equals(loggingLevel)) { 224 logVSSTempFile(); 225 } 226 227 File tempFile = getTempFile(); 228 BufferedReader reader = new BufferedReader (new FileReader (tempFile)); 229 230 parseHistoryEntries(modifications, reader); 231 232 reader.close(); 233 tempFile.delete(); 234 } 235 236 private void logVSSTempFile() throws IOException { 237 BufferedReader reader = new BufferedReader (new FileReader (getTempFile())); 238 String currLine = reader.readLine(); 239 LOG.debug(" "); 240 while (currLine != null) { 241 LOG.debug(getTempFile().getName() + ": " + currLine); 242 currLine = reader.readLine(); 243 } 244 LOG.debug(" "); 245 reader.close(); 246 } 247 248 private File getTempFile() { 249 return new File (createFileNameFromVssPath()); 250 } 251 252 String createFileNameFromVssPath() { 253 String filename = vssPath.substring(1).replace('/', '_') + ".tmp"; 255 while (filename.charAt(0) == '_') { 256 filename = filename.substring(1); 257 } 258 return filename; 259 } 260 261 void parseHistoryEntries(ArrayList modifications, BufferedReader reader) throws IOException { 262 String currLine = reader.readLine(); 263 264 while (currLine != null) { 265 if (currLine.startsWith("*****")) { 266 ArrayList vssEntry = new ArrayList (); 267 vssEntry.add(currLine); 268 currLine = reader.readLine(); 269 while (currLine != null && !currLine.startsWith("*****")) { 270 vssEntry.add(currLine); 271 currLine = reader.readLine(); 272 } 273 Modification mod = handleEntry(vssEntry); 274 if (mod != null) { 275 modifications.add(mod); 276 } 277 } else { 278 currLine = reader.readLine(); 279 } 280 } 281 } 282 283 protected String [] getCommandLine(Date lastBuild, Date now) throws CruiseControlException { 284 Commandline commandline = new Commandline(); 285 String execCommand; 286 try { 287 execCommand = (ssDir != null) ? new File (ssDir, "ss.exe").getCanonicalPath() : "ss.exe"; 288 } catch (IOException e) { 289 throw new CruiseControlException(e); 290 } 291 292 commandline.setExecutable(execCommand); 293 commandline.createArgument().setValue("history"); 294 commandline.createArgument().setValue(vssPath); 295 commandline.createArgument().setValue("-R"); 296 commandline.createArgument().setValue("-Vd" + formatDateForVSS(now) + "~" + formatDateForVSS(lastBuild)); 297 commandline.createArgument().setValue("-Y" + login); 298 commandline.createArgument().setValue("-I-N"); 299 commandline.createArgument().setValue("-O" + getTempFile().getName()); 300 301 String [] line = commandline.getCommandline(); 302 303 LOG.debug(" "); 304 for (int i = 0; i < line.length; i++) { 305 LOG.debug("Vss command line arguments: " + line[i]); 306 } 307 LOG.debug(" "); 308 309 return line; 310 } 311 312 322 private String formatDateForVSS(Date d) { 323 SimpleDateFormat sdf = new SimpleDateFormat (dateFormat + ";" + timeFormat, Locale.US); 324 String vssFormattedDate = sdf.format(d); 325 if (timeFormat.endsWith("a")) { 326 return vssFormattedDate.substring(0, vssFormattedDate.length() - 1); 327 } 328 return vssFormattedDate; 329 } 330 331 333 338 protected Modification handleEntry(List entry) { 339 LOG.debug("VSS history entry BEGIN"); 340 for (Iterator i = entry.iterator(); i.hasNext();) { 341 LOG.debug("entry: " + i.next()); 342 } 343 LOG.debug("VSS history entry END"); 344 345 try { 346 final String labelDelimiter = "**********************"; 347 boolean isLabelEntry = labelDelimiter.equals(entry.get(0)); 348 349 if (isLabelEntry) { 350 LOG.debug("this is a label; ignoring this entry"); 351 return null; 352 } 353 354 365 int nameAndDateIndex = 2; 366 if (((String ) entry.get(0)).startsWith("***************** ")) { 367 nameAndDateIndex = 1; 368 } 369 String nameAndDateLine = (String ) entry.get(nameAndDateIndex); 370 if (nameAndDateLine.startsWith("Label:")) { 371 nameAndDateIndex++; 372 nameAndDateLine = (String ) entry.get(nameAndDateIndex); 373 LOG.debug("adjusting for the line that starts with Label"); 374 } 375 376 Modification modification = new Modification("vss"); 377 modification.userName = parseUser(nameAndDateLine); 378 modification.modifiedTime = parseDate(nameAndDateLine); 379 380 String folderLine = (String ) entry.get(0); 381 int fileIndex = nameAndDateIndex + 1; 382 String fileLine = (String ) entry.get(fileIndex); 383 384 if (fileLine.startsWith("Checked in")) { 385 386 LOG.debug("this is a checkin"); 387 int commentIndex = fileIndex + 1; 388 modification.comment = parseComment(entry, commentIndex); 389 String fileName = folderLine.substring(7, folderLine.indexOf(" *")); 390 String folderName = fileLine.substring(12); 391 392 Modification.ModifiedFile modfile = modification.createModifiedFile(fileName, folderName); 393 modfile.action = "checkin"; 394 395 } else if (fileLine.endsWith("Created")) { 396 modification.type = "create"; 397 LOG.debug("this folder was created"); 398 } else { 399 String fileName; 400 String folderName; 401 402 if (nameAndDateIndex == 1) { 403 folderName = vssPath; 404 } else { 405 folderName = vssPath + "\\" + folderLine.substring(7, folderLine.indexOf(" *")); 406 } 407 int lastSpace = fileLine.lastIndexOf(" "); 408 if (lastSpace != -1) { 409 fileName = fileLine.substring(0, lastSpace); 410 } else { 411 fileName = fileLine; 412 if (fileName.equals("Branched")) { 413 LOG.debug("Branched file, ignoring as branch directory is handled separately"); 414 return null; 415 } 416 } 417 418 Modification.ModifiedFile modfile = modification.createModifiedFile(fileName, folderName); 419 420 if (fileLine.endsWith("added")) { 421 modfile.action = "add"; 422 LOG.debug("this file was added"); 423 } else if (fileLine.endsWith("deleted")) { 424 modfile.action = "delete"; 425 LOG.debug("this file was deleted"); 426 addPropertyOnDelete(); 427 } else if (fileLine.endsWith("destroyed")) { 428 modfile.action = "destroy"; 429 LOG.debug("this file was destroyed"); 430 addPropertyOnDelete(); 431 } else if (fileLine.endsWith("recovered")) { 432 modfile.action = "recover"; 433 LOG.debug("this file was recovered"); 434 } else if (fileLine.endsWith("shared")) { 435 modfile.action = "share"; 436 LOG.debug("this file was shared"); 437 } else if (fileLine.endsWith("branched")) { 438 modfile.action = "branch"; 439 LOG.debug("this file was branched"); 440 } else if (fileLine.indexOf(" renamed to ") != -1) { 441 modfile.fileName = fileLine; 442 modfile.action = "rename"; 443 LOG.debug("this file was renamed"); 444 addPropertyOnDelete(); 445 } else if (fileLine.startsWith("Labeled")) { 446 LOG.debug("this is a label; ignoring this entry"); 447 return null; 448 } else { 449 LOG.debug("action for this vss entry (" + fileLine + ") is unknown"); 450 } 451 } 452 453 if (property != null) { 454 properties.put(property, "true"); 455 LOG.debug("setting property " + property + " to be true"); 456 } 457 458 LOG.debug(" "); 459 460 return modification; 461 462 } catch (RuntimeException e) { 463 LOG.fatal("RuntimeException handling VSS entry:"); 464 for (int i = 0; i < entry.size(); i++) { 465 LOG.fatal(entry.get(i)); 466 } 467 throw e; 468 } 469 } 470 471 private void addPropertyOnDelete() { 472 if (propertyOnDelete != null) { 473 properties.put(propertyOnDelete, "true"); 474 LOG.debug("setting property " + propertyOnDelete + " to be true"); 475 } 476 } 477 478 484 private String parseComment(List commentList, int commentIndex) { 485 StringBuffer comment = new StringBuffer (); 486 comment.append(commentList.get(commentIndex)).append(" "); 487 for (int i = commentIndex + 1; i < commentList.size(); i++) { 488 comment.append(commentList.get(i)).append(" "); 489 } 490 491 return comment.toString().trim(); 492 } 493 494 507 public Date parseDate(String nameAndDateLine) { 508 String dateAndTime = nameAndDateLine.substring(nameAndDateLine.indexOf("Date: ")); 509 510 int indexOfColon = dateAndTime.indexOf("/:"); 511 if (indexOfColon != -1) { 512 dateAndTime = dateAndTime.substring(0, indexOfColon) 513 + dateAndTime.substring(indexOfColon, indexOfColon + 2).replace(':', '0') 514 + dateAndTime.substring(indexOfColon + 2); 515 } 516 517 try { 518 Date lastModifiedDate; 519 if (timeFormat.endsWith("a")) { 520 lastModifiedDate = vssDateTimeFormat.parse(dateAndTime.trim() + "m"); 521 } else { 522 lastModifiedDate = vssDateTimeFormat.parse(dateAndTime.trim()); 523 } 524 525 return lastModifiedDate; 526 } catch (ParseException pe) { 527 LOG.warn(pe); 528 return null; 529 } 530 } 531 532 538 public String parseUser(String userLine) { 539 final int userIndex = "User: ".length(); 540 541 return userLine.substring(userIndex, userLine.indexOf("Date: ") - 1).trim(); 542 } 543 544 549 private void constructVssDateTimeFormat() { 550 vssDateTimeFormat = new SimpleDateFormat ("'Date: '" + dateFormat + " 'Time: '" + timeFormat, Locale.US); 551 } 552 553 protected SimpleDateFormat getVssDateTimeFormat() { 554 return vssDateTimeFormat; 555 } 556 557 } 558 | Popular Tags |