Show More
@@ -180,7 +180,7 dependencies = [ | |||||
180 | "js-sys", |
|
180 | "js-sys", | |
181 | "num-traits", |
|
181 | "num-traits", | |
182 | "wasm-bindgen", |
|
182 | "wasm-bindgen", | |
183 |
"windows-targets 0.52. |
|
183 | "windows-targets 0.52.6", | |
184 | ] |
|
184 | ] | |
185 |
|
185 | |||
186 | [[package]] |
|
186 | [[package]] | |
@@ -435,10 +435,16 dependencies = [ | |||||
435 | "libc", |
|
435 | "libc", | |
436 | "option-ext", |
|
436 | "option-ext", | |
437 | "redox_users", |
|
437 | "redox_users", | |
438 | "windows-sys", |
|
438 | "windows-sys 0.48.0", | |
439 | ] |
|
439 | ] | |
440 |
|
440 | |||
441 | [[package]] |
|
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 | name = "either" |
|
448 | name = "either" | |
443 | version = "1.8.0" |
|
449 | version = "1.8.0" | |
444 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
450 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
@@ -467,6 +473,18 dependencies = [ | |||||
467 | ] |
|
473 | ] | |
468 |
|
474 | |||
469 | [[package]] |
|
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 | name = "flate2" |
|
488 | name = "flate2" | |
471 | version = "1.0.24" |
|
489 | version = "1.0.24" | |
472 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
490 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
@@ -584,6 +602,8 dependencies = [ | |||||
584 | "clap", |
|
602 | "clap", | |
585 | "crossbeam-channel", |
|
603 | "crossbeam-channel", | |
586 | "derive_more", |
|
604 | "derive_more", | |
|
605 | "dyn-clone", | |||
|
606 | "filetime", | |||
587 | "flate2", |
|
607 | "flate2", | |
588 | "format-bytes", |
|
608 | "format-bytes", | |
589 | "hashbrown 0.13.1", |
|
609 | "hashbrown 0.13.1", | |
@@ -752,6 +772,7 checksum = "c0ff37bd590ca25063e35af745c3 | |||||
752 | dependencies = [ |
|
772 | dependencies = [ | |
753 | "bitflags 2.6.0", |
|
773 | "bitflags 2.6.0", | |
754 | "libc", |
|
774 | "libc", | |
|
775 | "redox_syscall 0.5.3", | |||
755 | ] |
|
776 | ] | |
756 |
|
777 | |||
757 | [[package]] |
|
778 | [[package]] | |
@@ -1123,6 +1144,15 dependencies = [ | |||||
1123 | ] |
|
1144 | ] | |
1124 |
|
1145 | |||
1125 | [[package]] |
|
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 | name = "redox_users" |
|
1156 | name = "redox_users" | |
1127 | version = "0.4.5" |
|
1157 | version = "0.4.5" | |
1128 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
1158 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
@@ -1348,7 +1378,7 dependencies = [ | |||||
1348 | "cfg-if", |
|
1378 | "cfg-if", | |
1349 | "fastrand", |
|
1379 | "fastrand", | |
1350 | "libc", |
|
1380 | "libc", | |
1351 | "redox_syscall", |
|
1381 | "redox_syscall 0.2.16", | |
1352 | "remove_dir_all", |
|
1382 | "remove_dir_all", | |
1353 | "winapi", |
|
1383 | "winapi", | |
1354 | ] |
|
1384 | ] | |
@@ -1615,6 +1645,15 dependencies = [ | |||||
1615 | ] |
|
1645 | ] | |
1616 |
|
1646 | |||
1617 | [[package]] |
|
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 | name = "windows-targets" |
|
1657 | name = "windows-targets" | |
1619 | version = "0.48.5" |
|
1658 | version = "0.48.5" | |
1620 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
1659 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
@@ -1631,17 +1670,18 dependencies = [ | |||||
1631 |
|
1670 | |||
1632 | [[package]] |
|
1671 | [[package]] | |
1633 | name = "windows-targets" |
|
1672 | name = "windows-targets" | |
1634 |
version = "0.52. |
|
1673 | version = "0.52.6" | |
1635 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
1674 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
1636 | checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" |
|
1675 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" | |
1637 | dependencies = [ |
|
1676 | dependencies = [ | |
1638 |
"windows_aarch64_gnullvm 0.52. |
|
1677 | "windows_aarch64_gnullvm 0.52.6", | |
1639 |
"windows_aarch64_msvc 0.52. |
|
1678 | "windows_aarch64_msvc 0.52.6", | |
1640 |
"windows_i686_gnu 0.52. |
|
1679 | "windows_i686_gnu 0.52.6", | |
1641 |
"windows_i686_ |
|
1680 | "windows_i686_gnullvm", | |
1642 |
"windows_ |
|
1681 | "windows_i686_msvc 0.52.6", | |
1643 |
"windows_x86_64_gnu |
|
1682 | "windows_x86_64_gnu 0.52.6", | |
1644 |
"windows_x86_64_m |
|
1683 | "windows_x86_64_gnullvm 0.52.6", | |
|
1684 | "windows_x86_64_msvc 0.52.6", | |||
1645 | ] |
|
1685 | ] | |
1646 |
|
1686 | |||
1647 | [[package]] |
|
1687 | [[package]] | |
@@ -1652,9 +1692,9 checksum = "2b38e32f0abccf9987a4e3079dfb | |||||
1652 |
|
1692 | |||
1653 | [[package]] |
|
1693 | [[package]] | |
1654 | name = "windows_aarch64_gnullvm" |
|
1694 | name = "windows_aarch64_gnullvm" | |
1655 |
version = "0.52. |
|
1695 | version = "0.52.6" | |
1656 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
1696 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
1657 | checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" |
|
1697 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" | |
1658 |
|
1698 | |||
1659 | [[package]] |
|
1699 | [[package]] | |
1660 | name = "windows_aarch64_msvc" |
|
1700 | name = "windows_aarch64_msvc" | |
@@ -1664,9 +1704,9 checksum = "dc35310971f3b2dbbf3f0690a219 | |||||
1664 |
|
1704 | |||
1665 | [[package]] |
|
1705 | [[package]] | |
1666 | name = "windows_aarch64_msvc" |
|
1706 | name = "windows_aarch64_msvc" | |
1667 |
version = "0.52. |
|
1707 | version = "0.52.6" | |
1668 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
1708 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
1669 | checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" |
|
1709 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" | |
1670 |
|
1710 | |||
1671 | [[package]] |
|
1711 | [[package]] | |
1672 | name = "windows_i686_gnu" |
|
1712 | name = "windows_i686_gnu" | |
@@ -1676,9 +1716,15 checksum = "a75915e7def60c94dcef72200b9a | |||||
1676 |
|
1716 | |||
1677 | [[package]] |
|
1717 | [[package]] | |
1678 | name = "windows_i686_gnu" |
|
1718 | name = "windows_i686_gnu" | |
1679 |
version = "0.52. |
|
1719 | version = "0.52.6" | |
1680 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
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 | [[package]] |
|
1729 | [[package]] | |
1684 | name = "windows_i686_msvc" |
|
1730 | name = "windows_i686_msvc" | |
@@ -1688,9 +1734,9 checksum = "8f55c233f70c4b27f66c523580f7 | |||||
1688 |
|
1734 | |||
1689 | [[package]] |
|
1735 | [[package]] | |
1690 | name = "windows_i686_msvc" |
|
1736 | name = "windows_i686_msvc" | |
1691 |
version = "0.52. |
|
1737 | version = "0.52.6" | |
1692 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
1738 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
1693 | checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" |
|
1739 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" | |
1694 |
|
1740 | |||
1695 | [[package]] |
|
1741 | [[package]] | |
1696 | name = "windows_x86_64_gnu" |
|
1742 | name = "windows_x86_64_gnu" | |
@@ -1700,9 +1746,9 checksum = "53d40abd2583d23e4718fddf1ebe | |||||
1700 |
|
1746 | |||
1701 | [[package]] |
|
1747 | [[package]] | |
1702 | name = "windows_x86_64_gnu" |
|
1748 | name = "windows_x86_64_gnu" | |
1703 |
version = "0.52. |
|
1749 | version = "0.52.6" | |
1704 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
1750 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
1705 | checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" |
|
1751 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" | |
1706 |
|
1752 | |||
1707 | [[package]] |
|
1753 | [[package]] | |
1708 | name = "windows_x86_64_gnullvm" |
|
1754 | name = "windows_x86_64_gnullvm" | |
@@ -1712,9 +1758,9 checksum = "0b7b52767868a23d5bab768e390d | |||||
1712 |
|
1758 | |||
1713 | [[package]] |
|
1759 | [[package]] | |
1714 | name = "windows_x86_64_gnullvm" |
|
1760 | name = "windows_x86_64_gnullvm" | |
1715 |
version = "0.52. |
|
1761 | version = "0.52.6" | |
1716 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
1762 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
1717 | checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" |
|
1763 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" | |
1718 |
|
1764 | |||
1719 | [[package]] |
|
1765 | [[package]] | |
1720 | name = "windows_x86_64_msvc" |
|
1766 | name = "windows_x86_64_msvc" | |
@@ -1724,9 +1770,9 checksum = "ed94fce61571a4006852b7389a06 | |||||
1724 |
|
1770 | |||
1725 | [[package]] |
|
1771 | [[package]] | |
1726 | name = "windows_x86_64_msvc" |
|
1772 | name = "windows_x86_64_msvc" | |
1727 |
version = "0.52. |
|
1773 | version = "0.52.6" | |
1728 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
1774 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
1729 | checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" |
|
1775 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" | |
1730 |
|
1776 | |||
1731 | [[package]] |
|
1777 | [[package]] | |
1732 | name = "wyz" |
|
1778 | name = "wyz" |
@@ -41,6 +41,8 format-bytes = "0.3.0" | |||||
41 | once_cell = "1.16.0" |
|
41 | once_cell = "1.16.0" | |
42 | bitvec = "1.0.1" |
|
42 | bitvec = "1.0.1" | |
43 | chrono = "0.4.34" |
|
43 | chrono = "0.4.34" | |
|
44 | dyn-clone = "1.0.16" | |||
|
45 | filetime = "0.2.23" | |||
44 |
|
46 | |||
45 | # We don't use the `miniz-oxide` backend to not change rhg benchmarks and until |
|
47 | # We don't use the `miniz-oxide` backend to not change rhg benchmarks and until | |
46 | # we have a clearer view of which backend is the fastest. |
|
48 | # we have a clearer view of which backend is the fastest. |
@@ -2,7 +2,7 | |||||
2 |
|
2 | |||
3 | use crate::errors::HgError; |
|
3 | use crate::errors::HgError; | |
4 | use crate::errors::HgResultExt; |
|
4 | use crate::errors::HgResultExt; | |
5 | use crate::vfs::Vfs; |
|
5 | use crate::vfs::VfsImpl; | |
6 | use std::io; |
|
6 | use std::io; | |
7 | use std::io::ErrorKind; |
|
7 | use std::io::ErrorKind; | |
8 |
|
8 | |||
@@ -21,7 +21,7 pub enum LockError { | |||||
21 | /// The return value of `f` is dropped in that case. If all is successful, the |
|
21 | /// The return value of `f` is dropped in that case. If all is successful, the | |
22 | /// return value of `f` is forwarded. |
|
22 | /// return value of `f` is forwarded. | |
23 | pub fn try_with_lock_no_wait<R>( |
|
23 | pub fn try_with_lock_no_wait<R>( | |
24 | hg_vfs: Vfs, |
|
24 | hg_vfs: &VfsImpl, | |
25 | lock_filename: &str, |
|
25 | lock_filename: &str, | |
26 | f: impl FnOnce() -> R, |
|
26 | f: impl FnOnce() -> R, | |
27 | ) -> Result<R, LockError> { |
|
27 | ) -> Result<R, LockError> { | |
@@ -57,7 +57,7 pub fn try_with_lock_no_wait<R>( | |||||
57 | Err(LockError::AlreadyHeld) |
|
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 | try_with_lock_no_wait(hg_vfs, &format!("{}.break", lock_filename), || { |
|
61 | try_with_lock_no_wait(hg_vfs, &format!("{}.break", lock_filename), || { | |
62 | // Check again in case some other process broke and |
|
62 | // Check again in case some other process broke and | |
63 | // acquired the lock in the meantime |
|
63 | // acquired the lock in the meantime | |
@@ -71,7 +71,7 fn break_lock(hg_vfs: Vfs, lock_filename | |||||
71 |
|
71 | |||
72 | #[cfg(unix)] |
|
72 | #[cfg(unix)] | |
73 | fn make_lock( |
|
73 | fn make_lock( | |
74 | hg_vfs: Vfs, |
|
74 | hg_vfs: &VfsImpl, | |
75 | lock_filename: &str, |
|
75 | lock_filename: &str, | |
76 | data: &str, |
|
76 | data: &str, | |
77 | ) -> Result<(), HgError> { |
|
77 | ) -> Result<(), HgError> { | |
@@ -82,7 +82,7 fn make_lock( | |||||
82 | } |
|
82 | } | |
83 |
|
83 | |||
84 | fn read_lock( |
|
84 | fn read_lock( | |
85 | hg_vfs: Vfs, |
|
85 | hg_vfs: &VfsImpl, | |
86 | lock_filename: &str, |
|
86 | lock_filename: &str, | |
87 | ) -> Result<Option<String>, HgError> { |
|
87 | ) -> Result<Option<String>, HgError> { | |
88 | let link_target = |
|
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 | hg_vfs.remove_file(lock_filename) |
|
102 | hg_vfs.remove_file(lock_filename) | |
103 | } |
|
103 | } | |
104 |
|
104 |
@@ -1,5 +1,5 | |||||
1 | use crate::errors::{HgError, HgResultExt, IoErrorContext, IoResultExt}; |
|
1 | use crate::errors::{HgError, HgResultExt, IoErrorContext, IoResultExt}; | |
2 | use crate::vfs::Vfs; |
|
2 | use crate::vfs::VfsImpl; | |
3 | use std::io::Write; |
|
3 | use std::io::Write; | |
4 |
|
4 | |||
5 | /// An utility to append to a log file with the given name, and optionally |
|
5 | /// An utility to append to a log file with the given name, and optionally | |
@@ -9,14 +9,14 use std::io::Write; | |||||
9 | /// "example.log.1" to "example.log.2" etc up to the given maximum number of |
|
9 | /// "example.log.1" to "example.log.2" etc up to the given maximum number of | |
10 | /// files. |
|
10 | /// files. | |
11 | pub struct LogFile<'a> { |
|
11 | pub struct LogFile<'a> { | |
12 |
vfs: Vfs |
|
12 | vfs: VfsImpl, | |
13 | name: &'a str, |
|
13 | name: &'a str, | |
14 | max_size: Option<u64>, |
|
14 | max_size: Option<u64>, | |
15 | max_files: u32, |
|
15 | max_files: u32, | |
16 | } |
|
16 | } | |
17 |
|
17 | |||
18 | impl<'a> LogFile<'a> { |
|
18 | impl<'a> LogFile<'a> { | |
19 |
pub fn new(vfs: Vfs |
|
19 | pub fn new(vfs: VfsImpl, name: &'a str) -> Self { | |
20 | Self { |
|
20 | Self { | |
21 | vfs, |
|
21 | vfs, | |
22 | name, |
|
22 | name, | |
@@ -87,8 +87,12 impl<'a> LogFile<'a> { | |||||
87 | #[test] |
|
87 | #[test] | |
88 | fn test_rotation() { |
|
88 | fn test_rotation() { | |
89 | let temp = tempfile::tempdir().unwrap(); |
|
89 | let temp = tempfile::tempdir().unwrap(); | |
90 |
let vfs = Vfs { |
|
90 | let vfs = VfsImpl { | |
91 | let logger = LogFile::new(vfs, "log").max_size(Some(3)).max_files(2); |
|
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 | logger.write(b"one\n").unwrap(); |
|
96 | logger.write(b"one\n").unwrap(); | |
93 | logger.write(b"two\n").unwrap(); |
|
97 | logger.write(b"two\n").unwrap(); | |
94 | logger.write(b"3\n").unwrap(); |
|
98 | logger.write(b"3\n").unwrap(); |
@@ -18,7 +18,7 use crate::utils::debug::debug_wait_for_ | |||||
18 | use crate::utils::files::get_path_from_bytes; |
|
18 | use crate::utils::files::get_path_from_bytes; | |
19 | use crate::utils::hg_path::HgPath; |
|
19 | use crate::utils::hg_path::HgPath; | |
20 | use crate::utils::SliceExt; |
|
20 | use crate::utils::SliceExt; | |
21 | use crate::vfs::{is_dir, is_file, Vfs}; |
|
21 | use crate::vfs::{is_dir, is_file, VfsImpl}; | |
22 | use crate::{ |
|
22 | use crate::{ | |
23 | requirements, NodePrefix, RevlogDataConfig, RevlogDeltaConfig, |
|
23 | requirements, NodePrefix, RevlogDataConfig, RevlogDeltaConfig, | |
24 | RevlogFeatureConfig, RevlogType, RevlogVersionOptions, UncheckedRevision, |
|
24 | RevlogFeatureConfig, RevlogType, RevlogVersionOptions, UncheckedRevision, | |
@@ -121,8 +121,10 impl Repo { | |||||
121 | let mut repo_config_files = |
|
121 | let mut repo_config_files = | |
122 | vec![dot_hg.join("hgrc"), dot_hg.join("hgrc-not-shared")]; |
|
122 | vec![dot_hg.join("hgrc"), dot_hg.join("hgrc-not-shared")]; | |
123 |
|
123 | |||
124 |
let hg_vfs = Vfs { |
|
124 | let hg_vfs = VfsImpl { | |
125 | let mut reqs = requirements::load_if_exists(hg_vfs)?; |
|
125 | base: dot_hg.to_owned(), | |
|
126 | }; | |||
|
127 | let mut reqs = requirements::load_if_exists(&hg_vfs)?; | |||
126 | let relative = |
|
128 | let relative = | |
127 | reqs.contains(requirements::RELATIVE_SHARED_REQUIREMENT); |
|
129 | reqs.contains(requirements::RELATIVE_SHARED_REQUIREMENT); | |
128 | let shared = |
|
130 | let shared = | |
@@ -163,9 +165,10 impl Repo { | |||||
163 |
|
165 | |||
164 | store_path = shared_path.join("store"); |
|
166 | store_path = shared_path.join("store"); | |
165 |
|
167 | |||
166 | let source_is_share_safe = |
|
168 | let source_is_share_safe = requirements::load(VfsImpl { | |
167 |
|
|
169 | base: shared_path.to_owned(), | |
168 | .contains(requirements::SHARESAFE_REQUIREMENT); |
|
170 | })? | |
|
171 | .contains(requirements::SHARESAFE_REQUIREMENT); | |||
169 |
|
172 | |||
170 | if share_safe != source_is_share_safe { |
|
173 | if share_safe != source_is_share_safe { | |
171 | return Err(HgError::unsupported("share-safe mismatch").into()); |
|
174 | return Err(HgError::unsupported("share-safe mismatch").into()); | |
@@ -176,7 +179,9 impl Repo { | |||||
176 | } |
|
179 | } | |
177 | } |
|
180 | } | |
178 | if share_safe { |
|
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 | let repo_config = if std::env::var_os("HGRCSKIPREPO").is_none() { |
|
187 | let repo_config = if std::env::var_os("HGRCSKIPREPO").is_none() { | |
@@ -216,19 +221,23 impl Repo { | |||||
216 |
|
221 | |||
217 | /// For accessing repository files (in `.hg`), except for the store |
|
222 | /// For accessing repository files (in `.hg`), except for the store | |
218 | /// (`.hg/store`). |
|
223 | /// (`.hg/store`). | |
219 |
pub fn hg_vfs(&self) -> Vfs |
|
224 | pub fn hg_vfs(&self) -> VfsImpl { | |
220 | Vfs { base: &self.dot_hg } |
|
225 | VfsImpl { | |
|
226 | base: self.dot_hg.to_owned(), | |||
|
227 | } | |||
221 | } |
|
228 | } | |
222 |
|
229 | |||
223 | /// For accessing repository store files (in `.hg/store`) |
|
230 | /// For accessing repository store files (in `.hg/store`) | |
224 |
pub fn store_vfs(&self) -> Vfs |
|
231 | pub fn store_vfs(&self) -> VfsImpl { | |
225 | Vfs { base: &self.store } |
|
232 | VfsImpl { | |
|
233 | base: self.store.to_owned(), | |||
|
234 | } | |||
226 | } |
|
235 | } | |
227 |
|
236 | |||
228 | /// For accessing the working copy |
|
237 | /// For accessing the working copy | |
229 |
pub fn working_directory_vfs(&self) -> Vfs |
|
238 | pub fn working_directory_vfs(&self) -> VfsImpl { | |
230 | Vfs { |
|
239 | VfsImpl { | |
231 |
base: |
|
240 | base: self.working_directory.to_owned(), | |
232 | } |
|
241 | } | |
233 | } |
|
242 | } | |
234 |
|
243 | |||
@@ -236,7 +245,7 impl Repo { | |||||
236 | &self, |
|
245 | &self, | |
237 | f: impl FnOnce() -> R, |
|
246 | f: impl FnOnce() -> R, | |
238 | ) -> Result<R, LockError> { |
|
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 | /// Whether this repo should use dirstate-v2. |
|
251 | /// Whether this repo should use dirstate-v2. |
@@ -1,7 +1,7 | |||||
1 | use crate::errors::{HgError, HgResultExt}; |
|
1 | use crate::errors::{HgError, HgResultExt}; | |
2 | use crate::repo::Repo; |
|
2 | use crate::repo::Repo; | |
3 | use crate::utils::join_display; |
|
3 | use crate::utils::join_display; | |
4 | use crate::vfs::Vfs; |
|
4 | use crate::vfs::VfsImpl; | |
5 | use std::collections::HashSet; |
|
5 | use std::collections::HashSet; | |
6 |
|
6 | |||
7 | fn parse(bytes: &[u8]) -> Result<HashSet<String>, HgError> { |
|
7 | fn parse(bytes: &[u8]) -> Result<HashSet<String>, HgError> { | |
@@ -24,11 +24,13 fn parse(bytes: &[u8]) -> Result<HashSet | |||||
24 | .collect() |
|
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 | parse(&hg_vfs.read("requires")?) |
|
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 | if let Some(bytes) = hg_vfs.read("requires").io_not_found_as_none()? { |
|
34 | if let Some(bytes) = hg_vfs.read("requires").io_not_found_as_none()? { | |
33 | parse(&bytes) |
|
35 | parse(&bytes) | |
34 | } else { |
|
36 | } else { |
@@ -13,7 +13,7 use crate::revlog::Revision; | |||||
13 | use crate::revlog::{Node, NodePrefix}; |
|
13 | use crate::revlog::{Node, NodePrefix}; | |
14 | use crate::revlog::{Revlog, RevlogEntry, RevlogError}; |
|
14 | use crate::revlog::{Revlog, RevlogEntry, RevlogError}; | |
15 | use crate::utils::hg_path::HgPath; |
|
15 | use crate::utils::hg_path::HgPath; | |
16 | use crate::vfs::Vfs; |
|
16 | use crate::vfs::VfsImpl; | |
17 | use crate::{Graph, GraphError, RevlogOpenOptions, UncheckedRevision}; |
|
17 | use crate::{Graph, GraphError, RevlogOpenOptions, UncheckedRevision}; | |
18 |
|
18 | |||
19 | /// A specialized `Revlog` to work with changelog data format. |
|
19 | /// A specialized `Revlog` to work with changelog data format. | |
@@ -25,7 +25,7 pub struct Changelog { | |||||
25 | impl Changelog { |
|
25 | impl Changelog { | |
26 | /// Open the `changelog` of a repository given by its root. |
|
26 | /// Open the `changelog` of a repository given by its root. | |
27 | pub fn open( |
|
27 | pub fn open( | |
28 | store_vfs: &Vfs, |
|
28 | store_vfs: &VfsImpl, | |
29 | options: RevlogOpenOptions, |
|
29 | options: RevlogOpenOptions, | |
30 | ) -> Result<Self, HgError> { |
|
30 | ) -> Result<Self, HgError> { | |
31 | let revlog = Revlog::open(store_vfs, "00changelog.i", None, options)?; |
|
31 | let revlog = Revlog::open(store_vfs, "00changelog.i", None, options)?; | |
@@ -500,7 +500,7 fn unescape_extra(bytes: &[u8]) -> Vec<u | |||||
500 | #[cfg(test)] |
|
500 | #[cfg(test)] | |
501 | mod tests { |
|
501 | mod tests { | |
502 | use super::*; |
|
502 | use super::*; | |
503 | use crate::vfs::Vfs; |
|
503 | use crate::vfs::VfsImpl; | |
504 | use crate::{ |
|
504 | use crate::{ | |
505 | RevlogDataConfig, RevlogDeltaConfig, RevlogFeatureConfig, |
|
505 | RevlogDataConfig, RevlogDeltaConfig, RevlogFeatureConfig, | |
506 | NULL_REVISION, |
|
506 | NULL_REVISION, | |
@@ -563,7 +563,9 message", | |||||
563 | fn test_data_from_rev_null() -> Result<(), RevlogError> { |
|
563 | fn test_data_from_rev_null() -> Result<(), RevlogError> { | |
564 | // an empty revlog will be enough for this case |
|
564 | // an empty revlog will be enough for this case | |
565 | let temp = tempfile::tempdir().unwrap(); |
|
565 | let temp = tempfile::tempdir().unwrap(); | |
566 |
let vfs = Vfs { |
|
566 | let vfs = VfsImpl { | |
|
567 | base: temp.path().to_owned(), | |||
|
568 | }; | |||
567 | std::fs::write(temp.path().join("foo.i"), b"").unwrap(); |
|
569 | std::fs::write(temp.path().join("foo.i"), b"").unwrap(); | |
568 | std::fs::write(temp.path().join("foo.d"), b"").unwrap(); |
|
570 | std::fs::write(temp.path().join("foo.d"), b"").unwrap(); | |
569 | let revlog = Revlog::open( |
|
571 | let revlog = Revlog::open( |
@@ -29,7 +29,7 impl Graph for Filelog { | |||||
29 |
|
29 | |||
30 | impl Filelog { |
|
30 | impl Filelog { | |
31 | pub fn open_vfs( |
|
31 | pub fn open_vfs( | |
32 |
store_vfs: &crate::vfs::Vfs |
|
32 | store_vfs: &crate::vfs::VfsImpl, | |
33 | file_path: &HgPath, |
|
33 | file_path: &HgPath, | |
34 | options: RevlogOpenOptions, |
|
34 | options: RevlogOpenOptions, | |
35 | ) -> Result<Self, HgError> { |
|
35 | ) -> Result<Self, HgError> { |
@@ -3,7 +3,7 use crate::revlog::{Node, NodePrefix}; | |||||
3 | use crate::revlog::{Revlog, RevlogError}; |
|
3 | use crate::revlog::{Revlog, RevlogError}; | |
4 | use crate::utils::hg_path::HgPath; |
|
4 | use crate::utils::hg_path::HgPath; | |
5 | use crate::utils::SliceExt; |
|
5 | use crate::utils::SliceExt; | |
6 | use crate::vfs::Vfs; |
|
6 | use crate::vfs::VfsImpl; | |
7 | use crate::{ |
|
7 | use crate::{ | |
8 | Graph, GraphError, Revision, RevlogOpenOptions, UncheckedRevision, |
|
8 | Graph, GraphError, Revision, RevlogOpenOptions, UncheckedRevision, | |
9 | }; |
|
9 | }; | |
@@ -23,7 +23,7 impl Graph for Manifestlog { | |||||
23 | impl Manifestlog { |
|
23 | impl Manifestlog { | |
24 | /// Open the `manifest` of a repository given by its root. |
|
24 | /// Open the `manifest` of a repository given by its root. | |
25 | pub fn open( |
|
25 | pub fn open( | |
26 | store_vfs: &Vfs, |
|
26 | store_vfs: &VfsImpl, | |
27 | options: RevlogOpenOptions, |
|
27 | options: RevlogOpenOptions, | |
28 | ) -> Result<Self, HgError> { |
|
28 | ) -> Result<Self, HgError> { | |
29 | let revlog = Revlog::open(store_vfs, "00manifest.i", None, options)?; |
|
29 | let revlog = Revlog::open(store_vfs, "00manifest.i", None, options)?; |
@@ -38,7 +38,7 use crate::exit_codes; | |||||
38 | use crate::requirements::{ |
|
38 | use crate::requirements::{ | |
39 | GENERALDELTA_REQUIREMENT, NARROW_REQUIREMENT, SPARSEREVLOG_REQUIREMENT, |
|
39 | GENERALDELTA_REQUIREMENT, NARROW_REQUIREMENT, SPARSEREVLOG_REQUIREMENT, | |
40 | }; |
|
40 | }; | |
41 | use crate::vfs::Vfs; |
|
41 | use crate::vfs::VfsImpl; | |
42 |
|
42 | |||
43 | /// As noted in revlog.c, revision numbers are actually encoded in |
|
43 | /// As noted in revlog.c, revision numbers are actually encoded in | |
44 | /// 4 bytes, and are liberally converted to ints, whence the i32 |
|
44 | /// 4 bytes, and are liberally converted to ints, whence the i32 | |
@@ -708,7 +708,8 impl Revlog { | |||||
708 | /// It will also open the associated data file if index and data are not |
|
708 | /// It will also open the associated data file if index and data are not | |
709 | /// interleaved. |
|
709 | /// interleaved. | |
710 | pub fn open( |
|
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 | index_path: impl AsRef<Path>, |
|
713 | index_path: impl AsRef<Path>, | |
713 | data_path: Option<&Path>, |
|
714 | data_path: Option<&Path>, | |
714 | options: RevlogOpenOptions, |
|
715 | options: RevlogOpenOptions, | |
@@ -717,7 +718,8 impl Revlog { | |||||
717 | } |
|
718 | } | |
718 |
|
719 | |||
719 | fn open_gen( |
|
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 | index_path: impl AsRef<Path>, |
|
723 | index_path: impl AsRef<Path>, | |
722 | data_path: Option<&Path>, |
|
724 | data_path: Option<&Path>, | |
723 | options: RevlogOpenOptions, |
|
725 | options: RevlogOpenOptions, | |
@@ -1298,7 +1300,9 mod tests { | |||||
1298 | #[test] |
|
1300 | #[test] | |
1299 | fn test_empty() { |
|
1301 | fn test_empty() { | |
1300 | let temp = tempfile::tempdir().unwrap(); |
|
1302 | let temp = tempfile::tempdir().unwrap(); | |
1301 |
let vfs = Vfs { |
|
1303 | let vfs = VfsImpl { | |
|
1304 | base: temp.path().to_owned(), | |||
|
1305 | }; | |||
1302 | std::fs::write(temp.path().join("foo.i"), b"").unwrap(); |
|
1306 | std::fs::write(temp.path().join("foo.i"), b"").unwrap(); | |
1303 | std::fs::write(temp.path().join("foo.d"), b"").unwrap(); |
|
1307 | std::fs::write(temp.path().join("foo.d"), b"").unwrap(); | |
1304 | let revlog = |
|
1308 | let revlog = | |
@@ -1320,7 +1324,9 mod tests { | |||||
1320 | #[test] |
|
1324 | #[test] | |
1321 | fn test_inline() { |
|
1325 | fn test_inline() { | |
1322 | let temp = tempfile::tempdir().unwrap(); |
|
1326 | let temp = tempfile::tempdir().unwrap(); | |
1323 |
let vfs = Vfs { |
|
1327 | let vfs = VfsImpl { | |
|
1328 | base: temp.path().to_owned(), | |||
|
1329 | }; | |||
1324 | let node0 = Node::from_hex("2ed2a3912a0b24502043eae84ee4b279c18b90dd") |
|
1330 | let node0 = Node::from_hex("2ed2a3912a0b24502043eae84ee4b279c18b90dd") | |
1325 | .unwrap(); |
|
1331 | .unwrap(); | |
1326 | let node1 = Node::from_hex("b004912a8510032a0350a74daa2803dadfb00e12") |
|
1332 | let node1 = Node::from_hex("b004912a8510032a0350a74daa2803dadfb00e12") | |
@@ -1387,7 +1393,9 mod tests { | |||||
1387 | #[test] |
|
1393 | #[test] | |
1388 | fn test_nodemap() { |
|
1394 | fn test_nodemap() { | |
1389 | let temp = tempfile::tempdir().unwrap(); |
|
1395 | let temp = tempfile::tempdir().unwrap(); | |
1390 |
let vfs = Vfs { |
|
1396 | let vfs = VfsImpl { | |
|
1397 | base: temp.path().to_owned(), | |||
|
1398 | }; | |||
1391 |
|
1399 | |||
1392 | // building a revlog with a forced Node starting with zeros |
|
1400 | // building a revlog with a forced Node starting with zeros | |
1393 | // This is a corruption, but it does not preclude using the nodemap |
|
1401 | // This is a corruption, but it does not preclude using the nodemap |
@@ -3,7 +3,7 use bytes_cast::{unaligned, BytesCast}; | |||||
3 | use memmap2::Mmap; |
|
3 | use memmap2::Mmap; | |
4 | use std::path::{Path, PathBuf}; |
|
4 | use std::path::{Path, PathBuf}; | |
5 |
|
5 | |||
6 | use crate::vfs::Vfs; |
|
6 | use crate::vfs::VfsImpl; | |
7 |
|
7 | |||
8 | const ONDISK_VERSION: u8 = 1; |
|
8 | const ONDISK_VERSION: u8 = 1; | |
9 |
|
9 | |||
@@ -33,7 +33,7 impl NodeMapDocket { | |||||
33 | /// * The docket file points to a missing (likely deleted) data file (this |
|
33 | /// * The docket file points to a missing (likely deleted) data file (this | |
34 | /// can happen in a rare race condition). |
|
34 | /// can happen in a rare race condition). | |
35 | pub fn read_from_file( |
|
35 | pub fn read_from_file( | |
36 | store_vfs: &Vfs, |
|
36 | store_vfs: &VfsImpl, | |
37 | index_path: &Path, |
|
37 | index_path: &Path, | |
38 | ) -> Result<Option<(Self, Mmap)>, HgError> { |
|
38 | ) -> Result<Option<(Self, Mmap)>, HgError> { | |
39 | let docket_path = index_path.with_extension("n"); |
|
39 | let docket_path = index_path.with_extension("n"); |
@@ -1,17 +1,21 | |||||
1 | use crate::errors::{HgError, IoErrorContext, IoResultExt}; |
|
1 | use crate::errors::{HgError, IoErrorContext, IoResultExt}; | |
|
2 | use crate::exit_codes; | |||
|
3 | use dyn_clone::DynClone; | |||
2 | use memmap2::{Mmap, MmapOptions}; |
|
4 | use memmap2::{Mmap, MmapOptions}; | |
|
5 | use std::fs::File; | |||
3 | use std::io::{ErrorKind, Write}; |
|
6 | use std::io::{ErrorKind, Write}; | |
|
7 | use std::os::unix::fs::MetadataExt; | |||
4 | use std::path::{Path, PathBuf}; |
|
8 | use std::path::{Path, PathBuf}; | |
5 |
|
9 | |||
6 | /// Filesystem access abstraction for the contents of a given "base" diretory |
|
10 | /// Filesystem access abstraction for the contents of a given "base" diretory | |
7 |
#[derive(Clone |
|
11 | #[derive(Clone)] | |
8 |
pub struct Vfs |
|
12 | pub struct VfsImpl { | |
9 |
pub(crate) base: |
|
13 | pub(crate) base: PathBuf, | |
10 | } |
|
14 | } | |
11 |
|
15 | |||
12 | struct FileNotFound(std::io::Error, PathBuf); |
|
16 | struct FileNotFound(std::io::Error, PathBuf); | |
13 |
|
17 | |||
14 |
impl Vfs |
|
18 | impl VfsImpl { | |
15 | pub fn join(&self, relative_path: impl AsRef<Path>) -> PathBuf { |
|
19 | pub fn join(&self, relative_path: impl AsRef<Path>) -> PathBuf { | |
16 | self.base.join(relative_path) |
|
20 | self.base.join(relative_path) | |
17 | } |
|
21 | } | |
@@ -71,7 +75,12 impl Vfs<'_> { | |||||
71 | } |
|
75 | } | |
72 | Ok(file) => file, |
|
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 | let mmap = unsafe { MmapOptions::new().map(&file) } |
|
84 | let mmap = unsafe { MmapOptions::new().map(&file) } | |
76 | .when_reading_file(&path)?; |
|
85 | .when_reading_file(&path)?; | |
77 | Ok(Ok(mmap)) |
|
86 | Ok(Ok(mmap)) | |
@@ -134,8 +143,8 impl Vfs<'_> { | |||||
134 | relative_path: impl AsRef<Path>, |
|
143 | relative_path: impl AsRef<Path>, | |
135 | contents: &[u8], |
|
144 | contents: &[u8], | |
136 | ) -> Result<(), HgError> { |
|
145 | ) -> Result<(), HgError> { | |
137 | let mut tmp = tempfile::NamedTempFile::new_in(self.base) |
|
146 | let mut tmp = tempfile::NamedTempFile::new_in(&self.base) | |
138 | .when_writing_file(self.base)?; |
|
147 | .when_writing_file(&self.base)?; | |
139 | tmp.write_all(contents) |
|
148 | tmp.write_all(contents) | |
140 | .and_then(|()| tmp.flush()) |
|
149 | .and_then(|()| tmp.flush()) | |
141 | .when_writing_file(tmp.path())?; |
|
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 | pub(crate) fn is_dir(path: impl AsRef<Path>) -> Result<bool, HgError> { |
|
345 | pub(crate) fn is_dir(path: impl AsRef<Path>) -> Result<bool, HgError> { | |
169 | Ok(fs_metadata(path)?.map_or(false, |meta| meta.is_dir())) |
|
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 | // + map_err + collect, so let's just inline some of the |
|
393 | // + map_err + collect, so let's just inline some of the | |
394 | // logic. |
|
394 | // logic. | |
395 | match unsure_is_modified( |
|
395 | match unsure_is_modified( | |
396 | working_directory_vfs, |
|
396 | &working_directory_vfs, | |
397 | store_vfs, |
|
397 | &store_vfs, | |
398 | check_exec, |
|
398 | check_exec, | |
399 | &manifest, |
|
399 | &manifest, | |
400 | &to_check.path, |
|
400 | &to_check.path, | |
@@ -748,8 +748,8 enum UnsureOutcome { | |||||
748 | /// This meant to be used for those that the dirstate cannot resolve, due |
|
748 | /// This meant to be used for those that the dirstate cannot resolve, due | |
749 | /// to time resolution limits. |
|
749 | /// to time resolution limits. | |
750 | fn unsure_is_modified( |
|
750 | fn unsure_is_modified( | |
751 | working_directory_vfs: hg::vfs::Vfs, |
|
751 | working_directory_vfs: &hg::vfs::VfsImpl, | |
752 | store_vfs: hg::vfs::Vfs, |
|
752 | store_vfs: &hg::vfs::VfsImpl, | |
753 | check_exec: bool, |
|
753 | check_exec: bool, | |
754 | manifest: &Manifest, |
|
754 | manifest: &Manifest, | |
755 | hg_path: &HgPath, |
|
755 | hg_path: &HgPath, | |
@@ -786,7 +786,7 fn unsure_is_modified( | |||||
786 | return Ok(UnsureOutcome::Modified); |
|
786 | return Ok(UnsureOutcome::Modified); | |
787 | } |
|
787 | } | |
788 | let filelog = hg::filelog::Filelog::open_vfs( |
|
788 | let filelog = hg::filelog::Filelog::open_vfs( | |
789 |
|
|
789 | store_vfs, | |
790 | hg_path, |
|
790 | hg_path, | |
791 | revlog_open_options, |
|
791 | revlog_open_options, | |
792 | )?; |
|
792 | )?; |
General Comments 0
You need to be logged in to leave comments.
Login now