Browse Source

CLI status should support --porcelain

Add support for the machine-readable output format along with the
existing default long format.

Bug: 419968
Change-Id: I37fe5121b4c9dbae1106b1d18e9fdc134070a9dd
Signed-off-by: Kaloyan Raev <kaloyan.r@zend.com>
tags/v3.2.0.201312181205-r
Kaloyan Raev 10 years ago
parent
commit
7026658ac8

+ 118
- 0
org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/StatusTest.java View File

@@ -213,4 +213,122 @@ public class StatusTest extends CLIRepositoryTestCase {
"" //
}, execute("git status")); //
}

@Test
public void testStatusPorcelain() throws Exception {
Git git = new Git(db);
// Write all files
writeTrashFile("tracked", "tracked");
writeTrashFile("stagedNew", "stagedNew");
writeTrashFile("stagedModified", "stagedModified");
writeTrashFile("stagedDeleted", "stagedDeleted");
writeTrashFile("trackedModified", "trackedModified");
writeTrashFile("trackedDeleted", "trackedDeleted");
writeTrashFile("untracked", "untracked");
// Test untracked
assertArrayOfLinesEquals(new String[] { // git status output
"?? stagedDeleted", //
"?? stagedModified", //
"?? stagedNew", //
"?? tracked", //
"?? trackedDeleted", //
"?? trackedModified", //
"?? untracked", //
"" //
}, execute("git status --porcelain")); //
// Add to index
git.add().addFilepattern("tracked").call();
git.add().addFilepattern("stagedModified").call();
git.add().addFilepattern("stagedDeleted").call();
git.add().addFilepattern("trackedModified").call();
git.add().addFilepattern("trackedDeleted").call();
// Test staged count
assertArrayOfLinesEquals(new String[] { // git status output
"A stagedDeleted", //
"A stagedModified", //
"A tracked", //
"A trackedDeleted", //
"A trackedModified", //
"?? stagedNew", //
"?? untracked", //
"" //
}, execute("git status --porcelain")); //
// Commit
git.commit().setMessage("initial commit").call();
assertArrayOfLinesEquals(new String[] { // git status output
"?? stagedNew", //
"?? untracked", //
"" //
}, execute("git status --porcelain")); //
// Make some changes and stage them
writeTrashFile("stagedModified", "stagedModified modified");
deleteTrashFile("stagedDeleted");
writeTrashFile("trackedModified", "trackedModified modified");
deleteTrashFile("trackedDeleted");
git.add().addFilepattern("stagedModified").call();
git.rm().addFilepattern("stagedDeleted").call();
git.add().addFilepattern("stagedNew").call();
// Test staged/not-staged status
assertArrayOfLinesEquals(new String[] { // git status output
"D stagedDeleted", //
"M stagedModified", //
"A stagedNew", //
" D trackedDeleted", //
" M trackedModified", //
"?? untracked", //
"" //
}, execute("git status --porcelain")); //
// Create unmerged file
writeTrashFile("unmerged", "unmerged");
git.add().addFilepattern("unmerged").call();
// Commit pending changes
git.add().addFilepattern("trackedModified").call();
git.rm().addFilepattern("trackedDeleted").call();
git.commit().setMessage("commit before branching").call();
assertArrayOfLinesEquals(new String[] { // git status output
"?? untracked", //
"" //
}, execute("git status --porcelain")); //
// Checkout new branch
git.checkout().setCreateBranch(true).setName("test").call();
// Test branch status
assertArrayOfLinesEquals(new String[] { // git status output
"?? untracked", //
"" //
}, execute("git status --porcelain")); //
// Commit change and checkout master again
writeTrashFile("unmerged", "changed in test branch");
git.add().addFilepattern("unmerged").call();
RevCommit testBranch = git.commit()
.setMessage("changed unmerged in test branch").call();
assertArrayOfLinesEquals(new String[] { // git status output
"?? untracked", //
"" //
}, execute("git status --porcelain")); //
git.checkout().setName("master").call();
// Change the same file and commit
writeTrashFile("unmerged", "changed in master branch");
git.add().addFilepattern("unmerged").call();
git.commit().setMessage("changed unmerged in master branch").call();
assertArrayOfLinesEquals(new String[] { // git status output
"?? untracked", //
"" //
}, execute("git status --porcelain")); //
// Merge test branch into master
git.merge().include(testBranch.getId()).call();
// Test unmerged status
assertArrayOfLinesEquals(new String[] { // git status output
"UU unmerged", //
"?? untracked", //
"" //
}, execute("git status --porcelain")); //
// Test detached head
String commitId = db.getRef(Constants.MASTER).getObjectId().name();
git.checkout().setName(commitId).call();
assertArrayOfLinesEquals(new String[] { // git status output
"UU unmerged", //
"?? untracked", //
"" //
}, execute("git status --porcelain")); //
}
}

