1 12 package org.eclipse.team.internal.ccvs.core.syncinfo; 13 14 15 import java.text.ParseException ; 16 import java.util.Date ; 17 18 import org.eclipse.core.runtime.Assert; 19 import org.eclipse.osgi.util.NLS; 20 import org.eclipse.team.internal.ccvs.core.*; 21 import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; 22 import org.eclipse.team.internal.ccvs.core.resources.CVSEntryLineTag; 23 import org.eclipse.team.internal.ccvs.core.util.CVSDateFormatter; 24 import org.eclipse.team.internal.ccvs.core.util.Util; 25 26 46 public class ResourceSyncInfo { 47 48 private static final String DEFAULT_PERMISSIONS = "u=rw,g=rw,o=r"; private static final String DEFAULT_EXECUTABLE_PERMISSIONS = "u=rwx,g=rwx,o=rx"; 54 private static final String DELETED_PREFIX = "-"; private static final byte DELETED_PREFIX_BYTE = '-'; 58 59 private static final String LOCKEDBY_SUFFIX = "\tlocked by"; 63 public static final String ADDED_REVISION = "0"; 68 protected static final int TYPE_REGULAR = 1; 70 protected static final int TYPE_MERGED = 2; 71 protected static final int TYPE_MERGED_WITH_CONFLICTS = 3; 72 73 protected static final String TIMESTAMP_DUMMY = "dummy timestamp"; protected static final String TIMESTAMP_MERGED = "Result of merge"; protected static final String TIMESTAMP_MERGED_WITH_CONFLICT = TIMESTAMP_MERGED + "+"; 77 protected static final String TIMESTAMP_SERVER_MERGED = "+modified"; protected static final String TIMESTAMP_SERVER_MERGED_WITH_CONFLICT = "+="; 80 protected boolean isDirectory = false; 82 protected boolean isDeleted = false; 83 84 protected static final String DIRECTORY_PREFIX = "D"; protected static final String SEPARATOR = "/"; protected static final byte SEPARATOR_BYTE = (byte)'/'; 88 89 protected String name; 91 protected String revision; 92 protected Date timeStamp; 93 protected KSubstOption keywordMode; 94 protected CVSEntryLineTag tag; 95 96 protected int syncType = TYPE_REGULAR; 98 protected ResourceSyncInfo() { 99 } 101 102 public ResourceSyncInfo(byte[] entryLine) throws CVSException { 103 this(new String (entryLine), null); 104 } 105 106 116 public ResourceSyncInfo(String entryLine, Date timestamp) throws CVSException { 117 Assert.isNotNull(entryLine); 118 setEntryLine(entryLine); 119 120 if(timestamp!=null) { 123 this.timeStamp = timestamp; 124 } 125 } 126 127 132 public ResourceSyncInfo(String name) { 133 Assert.isNotNull(name); 134 this.name = name; 135 this.isDirectory = true; 136 } 137 144 public boolean isDirectory() { 145 return isDirectory; 146 } 147 148 156 public boolean isNeedsMerge(Date otherTimestamp) { 157 return syncType == TYPE_MERGED_WITH_CONFLICTS && timeStamp != null && timeStamp.equals(otherTimestamp); 158 } 159 160 167 public boolean isMergedWithConflicts() { 168 return syncType == TYPE_MERGED_WITH_CONFLICTS; 169 } 170 171 177 public boolean isMerged() { 178 return syncType == TYPE_MERGED || isMergedWithConflicts(); 179 } 180 181 189 public boolean isAdded() { 190 if(!isDirectory) { 191 return getRevision().equals(ADDED_REVISION); 192 } else { 193 return false; 194 } 195 } 196 197 204 public boolean isDeleted() { 205 return isDeleted; 206 } 207 208 214 public String getEntryLine() { 215 return getEntryLine(true , null ); 216 } 217 218 225 public String getServerEntryLine(Date fileTimestamp) { 226 String serverTimestamp; 227 if(fileTimestamp != null && (isMerged() || isMergedWithConflicts())) { 228 if(isNeedsMerge(fileTimestamp)) { 229 serverTimestamp = TIMESTAMP_SERVER_MERGED_WITH_CONFLICT; 230 } else { 231 serverTimestamp = TIMESTAMP_SERVER_MERGED; 232 } 233 return getEntryLine(true, serverTimestamp); 234 } else { 235 return getEntryLine(false, null); 236 } 237 } 238 239 244 public CVSTag getTag() { 245 return tag; 246 } 247 252 public Date getTimeStamp() { 253 return timeStamp; 254 } 255 262 public String getRevision() { 263 return revision; 264 } 265 266 271 public String getName() { 272 return name; 273 } 274 278 public KSubstOption getKeywordMode() { 279 return keywordMode; 280 } 281 282 285 public static String getDefaultPermissions() { 286 return DEFAULT_PERMISSIONS; 287 } 288 289 292 public static String getDefaultExecutablePermissions() { 293 return DEFAULT_EXECUTABLE_PERMISSIONS; 294 } 295 296 299 public boolean equals(Object other) { 300 if(other instanceof ResourceSyncInfo) { 301 ResourceSyncInfo syncInfo = ((ResourceSyncInfo)other); 302 if(other == this) return true; 303 if(getName() == syncInfo.getName()) return true; 304 return getName().equals(syncInfo.getName()); 305 } else { 306 return false; 307 } 308 } 309 310 public int hashCode() { 311 return getName().hashCode(); 312 } 313 314 317 public String toString() { 318 return getEntryLine(true, null ); 319 } 320 public MutableResourceSyncInfo cloneMutable() { 321 MutableResourceSyncInfo newSync = new MutableResourceSyncInfo(this); 322 return newSync; 323 } 324 327 protected void setTag(CVSTag tag) { 328 if(tag!=null) { 329 this.tag = new CVSEntryLineTag(tag); 330 } else { 331 this.tag = null; 332 } 333 } 334 335 336 339 protected void setSyncType(int syncType) { 340 this.syncType = syncType; 341 } 342 348 protected void setRevision(String revision) { 349 if(revision==null || revision.equals(ADDED_REVISION)) { 350 this.revision = ADDED_REVISION; 351 timeStamp = null; 352 syncType = TYPE_REGULAR; 353 isDeleted = false; 354 } else if(revision.startsWith(DELETED_PREFIX)) { 355 this.revision = revision.substring(DELETED_PREFIX.length()); 356 isDeleted = true; 357 } else { 358 this.revision = revision; 359 isDeleted = false; 360 } 361 } 362 363 368 protected void setEntryLine(String entryLine) throws CVSException { 369 370 String [] strings = Util.parseIntoSubstrings(entryLine, SEPARATOR); 371 if(strings.length < 6) { 372 throw new CVSException(CVSMessages.Malformed_entry_line___11 + entryLine); 373 } 374 375 isDirectory = (strings[0].equals(DIRECTORY_PREFIX)); 376 377 name = strings[1]; 378 379 if(name.length()==0) { 380 throw new CVSException(CVSMessages.Malformed_entry_line__missing_name___12 + entryLine); 381 } 382 383 String rev = strings[2]; 384 385 if(rev.length()==0 && !isDirectory()) { 386 throw new CVSException(CVSMessages.Malformed_entry_line__missing_revision___13 + entryLine); 387 } else { 388 setRevision(rev); 389 } 390 391 String date = strings[3]; 392 393 if(date.indexOf(ResourceSyncInfo.TIMESTAMP_SERVER_MERGED) != -1) { 407 syncType = TYPE_MERGED; 408 date = null; 409 } else if(date.indexOf(ResourceSyncInfo.TIMESTAMP_SERVER_MERGED_WITH_CONFLICT) != -1) { 410 syncType = TYPE_MERGED_WITH_CONFLICTS; 411 date = null; 412 } else if(date.indexOf(TIMESTAMP_MERGED_WITH_CONFLICT)!=-1) { 413 date = date.substring(date.indexOf("+") + 1); syncType = TYPE_MERGED_WITH_CONFLICTS; 415 } else if(date.indexOf(TIMESTAMP_MERGED)!=-1) { 416 syncType = TYPE_MERGED; 417 date = null; 418 } 419 420 if(date==null || "".equals(date)) { timeStamp = null; 422 } else { 423 try { 424 timeStamp = CVSDateFormatter.entryLineToDate(date); 425 } catch(ParseException e) { 426 timeStamp = null; 429 } 430 } 431 keywordMode = KSubstOption.fromMode(strings[4]); 432 String tagEntry; 433 if (strings.length == 6) { 434 tagEntry = strings[5]; 435 } else { 436 StringBuffer buffer = new StringBuffer (); 439 for (int i = 5; i < strings.length; i++) { 440 buffer.append(strings[i]); 441 if (i < strings.length - 1) { 442 buffer.append(SEPARATOR); 443 } 444 } 445 tagEntry = buffer.toString(); 446 } 447 448 if(tagEntry.length()>0) { 449 tag = new CVSEntryLineTag(tagEntry); 450 } else { 451 tag = null; 452 } 453 } 454 455 private String getEntryLine(boolean includeTimeStamp, String timestampOverride) { 456 StringBuffer result = new StringBuffer (); 457 458 if(isDirectory) { 459 result.append(DIRECTORY_PREFIX); 460 result.append(SEPARATOR); 461 result.append(name); 462 for (int i = 0; i < 4; i++) { 463 result.append(SEPARATOR); 464 } 465 } else { 466 result.append(SEPARATOR); 467 result.append(name); 468 result.append(SEPARATOR); 469 470 if(isDeleted){ 471 result.append(DELETED_PREFIX); 472 } 473 result.append(revision); 474 result.append(SEPARATOR); 475 if(includeTimeStamp) { 476 String entryLineTimestamp = ""; if(timestampOverride!=null) { 478 entryLineTimestamp = timestampOverride; 479 } else { 480 switch(syncType) { 481 case TYPE_REGULAR: 482 if(timeStamp==null) { 483 entryLineTimestamp = TIMESTAMP_DUMMY; 484 } else { 485 entryLineTimestamp = CVSDateFormatter.dateToEntryLine(timeStamp); 486 } break; 487 case TYPE_MERGED: 488 entryLineTimestamp = TIMESTAMP_MERGED; break; 489 case TYPE_MERGED_WITH_CONFLICTS: 490 entryLineTimestamp = TIMESTAMP_MERGED_WITH_CONFLICT + CVSDateFormatter.dateToEntryLine(timeStamp); break; 491 } 492 } 493 result.append(entryLineTimestamp); 494 } 495 result.append(SEPARATOR); 496 if (keywordMode != null) result.append(keywordMode.toEntryLineMode()); 497 result.append(SEPARATOR); 498 if (tag != null) { 499 result.append(tag.toEntryLineFormat(true)); 500 } 501 } 502 return result.toString(); 503 } 504 505 509 public byte[] getBytes() { 510 return getEntryLine().getBytes(); 511 } 512 513 518 public static String getName(byte[] syncBytes) throws CVSException { 519 String name = Util.getSubstring(syncBytes, SEPARATOR_BYTE, 1, false); 520 if (name == null) { 521 throw new CVSException(NLS.bind(CVSMessages.ResourceSyncInfo_malformedSyncBytes, new String [] { new String (syncBytes) })); 522 } 523 return name; 524 } 525 526 531 public static KSubstOption getKeywordMode(byte[] syncBytes) throws CVSException { 532 String mode = Util.getSubstring(syncBytes, SEPARATOR_BYTE, 4, false); 533 if (mode == null) { 534 throw new CVSException(NLS.bind(CVSMessages.ResourceSyncInfo_malformedSyncBytes, new String [] { new String (syncBytes) })); 535 } 536 return KSubstOption.fromMode(mode); 537 } 538 539 544 public static byte[] setKeywordMode(byte[] syncBytes, KSubstOption mode) throws CVSException { 545 return setKeywordMode(syncBytes, mode.toEntryLineMode().getBytes()); 546 } 547 548 553 public static byte[] setKeywordMode(byte[] syncBytes, byte[] modeBytes) throws CVSException { 554 return setSlot(syncBytes, 4, modeBytes); 555 } 556 557 563 public static boolean isBinary(byte[] syncBytes) throws CVSException { 564 if (syncBytes == null) return false; 565 String mode = Util.getSubstring(syncBytes, SEPARATOR_BYTE, 4, false); 566 if (mode == null) { 567 throw new CVSException(NLS.bind(CVSMessages.ResourceSyncInfo_malformedSyncBytes, new String [] { new String (syncBytes) })); 568 } 569 return "-kb".equals(mode); } 571 572 577 public static boolean isFolder(byte[] syncBytes) { 578 return syncBytes.length > 0 && syncBytes[0] == 'D'; 579 } 580 581 586 public static boolean isAddition(byte[] syncBytes) throws CVSException { 587 int start = startOfSlot(syncBytes, 2); 588 if (start == -1 || start > syncBytes.length - 3) { 590 throw new CVSException(NLS.bind(CVSMessages.ResourceSyncInfo_malformedSyncBytes, new String [] { new String (syncBytes) })); 591 } 592 return syncBytes[start + 1] == '0' && syncBytes[start + 2] != '.'; 594 } 595 596 601 public static boolean isDeletion(byte[] syncBytes) throws CVSException { 602 int start = startOfSlot(syncBytes, 2); 603 if (start == -1 || start >= syncBytes.length) { 604 throw new CVSException(NLS.bind(CVSMessages.ResourceSyncInfo_malformedSyncBytes, new String [] { new String (syncBytes) })); 605 } 606 return syncBytes[start + 1] == DELETED_PREFIX_BYTE; 607 } 608 609 614 public static byte[] convertToDeletion(byte[] syncBytes) throws CVSException { 615 int index = startOfSlot(syncBytes, 2); 616 if (index == -1) { 617 throw new CVSException(NLS.bind(CVSMessages.ResourceSyncInfo_malformedSyncBytes, new String [] { new String (syncBytes) })); 618 } 619 if (syncBytes.length > index && syncBytes[index+1] != DELETED_PREFIX_BYTE) { 620 byte[] newSyncBytes = new byte[syncBytes.length + 1]; 621 System.arraycopy(syncBytes, 0, newSyncBytes, 0, index + 1); 622 newSyncBytes[index + 1] = DELETED_PREFIX_BYTE; 623 System.arraycopy(syncBytes, index + 1, newSyncBytes, index + 2, syncBytes.length - index - 1); 624 return newSyncBytes; 625 } 626 return syncBytes; 627 } 628 629 634 public static byte[] convertFromDeletion(byte[] syncBytes) throws CVSException { 635 int index = startOfSlot(syncBytes, 2); 636 if (index == -1) { 637 throw new CVSException(NLS.bind(CVSMessages.ResourceSyncInfo_malformedSyncBytes, new String [] { new String (syncBytes) })); 638 } 639 if (syncBytes.length > index && syncBytes[index+1] == DELETED_PREFIX_BYTE) { 640 byte[] newSyncBytes = new byte[syncBytes.length - 1]; 641 System.arraycopy(syncBytes, 0, newSyncBytes, 0, index + 1); 642 System.arraycopy(syncBytes, index + 2, newSyncBytes, index + 1, newSyncBytes.length - index - 1); 643 return newSyncBytes; 644 } 645 return syncBytes; 646 } 647 656 private static int startOfSlot(byte[] syncBytes, int slot) { 657 int count = 0; 658 for (int j = 0; j < syncBytes.length; j++) { 659 if (syncBytes[j] == SEPARATOR_BYTE) { 660 count++; 661 if (count == slot) return j; 662 } 663 } 664 return -1; 665 } 666 667 674 private static byte[] setSlot(byte[] syncBytes, int slot, byte[] newBytes) throws CVSException { 675 int start = startOfSlot(syncBytes, slot); 676 if (start == -1) { 677 throw new CVSException(NLS.bind(CVSMessages.ResourceSyncInfo_malformedSyncBytes, new String [] { new String (syncBytes) })); 678 } 679 int end = startOfSlot(syncBytes, slot + 1); 680 int totalLength = start + 1 + newBytes.length; 681 if (end != -1) { 682 totalLength += syncBytes.length - end; 683 } 684 byte[] result = new byte[totalLength]; 685 System.arraycopy(syncBytes, 0, result, 0, start + 1); 686 System.arraycopy(newBytes, 0, result, start + 1, newBytes.length); 687 if (end != -1) { 688 System.arraycopy(syncBytes, end, result, start + 1 + newBytes.length, syncBytes.length - end); 689 } 690 return result; 691 } 692 693 701 public static String getTimestampToServer(byte[] syncBytes, Date fileTimestamp) throws CVSException { 702 if(fileTimestamp != null) { 703 String syncTimestamp = Util.getSubstring(syncBytes, SEPARATOR_BYTE, 3, false); 704 if (syncTimestamp == null) { 705 throw new CVSException(NLS.bind(CVSMessages.ResourceSyncInfo_malformedSyncBytes, new String [] { new String (syncBytes) })); 706 } 707 int syncType = getSyncType(syncTimestamp); 708 if (syncType != TYPE_REGULAR) { 709 if (syncType == TYPE_MERGED_WITH_CONFLICTS && fileTimestamp.equals(getTimestamp(syncTimestamp))) { 710 return TIMESTAMP_SERVER_MERGED_WITH_CONFLICT; 711 } else { 712 return TIMESTAMP_SERVER_MERGED; 713 } 714 } 715 } 716 return null; 717 } 718 723 private static Date getTimestamp(String syncTimestamp) { 724 String dateString= syncTimestamp; 725 if(syncTimestamp.indexOf(ResourceSyncInfo.TIMESTAMP_SERVER_MERGED) != -1) { 726 dateString = null; 727 } else if(syncTimestamp.indexOf(ResourceSyncInfo.TIMESTAMP_SERVER_MERGED_WITH_CONFLICT) != -1) { 728 dateString = null; 729 } else if(syncTimestamp.indexOf(TIMESTAMP_MERGED_WITH_CONFLICT)!=-1) { 730 dateString = syncTimestamp.substring(syncTimestamp.indexOf("+") + 1); } else if(syncTimestamp.indexOf(TIMESTAMP_MERGED)!=-1) { 732 dateString = null; 733 } 734 735 if(dateString==null || "".equals(dateString)) { return null; 737 } else { 738 try { 739 return CVSDateFormatter.entryLineToDate(dateString); 740 } catch(ParseException e) { 741 return null; 744 } 745 } 746 } 747 748 753 private static int getSyncType(String date) { 754 if(date.indexOf(ResourceSyncInfo.TIMESTAMP_SERVER_MERGED) != -1) { 755 return TYPE_MERGED; 756 } else if(date.indexOf(ResourceSyncInfo.TIMESTAMP_SERVER_MERGED_WITH_CONFLICT) != -1) { 757 return TYPE_MERGED_WITH_CONFLICTS; 758 } else if(date.indexOf(TIMESTAMP_MERGED_WITH_CONFLICT)!=-1) { 759 return TYPE_MERGED_WITH_CONFLICTS; 760 } else if(date.indexOf(TIMESTAMP_MERGED)!=-1) { 761 return TYPE_MERGED; 762 } 763 return TYPE_REGULAR; 764 } 765 766 771 public static byte[] getTagBytes(byte[] syncBytes) throws CVSException { 772 byte[] tag = Util.getBytesForSlot(syncBytes, SEPARATOR_BYTE, 5, true); 773 if (tag == null) { 774 throw new CVSException(NLS.bind(CVSMessages.ResourceSyncInfo_malformedSyncBytes, new String [] { new String (syncBytes) })); 775 } 776 return tag; 777 } 778 779 785 public static byte[] setTag(byte[] syncBytes, byte[] tagBytes) throws CVSException { 786 return setSlot(syncBytes, 5, tagBytes); 787 } 788 789 795 public static byte[] setTag(byte[] syncBytes, CVSTag tag) throws CVSException { 796 CVSEntryLineTag entryTag; 797 if (tag instanceof CVSEntryLineTag) { 798 entryTag = (CVSEntryLineTag)tag; 799 } else { 800 entryTag = new CVSEntryLineTag(tag); 801 } 802 return setTag(syncBytes, entryTag.toEntryLineFormat(true).getBytes()); 803 } 804 805 809 public static String getRevision(byte[] syncBytes) throws CVSException { 810 String revision = Util.getSubstring(syncBytes, SEPARATOR_BYTE, 2, false); 811 if (revision == null) { 812 throw new CVSException(NLS.bind(CVSMessages.ResourceSyncInfo_malformedSyncBytes, new String [] { new String (syncBytes) })); 813 } 814 if(revision.startsWith(DELETED_PREFIX)) { 815 revision = revision.substring(DELETED_PREFIX.length()); 816 } 817 int lockedIdx = revision.indexOf(LOCKEDBY_SUFFIX); 818 if (lockedIdx >= 0) { 819 revision = revision.substring(0, lockedIdx); 820 } 821 return revision; 822 } 823 824 830 public static byte[] setRevision(byte[] syncBytes, String revision) throws CVSException { 831 return setSlot(syncBytes, 2, revision.getBytes()); 832 } 833 834 839 public static boolean isMerge(byte[] syncBytes) throws CVSException { 840 String timestamp = Util.getSubstring(syncBytes, SEPARATOR_BYTE, 3, false); 841 if (timestamp == null) { 842 throw new CVSException(NLS.bind(CVSMessages.ResourceSyncInfo_malformedSyncBytes, new String [] { new String (syncBytes) })); 843 } 844 int syncType = getSyncType(timestamp); 845 return syncType == TYPE_MERGED || syncType == TYPE_MERGED_WITH_CONFLICTS; 846 } 847 848 853 public static boolean isMergedWithConflicts(byte[] syncBytes) throws CVSException { 854 String timestamp = Util.getSubstring(syncBytes, SEPARATOR_BYTE, 3, false); 855 if (timestamp == null) { 856 throw new CVSException(NLS.bind(CVSMessages.ResourceSyncInfo_malformedSyncBytes, new String [] { new String (syncBytes) })); 857 } 858 int syncType = getSyncType(timestamp); 859 return syncType == TYPE_MERGED_WITH_CONFLICTS; 860 } 861 862 863 871 public static boolean isLaterRevisionOnSameBranch(byte[] remoteBytes, byte[] localBytes) throws CVSException { 872 if (remoteBytes == localBytes) return false; 874 byte[] remoteTag = ResourceSyncInfo.getTagBytes(remoteBytes); 876 byte[] localTag = ResourceSyncInfo.getTagBytes(localBytes); 877 if (!Util.equals(remoteTag, localTag)) return false; 878 String remoteRevision = ResourceSyncInfo.getRevision(remoteBytes); 880 String localRevision = ResourceSyncInfo.getRevision(localBytes); 881 if (remoteRevision.equals(localRevision)) return false; 882 return isLaterRevision(remoteRevision, localRevision); 883 } 884 885 892 public static boolean isLaterRevision(String remoteRevision, String localRevision) { 893 int localDigits[] = Util.convertToDigits(localRevision); 894 if (localDigits.length == 0) return false; 895 int remoteDigits[] = Util.convertToDigits(remoteRevision); 896 if (remoteDigits.length == 0) return false; 897 898 if (localRevision.equals(ADDED_REVISION)) { 899 return (remoteDigits.length >= 2); 900 } 901 if (localDigits.length < remoteDigits.length) { 902 for (int i = 0; i < localDigits.length; i++) { 905 int localDigit = localDigits[i]; 906 int remoteDigit = remoteDigits[i]; 907 if (remoteDigit != localDigit) return false; 908 } 909 return true; 910 } 911 for (int i = 0; i < remoteDigits.length - 1; i++) { 916 int localDigit = localDigits[i]; 917 int remoteDigit = remoteDigits[i]; 918 if (remoteDigit != localDigit) return false; 919 } 920 return localDigits[remoteDigits.length - 1] < remoteDigits[remoteDigits.length - 1] ; 922 } 923 } 924 | Popular Tags |