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");