Show More
@@ -180,7 +180,7 dependencies = [ | |||
|
180 | 180 | "js-sys", |
|
181 | 181 | "num-traits", |
|
182 | 182 | "wasm-bindgen", |
|
183 |
"windows-targets 0.52. |
|
|
183 | "windows-targets 0.52.6", | |
|
184 | 184 | ] |
|
185 | 185 | |
|
186 | 186 | [[package]] |
@@ -435,10 +435,16 dependencies = [ | |||
|
435 | 435 | "libc", |
|
436 | 436 | "option-ext", |
|
437 | 437 | "redox_users", |
|
438 | "windows-sys", | |
|
438 | "windows-sys 0.48.0", | |
|
439 | 439 | ] |
|
440 | 440 | |
|
441 | 441 | [[package]] |
|
442 | name = "dyn-clone" | |
|
443 | version = "1.0.17" | |
|
444 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
|
445 | checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" | |
|
446 | ||
|
447 | [[package]] | |
|
442 | 448 | name = "either" |
|
443 | 449 | version = "1.8.0" |
|
444 | 450 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -467,6 +473,18 dependencies = [ | |||
|
467 | 473 | ] |
|
468 | 474 | |
|
469 | 475 | [[package]] |
|
476 | name = "filetime" | |
|
477 | version = "0.2.25" | |
|
478 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
|
479 | checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" | |
|
480 | dependencies = [ | |
|
481 | "cfg-if", | |
|
482 | "libc", | |
|
483 | "libredox", | |
|
484 | "windows-sys 0.59.0", | |
|
485 | ] | |
|
486 | ||
|
487 | [[package]] | |
|
470 | 488 | name = "flate2" |
|
471 | 489 | version = "1.0.24" |
|
472 | 490 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -584,6 +602,8 dependencies = [ | |||
|
584 | 602 | "clap", |
|
585 | 603 | "crossbeam-channel", |
|
586 | 604 | "derive_more", |
|
605 | "dyn-clone", | |
|
606 | "filetime", | |
|
587 | 607 | "flate2", |
|
588 | 608 | "format-bytes", |
|
589 | 609 | "hashbrown 0.13.1", |
@@ -752,6 +772,7 checksum = "c0ff37bd590ca25063e35af745c3 | |||
|
752 | 772 | dependencies = [ |
|
753 | 773 | "bitflags 2.6.0", |
|
754 | 774 | "libc", |
|
775 | "redox_syscall 0.5.3", | |
|
755 | 776 | ] |
|
756 | 777 | |
|
757 | 778 | [[package]] |
@@ -1123,6 +1144,15 dependencies = [ | |||
|
1123 | 1144 | ] |
|
1124 | 1145 | |
|
1125 | 1146 | [[package]] |
|
1147 | name = "redox_syscall" | |
|
1148 | version = "0.5.3" | |
|
1149 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
|
1150 | checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" | |
|
1151 | dependencies = [ | |
|
1152 | "bitflags 2.6.0", | |
|
1153 | ] | |
|
1154 | ||
|
1155 | [[package]] | |
|
1126 | 1156 | name = "redox_users" |
|
1127 | 1157 | version = "0.4.5" |
|
1128 | 1158 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -1348,7 +1378,7 dependencies = [ | |||
|
1348 | 1378 | "cfg-if", |
|
1349 | 1379 | "fastrand", |
|
1350 | 1380 | "libc", |
|
1351 | "redox_syscall", | |
|
1381 | "redox_syscall 0.2.16", | |
|
1352 | 1382 | "remove_dir_all", |
|
1353 | 1383 | "winapi", |
|
1354 | 1384 | ] |
@@ -1615,6 +1645,15 dependencies = [ | |||
|
1615 | 1645 | ] |
|
1616 | 1646 | |
|
1617 | 1647 | [[package]] |
|
1648 | name = "windows-sys" | |
|
1649 | version = "0.59.0" | |
|
1650 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
|
1651 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" | |
|
1652 | dependencies = [ | |
|
1653 | "windows-targets 0.52.6", | |
|
1654 | ] | |
|
1655 | ||
|
1656 | [[package]] | |
|
1618 | 1657 | name = "windows-targets" |
|
1619 | 1658 | version = "0.48.5" |
|
1620 | 1659 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -1631,17 +1670,18 dependencies = [ | |||
|
1631 | 1670 | |
|
1632 | 1671 | [[package]] |
|
1633 | 1672 | name = "windows-targets" |
|
1634 |
version = "0.52. |
|
|
1673 | version = "0.52.6" | |
|
1635 | 1674 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
1636 | checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" | |
|
1675 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" | |
|
1637 | 1676 | dependencies = [ |
|
1638 |
"windows_aarch64_gnullvm 0.52. |
|
|
1639 |
"windows_aarch64_msvc 0.52. |
|
|
1640 |
"windows_i686_gnu 0.52. |
|
|
1641 |
"windows_i686_ |
|
|
1642 |
"windows_ |
|
|
1643 |
"windows_x86_64_gnu |
|
|
1644 |
"windows_x86_64_m |
|
|
1677 | "windows_aarch64_gnullvm 0.52.6", | |
|
1678 | "windows_aarch64_msvc 0.52.6", | |
|
1679 | "windows_i686_gnu 0.52.6", | |
|
1680 | "windows_i686_gnullvm", | |
|
1681 | "windows_i686_msvc 0.52.6", | |
|
1682 | "windows_x86_64_gnu 0.52.6", | |
|
1683 | "windows_x86_64_gnullvm 0.52.6", | |
|
1684 | "windows_x86_64_msvc 0.52.6", | |
|
1645 | 1685 | ] |
|
1646 | 1686 | |
|
1647 | 1687 | [[package]] |
@@ -1652,9 +1692,9 checksum = "2b38e32f0abccf9987a4e3079dfb | |||
|
1652 | 1692 | |
|
1653 | 1693 | [[package]] |
|
1654 | 1694 | name = "windows_aarch64_gnullvm" |
|
1655 |
version = "0.52. |
|
|
1695 | version = "0.52.6" | |
|
1656 | 1696 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
1657 | checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" | |
|
1697 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" | |
|
1658 | 1698 | |
|
1659 | 1699 | [[package]] |
|
1660 | 1700 | name = "windows_aarch64_msvc" |
@@ -1664,9 +1704,9 checksum = "dc35310971f3b2dbbf3f0690a219 | |||
|
1664 | 1704 | |
|
1665 | 1705 | [[package]] |
|
1666 | 1706 | name = "windows_aarch64_msvc" |
|
1667 |
version = "0.52. |
|
|
1707 | version = "0.52.6" | |
|
1668 | 1708 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
1669 | checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" | |
|
1709 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" | |
|
1670 | 1710 | |
|
1671 | 1711 | [[package]] |
|
1672 | 1712 | name = "windows_i686_gnu" |
@@ -1676,9 +1716,15 checksum = "a75915e7def60c94dcef72200b9a | |||
|
1676 | 1716 | |
|
1677 | 1717 | [[package]] |
|
1678 | 1718 | name = "windows_i686_gnu" |
|
1679 |
version = "0.52. |
|
|
1719 | version = "0.52.6" | |
|
1680 | 1720 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
1681 | checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" | |
|
1721 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" | |
|
1722 | ||
|
1723 | [[package]] | |
|
1724 | name = "windows_i686_gnullvm" | |
|
1725 | version = "0.52.6" | |
|
1726 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
|
1727 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" | |
|
1682 | 1728 | |
|
1683 | 1729 | [[package]] |
|
1684 | 1730 | name = "windows_i686_msvc" |
@@ -1688,9 +1734,9 checksum = "8f55c233f70c4b27f66c523580f7 | |||
|
1688 | 1734 | |
|
1689 | 1735 | [[package]] |
|
1690 | 1736 | name = "windows_i686_msvc" |
|
1691 |
version = "0.52. |
|
|
1737 | version = "0.52.6" | |
|
1692 | 1738 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
1693 | checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" | |
|
1739 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" | |
|
1694 | 1740 | |
|
1695 | 1741 | [[package]] |
|
1696 | 1742 | name = "windows_x86_64_gnu" |
@@ -1700,9 +1746,9 checksum = "53d40abd2583d23e4718fddf1ebe | |||
|
1700 | 1746 | |
|
1701 | 1747 | [[package]] |
|
1702 | 1748 | name = "windows_x86_64_gnu" |
|
1703 |
version = "0.52. |
|
|
1749 | version = "0.52.6" | |
|
1704 | 1750 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
1705 | checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" | |
|
1751 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" | |
|
1706 | 1752 | |
|
1707 | 1753 | [[package]] |
|
1708 | 1754 | name = "windows_x86_64_gnullvm" |
@@ -1712,9 +1758,9 checksum = "0b7b52767868a23d5bab768e390d | |||
|
1712 | 1758 | |
|
1713 | 1759 | [[package]] |
|
1714 | 1760 | name = "windows_x86_64_gnullvm" |
|
1715 |
version = "0.52. |
|
|
1761 | version = "0.52.6" | |
|
1716 | 1762 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
1717 | checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" | |
|
1763 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" | |
|
1718 | 1764 | |
|
1719 | 1765 | [[package]] |
|
1720 | 1766 | name = "windows_x86_64_msvc" |
@@ -1724,9 +1770,9 checksum = "ed94fce61571a4006852b7389a06 | |||
|
1724 | 1770 | |
|
1725 | 1771 | [[package]] |
|
1726 | 1772 | name = "windows_x86_64_msvc" |
|
1727 |
version = "0.52. |
|
|
1773 | version = "0.52.6" | |
|
1728 | 1774 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
1729 | checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" | |
|
1775 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" | |
|
1730 | 1776 | |
|
1731 | 1777 | [[package]] |
|
1732 | 1778 | name = "wyz" |
@@ -41,6 +41,8 format-bytes = "0.3.0" | |||
|
41 | 41 | once_cell = "1.16.0" |
|
42 | 42 | bitvec = "1.0.1" |
|
43 | 43 | chrono = "0.4.34" |
|
44 | dyn-clone = "1.0.16" | |
|
45 | filetime = "0.2.23" | |
|
44 | 46 | |
|
45 | 47 | # We don't use the `miniz-oxide` backend to not change rhg benchmarks and until |
|
46 | 48 | # we have a clearer view of which backend is the fastest. |
@@ -2,7 +2,7 | |||
|
2 | 2 | |
|
3 | 3 | use crate::errors::HgError; |
|
4 | 4 | use crate::errors::HgResultExt; |
|
5 | use crate::vfs::Vfs; | |
|
5 | use crate::vfs::VfsImpl; | |
|
6 | 6 | use std::io; |
|
7 | 7 | use std::io::ErrorKind; |
|
8 | 8 | |
@@ -21,7 +21,7 pub enum LockError { | |||
|
21 | 21 | /// The return value of `f` is dropped in that case. If all is successful, the |
|
22 | 22 | /// return value of `f` is forwarded. |
|
23 | 23 | pub fn try_with_lock_no_wait<R>( |
|
24 | hg_vfs: Vfs, | |
|
24 | hg_vfs: &VfsImpl, | |
|
25 | 25 | lock_filename: &str, |
|
26 | 26 | f: impl FnOnce() -> R, |
|
27 | 27 | ) -> Result<R, LockError> { |
@@ -57,7 +57,7 pub fn try_with_lock_no_wait<R>( | |||
|
57 | 57 | Err(LockError::AlreadyHeld) |
|
58 | 58 | } |
|
59 | 59 | |
|
60 | fn break_lock(hg_vfs: Vfs, lock_filename: &str) -> Result<(), LockError> { | |
|
60 | fn break_lock(hg_vfs: &VfsImpl, lock_filename: &str) -> Result<(), LockError> { | |
|
61 | 61 | try_with_lock_no_wait(hg_vfs, &format!("{}.break", lock_filename), || { |
|
62 | 62 | // Check again in case some other process broke and |
|
63 | 63 | // acquired the lock in the meantime |
@@ -71,7 +71,7 fn break_lock(hg_vfs: Vfs, lock_filename | |||
|
71 | 71 | |
|
72 | 72 | #[cfg(unix)] |
|
73 | 73 | fn make_lock( |
|
74 | hg_vfs: Vfs, | |
|
74 | hg_vfs: &VfsImpl, | |
|
75 | 75 | lock_filename: &str, |
|
76 | 76 | data: &str, |
|
77 | 77 | ) -> Result<(), HgError> { |
@@ -82,7 +82,7 fn make_lock( | |||
|
82 | 82 | } |
|
83 | 83 | |
|
84 | 84 | fn read_lock( |
|
85 | hg_vfs: Vfs, | |
|
85 | hg_vfs: &VfsImpl, | |
|
86 | 86 | lock_filename: &str, |
|
87 | 87 | ) -> Result<Option<String>, HgError> { |
|
88 | 88 | let link_target = |
@@ -98,7 +98,7 fn read_lock( | |||
|
98 | 98 | } |
|
99 | 99 | } |
|
100 | 100 | |
|
101 | fn unlock(hg_vfs: Vfs, lock_filename: &str) -> Result<(), HgError> { | |
|
101 | fn unlock(hg_vfs: &VfsImpl, lock_filename: &str) -> Result<(), HgError> { | |
|
102 | 102 | hg_vfs.remove_file(lock_filename) |
|
103 | 103 | } |
|
104 | 104 |
@@ -1,5 +1,5 | |||
|
1 | 1 | use crate::errors::{HgError, HgResultExt, IoErrorContext, IoResultExt}; |
|
2 | use crate::vfs::Vfs; | |
|
2 | use crate::vfs::VfsImpl; | |
|
3 | 3 | use std::io::Write; |
|
4 | 4 | |
|
5 | 5 | /// An utility to append to a log file with the given name, and optionally |
@@ -9,14 +9,14 use std::io::Write; | |||
|
9 | 9 | /// "example.log.1" to "example.log.2" etc up to the given maximum number of |
|
10 | 10 | /// files. |
|
11 | 11 | pub struct LogFile<'a> { |
|
12 |
vfs: Vfs |
|
|
12 | vfs: VfsImpl, | |
|
13 | 13 | name: &'a str, |
|
14 | 14 | max_size: Option<u64>, |
|
15 | 15 | max_files: u32, |
|
16 | 16 | } |
|
17 | 17 | |
|
18 | 18 | impl<'a> LogFile<'a> { |
|
19 |
pub fn new(vfs: Vfs |
|
|
19 | pub fn new(vfs: VfsImpl, name: &'a str) -> Self { | |
|
20 | 20 | Self { |
|
21 | 21 | vfs, |
|
22 | 22 | name, |
@@ -87,8 +87,12 impl<'a> LogFile<'a> { | |||
|
87 | 87 | #[test] |
|
88 | 88 | fn test_rotation() { |
|
89 | 89 | let temp = tempfile::tempdir().unwrap(); |
|
90 |
let vfs = Vfs { |
|
|
91 | let logger = LogFile::new(vfs, "log").max_size(Some(3)).max_files(2); | |
|
90 | let vfs = VfsImpl { | |
|
91 | base: temp.path().to_owned(), | |
|
92 | }; | |
|
93 | let logger = LogFile::new(vfs.clone(), "log") | |
|
94 | .max_size(Some(3)) | |
|
95 | .max_files(2); | |
|
92 | 96 | logger.write(b"one\n").unwrap(); |
|
93 | 97 | logger.write(b"two\n").unwrap(); |
|
94 | 98 | logger.write(b"3\n").unwrap(); |
@@ -18,7 +18,7 use crate::utils::debug::debug_wait_for_ | |||
|
18 | 18 | use crate::utils::files::get_path_from_bytes; |
|
19 | 19 | use crate::utils::hg_path::HgPath; |
|
20 | 20 | use crate::utils::SliceExt; |
|
21 | use crate::vfs::{is_dir, is_file, Vfs}; | |
|
21 | use crate::vfs::{is_dir, is_file, VfsImpl}; | |
|
22 | 22 | use crate::{ |
|
23 | 23 | requirements, NodePrefix, RevlogDataConfig, RevlogDeltaConfig, |
|
24 | 24 | RevlogFeatureConfig, RevlogType, RevlogVersionOptions, UncheckedRevision, |
@@ -121,8 +121,10 impl Repo { | |||
|
121 | 121 | let mut repo_config_files = |
|
122 | 122 | vec![dot_hg.join("hgrc"), dot_hg.join("hgrc-not-shared")]; |
|
123 | 123 | |
|
124 |
let hg_vfs = Vfs { |
|
|
125 | let mut reqs = requirements::load_if_exists(hg_vfs)?; | |
|
124 | let hg_vfs = VfsImpl { | |
|
125 | base: dot_hg.to_owned(), | |
|
126 | }; | |
|
127 | let mut reqs = requirements::load_if_exists(&hg_vfs)?; | |
|
126 | 128 | let relative = |
|
127 | 129 | reqs.contains(requirements::RELATIVE_SHARED_REQUIREMENT); |
|
128 | 130 | let shared = |
@@ -163,9 +165,10 impl Repo { | |||
|
163 | 165 | |
|
164 | 166 | store_path = shared_path.join("store"); |
|
165 | 167 | |
|
166 | let source_is_share_safe = | |
|
167 |
|
|
|
168 | .contains(requirements::SHARESAFE_REQUIREMENT); | |
|
168 | let source_is_share_safe = requirements::load(VfsImpl { | |
|
169 | base: shared_path.to_owned(), | |
|
170 | })? | |
|
171 | .contains(requirements::SHARESAFE_REQUIREMENT); | |
|
169 | 172 | |
|
170 | 173 | if share_safe != source_is_share_safe { |
|
171 | 174 | return Err(HgError::unsupported("share-safe mismatch").into()); |
@@ -176,7 +179,9 impl Repo { | |||
|
176 | 179 | } |
|
177 | 180 | } |
|
178 | 181 | if share_safe { |
|
179 |
reqs.extend(requirements::load(Vfs { |
|
|
182 | reqs.extend(requirements::load(VfsImpl { | |
|
183 | base: store_path.to_owned(), | |
|
184 | })?); | |
|
180 | 185 | } |
|
181 | 186 | |
|
182 | 187 | let repo_config = if std::env::var_os("HGRCSKIPREPO").is_none() { |
@@ -216,19 +221,23 impl Repo { | |||
|
216 | 221 | |
|
217 | 222 | /// For accessing repository files (in `.hg`), except for the store |
|
218 | 223 | /// (`.hg/store`). |
|
219 |
pub fn hg_vfs(&self) -> Vfs |
|
|
220 | Vfs { base: &self.dot_hg } | |
|
224 | pub fn hg_vfs(&self) -> VfsImpl { | |
|
225 | VfsImpl { | |
|
226 | base: self.dot_hg.to_owned(), | |
|
227 | } | |
|
221 | 228 | } |
|
222 | 229 | |
|
223 | 230 | /// For accessing repository store files (in `.hg/store`) |
|
224 |
pub fn store_vfs(&self) -> Vfs |
|
|
225 | Vfs { base: &self.store } | |
|
231 | pub fn store_vfs(&self) -> VfsImpl { | |
|
232 | VfsImpl { | |
|
233 | base: self.store.to_owned(), | |
|
234 | } | |
|
226 | 235 | } |
|
227 | 236 | |
|
228 | 237 | /// For accessing the working copy |
|
229 |
pub fn working_directory_vfs(&self) -> Vfs |
|
|
230 | Vfs { | |
|
231 |
base: |
|
|
238 | pub fn working_directory_vfs(&self) -> VfsImpl { | |
|
239 | VfsImpl { | |
|
240 | base: self.working_directory.to_owned(), | |
|
232 | 241 | } |
|
233 | 242 | } |
|
234 | 243 | |
@@ -236,7 +245,7 impl Repo { | |||
|
236 | 245 | &self, |
|
237 | 246 | f: impl FnOnce() -> R, |
|
238 | 247 | ) -> Result<R, LockError> { |
|
239 | try_with_lock_no_wait(self.hg_vfs(), "wlock", f) | |
|
248 | try_with_lock_no_wait(&self.hg_vfs(), "wlock", f) | |
|
240 | 249 | } |
|
241 | 250 | |
|
242 | 251 | /// Whether this repo should use dirstate-v2. |
@@ -1,7 +1,7 | |||
|
1 | 1 | use crate::errors::{HgError, HgResultExt}; |
|
2 | 2 | use crate::repo::Repo; |
|
3 | 3 | use crate::utils::join_display; |
|
4 | use crate::vfs::Vfs; | |
|
4 | use crate::vfs::VfsImpl; | |
|
5 | 5 | use std::collections::HashSet; |
|
6 | 6 | |
|
7 | 7 | fn parse(bytes: &[u8]) -> Result<HashSet<String>, HgError> { |
@@ -24,11 +24,13 fn parse(bytes: &[u8]) -> Result<HashSet | |||
|
24 | 24 | .collect() |
|
25 | 25 | } |
|
26 | 26 | |
|
27 | pub(crate) fn load(hg_vfs: Vfs) -> Result<HashSet<String>, HgError> { | |
|
27 | pub(crate) fn load(hg_vfs: VfsImpl) -> Result<HashSet<String>, HgError> { | |
|
28 | 28 | parse(&hg_vfs.read("requires")?) |
|
29 | 29 | } |
|
30 | 30 | |
|
31 | pub(crate) fn load_if_exists(hg_vfs: Vfs) -> Result<HashSet<String>, HgError> { | |
|
31 | pub(crate) fn load_if_exists( | |
|
32 | hg_vfs: &VfsImpl, | |
|
33 | ) -> Result<HashSet<String>, HgError> { | |
|
32 | 34 | if let Some(bytes) = hg_vfs.read("requires").io_not_found_as_none()? { |
|
33 | 35 | parse(&bytes) |
|
34 | 36 | } else { |
@@ -13,7 +13,7 use crate::revlog::Revision; | |||
|
13 | 13 | use crate::revlog::{Node, NodePrefix}; |
|
14 | 14 | use crate::revlog::{Revlog, RevlogEntry, RevlogError}; |
|
15 | 15 | use crate::utils::hg_path::HgPath; |
|
16 | use crate::vfs::Vfs; | |
|
16 | use crate::vfs::VfsImpl; | |
|
17 | 17 | use crate::{Graph, GraphError, RevlogOpenOptions, UncheckedRevision}; |
|
18 | 18 | |
|
19 | 19 | /// A specialized `Revlog` to work with changelog data format. |
@@ -25,7 +25,7 pub struct Changelog { | |||
|
25 | 25 | impl Changelog { |
|
26 | 26 | /// Open the `changelog` of a repository given by its root. |
|
27 | 27 | pub fn open( |
|
28 | store_vfs: &Vfs, | |
|
28 | store_vfs: &VfsImpl, | |
|
29 | 29 | options: RevlogOpenOptions, |
|
30 | 30 | ) -> Result<Self, HgError> { |
|
31 | 31 | let revlog = Revlog::open(store_vfs, "00changelog.i", None, options)?; |
@@ -500,7 +500,7 fn unescape_extra(bytes: &[u8]) -> Vec<u | |||
|
500 | 500 | #[cfg(test)] |
|
501 | 501 | mod tests { |
|
502 | 502 | use super::*; |
|
503 | use crate::vfs::Vfs; | |
|
503 | use crate::vfs::VfsImpl; | |
|
504 | 504 | use crate::{ |
|
505 | 505 | RevlogDataConfig, RevlogDeltaConfig, RevlogFeatureConfig, |
|
506 | 506 | NULL_REVISION, |
@@ -563,7 +563,9 message", | |||
|
563 | 563 | fn test_data_from_rev_null() -> Result<(), RevlogError> { |
|
564 | 564 | // an empty revlog will be enough for this case |
|
565 | 565 | let temp = tempfile::tempdir().unwrap(); |
|
566 |
let vfs = Vfs { |
|
|
566 | let vfs = VfsImpl { | |
|
567 | base: temp.path().to_owned(), | |
|
568 | }; | |
|
567 | 569 | std::fs::write(temp.path().join("foo.i"), b"").unwrap(); |
|
568 | 570 | std::fs::write(temp.path().join("foo.d"), b"").unwrap(); |
|
569 | 571 | let revlog = Revlog::open( |
@@ -29,7 +29,7 impl Graph for Filelog { | |||
|
29 | 29 | |
|
30 | 30 | impl Filelog { |
|
31 | 31 | pub fn open_vfs( |
|
32 |
store_vfs: &crate::vfs::Vfs |
|
|
32 | store_vfs: &crate::vfs::VfsImpl, | |
|
33 | 33 | file_path: &HgPath, |
|
34 | 34 | options: RevlogOpenOptions, |
|
35 | 35 | ) -> Result<Self, HgError> { |
@@ -3,7 +3,7 use crate::revlog::{Node, NodePrefix}; | |||
|
3 | 3 | use crate::revlog::{Revlog, RevlogError}; |
|
4 | 4 | use crate::utils::hg_path::HgPath; |
|
5 | 5 | use crate::utils::SliceExt; |
|
6 | use crate::vfs::Vfs; | |
|
6 | use crate::vfs::VfsImpl; | |
|
7 | 7 | use crate::{ |
|
8 | 8 | Graph, GraphError, Revision, RevlogOpenOptions, UncheckedRevision, |
|
9 | 9 | }; |
@@ -23,7 +23,7 impl Graph for Manifestlog { | |||
|
23 | 23 | impl Manifestlog { |
|
24 | 24 | /// Open the `manifest` of a repository given by its root. |
|
25 | 25 | pub fn open( |
|
26 | store_vfs: &Vfs, | |
|
26 | store_vfs: &VfsImpl, | |
|
27 | 27 | options: RevlogOpenOptions, |
|
28 | 28 | ) -> Result<Self, HgError> { |
|
29 | 29 | let revlog = Revlog::open(store_vfs, "00manifest.i", None, options)?; |
@@ -38,7 +38,7 use crate::exit_codes; | |||
|
38 | 38 | use crate::requirements::{ |
|
39 | 39 | GENERALDELTA_REQUIREMENT, NARROW_REQUIREMENT, SPARSEREVLOG_REQUIREMENT, |
|
40 | 40 | }; |
|
41 | use crate::vfs::Vfs; | |
|
41 | use crate::vfs::VfsImpl; | |
|
42 | 42 | |
|
43 | 43 | /// As noted in revlog.c, revision numbers are actually encoded in |
|
44 | 44 | /// 4 bytes, and are liberally converted to ints, whence the i32 |
@@ -708,7 +708,8 impl Revlog { | |||
|
708 | 708 | /// It will also open the associated data file if index and data are not |
|
709 | 709 | /// interleaved. |
|
710 | 710 | pub fn open( |
|
711 | store_vfs: &Vfs, | |
|
711 | // Todo use the `Vfs` trait here once we create a function for mmap | |
|
712 | store_vfs: &VfsImpl, | |
|
712 | 713 | index_path: impl AsRef<Path>, |
|
713 | 714 | data_path: Option<&Path>, |
|
714 | 715 | options: RevlogOpenOptions, |
@@ -717,7 +718,8 impl Revlog { | |||
|
717 | 718 | } |
|
718 | 719 | |
|
719 | 720 | fn open_gen( |
|
720 | store_vfs: &Vfs, | |
|
721 | // Todo use the `Vfs` trait here once we create a function for mmap | |
|
722 | store_vfs: &VfsImpl, | |
|
721 | 723 | index_path: impl AsRef<Path>, |
|
722 | 724 | data_path: Option<&Path>, |
|
723 | 725 | options: RevlogOpenOptions, |
@@ -1298,7 +1300,9 mod tests { | |||
|
1298 | 1300 | #[test] |
|
1299 | 1301 | fn test_empty() { |
|
1300 | 1302 | let temp = tempfile::tempdir().unwrap(); |
|
1301 |
let vfs = Vfs { |
|
|
1303 | let vfs = VfsImpl { | |
|
1304 | base: temp.path().to_owned(), | |
|
1305 | }; | |
|
1302 | 1306 | std::fs::write(temp.path().join("foo.i"), b"").unwrap(); |
|
1303 | 1307 | std::fs::write(temp.path().join("foo.d"), b"").unwrap(); |
|
1304 | 1308 | let revlog = |
@@ -1320,7 +1324,9 mod tests { | |||
|
1320 | 1324 | #[test] |
|
1321 | 1325 | fn test_inline() { |
|
1322 | 1326 | let temp = tempfile::tempdir().unwrap(); |
|
1323 |
let vfs = Vfs { |
|
|
1327 | let vfs = VfsImpl { | |
|
1328 | base: temp.path().to_owned(), | |
|
1329 | }; | |
|
1324 | 1330 | let node0 = Node::from_hex("2ed2a3912a0b24502043eae84ee4b279c18b90dd") |
|
1325 | 1331 | .unwrap(); |
|
1326 | 1332 | let node1 = Node::from_hex("b004912a8510032a0350a74daa2803dadfb00e12") |
@@ -1387,7 +1393,9 mod tests { | |||
|
1387 | 1393 | #[test] |
|
1388 | 1394 | fn test_nodemap() { |
|
1389 | 1395 | let temp = tempfile::tempdir().unwrap(); |
|
1390 |
let vfs = Vfs { |
|
|
1396 | let vfs = VfsImpl { | |
|
1397 | base: temp.path().to_owned(), | |
|
1398 | }; | |
|
1391 | 1399 | |
|
1392 | 1400 | // building a revlog with a forced Node starting with zeros |
|
1393 | 1401 | // This is a corruption, but it does not preclude using the nodemap |
@@ -3,7 +3,7 use bytes_cast::{unaligned, BytesCast}; | |||
|
3 | 3 | use memmap2::Mmap; |
|
4 | 4 | use std::path::{Path, PathBuf}; |
|
5 | 5 | |
|
6 | use crate::vfs::Vfs; | |
|
6 | use crate::vfs::VfsImpl; | |
|
7 | 7 | |
|
8 | 8 | const ONDISK_VERSION: u8 = 1; |
|
9 | 9 | |
@@ -33,7 +33,7 impl NodeMapDocket { | |||
|
33 | 33 | /// * The docket file points to a missing (likely deleted) data file (this |
|
34 | 34 | /// can happen in a rare race condition). |
|
35 | 35 | pub fn read_from_file( |
|
36 | store_vfs: &Vfs, | |
|
36 | store_vfs: &VfsImpl, | |
|
37 | 37 | index_path: &Path, |
|
38 | 38 | ) -> Result<Option<(Self, Mmap)>, HgError> { |
|
39 | 39 | let docket_path = index_path.with_extension("n"); |
@@ -1,17 +1,21 | |||
|
1 | 1 | use crate::errors::{HgError, IoErrorContext, IoResultExt}; |
|
2 | use crate::exit_codes; | |
|
3 | use dyn_clone::DynClone; | |
|
2 | 4 | use memmap2::{Mmap, MmapOptions}; |
|
5 | use std::fs::File; | |
|
3 | 6 | use std::io::{ErrorKind, Write}; |
|
7 | use std::os::unix::fs::MetadataExt; | |
|
4 | 8 | use std::path::{Path, PathBuf}; |
|
5 | 9 | |
|
6 | 10 | /// Filesystem access abstraction for the contents of a given "base" diretory |
|
7 |
#[derive(Clone |
|
|
8 |
pub struct Vfs |
|
|
9 |
pub(crate) base: |
|
|
11 | #[derive(Clone)] | |
|
12 | pub struct VfsImpl { | |
|
13 | pub(crate) base: PathBuf, | |
|
10 | 14 | } |
|
11 | 15 | |
|
12 | 16 | struct FileNotFound(std::io::Error, PathBuf); |
|
13 | 17 | |
|
14 |
impl Vfs |
|
|
18 | impl VfsImpl { | |
|
15 | 19 | pub fn join(&self, relative_path: impl AsRef<Path>) -> PathBuf { |
|
16 | 20 | self.base.join(relative_path) |
|
17 | 21 | } |
@@ -71,7 +75,12 impl Vfs<'_> { | |||
|
71 | 75 | } |
|
72 | 76 | Ok(file) => file, |
|
73 | 77 | }; |
|
74 | // TODO: what are the safety requirements here? | |
|
78 | // Safety is "enforced" by locks and assuming other processes are | |
|
79 | // well-behaved. If any misbehaving or malicious process does touch | |
|
80 | // the index, it could lead to corruption. This is inherent | |
|
81 | // to file-based `mmap`, though some platforms have some ways of | |
|
82 | // mitigating. | |
|
83 | // TODO linux: set the immutable flag with `chattr(1)`? | |
|
75 | 84 | let mmap = unsafe { MmapOptions::new().map(&file) } |
|
76 | 85 | .when_reading_file(&path)?; |
|
77 | 86 | Ok(Ok(mmap)) |
@@ -134,8 +143,8 impl Vfs<'_> { | |||
|
134 | 143 | relative_path: impl AsRef<Path>, |
|
135 | 144 | contents: &[u8], |
|
136 | 145 | ) -> Result<(), HgError> { |
|
137 | let mut tmp = tempfile::NamedTempFile::new_in(self.base) | |
|
138 | .when_writing_file(self.base)?; | |
|
146 | let mut tmp = tempfile::NamedTempFile::new_in(&self.base) | |
|
147 | .when_writing_file(&self.base)?; | |
|
139 | 148 | tmp.write_all(contents) |
|
140 | 149 | .and_then(|()| tmp.flush()) |
|
141 | 150 | .when_writing_file(tmp.path())?; |
@@ -165,6 +174,174 fn fs_metadata( | |||
|
165 | 174 | } |
|
166 | 175 | } |
|
167 | 176 | |
|
177 | /// Writable file object that atomically updates a file | |
|
178 | /// | |
|
179 | /// All writes will go to a temporary copy of the original file. Call | |
|
180 | /// [`Self::close`] when you are done writing, and [`Self`] will rename | |
|
181 | /// the temporary copy to the original name, making the changes | |
|
182 | /// visible. If the object is destroyed without being closed, all your | |
|
183 | /// writes are discarded. | |
|
184 | pub struct AtomicFile { | |
|
185 | /// The temporary file to write to | |
|
186 | fp: std::fs::File, | |
|
187 | /// Path of the temp file | |
|
188 | temp_path: PathBuf, | |
|
189 | /// Used when stat'ing the file, is useful only if the target file is | |
|
190 | /// guarded by any lock (e.g. repo.lock or repo.wlock). | |
|
191 | check_ambig: bool, | |
|
192 | /// Path of the target file | |
|
193 | target_name: PathBuf, | |
|
194 | /// Whether the file is open or not | |
|
195 | is_open: bool, | |
|
196 | } | |
|
197 | ||
|
198 | impl AtomicFile { | |
|
199 | pub fn new( | |
|
200 | fp: std::fs::File, | |
|
201 | check_ambig: bool, | |
|
202 | temp_name: PathBuf, | |
|
203 | target_name: PathBuf, | |
|
204 | ) -> Self { | |
|
205 | Self { | |
|
206 | fp, | |
|
207 | check_ambig, | |
|
208 | temp_path: temp_name, | |
|
209 | target_name, | |
|
210 | is_open: true, | |
|
211 | } | |
|
212 | } | |
|
213 | ||
|
214 | /// Write `buf` to the temporary file | |
|
215 | pub fn write_all(&mut self, buf: &[u8]) -> Result<(), std::io::Error> { | |
|
216 | self.fp.write_all(buf) | |
|
217 | } | |
|
218 | ||
|
219 | fn target(&self) -> PathBuf { | |
|
220 | self.temp_path | |
|
221 | .parent() | |
|
222 | .expect("should not be at the filesystem root") | |
|
223 | .join(&self.target_name) | |
|
224 | } | |
|
225 | ||
|
226 | /// Close the temporary file and rename to the target | |
|
227 | pub fn close(mut self) -> Result<(), std::io::Error> { | |
|
228 | self.fp.flush()?; | |
|
229 | let target = self.target(); | |
|
230 | if self.check_ambig { | |
|
231 | if let Ok(stat) = std::fs::metadata(&target) { | |
|
232 | std::fs::rename(&self.temp_path, &target)?; | |
|
233 | let new_stat = std::fs::metadata(&target)?; | |
|
234 | let ctime = new_stat.ctime(); | |
|
235 | let is_ambiguous = ctime == stat.ctime(); | |
|
236 | if is_ambiguous { | |
|
237 | let advanced = | |
|
238 | filetime::FileTime::from_unix_time(ctime + 1, 0); | |
|
239 | filetime::set_file_times(target, advanced, advanced)?; | |
|
240 | } | |
|
241 | } else { | |
|
242 | std::fs::rename(&self.temp_path, target)?; | |
|
243 | } | |
|
244 | } else { | |
|
245 | std::fs::rename(&self.temp_path, target).unwrap(); | |
|
246 | } | |
|
247 | self.is_open = false; | |
|
248 | Ok(()) | |
|
249 | } | |
|
250 | } | |
|
251 | ||
|
252 | impl Drop for AtomicFile { | |
|
253 | fn drop(&mut self) { | |
|
254 | if self.is_open { | |
|
255 | std::fs::remove_file(self.target()).ok(); | |
|
256 | } | |
|
257 | } | |
|
258 | } | |
|
259 | ||
|
260 | /// Abstracts over the VFS to allow for different implementations of the | |
|
261 | /// filesystem layer (like passing one from Python). | |
|
262 | pub trait Vfs: Sync + Send + DynClone { | |
|
263 | fn open(&self, filename: &Path) -> Result<std::fs::File, HgError>; | |
|
264 | fn open_read(&self, filename: &Path) -> Result<std::fs::File, HgError>; | |
|
265 | fn open_check_ambig( | |
|
266 | &self, | |
|
267 | filename: &Path, | |
|
268 | ) -> Result<std::fs::File, HgError>; | |
|
269 | fn create(&self, filename: &Path) -> Result<std::fs::File, HgError>; | |
|
270 | /// Must truncate the new file if exist | |
|
271 | fn create_atomic( | |
|
272 | &self, | |
|
273 | filename: &Path, | |
|
274 | check_ambig: bool, | |
|
275 | ) -> Result<AtomicFile, HgError>; | |
|
276 | fn file_size(&self, file: &File) -> Result<u64, HgError>; | |
|
277 | fn exists(&self, filename: &Path) -> bool; | |
|
278 | fn unlink(&self, filename: &Path) -> Result<(), HgError>; | |
|
279 | fn rename( | |
|
280 | &self, | |
|
281 | from: &Path, | |
|
282 | to: &Path, | |
|
283 | check_ambig: bool, | |
|
284 | ) -> Result<(), HgError>; | |
|
285 | fn copy(&self, from: &Path, to: &Path) -> Result<(), HgError>; | |
|
286 | } | |
|
287 | ||
|
288 | /// These methods will need to be implemented once `rhg` (and other) non-Python | |
|
289 | /// users of `hg-core` start doing more on their own, like writing to files. | |
|
290 | impl Vfs for VfsImpl { | |
|
291 | fn open(&self, _filename: &Path) -> Result<std::fs::File, HgError> { | |
|
292 | todo!() | |
|
293 | } | |
|
294 | fn open_read(&self, filename: &Path) -> Result<std::fs::File, HgError> { | |
|
295 | let path = self.base.join(filename); | |
|
296 | std::fs::File::open(&path).when_reading_file(&path) | |
|
297 | } | |
|
298 | fn open_check_ambig( | |
|
299 | &self, | |
|
300 | _filename: &Path, | |
|
301 | ) -> Result<std::fs::File, HgError> { | |
|
302 | todo!() | |
|
303 | } | |
|
304 | fn create(&self, _filename: &Path) -> Result<std::fs::File, HgError> { | |
|
305 | todo!() | |
|
306 | } | |
|
307 | fn create_atomic( | |
|
308 | &self, | |
|
309 | _filename: &Path, | |
|
310 | _check_ambig: bool, | |
|
311 | ) -> Result<AtomicFile, HgError> { | |
|
312 | todo!() | |
|
313 | } | |
|
314 | fn file_size(&self, file: &File) -> Result<u64, HgError> { | |
|
315 | Ok(file | |
|
316 | .metadata() | |
|
317 | .map_err(|e| { | |
|
318 | HgError::abort( | |
|
319 | format!("Could not get file metadata: {}", e), | |
|
320 | exit_codes::ABORT, | |
|
321 | None, | |
|
322 | ) | |
|
323 | })? | |
|
324 | .size()) | |
|
325 | } | |
|
326 | fn exists(&self, _filename: &Path) -> bool { | |
|
327 | todo!() | |
|
328 | } | |
|
329 | fn unlink(&self, _filename: &Path) -> Result<(), HgError> { | |
|
330 | todo!() | |
|
331 | } | |
|
332 | fn rename( | |
|
333 | &self, | |
|
334 | _from: &Path, | |
|
335 | _to: &Path, | |
|
336 | _check_ambig: bool, | |
|
337 | ) -> Result<(), HgError> { | |
|
338 | todo!() | |
|
339 | } | |
|
340 | fn copy(&self, _from: &Path, _to: &Path) -> Result<(), HgError> { | |
|
341 | todo!() | |
|
342 | } | |
|
343 | } | |
|
344 | ||
|
168 | 345 | pub(crate) fn is_dir(path: impl AsRef<Path>) -> Result<bool, HgError> { |
|
169 | 346 | Ok(fs_metadata(path)?.map_or(false, |meta| meta.is_dir())) |
|
170 | 347 | } |
@@ -393,8 +393,8 pub fn run(invocation: &crate::CliInvoca | |||
|
393 | 393 | // + map_err + collect, so let's just inline some of the |
|
394 | 394 | // logic. |
|
395 | 395 | match unsure_is_modified( |
|
396 | working_directory_vfs, | |
|
397 | store_vfs, | |
|
396 | &working_directory_vfs, | |
|
397 | &store_vfs, | |
|
398 | 398 | check_exec, |
|
399 | 399 | &manifest, |
|
400 | 400 | &to_check.path, |
@@ -748,8 +748,8 enum UnsureOutcome { | |||
|
748 | 748 | /// This meant to be used for those that the dirstate cannot resolve, due |
|
749 | 749 | /// to time resolution limits. |
|
750 | 750 | fn unsure_is_modified( |
|
751 | working_directory_vfs: hg::vfs::Vfs, | |
|
752 | store_vfs: hg::vfs::Vfs, | |
|
751 | working_directory_vfs: &hg::vfs::VfsImpl, | |
|
752 | store_vfs: &hg::vfs::VfsImpl, | |
|
753 | 753 | check_exec: bool, |
|
754 | 754 | manifest: &Manifest, |
|
755 | 755 | hg_path: &HgPath, |
@@ -786,7 +786,7 fn unsure_is_modified( | |||
|
786 | 786 | return Ok(UnsureOutcome::Modified); |
|
787 | 787 | } |
|
788 | 788 | let filelog = hg::filelog::Filelog::open_vfs( |
|
789 |
|
|
|
789 | store_vfs, | |
|
790 | 790 | hg_path, |
|
791 | 791 | revlog_open_options, |
|
792 | 792 | )?; |
General Comments 0
You need to be logged in to leave comments.
Login now