Пример #1
0
  public void testNoPostOrder() throws Exception {
    final DirCache tree = db.readDirCache();
    {
      final DirCacheBuilder b = tree.builder();

      b.add(makeFile("a"));
      b.add(makeFile("b/c"));
      b.add(makeFile("b/d"));
      b.add(makeFile("q"));

      b.finish();
      assertEquals(4, tree.getEntryCount());
    }

    final TreeWalk tw = new TreeWalk(db);
    tw.reset();
    tw.setPostOrderTraversal(false);
    tw.addTree(new DirCacheIterator(tree));

    assertModes("a", REGULAR_FILE, tw);
    assertModes("b", TREE, tw);
    assertTrue(tw.isSubtree());
    assertFalse(tw.isPostChildren());
    tw.enterSubtree();
    assertModes("b/c", REGULAR_FILE, tw);
    assertModes("b/d", REGULAR_FILE, tw);
    assertModes("q", REGULAR_FILE, tw);
  }
Пример #2
0
  @Test
  public void testPathsResetWithUnmerged() throws Exception {
    setupRepository();

    String file = "a.txt";
    writeTrashFile(file, "data");

    git.add().addFilepattern(file).call();
    git.commit().setMessage("commit").call();

    DirCache index = db.lockDirCache();
    DirCacheBuilder builder = index.builder();
    builder.add(createEntry(file, FileMode.REGULAR_FILE, 1, ""));
    builder.add(createEntry(file, FileMode.REGULAR_FILE, 2, ""));
    builder.add(createEntry(file, FileMode.REGULAR_FILE, 3, ""));
    builder.add(createEntry("b.txt", FileMode.REGULAR_FILE));
    assertTrue(builder.commit());

    assertEquals(
        "[a.txt, mode:100644, stage:1]"
            + "[a.txt, mode:100644, stage:2]"
            + "[a.txt, mode:100644, stage:3]"
            + "[b.txt, mode:100644]",
        indexState(0));

    git.reset().addPath(file).call();

    assertEquals("[a.txt, mode:100644]" + "[b.txt, mode:100644]", indexState(0));
  }
  /**
   * Creates an in-memory index of the ticket change.
   *
   * @param changeId
   * @param change
   * @return an in-memory index
   * @throws IOException
   */
  private DirCache createIndex(Repository db, long ticketId, Change change)
      throws IOException, ClassNotFoundException, NoSuchFieldException {

    String ticketPath = toTicketPath(ticketId);
    DirCache newIndex = DirCache.newInCore();
    DirCacheBuilder builder = newIndex.builder();

    Set<String> ignorePaths = new TreeSet<String>();
    try (ObjectInserter inserter = db.newObjectInserter()) {
      // create/update the journal
      // exclude the attachment content
      List<Change> changes = getJournal(db, ticketId);
      changes.add(change);
      String journal = TicketSerializer.serializeJournal(changes).trim();

      byte[] journalBytes = journal.getBytes(Constants.ENCODING);
      String journalPath = ticketPath + "/" + JOURNAL;
      final DirCacheEntry journalEntry = new DirCacheEntry(journalPath);
      journalEntry.setLength(journalBytes.length);
      journalEntry.setLastModified(change.date.getTime());
      journalEntry.setFileMode(FileMode.REGULAR_FILE);
      journalEntry.setObjectId(
          inserter.insert(org.eclipse.jgit.lib.Constants.OBJ_BLOB, journalBytes));

      // add journal to index
      builder.add(journalEntry);
      ignorePaths.add(journalEntry.getPathString());

      // Add any attachments to the index
      if (change.hasAttachments()) {
        for (Attachment attachment : change.attachments) {
          // build a path name for the attachment and mark as ignored
          String path = toAttachmentPath(ticketId, attachment.name);
          ignorePaths.add(path);

          // create an index entry for this attachment
          final DirCacheEntry entry = new DirCacheEntry(path);
          entry.setLength(attachment.content.length);
          entry.setLastModified(change.date.getTime());
          entry.setFileMode(FileMode.REGULAR_FILE);

          // insert object
          entry.setObjectId(
              inserter.insert(org.eclipse.jgit.lib.Constants.OBJ_BLOB, attachment.content));

          // add to temporary in-core index
          builder.add(entry);
        }
      }

      for (DirCacheEntry entry : getTreeEntries(db, ignorePaths)) {
        builder.add(entry);
      }

      // finish the index
      builder.finish();
    }
    return newIndex;
  }
