Skip to content

Commit 8dcba40

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 41f9d92 commit 8dcba40

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
@@ -1811,6 +1811,289 @@ static void wt_porcelain_print(struct wt_status *s)
18111811
wt_shortstatus_print(s);
18121812
}
18131813

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

0 commit comments

Comments
 (0)