Skip to content

Commit 288fd85

Browse files
jeffhostetlerdscho
authored andcommitted
status: print per-file porcelain v2 status data
Print per-file information in porcelain v2 format. Signed-off-by: Jeff Hostetler <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent c6d0887 commit 288fd85

File tree

1 file changed

+284
-1
lines changed

1 file changed

+284
-1
lines changed

wt-status.c

Lines changed: 284 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1814,6 +1814,289 @@ static void wt_porcelain_print(struct wt_status *s)
18141814
wt_shortstatus_print(s);
18151815
}
18161816

1817+
/*
1818+
* Convert various submodule status values into a
1819+
* fixed-length string of characters in the buffer provided.
1820+
*/
1821+
static void wt_porcelain_v2_submodule_state(
1822+
struct wt_status_change_data *d,
1823+
char sub[5])
1824+
{
1825+
if (S_ISGITLINK(d->mode_head) ||
1826+
S_ISGITLINK(d->mode_index) ||
1827+
S_ISGITLINK(d->mode_worktree)) {
1828+
sub[0] = 'S';
1829+
sub[1] = d->new_submodule_commits ? 'C' : '.';
1830+
sub[2] = (d->dirty_submodule & DIRTY_SUBMODULE_MODIFIED) ? 'M' : '.';
1831+
sub[3] = (d->dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) ? 'U' : '.';
1832+
} else {
1833+
sub[0] = 'N';
1834+
sub[1] = '.';
1835+
sub[2] = '.';
1836+
sub[3] = '.';
1837+
}
1838+
sub[4] = 0;
1839+
}
1840+
1841+
/*
1842+
* Fix-up changed entries before we print them.
1843+
*/
1844+
static void wt_porcelain_v2_fix_up_changed(
1845+
struct string_list_item *it,
1846+
struct wt_status *s)
1847+
{
1848+
struct wt_status_change_data *d = it->util;
1849+
1850+
if (!d->index_status) {
1851+
/*
1852+
* This entry is unchanged in the index (relative to the head).
1853+
* Therefore, the collect_updated_cb was never called for this
1854+
* entry (during the head-vs-index scan) and so the head column
1855+
* fields were never set.
1856+
*
1857+
* We must have data for the index column (from the
1858+
* index-vs-worktree scan (otherwise, this entry should not be
1859+
* in the list of changes)).
1860+
*
1861+
* Copy index column fields to the head column, so that our
1862+
* output looks complete.
1863+
*/
1864+
assert(d->mode_head == 0);
1865+
d->mode_head = d->mode_index;
1866+
oidcpy(&d->oid_head, &d->oid_index);
1867+
}
1868+
1869+
if (!d->worktree_status) {
1870+
/*
1871+
* This entry is unchanged in the worktree (relative to the index).
1872+
* Therefore, the collect_changed_cb was never called for this entry
1873+
* (during the index-vs-worktree scan) and so the worktree column
1874+
* fields were never set.
1875+
*
1876+
* We must have data for the index column (from the head-vs-index
1877+
* scan).
1878+
*
1879+
* Copy the index column fields to the worktree column so that
1880+
* our output looks complete.
1881+
*
1882+
* Note that we only have a mode field in the worktree column
1883+
* because the scan code tries really hard to not have to compute it.
1884+
*/
1885+
assert(d->mode_worktree == 0);
1886+
d->mode_worktree = d->mode_index;
1887+
}
1888+
}
1889+
1890+
/*
1891+
* Print porcelain v2 info for tracked entries with changes.
1892+
*/
1893+
static void wt_porcelain_v2_print_changed_entry(
1894+
struct string_list_item *it,
1895+
struct wt_status *s)
1896+
{
1897+
struct wt_status_change_data *d = it->util;
1898+
struct strbuf buf_index = STRBUF_INIT;
1899+
struct strbuf buf_head = STRBUF_INIT;
1900+
const char *path_index = NULL;
1901+
const char *path_head = NULL;
1902+
char key[3];
1903+
char submodule_token[5];
1904+
char sep_char, eol_char;
1905+
1906+
wt_porcelain_v2_fix_up_changed(it, s);
1907+
wt_porcelain_v2_submodule_state(d, submodule_token);
1908+
1909+
key[0] = d->index_status ? d->index_status : '.';
1910+
key[1] = d->worktree_status ? d->worktree_status : '.';
1911+
key[2] = 0;
1912+
1913+
if (s->null_termination) {
1914+
/*
1915+
* In -z mode, we DO NOT C-quote pathnames. Current path is ALWAYS first.
1916+
* A single NUL character separates them.
1917+
*/
1918+
sep_char = '\0';
1919+
eol_char = '\0';
1920+
path_index = it->string;
1921+
path_head = d->head_path;
1922+
} else {
1923+
/*
1924+
* Path(s) are C-quoted if necessary. Current path is ALWAYS first.
1925+
* The source path is only present when necessary.
1926+
* A single TAB separates them (because paths can contain spaces
1927+
* which are not escaped and C-quoting does escape TAB characters).
1928+
*/
1929+
sep_char = '\t';
1930+
eol_char = '\n';
1931+
path_index = quote_path(it->string, s->prefix, &buf_index);
1932+
if (d->head_path)
1933+
path_head = quote_path(d->head_path, s->prefix, &buf_head);
1934+
}
1935+
1936+
if (path_head)
1937+
fprintf(s->fp, "2 %s %s %06o %06o %06o %s %s %c%d %s%c%s%c",
1938+
key, submodule_token,
1939+
d->mode_head, d->mode_index, d->mode_worktree,
1940+
oid_to_hex(&d->oid_head), oid_to_hex(&d->oid_index),
1941+
key[0], d->score,
1942+
path_index, sep_char, path_head, eol_char);
1943+
else
1944+
fprintf(s->fp, "1 %s %s %06o %06o %06o %s %s %s%c",
1945+
key, submodule_token,
1946+
d->mode_head, d->mode_index, d->mode_worktree,
1947+
oid_to_hex(&d->oid_head), oid_to_hex(&d->oid_index),
1948+
path_index, eol_char);
1949+
1950+
strbuf_release(&buf_index);
1951+
strbuf_release(&buf_head);
1952+
}
1953+
1954+
/*
1955+
* Print porcelain v2 status info for unmerged entries.
1956+
*/
1957+
static void wt_porcelain_v2_print_unmerged_entry(
1958+
struct string_list_item *it,
1959+
struct wt_status *s)
1960+
{
1961+
struct wt_status_change_data *d = it->util;
1962+
const struct cache_entry *ce;
1963+
struct strbuf buf_index = STRBUF_INIT;
1964+
const char *path_index = NULL;
1965+
int pos, stage, sum;
1966+
struct {
1967+
int mode;
1968+
struct object_id oid;
1969+
} stages[3];
1970+
char *key;
1971+
char submodule_token[5];
1972+
char unmerged_prefix = 'u';
1973+
char eol_char = s->null_termination ? '\0' : '\n';
1974+
1975+
wt_porcelain_v2_submodule_state(d, submodule_token);
1976+
1977+
switch (d->stagemask) {
1978+
case 1: key = "DD"; break; /* both deleted */
1979+
case 2: key = "AU"; break; /* added by us */
1980+
case 3: key = "UD"; break; /* deleted by them */
1981+
case 4: key = "UA"; break; /* added by them */
1982+
case 5: key = "DU"; break; /* deleted by us */
1983+
case 6: key = "AA"; break; /* both added */
1984+
case 7: key = "UU"; break; /* both modified */
1985+
default:
1986+
die("BUG: unhandled unmerged status %x", d->stagemask);
1987+
}
1988+
1989+
/*
1990+
* Disregard d.aux.porcelain_v2 data that we accumulated
1991+
* for the head and index columns during the scans and
1992+
* replace with the actual stage data.
1993+
*
1994+
* Note that this is a last-one-wins for each the individual
1995+
* stage [123] columns in the event of multiple cache entries
1996+
* for same stage.
1997+
*/
1998+
memset(stages, 0, sizeof(stages));
1999+
sum = 0;
2000+
pos = cache_name_pos(it->string, strlen(it->string));
2001+
assert(pos < 0);
2002+
pos = -pos-1;
2003+
while (pos < active_nr) {
2004+
ce = active_cache[pos++];
2005+
stage = ce_stage(ce);
2006+
if (strcmp(ce->name, it->string) || !stage)
2007+
break;
2008+
stages[stage - 1].mode = ce->ce_mode;
2009+
hashcpy(stages[stage - 1].oid.hash, ce->sha1);
2010+
sum |= (1 << (stage - 1));
2011+
}
2012+
if (sum != d->stagemask)
2013+
die("BUG: observed stagemask 0x%x != expected stagemask 0x%x", sum, d->stagemask);
2014+
2015+
if (s->null_termination)
2016+
path_index = it->string;
2017+
else
2018+
path_index = quote_path(it->string, s->prefix, &buf_index);
2019+
2020+
fprintf(s->fp, "%c %s %s %06o %06o %06o %06o %s %s %s %s%c",
2021+
unmerged_prefix, key, submodule_token,
2022+
stages[0].mode, /* stage 1 */
2023+
stages[1].mode, /* stage 2 */
2024+
stages[2].mode, /* stage 3 */
2025+
d->mode_worktree,
2026+
oid_to_hex(&stages[0].oid), /* stage 1 */
2027+
oid_to_hex(&stages[1].oid), /* stage 2 */
2028+
oid_to_hex(&stages[2].oid), /* stage 3 */
2029+
path_index,
2030+
eol_char);
2031+
2032+
strbuf_release(&buf_index);
2033+
}
2034+
2035+
/*
2036+
* Print porcelain V2 status info for untracked and ignored entries.
2037+
*/
2038+
static void wt_porcelain_v2_print_other(
2039+
struct string_list_item *it,
2040+
struct wt_status *s,
2041+
char prefix)
2042+
{
2043+
struct strbuf buf = STRBUF_INIT;
2044+
const char *path;
2045+
char eol_char;
2046+
2047+
if (s->null_termination) {
2048+
path = it->string;
2049+
eol_char = '\0';
2050+
} else {
2051+
path = quote_path(it->string, s->prefix, &buf);
2052+
eol_char = '\n';
2053+
}
2054+
2055+
fprintf(s->fp, "%c %s%c", prefix, path, eol_char);
2056+
2057+
strbuf_release(&buf);
2058+
}
2059+
2060+
/*
2061+
* Print porcelain V2 status.
2062+
*
2063+
* [<v2_changed_items>]*
2064+
* [<v2_unmerged_items>]*
2065+
* [<v2_untracked_items>]*
2066+
* [<v2_ignored_items>]*
2067+
*
2068+
*/
2069+
static void wt_porcelain_v2_print(struct wt_status *s)
2070+
{
2071+
struct wt_status_change_data *d;
2072+
struct string_list_item *it;
2073+
int i;
2074+
2075+
for (i = 0; i < s->change.nr; i++) {
2076+
it = &(s->change.items[i]);
2077+
d = it->util;
2078+
if (!d->stagemask)
2079+
wt_porcelain_v2_print_changed_entry(it, s);
2080+
}
2081+
2082+
for (i = 0; i < s->change.nr; i++) {
2083+
it = &(s->change.items[i]);
2084+
d = it->util;
2085+
if (d->stagemask)
2086+
wt_porcelain_v2_print_unmerged_entry(it, s);
2087+
}
2088+
2089+
for (i = 0; i < s->untracked.nr; i++) {
2090+
it = &(s->untracked.items[i]);
2091+
wt_porcelain_v2_print_other(it, s, '?');
2092+
}
2093+
2094+
for (i = 0; i < s->ignored.nr; i++) {
2095+
it = &(s->ignored.items[i]);
2096+
wt_porcelain_v2_print_other(it, s, '!');
2097+
}
2098+
}
2099+
18172100
void wt_status_print(struct wt_status *s)
18182101
{
18192102
switch (s->status_format) {
@@ -1824,7 +2107,7 @@ void wt_status_print(struct wt_status *s)
18242107
wt_porcelain_print(s);
18252108
break;
18262109
case STATUS_FORMAT_PORCELAIN_V2:
1827-
/* TODO */
2110+
wt_porcelain_v2_print(s);
18282111
break;
18292112
case STATUS_FORMAT_UNSPECIFIED:
18302113
die("BUG: finalize_deferred_config() should have been called");

0 commit comments

Comments
 (0)