##// END OF EJS Templates
merge: with stable
Augie Fackler -
r50054:9d1e9689 merge default draft
parent child Browse files
Show More
@@ -21,7 +21,7 b' except ImportError:'
21 21 # available. Relax C module requirements.
22 22 os.environ['HGMODULEPOLICY'] = 'allow'
23 23 # import from the live mercurial repo
24 sys.path.insert(0, "..")
24 sys.path.insert(0, os.path.abspath(".."))
25 25 from mercurial import demandimport
26 26
27 27 demandimport.enable()
@@ -46,6 +46,7 b' from . import ('
46 46 context,
47 47 copies,
48 48 dagparser,
49 dirstateutils,
49 50 encoding,
50 51 error,
51 52 exchange,
@@ -939,6 +940,12 b' def debugdeltachain(ui, repo, file_=None'
939 940 (b'', b'datesort', None, _(b'sort by saved mtime')),
940 941 (
941 942 b'',
943 b'docket',
944 False,
945 _(b'display the docket (metadata file) instead'),
946 ),
947 (
948 b'',
942 949 b'all',
943 950 False,
944 951 _(b'display dirstate-v2 tree nodes that would not exist in v1'),
@@ -949,6 +956,33 b' def debugdeltachain(ui, repo, file_=None'
949 956 def debugstate(ui, repo, **opts):
950 957 """show the contents of the current dirstate"""
951 958
959 if opts.get("docket"):
960 if not repo.dirstate._use_dirstate_v2:
961 raise error.Abort(_(b'dirstate v1 does not have a docket'))
962
963 docket = repo.dirstate._map.docket
964 (
965 start_offset,
966 root_nodes,
967 nodes_with_entry,
968 nodes_with_copy,
969 unused_bytes,
970 _unused,
971 ignore_pattern,
972 ) = dirstateutils.v2.TREE_METADATA.unpack(docket.tree_metadata)
973
974 ui.write(_(b"size of dirstate data: %d\n") % docket.data_size)
975 ui.write(_(b"data file uuid: %s\n") % docket.uuid)
976 ui.write(_(b"start offset of root nodes: %d\n") % start_offset)
977 ui.write(_(b"number of root nodes: %d\n") % root_nodes)
978 ui.write(_(b"nodes with entries: %d\n") % nodes_with_entry)
979 ui.write(_(b"nodes with copies: %d\n") % nodes_with_copy)
980 ui.write(_(b"number of unused bytes: %d\n") % unused_bytes)
981 ui.write(
982 _(b"ignore pattern hash: %s\n") % binascii.hexlify(ignore_pattern)
983 )
984 return
985
952 986 nodates = not opts['dates']
953 987 if opts.get('nodates') is not None:
954 988 nodates = True
@@ -983,22 +1017,6 b' def debugstate(ui, repo, **opts):'
983 1017
984 1018
985 1019 @command(
986 b'debugdirstateignorepatternshash',
987 [],
988 _(b''),
989 )
990 def debugdirstateignorepatternshash(ui, repo, **opts):
991 """show the hash of ignore patterns stored in dirstate if v2,
992 or nothing for dirstate-v2
993 """
994 if repo.dirstate._use_dirstate_v2:
995 docket = repo.dirstate._map.docket
996 hash_len = 20 # 160 bits for SHA-1
997 hash_bytes = docket.tree_metadata[-hash_len:]
998 ui.write(binascii.hexlify(hash_bytes) + b'\n')
999
1000
1001 @command(
1002 1020 b'debugdiscovery',
1003 1021 [
1004 1022 (b'', b'old', None, _(b'use old-style discovery')),
@@ -28,7 +28,8 b' in progress. For more experimental work '
28 28 Checking for Rust
29 29 =================
30 30
31 You may already have the Rust extensions depending on how you install Mercurial.
31 You may already have the Rust extensions depending on how you install
32 Mercurial::
32 33
33 34 $ hg debuginstall | grep -i rust
34 35 checking Rust extensions (installed)
@@ -46,7 +47,7 b' version to use.'
46 47 Using pip
47 48 ---------
48 49
49 Users of `pip` can install the Rust extensions with the following command:
50 Users of `pip` can install the Rust extensions with the following command::
50 51
51 52 $ pip install mercurial --global-option --rust --no-use-pep517
52 53
@@ -3175,7 +3175,7 b' class localrepository:'
3175 3175 # Save commit message in case this transaction gets rolled back
3176 3176 # (e.g. by a pretxncommit hook). Leave the content alone on
3177 3177 # the assumption that the user will use the same editor again.
3178 msgfn = self.savecommitmessage(cctx._text)
3178 msg_path = self.savecommitmessage(cctx._text)
3179 3179
3180 3180 # commit subs and write new state
3181 3181 if subs:
@@ -3205,13 +3205,14 b' class localrepository:'
3205 3205 except: # re-raises
3206 3206 if edited:
3207 3207 self.ui.write(
3208 _(b'note: commit message saved in %s\n') % msgfn
3208 _(b'note: commit message saved in %s\n') % msg_path
3209 3209 )
3210 3210 self.ui.write(
3211 3211 _(
3212 3212 b"note: use 'hg commit --logfile "
3213 b".hg/last-message.txt --edit' to reuse it\n"
3213 b"%s --edit' to reuse it\n"
3214 3214 )
3215 % msg_path
3215 3216 )
3216 3217 raise
3217 3218
@@ -590,9 +590,9 b' checksum = "e2abad23fbc42b3700f2f279844d'
590 590
591 591 [[package]]
592 592 name = "libc"
593 version = "0.2.119"
593 version = "0.2.124"
594 594 source = "registry+https://github.com/rust-lang/crates.io-index"
595 checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
595 checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50"
596 596
597 597 [[package]]
598 598 name = "libm"
@@ -1032,6 +1032,7 b' dependencies = ['
1032 1032 "micro-timer 0.4.0",
1033 1033 "regex",
1034 1034 "users",
1035 "which",
1035 1036 ]
1036 1037
1037 1038 [[package]]
@@ -1251,6 +1252,17 b' source = "registry+https://github.com/ru'
1251 1252 checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
1252 1253
1253 1254 [[package]]
1255 name = "which"
1256 version = "4.2.5"
1257 source = "registry+https://github.com/rust-lang/crates.io-index"
1258 checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae"
1259 dependencies = [
1260 "either",
1261 "lazy_static",
1262 "libc",
1263 ]
1264
1265 [[package]]
1254 1266 name = "winapi"
1255 1267 version = "0.3.9"
1256 1268 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -622,13 +622,18 b' pub(super) fn write('
622 622
623 623 let root_nodes = writer.write_nodes(dirstate_map.root.as_ref())?;
624 624
625 let unreachable_bytes = if append {
626 dirstate_map.unreachable_bytes
627 } else {
628 0
629 };
625 630 let meta = TreeMetadata {
626 631 root_nodes,
627 632 nodes_with_entry_count: dirstate_map.nodes_with_entry_count.into(),
628 633 nodes_with_copy_source_count: dirstate_map
629 634 .nodes_with_copy_source_count
630 635 .into(),
631 unreachable_bytes: dirstate_map.unreachable_bytes.into(),
636 unreachable_bytes: unreachable_bytes.into(),
632 637 unused: [0; 4],
633 638 ignore_patterns_hash: dirstate_map.ignore_patterns_hash,
634 639 };
@@ -17,3 +17,6 b' pub const UNSUCCESSFUL: ExitCode = 1;'
17 17
18 18 /// Command or feature not implemented by rhg
19 19 pub const UNIMPLEMENTED: ExitCode = 252;
20
21 /// The fallback path is not valid
22 pub const INVALID_FALLBACK: ExitCode = 253;
@@ -424,25 +424,32 b' impl Repo {'
424 424 // it’s unset
425 425 let parents = self.dirstate_parents()?;
426 426 let (packed_dirstate, old_uuid_to_remove) = if self.has_dirstate_v2() {
427 let uuid = self.dirstate_data_file_uuid.get_or_init(self)?;
428 let mut uuid = uuid.as_ref();
429 let can_append = uuid.is_some();
427 let uuid_opt = self.dirstate_data_file_uuid.get_or_init(self)?;
428 let uuid_opt = uuid_opt.as_ref();
429 let can_append = uuid_opt.is_some();
430 430 let (data, tree_metadata, append, old_data_size) =
431 431 map.pack_v2(can_append)?;
432 if !append {
433 uuid = None
434 }
435 let (uuid, old_uuid) = if let Some(uuid) = uuid {
436 let as_str = std::str::from_utf8(uuid)
437 .map_err(|_| {
438 HgError::corrupted("non-UTF-8 dirstate data file ID")
439 })?
440 .to_owned();
441 let old_uuid_to_remove = Some(as_str.to_owned());
442 (as_str, old_uuid_to_remove)
443 } else {
444 (DirstateDocket::new_uid(), None)
432
433 // Reuse the uuid, or generate a new one, keeping the old for
434 // deletion.
435 let (uuid, old_uuid) = match uuid_opt {
436 Some(uuid) => {
437 let as_str = std::str::from_utf8(uuid)
438 .map_err(|_| {
439 HgError::corrupted(
440 "non-UTF-8 dirstate data file ID",
441 )
442 })?
443 .to_owned();
444 if append {
445 (as_str, None)
446 } else {
447 (DirstateDocket::new_uid(), Some(as_str))
448 }
449 }
450 None => (DirstateDocket::new_uid(), None),
445 451 };
452
446 453 let data_filename = format!("dirstate.{}", uuid);
447 454 let data_filename = self.hg_vfs().join(data_filename);
448 455 let mut options = std::fs::OpenOptions::new();
@@ -21,3 +21,4 b' regex = "1.5.5"'
21 21 env_logger = "0.9.0"
22 22 format-bytes = "0.3.0"
23 23 users = "0.11.0"
24 which = "4.2.5"
@@ -29,6 +29,9 b' pub enum CommandError {'
29 29 /// `rhg` may attempt to silently fall back to Python-based `hg`, which
30 30 /// may or may not support this feature.
31 31 UnsupportedFeature { message: Vec<u8> },
32 /// The fallback executable does not exist (or has some other problem if
33 /// we end up being more precise about broken fallbacks).
34 InvalidFallback { path: Vec<u8>, err: String },
32 35 }
33 36
34 37 impl CommandError {
@@ -13,6 +13,7 b' use hg::utils::files::{get_bytes_from_os'
13 13 use hg::utils::SliceExt;
14 14 use std::collections::HashSet;
15 15 use std::ffi::OsString;
16 use std::os::unix::prelude::CommandExt;
16 17 use std::path::PathBuf;
17 18 use std::process::Command;
18 19
@@ -381,12 +382,14 b' fn exit_code('
381 382 }
382 383 }
383 384 Err(CommandError::Unsuccessful) => exit_codes::UNSUCCESSFUL,
384
385 385 // Exit with a specific code and no error message to let a potential
386 386 // wrapper script fallback to Python-based Mercurial.
387 387 Err(CommandError::UnsupportedFeature { .. }) => {
388 388 exit_codes::UNIMPLEMENTED
389 389 }
390 Err(CommandError::InvalidFallback { .. }) => {
391 exit_codes::INVALID_FALLBACK
392 }
390 393 }
391 394 }
392 395
@@ -432,6 +435,17 b" fn exit<'a>("
432 435 } else {
433 436 log::debug!("falling back (see trace-level log)");
434 437 log::trace!("{}", local_to_utf8(message));
438 if let Err(err) = which::which(executable_path) {
439 exit_no_fallback(
440 ui,
441 OnUnsupported::Abort,
442 Err(CommandError::InvalidFallback {
443 path: executable.to_owned(),
444 err: err.to_string(),
445 }),
446 use_detailed_exit_code,
447 )
448 }
435 449 // `args` is now `argv[1..]` since we’ve already consumed
436 450 // `argv[0]`
437 451 let mut command = Command::new(executable_path);
@@ -439,19 +453,19 b" fn exit<'a>("
439 453 if let Some(initial) = initial_current_dir {
440 454 command.current_dir(initial);
441 455 }
442 let result = command.status();
443 match result {
444 Ok(status) => std::process::exit(
445 status.code().unwrap_or(exit_codes::ABORT),
446 ),
447 Err(error) => {
448 let _ = ui.write_stderr(&format_bytes!(
449 b"tried to fall back to a '{}' sub-process but got error {}\n",
450 executable, format_bytes::Utf8(error)
451 ));
452 on_unsupported = OnUnsupported::Abort
453 }
454 }
456 // We don't use subprocess because proper signal handling is harder
457 // and we don't want to keep `rhg` around after a fallback anyway.
458 // For example, if `rhg` is run in the background and falls back to
459 // `hg` which, in turn, waits for a signal, we'll get stuck if
460 // we're doing plain subprocess.
461 //
462 // If `exec` returns, we can only assume our process is very broken
463 // (see its documentation), so only try to forward the error code
464 // when exiting.
465 let err = command.exec();
466 std::process::exit(
467 err.raw_os_error().unwrap_or(exit_codes::ABORT),
468 );
455 469 }
456 470 }
457 471 exit_no_fallback(ui, on_unsupported, result, use_detailed_exit_code)
@@ -488,6 +502,13 b' fn exit_no_fallback('
488 502 OnUnsupported::Fallback { .. } => unreachable!(),
489 503 }
490 504 }
505 Err(CommandError::InvalidFallback { path, err }) => {
506 let _ = ui.write_stderr(&format_bytes!(
507 b"abort: invalid fallback '{}': {}\n",
508 path,
509 err.as_bytes(),
510 ));
511 }
491 512 }
492 513 std::process::exit(exit_code(&result, use_detailed_exit_code))
493 514 }
@@ -94,7 +94,6 b' Show debug commands if there are no othe'
94 94 debugdate
95 95 debugdeltachain
96 96 debugdirstate
97 debugdirstateignorepatternshash
98 97 debugdiscovery
99 98 debugdownload
100 99 debugextensions
@@ -285,8 +284,7 b' Show all commands + options'
285 284 debugdata: changelog, manifest, dir
286 285 debugdate: extended
287 286 debugdeltachain: changelog, manifest, dir, template
288 debugdirstateignorepatternshash:
289 debugdirstate: nodates, dates, datesort, all
287 debugdirstate: nodates, dates, datesort, docket, all
290 288 debugdiscovery: old, nonheads, rev, seed, local-as-revs, remote-as-revs, ssh, remotecmd, insecure, template
291 289 debugdownload: output
292 290 debugextensions: template
@@ -119,4 +119,88 b' infinite loop.'
119 119 C hgext3rd/__init__.py
120 120
121 121 $ cd ..
122
123 Check that the old dirstate data file is removed correctly and the new one is
124 valid.
125
126 $ dirstate_data_files () {
127 > find .hg -maxdepth 1 -name "dirstate.*"
128 > }
129
130 $ find_dirstate_uuid () {
131 > hg debugstate --docket | grep uuid | sed 's/.*uuid: \(.*\)/\1/'
132 > }
133
134 $ dirstate_uuid_has_not_changed () {
135 > # Non-Rust always rewrites the whole dirstate
136 > if [ $# -eq 1 ] || ([ -n "$HGMODULEPOLICY" ] && [ -z "${HGMODULEPOLICY##*rust*}" ]) || [ -n "$RHG_INSTALLED_AS_HG" ]; then
137 > test $current_uid = $(find_dirstate_uuid)
138 > else
139 > echo "not testing because using Python implementation"
140 > fi
141 > }
142
143 $ cd ..
144 $ hg init append-mostly
145 $ cd append-mostly
146 $ mkdir dir dir2
147 $ touch dir/a dir/b dir/c dir/d dir/e dir2/f
148 $ hg commit -Aqm initial
149 $ hg st
150 $ dirstate_data_files | wc -l
151 *1 (re)
152 $ current_uid=$(find_dirstate_uuid)
153
154 Nothing changes here
155
156 $ hg st
157 $ dirstate_data_files | wc -l
158 *1 (re)
159 $ dirstate_uuid_has_not_changed
160 not testing because using Python implementation (no-rust no-rhg !)
161
162 Trigger an append with a small change
163
164 $ echo "modified" > dir2/f
165 $ hg st
166 M dir2/f
167 $ dirstate_data_files | wc -l
168 *1 (re)
169 $ dirstate_uuid_has_not_changed
170 not testing because using Python implementation (no-rust no-rhg !)
171
172 Unused bytes counter is non-0 when appending
173 $ touch file
174 $ hg add file
175 $ current_uid=$(find_dirstate_uuid)
176
177 Trigger a rust/rhg run which updates the unused bytes value
178 $ hg st
179 M dir2/f
180 A file
181 $ dirstate_data_files | wc -l
182 *1 (re)
183 $ dirstate_uuid_has_not_changed
184 not testing because using Python implementation (no-rust no-rhg !)
185
186 $ hg debugstate --docket | grep unused
187 number of unused bytes: 0 (no-rust no-rhg !)
188 number of unused bytes: [1-9]\d* (re) (rhg no-rust !)
189 number of unused bytes: [1-9]\d* (re) (rust no-rhg !)
190 number of unused bytes: [1-9]\d* (re) (rust rhg !)
191
192 Delete most of the dirstate to trigger a non-append
193 $ hg rm dir/a dir/b dir/c dir/d
194 $ dirstate_data_files | wc -l
195 *1 (re)
196 $ dirstate_uuid_has_not_changed also-if-python
197 [1]
198
199 Check that unused bytes counter is reset when creating a new docket
200
201 $ hg debugstate --docket | grep unused
202 number of unused bytes: 0
203
122 204 #endif
205
206 $ cd ..
@@ -1013,8 +1013,6 b' Test list of internal help commands'
1013 1013 dump information about delta chains in a revlog
1014 1014 debugdirstate
1015 1015 show the contents of the current dirstate
1016 debugdirstateignorepatternshash
1017 show the hash of ignore patterns stored in dirstate if v2,
1018 1016 debugdiscovery
1019 1017 runs the changeset discovery protocol in isolation
1020 1018 debugdownload
@@ -418,14 +418,14 b' This is an optimization that is only rel'
418 418 $ hg status > /dev/null
419 419 $ cat .hg/testhgignore .hg/testhgignorerel .hgignore dir2/.hgignore dir1/.hgignore dir1/.hgignoretwo | $TESTDIR/f --sha1
420 420 sha1=6e315b60f15fb5dfa02be00f3e2c8f923051f5ff
421 $ hg debugdirstateignorepatternshash
422 6e315b60f15fb5dfa02be00f3e2c8f923051f5ff
421 $ hg debugstate --docket | grep ignore
422 ignore pattern hash: 6e315b60f15fb5dfa02be00f3e2c8f923051f5ff
423 423
424 424 $ echo rel > .hg/testhgignorerel
425 425 $ hg status > /dev/null
426 426 $ cat .hg/testhgignore .hg/testhgignorerel .hgignore dir2/.hgignore dir1/.hgignore dir1/.hgignoretwo | $TESTDIR/f --sha1
427 427 sha1=dea19cc7119213f24b6b582a4bae7b0cb063e34e
428 $ hg debugdirstateignorepatternshash
429 dea19cc7119213f24b6b582a4bae7b0cb063e34e
428 $ hg debugstate --docket | grep ignore
429 ignore pattern hash: dea19cc7119213f24b6b582a4bae7b0cb063e34e
430 430
431 431 #endif
@@ -356,6 +356,8 b' check saving last-message.txt, at first'
356 356 A f
357 357
358 358 $ rm -f .hg/last-message.txt
359 $ mkdir dir
360 $ cd dir
359 361 $ HGEDITOR="sh $TESTTMP/editor.sh" hg histedit tip --commands - 2>&1 << EOF
360 362 > mess 1fd3b2fe7754 f
361 363 > EOF
@@ -372,10 +374,11 b' check saving last-message.txt, at first'
372 374 ====
373 375 transaction abort!
374 376 rollback completed
375 note: commit message saved in .hg/last-message.txt
376 note: use 'hg commit --logfile .hg/last-message.txt --edit' to reuse it
377 note: commit message saved in ../.hg/last-message.txt
378 note: use 'hg commit --logfile ../.hg/last-message.txt --edit' to reuse it
377 379 abort: pretxncommit.unexpectedabort hook exited with status 1
378 380 [40]
381 $ cd ..
379 382 $ cat .hg/last-message.txt
380 383 f
381 384
@@ -179,15 +179,8 b' Fallback to Python'
179 179 [1]
180 180
181 181 $ rhg cat original --exclude="*.rs" --config rhg.fallback-executable=hg-non-existent
182 tried to fall back to a 'hg-non-existent' sub-process but got error $ENOENT$
183 unsupported feature: error: Found argument '--exclude' which wasn't expected, or isn't valid in this context
184
185 USAGE:
186 rhg cat [OPTIONS] <FILE>...
187
188 For more information try --help
189
190 [252]
182 abort: invalid fallback 'hg-non-existent': cannot find binary path
183 [253]
191 184
192 185 $ rhg cat original --exclude="*.rs" --config rhg.fallback-executable=rhg
193 186 Blocking recursive fallback. The 'rhg.fallback-executable = rhg' config points to `rhg` itself.
General Comments 0
You need to be logged in to leave comments. Login now