Пример #4
0
    CommitBuilder(CommitBuilder prior) throws Exception {
      branch = prior.branch;

      DirCacheBuilder b = tree.builder();
      for (int i = 0; i < prior.tree.getEntryCount(); i++) b.add(prior.tree.getEntry(i));
      b.finish();

      parents.add(prior.create());
    }
Пример #5
0
 public CommitBuilder parent(RevCommit p) throws Exception {
   if (parents.isEmpty()) {
     DirCacheBuilder b = tree.builder();
     parseBody(p);
     b.addTree(new byte[0], DirCacheEntry.STAGE_0, pool.getObjectReader(), p.getTree());
     b.finish();
   }
   parents.add(p);
   return this;
 }
Пример #6
0
 protected DirCache readTree(RevTree tree)
     throws IOException, MissingObjectException, IncorrectObjectTypeException {
   DirCache dc = DirCache.newInCore();
   if (tree != null) {
     DirCacheBuilder b = dc.builder();
     b.addTree(new byte[0], DirCacheEntry.STAGE_0, reader, tree);
     b.finish();
   }
   return dc;
 }
Пример #7
0
  /**
   * The resolve conflict way of three way merging
   *
   * @param baseTree
   * @param headTree
   * @param mergeTree
   * @param ignoreConflicts Controls what to do in case a content-merge is done and a conflict is
   *     detected. The default setting for this should be <code>false</code>. In this case the
   *     working tree file is filled with new content (containing conflict markers) and the index is
   *     filled with multiple stages containing BASE, OURS and THEIRS content. Having such non-0
   *     stages is the sign to git tools that there are still conflicts for that path.
   *     <p>If <code>true</code> is specified the behavior is different. In case a conflict is
   *     detected the working tree file is again filled with new content (containing conflict
   *     markers). But also stage 0 of the index is filled with that content. No other stages are
   *     filled. Means: there is no conflict on that path but the new content (including conflict
   *     markers) is stored as successful merge result. This is needed in the context of {@link
   *     RecursiveMerger} where when determining merge bases we don't want to deal with
   *     content-merge conflicts.
   * @return whether the trees merged cleanly
   * @throws IOException
   * @since 3.5
   */
  protected boolean mergeTrees(
      AbstractTreeIterator baseTree, RevTree headTree, RevTree mergeTree, boolean ignoreConflicts)
      throws IOException {

    builder = dircache.builder();
    DirCacheBuildIterator buildIt = new DirCacheBuildIterator(builder);

    tw = new NameConflictTreeWalk(reader);
    tw.addTree(baseTree);
    tw.addTree(headTree);
    tw.addTree(mergeTree);
    tw.addTree(buildIt);
    if (workingTreeIterator != null) {
      tw.addTree(workingTreeIterator);
    } else {
      tw.setFilter(TreeFilter.ANY_DIFF);
    }

    if (!mergeTreeWalk(tw, ignoreConflicts)) {
      return false;
    }

    if (!inCore) {
      // No problem found. The only thing left to be done is to
      // checkout all files from "theirs" which have been selected to
      // go into the new index.
      checkout();

      // All content-merges are successfully done. If we can now write the
      // new index we are on quite safe ground. Even if the checkout of
      // files coming from "theirs" fails the user can work around such
      // failures by checking out the index again.
      if (!builder.commit()) {
        cleanUp();
        throw new IndexWriteException();
      }
      builder = null;

    } else {
      builder.finish();
      builder = null;
    }

    if (getUnmergedPaths().isEmpty() && !failed()) {
      resultTree = dircache.writeTree(getObjectInserter());
      return true;
    } else {
      resultTree = null;
      return false;
    }
  }
