status: print per-file porcelain v2 status data

Print per-file information in porcelain v2 format. Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

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