Skip to content

Commit a75d5ea

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 52e0938 commit a75d5ea

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
@@ -1815,6 +1815,289 @@ static void wt_porcelain_print(struct wt_status *s)
18151815
wt_shortstatus_print(s);
18161816
}
18171817

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

0 commit comments

Comments
 (0)