Пример #8
0
 private static DirCache readTree(final Repository pdb, final Ref branch)
     throws MissingObjectException, IncorrectObjectTypeException, IOException {
   try (RevWalk rw = new RevWalk(pdb)) {
     final DirCache dc = DirCache.newInCore();
     final DirCacheBuilder b = dc.builder();
     b.addTree(
         new byte[0], // no prefix path
         DirCacheEntry.STAGE_0, // standard stage
         pdb.newObjectReader(),
         rw.parseTree(branch.getObjectId()));
     b.finish();
     return dc;
   }
 }
Пример #9
0
 /**
  * Construct a tree from a specific listing of file entries.
  *
  * @param entries the files to include in the tree. The collection does not need to be sorted
  *     properly and may be empty.
  * @return reference to the tree specified by the entry list.
  * @throws Exception
  */
 public RevTree tree(final DirCacheEntry... entries) throws Exception {
   final DirCache dc = DirCache.newInCore();
   final DirCacheBuilder b = dc.builder();
   for (final DirCacheEntry e : entries) b.add(e);
   b.finish();
   ObjectId root;
   try {
     root = dc.writeTree(inserter);
     inserter.flush();
   } finally {
     inserter.release();
   }
   return pool.lookupTree(root);
 }
Пример #10
0
  @Test
  public void testEntriesWithin() throws Exception {
    final DirCache dc = db.readDirCache();

    final String[] paths = {"a.", "a/b", "a/c", "a/d", "a0b"};
    final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
    for (int i = 0; i < paths.length; i++) {
      ents[i] = new DirCacheEntry(paths[i]);
      ents[i].setFileMode(FileMode.REGULAR_FILE);
    }
    final int aFirst = 1;
    final int aLast = 3;

    final DirCacheBuilder b = dc.builder();
    for (int i = 0; i < ents.length; i++) b.add(ents[i]);
    b.finish();

    assertEquals(paths.length, dc.getEntryCount());
    for (int i = 0; i < ents.length; i++) assertSame(ents[i], dc.getEntry(i));

    {
      final DirCacheEntry[] aContents = dc.getEntriesWithin("a");
      assertNotNull(aContents);
      assertEquals(aLast - aFirst + 1, aContents.length);
      for (int i = aFirst, j = 0; i <= aLast; i++, j++) assertSame(ents[i], aContents[j]);
    }
    {
      final DirCacheEntry[] aContents = dc.getEntriesWithin("a/");
      assertNotNull(aContents);
      assertEquals(aLast - aFirst + 1, aContents.length);
      for (int i = aFirst, j = 0; i <= aLast; i++, j++) assertSame(ents[i], aContents[j]);
    }
    {
      final DirCacheEntry[] aContents = dc.getEntriesWithin("");
      assertNotNull(aContents);
      assertEquals(ents.length, aContents.length);
      for (int i = 0; i < ents.length; i++) assertSame(ents[i], aContents[i]);
    }

    assertNotNull(dc.getEntriesWithin("a."));
    assertEquals(0, dc.getEntriesWithin("a.").length);

    assertNotNull(dc.getEntriesWithin("a0b"));
    assertEquals(0, dc.getEntriesWithin("a0b.").length);

    assertNotNull(dc.getEntriesWithin("zoo"));
    assertEquals(0, dc.getEntriesWithin("zoo.").length);
  }
