Show More
@@ -962,6 +962,26 impl<'on_disk> DirstateMap<'on_disk> { | |||||
962 | } |
|
962 | } | |
963 | } |
|
963 | } | |
964 |
|
964 | |||
|
965 | /// Sets the parameters for resetting a dirstate entry | |||
|
966 | pub struct DirstateEntryReset<'a> { | |||
|
967 | /// Which entry are we resetting | |||
|
968 | pub filename: &'a HgPath, | |||
|
969 | /// Whether the entry is tracked in the working copy | |||
|
970 | pub wc_tracked: bool, | |||
|
971 | /// Whether the entry is tracked in p1 | |||
|
972 | pub p1_tracked: bool, | |||
|
973 | /// Whether the entry has merge information | |||
|
974 | pub p2_info: bool, | |||
|
975 | /// Whether the entry's mtime should be trusted | |||
|
976 | pub has_meaningful_mtime: bool, | |||
|
977 | /// Information from the parent file data (from the manifest) | |||
|
978 | pub parent_file_data_opt: Option<ParentFileData>, | |||
|
979 | /// Set this to `true` if you are *certain* that there is no old entry for | |||
|
980 | /// this filename. Yield better performance in cases where we do a lot | |||
|
981 | /// of additions to the dirstate. | |||
|
982 | pub from_empty: bool, | |||
|
983 | } | |||
|
984 | ||||
965 | type DebugDirstateTuple<'a> = (&'a HgPath, (u8, i32, i32, i32)); |
|
985 | type DebugDirstateTuple<'a> = (&'a HgPath, (u8, i32, i32, i32)); | |
966 |
|
986 | |||
967 | impl OwningDirstateMap { |
|
987 | impl OwningDirstateMap { | |
@@ -1048,28 +1068,31 impl OwningDirstateMap { | |||||
1048 |
|
1068 | |||
1049 | pub fn reset_state( |
|
1069 | pub fn reset_state( | |
1050 | &mut self, |
|
1070 | &mut self, | |
1051 | filename: &HgPath, |
|
1071 | reset: DirstateEntryReset, | |
1052 | wc_tracked: bool, |
|
|||
1053 | p1_tracked: bool, |
|
|||
1054 | p2_info: bool, |
|
|||
1055 | has_meaningful_mtime: bool, |
|
|||
1056 | parent_file_data_opt: Option<ParentFileData>, |
|
|||
1057 | ) -> Result<(), DirstateError> { |
|
1072 | ) -> Result<(), DirstateError> { | |
1058 | if !(p1_tracked || p2_info || wc_tracked) { |
|
1073 | if !(reset.p1_tracked || reset.p2_info || reset.wc_tracked) { | |
1059 | self.drop_entry_and_copy_source(filename)?; |
|
1074 | self.drop_entry_and_copy_source(reset.filename)?; | |
1060 | return Ok(()); |
|
1075 | return Ok(()); | |
1061 | } |
|
1076 | } | |
1062 | self.copy_map_remove(filename)?; |
|
1077 | if !reset.from_empty { | |
1063 | let old_entry_opt = self.get(filename)?; |
|
1078 | self.copy_map_remove(reset.filename)?; | |
|
1079 | } | |||
|
1080 | ||||
|
1081 | let old_entry_opt = if reset.from_empty { | |||
|
1082 | None | |||
|
1083 | } else { | |||
|
1084 | self.get(reset.filename)? | |||
|
1085 | }; | |||
|
1086 | ||||
1064 | self.with_dmap_mut(|map| { |
|
1087 | self.with_dmap_mut(|map| { | |
1065 | map.reset_state( |
|
1088 | map.reset_state( | |
1066 | filename, |
|
1089 | reset.filename, | |
1067 | old_entry_opt, |
|
1090 | old_entry_opt, | |
1068 | wc_tracked, |
|
1091 | reset.wc_tracked, | |
1069 | p1_tracked, |
|
1092 | reset.p1_tracked, | |
1070 | p2_info, |
|
1093 | reset.p2_info, | |
1071 | has_meaningful_mtime, |
|
1094 | reset.has_meaningful_mtime, | |
1072 | parent_file_data_opt, |
|
1095 | reset.parent_file_data_opt, | |
1073 | ) |
|
1096 | ) | |
1074 | }) |
|
1097 | }) | |
1075 | } |
|
1098 | } | |
@@ -1643,39 +1666,79 mod tests { | |||||
1643 | // A file that was just added |
|
1666 | // A file that was just added | |
1644 | map.set_tracked(p(b"some/nested/path"))?; |
|
1667 | map.set_tracked(p(b"some/nested/path"))?; | |
1645 | // This has no information, the dirstate should ignore it |
|
1668 | // This has no information, the dirstate should ignore it | |
1646 | map.reset_state(p(b"some/file"), false, false, false, false, None)?; |
|
1669 | let reset = DirstateEntryReset { | |
|
1670 | filename: p(b"some/file"), | |||
|
1671 | wc_tracked: false, | |||
|
1672 | p1_tracked: false, | |||
|
1673 | p2_info: false, | |||
|
1674 | has_meaningful_mtime: false, | |||
|
1675 | parent_file_data_opt: None, | |||
|
1676 | from_empty: false, | |||
|
1677 | }; | |||
|
1678 | map.reset_state(reset)?; | |||
1647 | assert_does_not_exist(&map, b"some/file"); |
|
1679 | assert_does_not_exist(&map, b"some/file"); | |
1648 |
|
1680 | |||
1649 | // A file that was removed |
|
1681 | // A file that was removed | |
1650 | map.reset_state( |
|
1682 | let reset = DirstateEntryReset { | |
1651 | p(b"some/nested/file"), |
|
1683 | filename: p(b"some/nested/file"), | |
1652 | false, |
|
1684 | wc_tracked: false, | |
1653 | true, |
|
1685 | p1_tracked: true, | |
1654 | false, |
|
1686 | p2_info: false, | |
1655 | false, |
|
1687 | has_meaningful_mtime: false, | |
1656 | None, |
|
1688 | parent_file_data_opt: None, | |
1657 | )?; |
|
1689 | from_empty: false, | |
|
1690 | }; | |||
|
1691 | map.reset_state(reset)?; | |||
1658 | assert!(!map.get(p(b"some/nested/file"))?.unwrap().tracked()); |
|
1692 | assert!(!map.get(p(b"some/nested/file"))?.unwrap().tracked()); | |
1659 | // Only present in p2 |
|
1693 | // Only present in p2 | |
1660 | map.reset_state(p(b"some/file3"), false, false, true, false, None)?; |
|
1694 | let reset = DirstateEntryReset { | |
|
1695 | filename: p(b"some/file3"), | |||
|
1696 | wc_tracked: false, | |||
|
1697 | p1_tracked: false, | |||
|
1698 | p2_info: true, | |||
|
1699 | has_meaningful_mtime: false, | |||
|
1700 | parent_file_data_opt: None, | |||
|
1701 | from_empty: false, | |||
|
1702 | }; | |||
|
1703 | map.reset_state(reset)?; | |||
1661 | assert!(!map.get(p(b"some/file3"))?.unwrap().tracked()); |
|
1704 | assert!(!map.get(p(b"some/file3"))?.unwrap().tracked()); | |
1662 | // A file that was merged |
|
1705 | // A file that was merged | |
1663 | map.reset_state(p(b"root_file"), true, true, true, false, None)?; |
|
1706 | let reset = DirstateEntryReset { | |
|
1707 | filename: p(b"root_file"), | |||
|
1708 | wc_tracked: true, | |||
|
1709 | p1_tracked: true, | |||
|
1710 | p2_info: true, | |||
|
1711 | has_meaningful_mtime: false, | |||
|
1712 | parent_file_data_opt: None, | |||
|
1713 | from_empty: false, | |||
|
1714 | }; | |||
|
1715 | map.reset_state(reset)?; | |||
1664 | assert!(map.get(p(b"root_file"))?.unwrap().tracked()); |
|
1716 | assert!(map.get(p(b"root_file"))?.unwrap().tracked()); | |
1665 | // A file that is added, with info from p2 |
|
1717 | // A file that is added, with info from p2 | |
1666 | // XXX is that actually possible? |
|
1718 | // XXX is that actually possible? | |
1667 | map.reset_state(p(b"some/file2"), true, false, true, false, None)?; |
|
1719 | let reset = DirstateEntryReset { | |
|
1720 | filename: p(b"some/file2"), | |||
|
1721 | wc_tracked: true, | |||
|
1722 | p1_tracked: false, | |||
|
1723 | p2_info: true, | |||
|
1724 | has_meaningful_mtime: false, | |||
|
1725 | parent_file_data_opt: None, | |||
|
1726 | from_empty: false, | |||
|
1727 | }; | |||
|
1728 | map.reset_state(reset)?; | |||
1668 | assert!(map.get(p(b"some/file2"))?.unwrap().tracked()); |
|
1729 | assert!(map.get(p(b"some/file2"))?.unwrap().tracked()); | |
1669 | // A clean file |
|
1730 | // A clean file | |
1670 | // One layer without any files to test deletion cascade |
|
1731 | // One layer without any files to test deletion cascade | |
1671 | map.reset_state( |
|
1732 | let reset = DirstateEntryReset { | |
1672 | p(b"some/other/nested/path"), |
|
1733 | filename: p(b"some/other/nested/path"), | |
1673 | true, |
|
1734 | wc_tracked: true, | |
1674 | true, |
|
1735 | p1_tracked: true, | |
1675 | false, |
|
1736 | p2_info: false, | |
1676 | false, |
|
1737 | has_meaningful_mtime: false, | |
1677 | None, |
|
1738 | parent_file_data_opt: None, | |
1678 | )?; |
|
1739 | from_empty: false, | |
|
1740 | }; | |||
|
1741 | map.reset_state(reset)?; | |||
1679 | assert!(map.get(p(b"some/other/nested/path"))?.unwrap().tracked()); |
|
1742 | assert!(map.get(p(b"some/other/nested/path"))?.unwrap().tracked()); | |
1680 |
|
1743 | |||
1681 | assert_eq!(map.len(), 6); |
|
1744 | assert_eq!(map.len(), 6); | |
@@ -1738,13 +1801,49 mod tests { | |||||
1738 | let mut map = OwningDirstateMap::new_empty(vec![], None); |
|
1801 | let mut map = OwningDirstateMap::new_empty(vec![], None); | |
1739 |
|
1802 | |||
1740 | // Clean file |
|
1803 | // Clean file | |
1741 | map.reset_state(p(b"files/clean"), true, true, false, false, None)?; |
|
1804 | let reset = DirstateEntryReset { | |
|
1805 | filename: p(b"files/clean"), | |||
|
1806 | wc_tracked: true, | |||
|
1807 | p1_tracked: true, | |||
|
1808 | p2_info: false, | |||
|
1809 | has_meaningful_mtime: false, | |||
|
1810 | parent_file_data_opt: None, | |||
|
1811 | from_empty: false, | |||
|
1812 | }; | |||
|
1813 | map.reset_state(reset)?; | |||
1742 | // Merged file |
|
1814 | // Merged file | |
1743 | map.reset_state(p(b"files/from_p2"), true, true, true, false, None)?; |
|
1815 | let reset = DirstateEntryReset { | |
|
1816 | filename: p(b"files/from_p2"), | |||
|
1817 | wc_tracked: true, | |||
|
1818 | p1_tracked: true, | |||
|
1819 | p2_info: true, | |||
|
1820 | has_meaningful_mtime: false, | |||
|
1821 | parent_file_data_opt: None, | |||
|
1822 | from_empty: false, | |||
|
1823 | }; | |||
|
1824 | map.reset_state(reset)?; | |||
1744 | // Removed file |
|
1825 | // Removed file | |
1745 | map.reset_state(p(b"removed"), false, true, false, false, None)?; |
|
1826 | let reset = DirstateEntryReset { | |
|
1827 | filename: p(b"removed"), | |||
|
1828 | wc_tracked: false, | |||
|
1829 | p1_tracked: true, | |||
|
1830 | p2_info: false, | |||
|
1831 | has_meaningful_mtime: false, | |||
|
1832 | parent_file_data_opt: None, | |||
|
1833 | from_empty: false, | |||
|
1834 | }; | |||
|
1835 | map.reset_state(reset)?; | |||
1746 | // Added file |
|
1836 | // Added file | |
1747 | map.reset_state(p(b"files/added"), true, false, false, false, None)?; |
|
1837 | let reset = DirstateEntryReset { | |
|
1838 | filename: p(b"files/added"), | |||
|
1839 | wc_tracked: true, | |||
|
1840 | p1_tracked: false, | |||
|
1841 | p2_info: false, | |||
|
1842 | has_meaningful_mtime: false, | |||
|
1843 | parent_file_data_opt: None, | |||
|
1844 | from_empty: false, | |||
|
1845 | }; | |||
|
1846 | map.reset_state(reset)?; | |||
1748 | // Add copy |
|
1847 | // Add copy | |
1749 | map.copy_map_insert(p(b"files/clean"), p(b"clean_copy_source"))?; |
|
1848 | map.copy_map_insert(p(b"files/clean"), p(b"clean_copy_source"))?; | |
1750 | assert_eq!(map.copy_map_len(), 1); |
|
1849 | assert_eq!(map.copy_map_len(), 1); | |
@@ -1799,49 +1898,66 mod tests { | |||||
1799 | map.copy_map_insert(p(b"some/nested/added"), p(b"added_copy_source"))?; |
|
1898 | map.copy_map_insert(p(b"some/nested/added"), p(b"added_copy_source"))?; | |
1800 |
|
1899 | |||
1801 | // A file that was removed |
|
1900 | // A file that was removed | |
1802 | map.reset_state( |
|
1901 | let reset = DirstateEntryReset { | |
1803 | p(b"some/nested/removed"), |
|
1902 | filename: p(b"some/nested/removed"), | |
1804 | false, |
|
1903 | wc_tracked: false, | |
1805 | true, |
|
1904 | p1_tracked: true, | |
1806 | false, |
|
1905 | p2_info: false, | |
1807 | false, |
|
1906 | has_meaningful_mtime: false, | |
1808 | None, |
|
1907 | parent_file_data_opt: None, | |
1809 | )?; |
|
1908 | from_empty: false, | |
|
1909 | }; | |||
|
1910 | map.reset_state(reset)?; | |||
1810 | // Only present in p2 |
|
1911 | // Only present in p2 | |
1811 | map.reset_state( |
|
1912 | let reset = DirstateEntryReset { | |
1812 | p(b"other/p2_info_only"), |
|
1913 | filename: p(b"other/p2_info_only"), | |
1813 | false, |
|
1914 | wc_tracked: false, | |
1814 | false, |
|
1915 | p1_tracked: false, | |
1815 | true, |
|
1916 | p2_info: true, | |
1816 | false, |
|
1917 | has_meaningful_mtime: false, | |
1817 | None, |
|
1918 | parent_file_data_opt: None, | |
1818 | )?; |
|
1919 | from_empty: false, | |
|
1920 | }; | |||
|
1921 | map.reset_state(reset)?; | |||
1819 | map.copy_map_insert( |
|
1922 | map.copy_map_insert( | |
1820 | p(b"other/p2_info_only"), |
|
1923 | p(b"other/p2_info_only"), | |
1821 | p(b"other/p2_info_copy_source"), |
|
1924 | p(b"other/p2_info_copy_source"), | |
1822 | )?; |
|
1925 | )?; | |
1823 | // A file that was merged |
|
1926 | // A file that was merged | |
1824 | map.reset_state(p(b"merged"), true, true, true, false, None)?; |
|
1927 | let reset = DirstateEntryReset { | |
|
1928 | filename: p(b"merged"), | |||
|
1929 | wc_tracked: true, | |||
|
1930 | p1_tracked: true, | |||
|
1931 | p2_info: true, | |||
|
1932 | has_meaningful_mtime: false, | |||
|
1933 | parent_file_data_opt: None, | |||
|
1934 | from_empty: false, | |||
|
1935 | }; | |||
|
1936 | map.reset_state(reset)?; | |||
1825 | // A file that is added, with info from p2 |
|
1937 | // A file that is added, with info from p2 | |
1826 | // XXX is that actually possible? |
|
1938 | // XXX is that actually possible? | |
1827 | map.reset_state( |
|
1939 | let reset = DirstateEntryReset { | |
1828 | p(b"other/added_with_p2"), |
|
1940 | filename: p(b"other/added_with_p2"), | |
1829 | true, |
|
1941 | wc_tracked: true, | |
1830 | false, |
|
1942 | p1_tracked: false, | |
1831 | true, |
|
1943 | p2_info: true, | |
1832 | false, |
|
1944 | has_meaningful_mtime: false, | |
1833 | None, |
|
1945 | parent_file_data_opt: None, | |
1834 | )?; |
|
1946 | from_empty: false, | |
|
1947 | }; | |||
|
1948 | map.reset_state(reset)?; | |||
1835 | // One layer without any files to test deletion cascade |
|
1949 | // One layer without any files to test deletion cascade | |
1836 | // A clean file |
|
1950 | // A clean file | |
1837 | map.reset_state( |
|
1951 | let reset = DirstateEntryReset { | |
1838 | p(b"some/other/nested/clean"), |
|
1952 | filename: p(b"some/other/nested/clean"), | |
1839 | true, |
|
1953 | wc_tracked: true, | |
1840 | true, |
|
1954 | p1_tracked: true, | |
1841 | false, |
|
1955 | p2_info: false, | |
1842 | false, |
|
1956 | has_meaningful_mtime: false, | |
1843 | None, |
|
1957 | parent_file_data_opt: None, | |
1844 | )?; |
|
1958 | from_empty: false, | |
|
1959 | }; | |||
|
1960 | map.reset_state(reset)?; | |||
1845 |
|
1961 | |||
1846 | let (packed, metadata, _should_append, _old_data_size) = |
|
1962 | let (packed, metadata, _should_append, _old_data_size) = | |
1847 | map.pack_v2(DirstateMapWriteMode::ForceNewDataFile)?; |
|
1963 | map.pack_v2(DirstateMapWriteMode::ForceNewDataFile)?; |
@@ -14,7 +14,10 use cpython::{ | |||||
14 | exc, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList, PyNone, PyObject, |
|
14 | exc, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList, PyNone, PyObject, | |
15 | PyResult, Python, PythonObject, ToPyObject, UnsafePyLeaked, |
|
15 | PyResult, Python, PythonObject, ToPyObject, UnsafePyLeaked, | |
16 | }; |
|
16 | }; | |
17 | use hg::dirstate::{ParentFileData, TruncatedTimestamp}; |
|
17 | use hg::{ | |
|
18 | dirstate::{ParentFileData, TruncatedTimestamp}, | |||
|
19 | dirstate_tree::dirstate_map::DirstateEntryReset, | |||
|
20 | }; | |||
18 |
|
21 | |||
19 | use crate::{ |
|
22 | use crate::{ | |
20 | dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator}, |
|
23 | dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator}, | |
@@ -196,14 +199,16 py_class!(pub class DirstateMap |py| { | |||||
196 | }; |
|
199 | }; | |
197 | let bytes = f.extract::<PyBytes>(py)?; |
|
200 | let bytes = f.extract::<PyBytes>(py)?; | |
198 | let path = HgPath::new(bytes.data(py)); |
|
201 | let path = HgPath::new(bytes.data(py)); | |
199 | let res = self.inner(py).borrow_mut().reset_state( |
|
202 | let reset = DirstateEntryReset { | |
200 | path, |
|
203 | filename: path, | |
201 | wc_tracked, |
|
204 | wc_tracked, | |
202 | p1_tracked, |
|
205 | p1_tracked, | |
203 | p2_info, |
|
206 | p2_info, | |
204 | has_meaningful_mtime, |
|
207 | has_meaningful_mtime, | |
205 | parent_file_data, |
|
208 | parent_file_data_opt: parent_file_data, | |
206 | ); |
|
209 | from_empty: false | |
|
210 | }; | |||
|
211 | let res = self.inner(py).borrow_mut().reset_state(reset); | |||
207 | res.map_err(|_| PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string()))?; |
|
212 | res.map_err(|_| PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string()))?; | |
208 | Ok(PyNone) |
|
213 | Ok(PyNone) | |
209 | } |
|
214 | } |
General Comments 0
You need to be logged in to leave comments.
Login now