+ 1
- 0
org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties View File

@@ -282,6 +282,7 @@ usage_inputOutputFile=Input/output file
usage_listBothRemoteTrackingAndLocalBranches=list both remote-tracking and local branches
usage_listCreateOrDeleteBranches=List, create, or delete branches
usage_logAllPretty=format:%H %ct %P' output=log --all '--pretty=format:%H %ct %P' output
usage_machineReadableOutput=machine-readable output
usage_manageReflogInformation=Manage reflog information
usage_mergeFf=When the merge resolves as a fast-forward, only update the branch pointer, without creating a merge commit.
usage_mergeNoFf=Create a merge commit even when the merge resolves as a fast-forward.

+ 117
- 8
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java View File

@@ -50,6 +50,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.StatusCommand;
@@ -71,26 +72,134 @@ class Status extends TextBuiltin {

protected final String statusFileListFormatUnmerged = CLIText.get().statusFileListFormatUnmerged;

@Option(name = "--porcelain", usage = "usage_machineReadableOutput")
protected boolean porcelain;

@Option(name = "--", metaVar = "metaVar_path", multiValued = true)
protected List<String> filterPaths;

@Override
protected void run() throws Exception {
StatusCommand statusCommand = new Git(db).status();
if (filterPaths != null && filterPaths.size() > 0)
for (String path : filterPaths)
statusCommand.addPath(path);
org.eclipse.jgit.api.Status status = statusCommand.call();
printStatus(status);
}

private void printStatus(org.eclipse.jgit.api.Status status)
throws IOException {
if (porcelain)
printPorcelainStatus(status);
else
printLongStatus(status);
}

private void printPorcelainStatus(org.eclipse.jgit.api.Status status)
throws IOException {

Collection<String> added = status.getAdded();
Collection<String> changed = status.getChanged();
Collection<String> removed = status.getRemoved();
Collection<String> modified = status.getModified();
Collection<String> missing = status.getMissing();
Map<String, StageState> conflicting = status.getConflictingStageState();

// build a sorted list of all paths except untracked and ignored
TreeSet<String> sorted = new TreeSet<String>();
sorted.addAll(added);
sorted.addAll(changed);
sorted.addAll(removed);
sorted.addAll(modified);
sorted.addAll(missing);
sorted.addAll(conflicting.keySet());

// list each path
for (String path : sorted) {
char x = ' ';
char y = ' ';

if (added.contains(path))
x = 'A';
else if (changed.contains(path))
x = 'M';
else if (removed.contains(path))
x = 'D';

if (modified.contains(path))
y = 'M';
else if (missing.contains(path))
y = 'D';

if (conflicting.containsKey(path)) {
StageState stageState = conflicting.get(path);

switch (stageState) {
case BOTH_DELETED:
x = 'D';
y = 'D';
break;
case ADDED_BY_US:
x = 'A';
y = 'U';
break;
case DELETED_BY_THEM:
x = 'U';
y = 'D';
break;
case ADDED_BY_THEM:
x = 'U';
y = 'A';
break;
case DELETED_BY_US:
x = 'D';
y = 'U';
break;
case BOTH_ADDED:
x = 'A';
y = 'A';
break;
case BOTH_MODIFIED:
x = 'U';
y = 'U';
break;
default:
throw new IllegalArgumentException("Unknown StageState: " //$NON-NLS-1$
+ stageState);
}
}

printPorcelainLine(x, y, path);
}

// untracked are always at the end of the list
TreeSet<String> untracked = new TreeSet<String>(status.getUntracked());
for (String path : untracked)
printPorcelainLine('?', '?', path);
}

private void printPorcelainLine(char x, char y, String path)
throws IOException {
StringBuilder lineBuilder = new StringBuilder();
lineBuilder.append(x).append(y).append(' ').append(path);
outw.println(lineBuilder.toString());
}

private void printLongStatus(org.eclipse.jgit.api.Status status)
throws IOException {
// Print current branch name
final Ref head = db.getRef(Constants.HEAD);
boolean firstHeader = true;
if (head != null && head.isSymbolic()) {
String branch = Repository.shortenRefName(head.getLeaf().getName());
outw.println(CLIText.formatLine(
MessageFormat.format(CLIText.get().onBranch, branch)));
outw.println(CLIText.formatLine(MessageFormat.format(
CLIText.get().onBranch, branch)));
} else
outw.println(CLIText.formatLine(CLIText.get().notOnAnyBranch));

// List changes
StatusCommand statusCommand = new Git(db).status();
if (filterPaths != null && filterPaths.size() > 0)
for (String path : filterPaths)
statusCommand.addPath(path);
org.eclipse.jgit.api.Status status = statusCommand.call();
boolean firstHeader = true;

Collection<String> added = status.getAdded();
Collection<String> changed = status.getChanged();
Collection<String> removed = status.getRemoved();

Loading…
Cancel
Save