Пример #11
0
  @Test
  public void testDetectUnmergedPaths() throws Exception {
    final DirCache dc = db.readDirCache();
    final DirCacheEntry[] ents = new DirCacheEntry[3];

    ents[0] = new DirCacheEntry("a", 1);
    ents[0].setFileMode(FileMode.REGULAR_FILE);
    ents[1] = new DirCacheEntry("a", 2);
    ents[1].setFileMode(FileMode.REGULAR_FILE);
    ents[2] = new DirCacheEntry("a", 3);
    ents[2].setFileMode(FileMode.REGULAR_FILE);

    final DirCacheBuilder b = dc.builder();
    for (int i = 0; i < ents.length; i++) b.add(ents[i]);
    b.finish();
    assertTrue(dc.hasUnmergedPaths());
  }
  /**
   * Writes a file to the tickets branch.
   *
   * @param db
   * @param file
   * @param content
   * @param createdBy
   * @param msg
   */
  private void writeTicketsFile(
      Repository db, String file, String content, String createdBy, String msg) {
    if (getTicketsBranch(db) == null) {
      createTicketsBranch(db);
    }

    DirCache newIndex = DirCache.newInCore();
    DirCacheBuilder builder = newIndex.builder();

    try (ObjectInserter inserter = db.newObjectInserter()) {
      // create an index entry for the revised index
      final DirCacheEntry idIndexEntry = new DirCacheEntry(file);
      idIndexEntry.setLength(content.length());
      idIndexEntry.setLastModified(System.currentTimeMillis());
      idIndexEntry.setFileMode(FileMode.REGULAR_FILE);

      // insert new ticket index
      idIndexEntry.setObjectId(
          inserter.insert(
              org.eclipse.jgit.lib.Constants.OBJ_BLOB, content.getBytes(Constants.ENCODING)));

      // add to temporary in-core index
      builder.add(idIndexEntry);

      Set<String> ignorePaths = new HashSet<String>();
      ignorePaths.add(file);

      for (DirCacheEntry entry : getTreeEntries(db, ignorePaths)) {
        builder.add(entry);
      }

      // finish temporary in-core index used for this commit
      builder.finish();

      // commit the change
      commitIndex(db, newIndex, createdBy, msg);

    } catch (ConcurrentRefUpdateException e) {
      log.error("", e);
    } catch (IOException e) {
      log.error("", e);
    }
  }
Пример #13
0
  /**
   * Scan head, index and merge tree. Used during normal checkout or merge operations.
   *
   * @throws CorruptObjectException
   * @throws IOException
   */
  public void preScanTwoTrees() throws CorruptObjectException, IOException {
    removed.clear();
    updated.clear();
    conflicts.clear();
    walk = new NameConflictTreeWalk(repo);
    builder = dc.builder();

    addTree(walk, headCommitTree);
    addTree(walk, mergeCommitTree);
    walk.addTree(new DirCacheBuildIterator(builder));
    walk.addTree(workingTree);

    while (walk.next()) {
      processEntry(
          walk.getTree(0, CanonicalTreeParser.class),
          walk.getTree(1, CanonicalTreeParser.class),
          walk.getTree(2, DirCacheBuildIterator.class),
          walk.getTree(3, WorkingTreeIterator.class));
      if (walk.isSubtree()) walk.enterSubtree();
    }
  }
Пример #14
0
  @Test
  public void testBuildThenClear() throws Exception {
    final DirCache dc = db.readDirCache();

    final String[] paths = {"a-", "a.b", "a/b", "a0b"};
    final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
    for (int i = 0; i < paths.length; i++) {
      ents[i] = new DirCacheEntry(paths[i]);
      ents[i].setFileMode(FileMode.REGULAR_FILE);
    }

    final DirCacheBuilder b = dc.builder();
    for (int i = 0; i < ents.length; i++) b.add(ents[i]);
    b.finish();
    assertFalse(dc.hasUnmergedPaths());

    assertEquals(paths.length, dc.getEntryCount());
    dc.clear();
    assertEquals(0, dc.getEntryCount());
    assertFalse(dc.hasUnmergedPaths());
  }
Пример #15
0
  /**
   * Scan index and merge tree (no HEAD). Used e.g. for initial checkout when there is no head yet.
   *
   * @throws MissingObjectException
   * @throws IncorrectObjectTypeException
   * @throws CorruptObjectException
   * @throws IOException
   */
  public void prescanOneTree()
      throws MissingObjectException, IncorrectObjectTypeException, CorruptObjectException,
          IOException {
    removed.clear();
    updated.clear();
    conflicts.clear();

    builder = dc.builder();

    walk = new NameConflictTreeWalk(repo);
    walk.addTree(mergeCommitTree);
    walk.addTree(new DirCacheBuildIterator(builder));
    walk.addTree(workingTree);

    while (walk.next()) {
      processEntry(
          walk.getTree(0, CanonicalTreeParser.class),
          walk.getTree(1, DirCacheBuildIterator.class),
          walk.getTree(2, WorkingTreeIterator.class));
      if (walk.isSubtree()) walk.enterSubtree();
    }
    conflicts.removeAll(removed);
  }
Пример #16
0
  @Test
  public void testRejectInvalidWindowsPaths() throws Exception {
    SystemReader.setInstance(
        new MockSystemReader() {
          {
            setUnix();
          }
        });

    String path = "src/con.txt";
    DirCache dc = db.lockDirCache();
    DirCacheBuilder b = dc.builder();
    DirCacheEntry e = new DirCacheEntry(path);
    e.setFileMode(FileMode.REGULAR_FILE);
    try (ObjectInserter.Formatter formatter = new ObjectInserter.Formatter()) {
      e.setObjectId(formatter.idFor(Constants.OBJ_BLOB, Constants.encode(path)));
    }
    b.add(e);
    b.commit();
    db.readDirCache();

    SystemReader.setInstance(
        new MockSystemReader() {
          {
            setWindows();
          }
        });

    try {
      db.readDirCache();
      fail("should have rejected " + path);
    } catch (CorruptObjectException err) {
      assertEquals(MessageFormat.format(JGitText.get().invalidPath, path), err.getMessage());
      assertNotNull(err.getCause());
      assertEquals("invalid name 'CON'", err.getCause().getMessage());
    }
  }
Пример #17
0
  private DirCache createTemporaryIndex(ObjectId headId, DirCache index, RevWalk rw)
      throws IOException {
    ObjectInserter inserter = null;

    // get DirCacheBuilder for existing index
    DirCacheBuilder existingBuilder = index.builder();

    // get DirCacheBuilder for newly created in-core index to build a
    // temporary index for this commit
    DirCache inCoreIndex = DirCache.newInCore();
    DirCacheBuilder tempBuilder = inCoreIndex.builder();

    onlyProcessed = new boolean[only.size()];
    boolean emptyCommit = true;

    try (TreeWalk treeWalk = new TreeWalk(repo)) {
      treeWalk.setOperationType(OperationType.CHECKIN_OP);
      int dcIdx = treeWalk.addTree(new DirCacheBuildIterator(existingBuilder));
      FileTreeIterator fti = new FileTreeIterator(repo);
      fti.setDirCacheIterator(treeWalk, 0);
      int fIdx = treeWalk.addTree(fti);
      int hIdx = -1;
      if (headId != null) hIdx = treeWalk.addTree(rw.parseTree(headId));
      treeWalk.setRecursive(true);

      String lastAddedFile = null;
      while (treeWalk.next()) {
        String path = treeWalk.getPathString();
        // check if current entry's path matches a specified path
        int pos = lookupOnly(path);

        CanonicalTreeParser hTree = null;
        if (hIdx != -1) hTree = treeWalk.getTree(hIdx, CanonicalTreeParser.class);

        DirCacheIterator dcTree = treeWalk.getTree(dcIdx, DirCacheIterator.class);

        if (pos >= 0) {
          // include entry in commit

          FileTreeIterator fTree = treeWalk.getTree(fIdx, FileTreeIterator.class);

          // check if entry refers to a tracked file
          boolean tracked = dcTree != null || hTree != null;
          if (!tracked) continue;

          // for an unmerged path, DirCacheBuildIterator will yield 3
          // entries, we only want to add one
          if (path.equals(lastAddedFile)) continue;

          lastAddedFile = path;

          if (fTree != null) {
            // create a new DirCacheEntry with data retrieved from
            // disk
            final DirCacheEntry dcEntry = new DirCacheEntry(path);
            long entryLength = fTree.getEntryLength();
            dcEntry.setLength(entryLength);
            dcEntry.setLastModified(fTree.getEntryLastModified());
            dcEntry.setFileMode(fTree.getIndexFileMode(dcTree));

            boolean objectExists =
                (dcTree != null && fTree.idEqual(dcTree))
                    || (hTree != null && fTree.idEqual(hTree));
            if (objectExists) {
              dcEntry.setObjectId(fTree.getEntryObjectId());
            } else {
              if (FileMode.GITLINK.equals(dcEntry.getFileMode()))
                dcEntry.setObjectId(fTree.getEntryObjectId());
              else {
                // insert object
                if (inserter == null) inserter = repo.newObjectInserter();
                long contentLength = fTree.getEntryContentLength();
                InputStream inputStream = fTree.openEntryStream();
                try {
                  dcEntry.setObjectId(
                      inserter.insert(Constants.OBJ_BLOB, contentLength, inputStream));
                } finally {
                  inputStream.close();
                }
              }
            }

            // add to existing index
            existingBuilder.add(dcEntry);
            // add to temporary in-core index
            tempBuilder.add(dcEntry);

            if (emptyCommit
                && (hTree == null
                    || !hTree.idEqual(fTree)
                    || hTree.getEntryRawMode() != fTree.getEntryRawMode()))
              // this is a change
              emptyCommit = false;
          } else {
            // if no file exists on disk, neither add it to
            // index nor to temporary in-core index

            if (emptyCommit && hTree != null)
              // this is a change
              emptyCommit = false;
          }

          // keep track of processed path
          onlyProcessed[pos] = true;
        } else {
          // add entries from HEAD for all other paths
          if (hTree != null) {
            // create a new DirCacheEntry with data retrieved from
            // HEAD
            final DirCacheEntry dcEntry = new DirCacheEntry(path);
            dcEntry.setObjectId(hTree.getEntryObjectId());
            dcEntry.setFileMode(hTree.getEntryFileMode());

            // add to temporary in-core index
            tempBuilder.add(dcEntry);
          }

          // preserve existing entry in index
          if (dcTree != null) existingBuilder.add(dcTree.getDirCacheEntry());
        }
      }
    }

    // there must be no unprocessed paths left at this point; otherwise an
    // untracked or unknown path has been specified
    for (int i = 0; i < onlyProcessed.length; i++)
      if (!onlyProcessed[i])
        throw new JGitInternalException(
            MessageFormat.format(JGitText.get().entryNotFoundByPath, only.get(i)));

    // there must be at least one change
    if (emptyCommit) throw new JGitInternalException(JGitText.get().emptyCommit);

    // update index
    existingBuilder.commit();
    // finish temporary in-core index used for this commit
    tempBuilder.finish();
    return inCoreIndex;
  }
  /**
   * Deletes a ticket from the repository.
   *
   * @param ticket
   * @return true if successful
   */
  @Override
  protected synchronized boolean deleteTicketImpl(
      RepositoryModel repository, TicketModel ticket, String deletedBy) {
    if (ticket == null) {
      throw new RuntimeException("must specify a ticket!");
    }

    boolean success = false;
    Repository db = repositoryManager.getRepository(ticket.repository);
    try {
      RefModel ticketsBranch = getTicketsBranch(db);

      if (ticketsBranch == null) {
        throw new RuntimeException(BRANCH + " does not exist!");
      }
      String ticketPath = toTicketPath(ticket.number);

      try {
        ObjectId treeId = db.resolve(BRANCH + "^{tree}");

        // Create the in-memory index of the new/updated ticket
        DirCache index = DirCache.newInCore();
        DirCacheBuilder builder = index.builder();

        // Traverse HEAD to add all other paths
        try (TreeWalk treeWalk = new TreeWalk(db)) {
          int hIdx = -1;
          if (treeId != null) {
            hIdx = treeWalk.addTree(treeId);
          }
          treeWalk.setRecursive(true);
          while (treeWalk.next()) {
            String path = treeWalk.getPathString();
            CanonicalTreeParser hTree = null;
            if (hIdx != -1) {
              hTree = treeWalk.getTree(hIdx, CanonicalTreeParser.class);
            }
            if (!path.startsWith(ticketPath)) {
              // add entries from HEAD for all other paths
              if (hTree != null) {
                final DirCacheEntry entry = new DirCacheEntry(path);
                entry.setObjectId(hTree.getEntryObjectId());
                entry.setFileMode(hTree.getEntryFileMode());

                // add to temporary in-core index
                builder.add(entry);
              }
            }
          }
        }

        // finish temporary in-core index used for this commit
        builder.finish();

        success = commitIndex(db, index, deletedBy, "- " + ticket.number);

      } catch (Throwable t) {
        log.error(
            MessageFormat.format(
                "Failed to delete ticket {0,number,0} from {1}", ticket.number, db.getDirectory()),
            t);
      }
    } finally {
      db.close();
    }
    return success;
  }