##// END OF EJS Templates
samplehgrcs: use single quotes in use warning
timeless -
r29978:3d2ea140 default
parent child Browse files
Show More
@@ -1,1370 +1,1370
1 1 # ui.py - user interface bits for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import errno
11 11 import getpass
12 12 import inspect
13 13 import os
14 14 import re
15 15 import socket
16 16 import sys
17 17 import tempfile
18 18 import traceback
19 19
20 20 from .i18n import _
21 21 from .node import hex
22 22
23 23 from . import (
24 24 config,
25 25 error,
26 26 formatter,
27 27 progress,
28 28 scmutil,
29 29 util,
30 30 )
31 31
32 32 urlreq = util.urlreq
33 33
34 34 samplehgrcs = {
35 35 'user':
36 """# example user config (see "hg help config" for more info)
36 """# example user config (see 'hg help config' for more info)
37 37 [ui]
38 38 # name and email, e.g.
39 39 # username = Jane Doe <jdoe@example.com>
40 40 username =
41 41
42 42 [extensions]
43 43 # uncomment these lines to enable some popular extensions
44 # (see "hg help extensions" for more info)
44 # (see 'hg help extensions' for more info)
45 45 #
46 46 # pager =
47 47 # color =""",
48 48
49 49 'cloned':
50 """# example repository config (see "hg help config" for more info)
50 """# example repository config (see 'hg help config' for more info)
51 51 [paths]
52 52 default = %s
53 53
54 54 # path aliases to other clones of this repo in URLs or filesystem paths
55 # (see "hg help config.paths" for more info)
55 # (see 'hg help config.paths' for more info)
56 56 #
57 57 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
58 58 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
59 59 # my-clone = /home/jdoe/jdoes-clone
60 60
61 61 [ui]
62 62 # name and email (local to this repository, optional), e.g.
63 63 # username = Jane Doe <jdoe@example.com>
64 64 """,
65 65
66 66 'local':
67 """# example repository config (see "hg help config" for more info)
67 """# example repository config (see 'hg help config' for more info)
68 68 [paths]
69 69 # path aliases to other clones of this repo in URLs or filesystem paths
70 # (see "hg help config.paths" for more info)
70 # (see 'hg help config.paths' for more info)
71 71 #
72 72 # default = http://example.com/hg/example-repo
73 73 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
74 74 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
75 75 # my-clone = /home/jdoe/jdoes-clone
76 76
77 77 [ui]
78 78 # name and email (local to this repository, optional), e.g.
79 79 # username = Jane Doe <jdoe@example.com>
80 80 """,
81 81
82 82 'global':
83 """# example system-wide hg config (see "hg help config" for more info)
83 """# example system-wide hg config (see 'hg help config' for more info)
84 84
85 85 [extensions]
86 86 # uncomment these lines to enable some popular extensions
87 # (see "hg help extensions" for more info)
87 # (see 'hg help extensions' for more info)
88 88 #
89 89 # blackbox =
90 90 # color =
91 91 # pager =""",
92 92 }
93 93
94 94 class ui(object):
95 95 def __init__(self, src=None):
96 96 # _buffers: used for temporary capture of output
97 97 self._buffers = []
98 98 # 3-tuple describing how each buffer in the stack behaves.
99 99 # Values are (capture stderr, capture subprocesses, apply labels).
100 100 self._bufferstates = []
101 101 # When a buffer is active, defines whether we are expanding labels.
102 102 # This exists to prevent an extra list lookup.
103 103 self._bufferapplylabels = None
104 104 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
105 105 self._reportuntrusted = True
106 106 self._ocfg = config.config() # overlay
107 107 self._tcfg = config.config() # trusted
108 108 self._ucfg = config.config() # untrusted
109 109 self._trustusers = set()
110 110 self._trustgroups = set()
111 111 self.callhooks = True
112 112 # Insecure server connections requested.
113 113 self.insecureconnections = False
114 114
115 115 if src:
116 116 self.fout = src.fout
117 117 self.ferr = src.ferr
118 118 self.fin = src.fin
119 119
120 120 self._tcfg = src._tcfg.copy()
121 121 self._ucfg = src._ucfg.copy()
122 122 self._ocfg = src._ocfg.copy()
123 123 self._trustusers = src._trustusers.copy()
124 124 self._trustgroups = src._trustgroups.copy()
125 125 self.environ = src.environ
126 126 self.callhooks = src.callhooks
127 127 self.insecureconnections = src.insecureconnections
128 128 self.fixconfig()
129 129
130 130 self.httppasswordmgrdb = src.httppasswordmgrdb
131 131 else:
132 132 self.fout = sys.stdout
133 133 self.ferr = sys.stderr
134 134 self.fin = sys.stdin
135 135
136 136 # shared read-only environment
137 137 self.environ = os.environ
138 138 # we always trust global config files
139 139 for f in scmutil.rcpath():
140 140 self.readconfig(f, trust=True)
141 141
142 142 self.httppasswordmgrdb = urlreq.httppasswordmgrwithdefaultrealm()
143 143
144 144 def copy(self):
145 145 return self.__class__(self)
146 146
147 147 def resetstate(self):
148 148 """Clear internal state that shouldn't persist across commands"""
149 149 if self._progbar:
150 150 self._progbar.resetstate() # reset last-print time of progress bar
151 151 self.httppasswordmgrdb = urlreq.httppasswordmgrwithdefaultrealm()
152 152
153 153 def formatter(self, topic, opts):
154 154 return formatter.formatter(self, topic, opts)
155 155
156 156 def _trusted(self, fp, f):
157 157 st = util.fstat(fp)
158 158 if util.isowner(st):
159 159 return True
160 160
161 161 tusers, tgroups = self._trustusers, self._trustgroups
162 162 if '*' in tusers or '*' in tgroups:
163 163 return True
164 164
165 165 user = util.username(st.st_uid)
166 166 group = util.groupname(st.st_gid)
167 167 if user in tusers or group in tgroups or user == util.username():
168 168 return True
169 169
170 170 if self._reportuntrusted:
171 171 self.warn(_('not trusting file %s from untrusted '
172 172 'user %s, group %s\n') % (f, user, group))
173 173 return False
174 174
175 175 def readconfig(self, filename, root=None, trust=False,
176 176 sections=None, remap=None):
177 177 try:
178 178 fp = open(filename)
179 179 except IOError:
180 180 if not sections: # ignore unless we were looking for something
181 181 return
182 182 raise
183 183
184 184 cfg = config.config()
185 185 trusted = sections or trust or self._trusted(fp, filename)
186 186
187 187 try:
188 188 cfg.read(filename, fp, sections=sections, remap=remap)
189 189 fp.close()
190 190 except error.ConfigError as inst:
191 191 if trusted:
192 192 raise
193 193 self.warn(_("ignored: %s\n") % str(inst))
194 194
195 195 if self.plain():
196 196 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
197 197 'logtemplate', 'statuscopies', 'style',
198 198 'traceback', 'verbose'):
199 199 if k in cfg['ui']:
200 200 del cfg['ui'][k]
201 201 for k, v in cfg.items('defaults'):
202 202 del cfg['defaults'][k]
203 203 # Don't remove aliases from the configuration if in the exceptionlist
204 204 if self.plain('alias'):
205 205 for k, v in cfg.items('alias'):
206 206 del cfg['alias'][k]
207 207 if self.plain('revsetalias'):
208 208 for k, v in cfg.items('revsetalias'):
209 209 del cfg['revsetalias'][k]
210 210 if self.plain('templatealias'):
211 211 for k, v in cfg.items('templatealias'):
212 212 del cfg['templatealias'][k]
213 213
214 214 if trusted:
215 215 self._tcfg.update(cfg)
216 216 self._tcfg.update(self._ocfg)
217 217 self._ucfg.update(cfg)
218 218 self._ucfg.update(self._ocfg)
219 219
220 220 if root is None:
221 221 root = os.path.expanduser('~')
222 222 self.fixconfig(root=root)
223 223
224 224 def fixconfig(self, root=None, section=None):
225 225 if section in (None, 'paths'):
226 226 # expand vars and ~
227 227 # translate paths relative to root (or home) into absolute paths
228 228 root = root or os.getcwd()
229 229 for c in self._tcfg, self._ucfg, self._ocfg:
230 230 for n, p in c.items('paths'):
231 231 # Ignore sub-options.
232 232 if ':' in n:
233 233 continue
234 234 if not p:
235 235 continue
236 236 if '%%' in p:
237 237 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
238 238 % (n, p, self.configsource('paths', n)))
239 239 p = p.replace('%%', '%')
240 240 p = util.expandpath(p)
241 241 if not util.hasscheme(p) and not os.path.isabs(p):
242 242 p = os.path.normpath(os.path.join(root, p))
243 243 c.set("paths", n, p)
244 244
245 245 if section in (None, 'ui'):
246 246 # update ui options
247 247 self.debugflag = self.configbool('ui', 'debug')
248 248 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
249 249 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
250 250 if self.verbose and self.quiet:
251 251 self.quiet = self.verbose = False
252 252 self._reportuntrusted = self.debugflag or self.configbool("ui",
253 253 "report_untrusted", True)
254 254 self.tracebackflag = self.configbool('ui', 'traceback', False)
255 255
256 256 if section in (None, 'trusted'):
257 257 # update trust information
258 258 self._trustusers.update(self.configlist('trusted', 'users'))
259 259 self._trustgroups.update(self.configlist('trusted', 'groups'))
260 260
261 261 def backupconfig(self, section, item):
262 262 return (self._ocfg.backup(section, item),
263 263 self._tcfg.backup(section, item),
264 264 self._ucfg.backup(section, item),)
265 265 def restoreconfig(self, data):
266 266 self._ocfg.restore(data[0])
267 267 self._tcfg.restore(data[1])
268 268 self._ucfg.restore(data[2])
269 269
270 270 def setconfig(self, section, name, value, source=''):
271 271 for cfg in (self._ocfg, self._tcfg, self._ucfg):
272 272 cfg.set(section, name, value, source)
273 273 self.fixconfig(section=section)
274 274
275 275 def _data(self, untrusted):
276 276 return untrusted and self._ucfg or self._tcfg
277 277
278 278 def configsource(self, section, name, untrusted=False):
279 279 return self._data(untrusted).source(section, name) or 'none'
280 280
281 281 def config(self, section, name, default=None, untrusted=False):
282 282 if isinstance(name, list):
283 283 alternates = name
284 284 else:
285 285 alternates = [name]
286 286
287 287 for n in alternates:
288 288 value = self._data(untrusted).get(section, n, None)
289 289 if value is not None:
290 290 name = n
291 291 break
292 292 else:
293 293 value = default
294 294
295 295 if self.debugflag and not untrusted and self._reportuntrusted:
296 296 for n in alternates:
297 297 uvalue = self._ucfg.get(section, n)
298 298 if uvalue is not None and uvalue != value:
299 299 self.debug("ignoring untrusted configuration option "
300 300 "%s.%s = %s\n" % (section, n, uvalue))
301 301 return value
302 302
303 303 def configsuboptions(self, section, name, default=None, untrusted=False):
304 304 """Get a config option and all sub-options.
305 305
306 306 Some config options have sub-options that are declared with the
307 307 format "key:opt = value". This method is used to return the main
308 308 option and all its declared sub-options.
309 309
310 310 Returns a 2-tuple of ``(option, sub-options)``, where `sub-options``
311 311 is a dict of defined sub-options where keys and values are strings.
312 312 """
313 313 data = self._data(untrusted)
314 314 main = data.get(section, name, default)
315 315 if self.debugflag and not untrusted and self._reportuntrusted:
316 316 uvalue = self._ucfg.get(section, name)
317 317 if uvalue is not None and uvalue != main:
318 318 self.debug('ignoring untrusted configuration option '
319 319 '%s.%s = %s\n' % (section, name, uvalue))
320 320
321 321 sub = {}
322 322 prefix = '%s:' % name
323 323 for k, v in data.items(section):
324 324 if k.startswith(prefix):
325 325 sub[k[len(prefix):]] = v
326 326
327 327 if self.debugflag and not untrusted and self._reportuntrusted:
328 328 for k, v in sub.items():
329 329 uvalue = self._ucfg.get(section, '%s:%s' % (name, k))
330 330 if uvalue is not None and uvalue != v:
331 331 self.debug('ignoring untrusted configuration option '
332 332 '%s:%s.%s = %s\n' % (section, name, k, uvalue))
333 333
334 334 return main, sub
335 335
336 336 def configpath(self, section, name, default=None, untrusted=False):
337 337 'get a path config item, expanded relative to repo root or config file'
338 338 v = self.config(section, name, default, untrusted)
339 339 if v is None:
340 340 return None
341 341 if not os.path.isabs(v) or "://" not in v:
342 342 src = self.configsource(section, name, untrusted)
343 343 if ':' in src:
344 344 base = os.path.dirname(src.rsplit(':')[0])
345 345 v = os.path.join(base, os.path.expanduser(v))
346 346 return v
347 347
348 348 def configbool(self, section, name, default=False, untrusted=False):
349 349 """parse a configuration element as a boolean
350 350
351 351 >>> u = ui(); s = 'foo'
352 352 >>> u.setconfig(s, 'true', 'yes')
353 353 >>> u.configbool(s, 'true')
354 354 True
355 355 >>> u.setconfig(s, 'false', 'no')
356 356 >>> u.configbool(s, 'false')
357 357 False
358 358 >>> u.configbool(s, 'unknown')
359 359 False
360 360 >>> u.configbool(s, 'unknown', True)
361 361 True
362 362 >>> u.setconfig(s, 'invalid', 'somevalue')
363 363 >>> u.configbool(s, 'invalid')
364 364 Traceback (most recent call last):
365 365 ...
366 366 ConfigError: foo.invalid is not a boolean ('somevalue')
367 367 """
368 368
369 369 v = self.config(section, name, None, untrusted)
370 370 if v is None:
371 371 return default
372 372 if isinstance(v, bool):
373 373 return v
374 374 b = util.parsebool(v)
375 375 if b is None:
376 376 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
377 377 % (section, name, v))
378 378 return b
379 379
380 380 def configint(self, section, name, default=None, untrusted=False):
381 381 """parse a configuration element as an integer
382 382
383 383 >>> u = ui(); s = 'foo'
384 384 >>> u.setconfig(s, 'int1', '42')
385 385 >>> u.configint(s, 'int1')
386 386 42
387 387 >>> u.setconfig(s, 'int2', '-42')
388 388 >>> u.configint(s, 'int2')
389 389 -42
390 390 >>> u.configint(s, 'unknown', 7)
391 391 7
392 392 >>> u.setconfig(s, 'invalid', 'somevalue')
393 393 >>> u.configint(s, 'invalid')
394 394 Traceback (most recent call last):
395 395 ...
396 396 ConfigError: foo.invalid is not an integer ('somevalue')
397 397 """
398 398
399 399 v = self.config(section, name, None, untrusted)
400 400 if v is None:
401 401 return default
402 402 try:
403 403 return int(v)
404 404 except ValueError:
405 405 raise error.ConfigError(_("%s.%s is not an integer ('%s')")
406 406 % (section, name, v))
407 407
408 408 def configbytes(self, section, name, default=0, untrusted=False):
409 409 """parse a configuration element as a quantity in bytes
410 410
411 411 Units can be specified as b (bytes), k or kb (kilobytes), m or
412 412 mb (megabytes), g or gb (gigabytes).
413 413
414 414 >>> u = ui(); s = 'foo'
415 415 >>> u.setconfig(s, 'val1', '42')
416 416 >>> u.configbytes(s, 'val1')
417 417 42
418 418 >>> u.setconfig(s, 'val2', '42.5 kb')
419 419 >>> u.configbytes(s, 'val2')
420 420 43520
421 421 >>> u.configbytes(s, 'unknown', '7 MB')
422 422 7340032
423 423 >>> u.setconfig(s, 'invalid', 'somevalue')
424 424 >>> u.configbytes(s, 'invalid')
425 425 Traceback (most recent call last):
426 426 ...
427 427 ConfigError: foo.invalid is not a byte quantity ('somevalue')
428 428 """
429 429
430 430 value = self.config(section, name)
431 431 if value is None:
432 432 if not isinstance(default, str):
433 433 return default
434 434 value = default
435 435 try:
436 436 return util.sizetoint(value)
437 437 except error.ParseError:
438 438 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
439 439 % (section, name, value))
440 440
441 441 def configlist(self, section, name, default=None, untrusted=False):
442 442 """parse a configuration element as a list of comma/space separated
443 443 strings
444 444
445 445 >>> u = ui(); s = 'foo'
446 446 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
447 447 >>> u.configlist(s, 'list1')
448 448 ['this', 'is', 'a small', 'test']
449 449 """
450 450
451 451 def _parse_plain(parts, s, offset):
452 452 whitespace = False
453 453 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
454 454 whitespace = True
455 455 offset += 1
456 456 if offset >= len(s):
457 457 return None, parts, offset
458 458 if whitespace:
459 459 parts.append('')
460 460 if s[offset] == '"' and not parts[-1]:
461 461 return _parse_quote, parts, offset + 1
462 462 elif s[offset] == '"' and parts[-1][-1] == '\\':
463 463 parts[-1] = parts[-1][:-1] + s[offset]
464 464 return _parse_plain, parts, offset + 1
465 465 parts[-1] += s[offset]
466 466 return _parse_plain, parts, offset + 1
467 467
468 468 def _parse_quote(parts, s, offset):
469 469 if offset < len(s) and s[offset] == '"': # ""
470 470 parts.append('')
471 471 offset += 1
472 472 while offset < len(s) and (s[offset].isspace() or
473 473 s[offset] == ','):
474 474 offset += 1
475 475 return _parse_plain, parts, offset
476 476
477 477 while offset < len(s) and s[offset] != '"':
478 478 if (s[offset] == '\\' and offset + 1 < len(s)
479 479 and s[offset + 1] == '"'):
480 480 offset += 1
481 481 parts[-1] += '"'
482 482 else:
483 483 parts[-1] += s[offset]
484 484 offset += 1
485 485
486 486 if offset >= len(s):
487 487 real_parts = _configlist(parts[-1])
488 488 if not real_parts:
489 489 parts[-1] = '"'
490 490 else:
491 491 real_parts[0] = '"' + real_parts[0]
492 492 parts = parts[:-1]
493 493 parts.extend(real_parts)
494 494 return None, parts, offset
495 495
496 496 offset += 1
497 497 while offset < len(s) and s[offset] in [' ', ',']:
498 498 offset += 1
499 499
500 500 if offset < len(s):
501 501 if offset + 1 == len(s) and s[offset] == '"':
502 502 parts[-1] += '"'
503 503 offset += 1
504 504 else:
505 505 parts.append('')
506 506 else:
507 507 return None, parts, offset
508 508
509 509 return _parse_plain, parts, offset
510 510
511 511 def _configlist(s):
512 512 s = s.rstrip(' ,')
513 513 if not s:
514 514 return []
515 515 parser, parts, offset = _parse_plain, [''], 0
516 516 while parser:
517 517 parser, parts, offset = parser(parts, s, offset)
518 518 return parts
519 519
520 520 result = self.config(section, name, untrusted=untrusted)
521 521 if result is None:
522 522 result = default or []
523 523 if isinstance(result, basestring):
524 524 result = _configlist(result.lstrip(' ,\n'))
525 525 if result is None:
526 526 result = default or []
527 527 return result
528 528
529 529 def hasconfig(self, section, name, untrusted=False):
530 530 return self._data(untrusted).hasitem(section, name)
531 531
532 532 def has_section(self, section, untrusted=False):
533 533 '''tell whether section exists in config.'''
534 534 return section in self._data(untrusted)
535 535
536 536 def configitems(self, section, untrusted=False, ignoresub=False):
537 537 items = self._data(untrusted).items(section)
538 538 if ignoresub:
539 539 newitems = {}
540 540 for k, v in items:
541 541 if ':' not in k:
542 542 newitems[k] = v
543 543 items = newitems.items()
544 544 if self.debugflag and not untrusted and self._reportuntrusted:
545 545 for k, v in self._ucfg.items(section):
546 546 if self._tcfg.get(section, k) != v:
547 547 self.debug("ignoring untrusted configuration option "
548 548 "%s.%s = %s\n" % (section, k, v))
549 549 return items
550 550
551 551 def walkconfig(self, untrusted=False):
552 552 cfg = self._data(untrusted)
553 553 for section in cfg.sections():
554 554 for name, value in self.configitems(section, untrusted):
555 555 yield section, name, value
556 556
557 557 def plain(self, feature=None):
558 558 '''is plain mode active?
559 559
560 560 Plain mode means that all configuration variables which affect
561 561 the behavior and output of Mercurial should be
562 562 ignored. Additionally, the output should be stable,
563 563 reproducible and suitable for use in scripts or applications.
564 564
565 565 The only way to trigger plain mode is by setting either the
566 566 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
567 567
568 568 The return value can either be
569 569 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
570 570 - True otherwise
571 571 '''
572 572 if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
573 573 return False
574 574 exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
575 575 if feature and exceptions:
576 576 return feature not in exceptions
577 577 return True
578 578
579 579 def username(self):
580 580 """Return default username to be used in commits.
581 581
582 582 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
583 583 and stop searching if one of these is set.
584 584 If not found and ui.askusername is True, ask the user, else use
585 585 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
586 586 """
587 587 user = os.environ.get("HGUSER")
588 588 if user is None:
589 589 user = self.config("ui", ["username", "user"])
590 590 if user is not None:
591 591 user = os.path.expandvars(user)
592 592 if user is None:
593 593 user = os.environ.get("EMAIL")
594 594 if user is None and self.configbool("ui", "askusername"):
595 595 user = self.prompt(_("enter a commit username:"), default=None)
596 596 if user is None and not self.interactive():
597 597 try:
598 598 user = '%s@%s' % (util.getuser(), socket.getfqdn())
599 599 self.warn(_("no username found, using '%s' instead\n") % user)
600 600 except KeyError:
601 601 pass
602 602 if not user:
603 603 raise error.Abort(_('no username supplied'),
604 604 hint=_("use 'hg config --edit' "
605 605 'to set your username'))
606 606 if "\n" in user:
607 607 raise error.Abort(_("username %s contains a newline\n")
608 608 % repr(user))
609 609 return user
610 610
611 611 def shortuser(self, user):
612 612 """Return a short representation of a user name or email address."""
613 613 if not self.verbose:
614 614 user = util.shortuser(user)
615 615 return user
616 616
617 617 def expandpath(self, loc, default=None):
618 618 """Return repository location relative to cwd or from [paths]"""
619 619 try:
620 620 p = self.paths.getpath(loc)
621 621 if p:
622 622 return p.rawloc
623 623 except error.RepoError:
624 624 pass
625 625
626 626 if default:
627 627 try:
628 628 p = self.paths.getpath(default)
629 629 if p:
630 630 return p.rawloc
631 631 except error.RepoError:
632 632 pass
633 633
634 634 return loc
635 635
636 636 @util.propertycache
637 637 def paths(self):
638 638 return paths(self)
639 639
640 640 def pushbuffer(self, error=False, subproc=False, labeled=False):
641 641 """install a buffer to capture standard output of the ui object
642 642
643 643 If error is True, the error output will be captured too.
644 644
645 645 If subproc is True, output from subprocesses (typically hooks) will be
646 646 captured too.
647 647
648 648 If labeled is True, any labels associated with buffered
649 649 output will be handled. By default, this has no effect
650 650 on the output returned, but extensions and GUI tools may
651 651 handle this argument and returned styled output. If output
652 652 is being buffered so it can be captured and parsed or
653 653 processed, labeled should not be set to True.
654 654 """
655 655 self._buffers.append([])
656 656 self._bufferstates.append((error, subproc, labeled))
657 657 self._bufferapplylabels = labeled
658 658
659 659 def popbuffer(self):
660 660 '''pop the last buffer and return the buffered output'''
661 661 self._bufferstates.pop()
662 662 if self._bufferstates:
663 663 self._bufferapplylabels = self._bufferstates[-1][2]
664 664 else:
665 665 self._bufferapplylabels = None
666 666
667 667 return "".join(self._buffers.pop())
668 668
669 669 def write(self, *args, **opts):
670 670 '''write args to output
671 671
672 672 By default, this method simply writes to the buffer or stdout,
673 673 but extensions or GUI tools may override this method,
674 674 write_err(), popbuffer(), and label() to style output from
675 675 various parts of hg.
676 676
677 677 An optional keyword argument, "label", can be passed in.
678 678 This should be a string containing label names separated by
679 679 space. Label names take the form of "topic.type". For example,
680 680 ui.debug() issues a label of "ui.debug".
681 681
682 682 When labeling output for a specific command, a label of
683 683 "cmdname.type" is recommended. For example, status issues
684 684 a label of "status.modified" for modified files.
685 685 '''
686 686 if self._buffers and not opts.get('prompt', False):
687 687 self._buffers[-1].extend(a for a in args)
688 688 else:
689 689 self._progclear()
690 690 for a in args:
691 691 self.fout.write(a)
692 692
693 693 def write_err(self, *args, **opts):
694 694 self._progclear()
695 695 try:
696 696 if self._bufferstates and self._bufferstates[-1][0]:
697 697 return self.write(*args, **opts)
698 698 if not getattr(self.fout, 'closed', False):
699 699 self.fout.flush()
700 700 for a in args:
701 701 self.ferr.write(a)
702 702 # stderr may be buffered under win32 when redirected to files,
703 703 # including stdout.
704 704 if not getattr(self.ferr, 'closed', False):
705 705 self.ferr.flush()
706 706 except IOError as inst:
707 707 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
708 708 raise
709 709
710 710 def flush(self):
711 711 try: self.fout.flush()
712 712 except (IOError, ValueError): pass
713 713 try: self.ferr.flush()
714 714 except (IOError, ValueError): pass
715 715
716 716 def _isatty(self, fh):
717 717 if self.configbool('ui', 'nontty', False):
718 718 return False
719 719 return util.isatty(fh)
720 720
721 721 def interface(self, feature):
722 722 """what interface to use for interactive console features?
723 723
724 724 The interface is controlled by the value of `ui.interface` but also by
725 725 the value of feature-specific configuration. For example:
726 726
727 727 ui.interface.histedit = text
728 728 ui.interface.chunkselector = curses
729 729
730 730 Here the features are "histedit" and "chunkselector".
731 731
732 732 The configuration above means that the default interfaces for commands
733 733 is curses, the interface for histedit is text and the interface for
734 734 selecting chunk is crecord (the best curses interface available).
735 735
736 736 Consider the following exemple:
737 737 ui.interface = curses
738 738 ui.interface.histedit = text
739 739
740 740 Then histedit will use the text interface and chunkselector will use
741 741 the default curses interface (crecord at the moment).
742 742 """
743 743 alldefaults = frozenset(["text", "curses"])
744 744
745 745 featureinterfaces = {
746 746 "chunkselector": [
747 747 "text",
748 748 "curses",
749 749 ]
750 750 }
751 751
752 752 # Feature-specific interface
753 753 if feature not in featureinterfaces.keys():
754 754 # Programming error, not user error
755 755 raise ValueError("Unknown feature requested %s" % feature)
756 756
757 757 availableinterfaces = frozenset(featureinterfaces[feature])
758 758 if alldefaults > availableinterfaces:
759 759 # Programming error, not user error. We need a use case to
760 760 # define the right thing to do here.
761 761 raise ValueError(
762 762 "Feature %s does not handle all default interfaces" %
763 763 feature)
764 764
765 765 if self.plain():
766 766 return "text"
767 767
768 768 # Default interface for all the features
769 769 defaultinterface = "text"
770 770 i = self.config("ui", "interface", None)
771 771 if i in alldefaults:
772 772 defaultinterface = i
773 773
774 774 choseninterface = defaultinterface
775 775 f = self.config("ui", "interface.%s" % feature, None)
776 776 if f in availableinterfaces:
777 777 choseninterface = f
778 778
779 779 if i is not None and defaultinterface != i:
780 780 if f is not None:
781 781 self.warn(_("invalid value for ui.interface: %s\n") %
782 782 (i,))
783 783 else:
784 784 self.warn(_("invalid value for ui.interface: %s (using %s)\n") %
785 785 (i, choseninterface))
786 786 if f is not None and choseninterface != f:
787 787 self.warn(_("invalid value for ui.interface.%s: %s (using %s)\n") %
788 788 (feature, f, choseninterface))
789 789
790 790 return choseninterface
791 791
792 792 def interactive(self):
793 793 '''is interactive input allowed?
794 794
795 795 An interactive session is a session where input can be reasonably read
796 796 from `sys.stdin'. If this function returns false, any attempt to read
797 797 from stdin should fail with an error, unless a sensible default has been
798 798 specified.
799 799
800 800 Interactiveness is triggered by the value of the `ui.interactive'
801 801 configuration variable or - if it is unset - when `sys.stdin' points
802 802 to a terminal device.
803 803
804 804 This function refers to input only; for output, see `ui.formatted()'.
805 805 '''
806 806 i = self.configbool("ui", "interactive", None)
807 807 if i is None:
808 808 # some environments replace stdin without implementing isatty
809 809 # usually those are non-interactive
810 810 return self._isatty(self.fin)
811 811
812 812 return i
813 813
814 814 def termwidth(self):
815 815 '''how wide is the terminal in columns?
816 816 '''
817 817 if 'COLUMNS' in os.environ:
818 818 try:
819 819 return int(os.environ['COLUMNS'])
820 820 except ValueError:
821 821 pass
822 822 return util.termwidth()
823 823
824 824 def formatted(self):
825 825 '''should formatted output be used?
826 826
827 827 It is often desirable to format the output to suite the output medium.
828 828 Examples of this are truncating long lines or colorizing messages.
829 829 However, this is not often not desirable when piping output into other
830 830 utilities, e.g. `grep'.
831 831
832 832 Formatted output is triggered by the value of the `ui.formatted'
833 833 configuration variable or - if it is unset - when `sys.stdout' points
834 834 to a terminal device. Please note that `ui.formatted' should be
835 835 considered an implementation detail; it is not intended for use outside
836 836 Mercurial or its extensions.
837 837
838 838 This function refers to output only; for input, see `ui.interactive()'.
839 839 This function always returns false when in plain mode, see `ui.plain()'.
840 840 '''
841 841 if self.plain():
842 842 return False
843 843
844 844 i = self.configbool("ui", "formatted", None)
845 845 if i is None:
846 846 # some environments replace stdout without implementing isatty
847 847 # usually those are non-interactive
848 848 return self._isatty(self.fout)
849 849
850 850 return i
851 851
852 852 def _readline(self, prompt=''):
853 853 if self._isatty(self.fin):
854 854 try:
855 855 # magically add command line editing support, where
856 856 # available
857 857 import readline
858 858 # force demandimport to really load the module
859 859 readline.read_history_file
860 860 # windows sometimes raises something other than ImportError
861 861 except Exception:
862 862 pass
863 863
864 864 # call write() so output goes through subclassed implementation
865 865 # e.g. color extension on Windows
866 866 self.write(prompt, prompt=True)
867 867
868 868 # instead of trying to emulate raw_input, swap (self.fin,
869 869 # self.fout) with (sys.stdin, sys.stdout)
870 870 oldin = sys.stdin
871 871 oldout = sys.stdout
872 872 sys.stdin = self.fin
873 873 sys.stdout = self.fout
874 874 # prompt ' ' must exist; otherwise readline may delete entire line
875 875 # - http://bugs.python.org/issue12833
876 876 line = raw_input(' ')
877 877 sys.stdin = oldin
878 878 sys.stdout = oldout
879 879
880 880 # When stdin is in binary mode on Windows, it can cause
881 881 # raw_input() to emit an extra trailing carriage return
882 882 if os.linesep == '\r\n' and line and line[-1] == '\r':
883 883 line = line[:-1]
884 884 return line
885 885
886 886 def prompt(self, msg, default="y"):
887 887 """Prompt user with msg, read response.
888 888 If ui is not interactive, the default is returned.
889 889 """
890 890 if not self.interactive():
891 891 self.write(msg, ' ', default or '', "\n")
892 892 return default
893 893 try:
894 894 r = self._readline(self.label(msg, 'ui.prompt'))
895 895 if not r:
896 896 r = default
897 897 if self.configbool('ui', 'promptecho'):
898 898 self.write(r, "\n")
899 899 return r
900 900 except EOFError:
901 901 raise error.ResponseExpected()
902 902
903 903 @staticmethod
904 904 def extractchoices(prompt):
905 905 """Extract prompt message and list of choices from specified prompt.
906 906
907 907 This returns tuple "(message, choices)", and "choices" is the
908 908 list of tuple "(response character, text without &)".
909 909
910 910 >>> ui.extractchoices("awake? $$ &Yes $$ &No")
911 911 ('awake? ', [('y', 'Yes'), ('n', 'No')])
912 912 >>> ui.extractchoices("line\\nbreak? $$ &Yes $$ &No")
913 913 ('line\\nbreak? ', [('y', 'Yes'), ('n', 'No')])
914 914 >>> ui.extractchoices("want lots of $$money$$?$$Ye&s$$N&o")
915 915 ('want lots of $$money$$?', [('s', 'Yes'), ('o', 'No')])
916 916 """
917 917
918 918 # Sadly, the prompt string may have been built with a filename
919 919 # containing "$$" so let's try to find the first valid-looking
920 920 # prompt to start parsing. Sadly, we also can't rely on
921 921 # choices containing spaces, ASCII, or basically anything
922 922 # except an ampersand followed by a character.
923 923 m = re.match(r'(?s)(.+?)\$\$([^\$]*&[^ \$].*)', prompt)
924 924 msg = m.group(1)
925 925 choices = [p.strip(' ') for p in m.group(2).split('$$')]
926 926 return (msg,
927 927 [(s[s.index('&') + 1].lower(), s.replace('&', '', 1))
928 928 for s in choices])
929 929
930 930 def promptchoice(self, prompt, default=0):
931 931 """Prompt user with a message, read response, and ensure it matches
932 932 one of the provided choices. The prompt is formatted as follows:
933 933
934 934 "would you like fries with that (Yn)? $$ &Yes $$ &No"
935 935
936 936 The index of the choice is returned. Responses are case
937 937 insensitive. If ui is not interactive, the default is
938 938 returned.
939 939 """
940 940
941 941 msg, choices = self.extractchoices(prompt)
942 942 resps = [r for r, t in choices]
943 943 while True:
944 944 r = self.prompt(msg, resps[default])
945 945 if r.lower() in resps:
946 946 return resps.index(r.lower())
947 947 self.write(_("unrecognized response\n"))
948 948
949 949 def getpass(self, prompt=None, default=None):
950 950 if not self.interactive():
951 951 return default
952 952 try:
953 953 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
954 954 # disable getpass() only if explicitly specified. it's still valid
955 955 # to interact with tty even if fin is not a tty.
956 956 if self.configbool('ui', 'nontty'):
957 957 return self.fin.readline().rstrip('\n')
958 958 else:
959 959 return getpass.getpass('')
960 960 except EOFError:
961 961 raise error.ResponseExpected()
962 962 def status(self, *msg, **opts):
963 963 '''write status message to output (if ui.quiet is False)
964 964
965 965 This adds an output label of "ui.status".
966 966 '''
967 967 if not self.quiet:
968 968 opts['label'] = opts.get('label', '') + ' ui.status'
969 969 self.write(*msg, **opts)
970 970 def warn(self, *msg, **opts):
971 971 '''write warning message to output (stderr)
972 972
973 973 This adds an output label of "ui.warning".
974 974 '''
975 975 opts['label'] = opts.get('label', '') + ' ui.warning'
976 976 self.write_err(*msg, **opts)
977 977 def note(self, *msg, **opts):
978 978 '''write note to output (if ui.verbose is True)
979 979
980 980 This adds an output label of "ui.note".
981 981 '''
982 982 if self.verbose:
983 983 opts['label'] = opts.get('label', '') + ' ui.note'
984 984 self.write(*msg, **opts)
985 985 def debug(self, *msg, **opts):
986 986 '''write debug message to output (if ui.debugflag is True)
987 987
988 988 This adds an output label of "ui.debug".
989 989 '''
990 990 if self.debugflag:
991 991 opts['label'] = opts.get('label', '') + ' ui.debug'
992 992 self.write(*msg, **opts)
993 993
994 994 def edit(self, text, user, extra=None, editform=None, pending=None):
995 995 extra_defaults = {
996 996 'prefix': 'editor',
997 997 'suffix': '.txt',
998 998 }
999 999 if extra is not None:
1000 1000 extra_defaults.update(extra)
1001 1001 extra = extra_defaults
1002 1002 (fd, name) = tempfile.mkstemp(prefix='hg-' + extra['prefix'] + '-',
1003 1003 suffix=extra['suffix'], text=True)
1004 1004 try:
1005 1005 f = os.fdopen(fd, "w")
1006 1006 f.write(text)
1007 1007 f.close()
1008 1008
1009 1009 environ = {'HGUSER': user}
1010 1010 if 'transplant_source' in extra:
1011 1011 environ.update({'HGREVISION': hex(extra['transplant_source'])})
1012 1012 for label in ('intermediate-source', 'source', 'rebase_source'):
1013 1013 if label in extra:
1014 1014 environ.update({'HGREVISION': extra[label]})
1015 1015 break
1016 1016 if editform:
1017 1017 environ.update({'HGEDITFORM': editform})
1018 1018 if pending:
1019 1019 environ.update({'HG_PENDING': pending})
1020 1020
1021 1021 editor = self.geteditor()
1022 1022
1023 1023 self.system("%s \"%s\"" % (editor, name),
1024 1024 environ=environ,
1025 1025 onerr=error.Abort, errprefix=_("edit failed"))
1026 1026
1027 1027 f = open(name)
1028 1028 t = f.read()
1029 1029 f.close()
1030 1030 finally:
1031 1031 os.unlink(name)
1032 1032
1033 1033 return t
1034 1034
1035 1035 def system(self, cmd, environ=None, cwd=None, onerr=None, errprefix=None):
1036 1036 '''execute shell command with appropriate output stream. command
1037 1037 output will be redirected if fout is not stdout.
1038 1038 '''
1039 1039 out = self.fout
1040 1040 if any(s[1] for s in self._bufferstates):
1041 1041 out = self
1042 1042 return util.system(cmd, environ=environ, cwd=cwd, onerr=onerr,
1043 1043 errprefix=errprefix, out=out)
1044 1044
1045 1045 def traceback(self, exc=None, force=False):
1046 1046 '''print exception traceback if traceback printing enabled or forced.
1047 1047 only to call in exception handler. returns true if traceback
1048 1048 printed.'''
1049 1049 if self.tracebackflag or force:
1050 1050 if exc is None:
1051 1051 exc = sys.exc_info()
1052 1052 cause = getattr(exc[1], 'cause', None)
1053 1053
1054 1054 if cause is not None:
1055 1055 causetb = traceback.format_tb(cause[2])
1056 1056 exctb = traceback.format_tb(exc[2])
1057 1057 exconly = traceback.format_exception_only(cause[0], cause[1])
1058 1058
1059 1059 # exclude frame where 'exc' was chained and rethrown from exctb
1060 1060 self.write_err('Traceback (most recent call last):\n',
1061 1061 ''.join(exctb[:-1]),
1062 1062 ''.join(causetb),
1063 1063 ''.join(exconly))
1064 1064 else:
1065 1065 output = traceback.format_exception(exc[0], exc[1], exc[2])
1066 1066 self.write_err(''.join(output))
1067 1067 return self.tracebackflag or force
1068 1068
1069 1069 def geteditor(self):
1070 1070 '''return editor to use'''
1071 1071 if sys.platform == 'plan9':
1072 1072 # vi is the MIPS instruction simulator on Plan 9. We
1073 1073 # instead default to E to plumb commit messages to
1074 1074 # avoid confusion.
1075 1075 editor = 'E'
1076 1076 else:
1077 1077 editor = 'vi'
1078 1078 return (os.environ.get("HGEDITOR") or
1079 1079 self.config("ui", "editor") or
1080 1080 os.environ.get("VISUAL") or
1081 1081 os.environ.get("EDITOR", editor))
1082 1082
1083 1083 @util.propertycache
1084 1084 def _progbar(self):
1085 1085 """setup the progbar singleton to the ui object"""
1086 1086 if (self.quiet or self.debugflag
1087 1087 or self.configbool('progress', 'disable', False)
1088 1088 or not progress.shouldprint(self)):
1089 1089 return None
1090 1090 return getprogbar(self)
1091 1091
1092 1092 def _progclear(self):
1093 1093 """clear progress bar output if any. use it before any output"""
1094 1094 if '_progbar' not in vars(self): # nothing loaded yet
1095 1095 return
1096 1096 if self._progbar is not None and self._progbar.printed:
1097 1097 self._progbar.clear()
1098 1098
1099 1099 def progress(self, topic, pos, item="", unit="", total=None):
1100 1100 '''show a progress message
1101 1101
1102 1102 By default a textual progress bar will be displayed if an operation
1103 1103 takes too long. 'topic' is the current operation, 'item' is a
1104 1104 non-numeric marker of the current position (i.e. the currently
1105 1105 in-process file), 'pos' is the current numeric position (i.e.
1106 1106 revision, bytes, etc.), unit is a corresponding unit label,
1107 1107 and total is the highest expected pos.
1108 1108
1109 1109 Multiple nested topics may be active at a time.
1110 1110
1111 1111 All topics should be marked closed by setting pos to None at
1112 1112 termination.
1113 1113 '''
1114 1114 if self._progbar is not None:
1115 1115 self._progbar.progress(topic, pos, item=item, unit=unit,
1116 1116 total=total)
1117 1117 if pos is None or not self.configbool('progress', 'debug'):
1118 1118 return
1119 1119
1120 1120 if unit:
1121 1121 unit = ' ' + unit
1122 1122 if item:
1123 1123 item = ' ' + item
1124 1124
1125 1125 if total:
1126 1126 pct = 100.0 * pos / total
1127 1127 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
1128 1128 % (topic, item, pos, total, unit, pct))
1129 1129 else:
1130 1130 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
1131 1131
1132 1132 def log(self, service, *msg, **opts):
1133 1133 '''hook for logging facility extensions
1134 1134
1135 1135 service should be a readily-identifiable subsystem, which will
1136 1136 allow filtering.
1137 1137
1138 1138 *msg should be a newline-terminated format string to log, and
1139 1139 then any values to %-format into that format string.
1140 1140
1141 1141 **opts currently has no defined meanings.
1142 1142 '''
1143 1143
1144 1144 def label(self, msg, label):
1145 1145 '''style msg based on supplied label
1146 1146
1147 1147 Like ui.write(), this just returns msg unchanged, but extensions
1148 1148 and GUI tools can override it to allow styling output without
1149 1149 writing it.
1150 1150
1151 1151 ui.write(s, 'label') is equivalent to
1152 1152 ui.write(ui.label(s, 'label')).
1153 1153 '''
1154 1154 return msg
1155 1155
1156 1156 def develwarn(self, msg, stacklevel=1, config=None):
1157 1157 """issue a developer warning message
1158 1158
1159 1159 Use 'stacklevel' to report the offender some layers further up in the
1160 1160 stack.
1161 1161 """
1162 1162 if not self.configbool('devel', 'all-warnings'):
1163 1163 if config is not None and not self.configbool('devel', config):
1164 1164 return
1165 1165 msg = 'devel-warn: ' + msg
1166 1166 stacklevel += 1 # get in develwarn
1167 1167 if self.tracebackflag:
1168 1168 util.debugstacktrace(msg, stacklevel, self.ferr, self.fout)
1169 1169 self.log('develwarn', '%s at:\n%s' %
1170 1170 (msg, ''.join(util.getstackframes(stacklevel))))
1171 1171 else:
1172 1172 curframe = inspect.currentframe()
1173 1173 calframe = inspect.getouterframes(curframe, 2)
1174 1174 self.write_err('%s at: %s:%s (%s)\n'
1175 1175 % ((msg,) + calframe[stacklevel][1:4]))
1176 1176 self.log('develwarn', '%s at: %s:%s (%s)\n',
1177 1177 msg, *calframe[stacklevel][1:4])
1178 1178 curframe = calframe = None # avoid cycles
1179 1179
1180 1180 def deprecwarn(self, msg, version):
1181 1181 """issue a deprecation warning
1182 1182
1183 1183 - msg: message explaining what is deprecated and how to upgrade,
1184 1184 - version: last version where the API will be supported,
1185 1185 """
1186 1186 if not (self.configbool('devel', 'all-warnings')
1187 1187 or self.configbool('devel', 'deprec-warn')):
1188 1188 return
1189 1189 msg += ("\n(compatibility will be dropped after Mercurial-%s,"
1190 1190 " update your code.)") % version
1191 1191 self.develwarn(msg, stacklevel=2, config='deprec-warn')
1192 1192
1193 1193 class paths(dict):
1194 1194 """Represents a collection of paths and their configs.
1195 1195
1196 1196 Data is initially derived from ui instances and the config files they have
1197 1197 loaded.
1198 1198 """
1199 1199 def __init__(self, ui):
1200 1200 dict.__init__(self)
1201 1201
1202 1202 for name, loc in ui.configitems('paths', ignoresub=True):
1203 1203 # No location is the same as not existing.
1204 1204 if not loc:
1205 1205 continue
1206 1206 loc, sub = ui.configsuboptions('paths', name)
1207 1207 self[name] = path(ui, name, rawloc=loc, suboptions=sub)
1208 1208
1209 1209 def getpath(self, name, default=None):
1210 1210 """Return a ``path`` from a string, falling back to default.
1211 1211
1212 1212 ``name`` can be a named path or locations. Locations are filesystem
1213 1213 paths or URIs.
1214 1214
1215 1215 Returns None if ``name`` is not a registered path, a URI, or a local
1216 1216 path to a repo.
1217 1217 """
1218 1218 # Only fall back to default if no path was requested.
1219 1219 if name is None:
1220 1220 if not default:
1221 1221 default = ()
1222 1222 elif not isinstance(default, (tuple, list)):
1223 1223 default = (default,)
1224 1224 for k in default:
1225 1225 try:
1226 1226 return self[k]
1227 1227 except KeyError:
1228 1228 continue
1229 1229 return None
1230 1230
1231 1231 # Most likely empty string.
1232 1232 # This may need to raise in the future.
1233 1233 if not name:
1234 1234 return None
1235 1235
1236 1236 try:
1237 1237 return self[name]
1238 1238 except KeyError:
1239 1239 # Try to resolve as a local path or URI.
1240 1240 try:
1241 1241 # We don't pass sub-options in, so no need to pass ui instance.
1242 1242 return path(None, None, rawloc=name)
1243 1243 except ValueError:
1244 1244 raise error.RepoError(_('repository %s does not exist') %
1245 1245 name)
1246 1246
1247 1247 _pathsuboptions = {}
1248 1248
1249 1249 def pathsuboption(option, attr):
1250 1250 """Decorator used to declare a path sub-option.
1251 1251
1252 1252 Arguments are the sub-option name and the attribute it should set on
1253 1253 ``path`` instances.
1254 1254
1255 1255 The decorated function will receive as arguments a ``ui`` instance,
1256 1256 ``path`` instance, and the string value of this option from the config.
1257 1257 The function should return the value that will be set on the ``path``
1258 1258 instance.
1259 1259
1260 1260 This decorator can be used to perform additional verification of
1261 1261 sub-options and to change the type of sub-options.
1262 1262 """
1263 1263 def register(func):
1264 1264 _pathsuboptions[option] = (attr, func)
1265 1265 return func
1266 1266 return register
1267 1267
1268 1268 @pathsuboption('pushurl', 'pushloc')
1269 1269 def pushurlpathoption(ui, path, value):
1270 1270 u = util.url(value)
1271 1271 # Actually require a URL.
1272 1272 if not u.scheme:
1273 1273 ui.warn(_('(paths.%s:pushurl not a URL; ignoring)\n') % path.name)
1274 1274 return None
1275 1275
1276 1276 # Don't support the #foo syntax in the push URL to declare branch to
1277 1277 # push.
1278 1278 if u.fragment:
1279 1279 ui.warn(_('("#fragment" in paths.%s:pushurl not supported; '
1280 1280 'ignoring)\n') % path.name)
1281 1281 u.fragment = None
1282 1282
1283 1283 return str(u)
1284 1284
1285 1285 @pathsuboption('pushrev', 'pushrev')
1286 1286 def pushrevpathoption(ui, path, value):
1287 1287 return value
1288 1288
1289 1289 class path(object):
1290 1290 """Represents an individual path and its configuration."""
1291 1291
1292 1292 def __init__(self, ui, name, rawloc=None, suboptions=None):
1293 1293 """Construct a path from its config options.
1294 1294
1295 1295 ``ui`` is the ``ui`` instance the path is coming from.
1296 1296 ``name`` is the symbolic name of the path.
1297 1297 ``rawloc`` is the raw location, as defined in the config.
1298 1298 ``pushloc`` is the raw locations pushes should be made to.
1299 1299
1300 1300 If ``name`` is not defined, we require that the location be a) a local
1301 1301 filesystem path with a .hg directory or b) a URL. If not,
1302 1302 ``ValueError`` is raised.
1303 1303 """
1304 1304 if not rawloc:
1305 1305 raise ValueError('rawloc must be defined')
1306 1306
1307 1307 # Locations may define branches via syntax <base>#<branch>.
1308 1308 u = util.url(rawloc)
1309 1309 branch = None
1310 1310 if u.fragment:
1311 1311 branch = u.fragment
1312 1312 u.fragment = None
1313 1313
1314 1314 self.url = u
1315 1315 self.branch = branch
1316 1316
1317 1317 self.name = name
1318 1318 self.rawloc = rawloc
1319 1319 self.loc = str(u)
1320 1320
1321 1321 # When given a raw location but not a symbolic name, validate the
1322 1322 # location is valid.
1323 1323 if not name and not u.scheme and not self._isvalidlocalpath(self.loc):
1324 1324 raise ValueError('location is not a URL or path to a local '
1325 1325 'repo: %s' % rawloc)
1326 1326
1327 1327 suboptions = suboptions or {}
1328 1328
1329 1329 # Now process the sub-options. If a sub-option is registered, its
1330 1330 # attribute will always be present. The value will be None if there
1331 1331 # was no valid sub-option.
1332 1332 for suboption, (attr, func) in _pathsuboptions.iteritems():
1333 1333 if suboption not in suboptions:
1334 1334 setattr(self, attr, None)
1335 1335 continue
1336 1336
1337 1337 value = func(ui, self, suboptions[suboption])
1338 1338 setattr(self, attr, value)
1339 1339
1340 1340 def _isvalidlocalpath(self, path):
1341 1341 """Returns True if the given path is a potentially valid repository.
1342 1342 This is its own function so that extensions can change the definition of
1343 1343 'valid' in this case (like when pulling from a git repo into a hg
1344 1344 one)."""
1345 1345 return os.path.isdir(os.path.join(path, '.hg'))
1346 1346
1347 1347 @property
1348 1348 def suboptions(self):
1349 1349 """Return sub-options and their values for this path.
1350 1350
1351 1351 This is intended to be used for presentation purposes.
1352 1352 """
1353 1353 d = {}
1354 1354 for subopt, (attr, _func) in _pathsuboptions.iteritems():
1355 1355 value = getattr(self, attr)
1356 1356 if value is not None:
1357 1357 d[subopt] = value
1358 1358 return d
1359 1359
1360 1360 # we instantiate one globally shared progress bar to avoid
1361 1361 # competing progress bars when multiple UI objects get created
1362 1362 _progresssingleton = None
1363 1363
1364 1364 def getprogbar(ui):
1365 1365 global _progresssingleton
1366 1366 if _progresssingleton is None:
1367 1367 # passing 'ui' object to the singleton is fishy,
1368 1368 # this is how the extension used to work but feel free to rework it.
1369 1369 _progresssingleton = progress.progbar(ui)
1370 1370 return _progresssingleton
@@ -1,239 +1,239
1 1 hide outer repo
2 2 $ hg init
3 3
4 4 Use hgrc within $TESTTMP
5 5
6 6 $ HGRCPATH=`pwd`/hgrc
7 7 $ export HGRCPATH
8 8
9 9 Use an alternate var for scribbling on hgrc to keep check-code from
10 10 complaining about the important settings we may be overwriting:
11 11
12 12 $ HGRC=`pwd`/hgrc
13 13 $ export HGRC
14 14
15 15 Basic syntax error
16 16
17 17 $ echo "invalid" > $HGRC
18 18 $ hg version
19 19 hg: parse error at $TESTTMP/hgrc:1: invalid
20 20 [255]
21 21 $ echo "" > $HGRC
22 22
23 23 Issue1199: Can't use '%' in hgrc (eg url encoded username)
24 24
25 25 $ hg init "foo%bar"
26 26 $ hg clone "foo%bar" foobar
27 27 updating to branch default
28 28 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
29 29 $ cd foobar
30 30 $ cat .hg/hgrc
31 # example repository config (see "hg help config" for more info)
31 # example repository config (see 'hg help config' for more info)
32 32 [paths]
33 33 default = $TESTTMP/foo%bar (glob)
34 34
35 35 # path aliases to other clones of this repo in URLs or filesystem paths
36 # (see "hg help config.paths" for more info)
36 # (see 'hg help config.paths' for more info)
37 37 #
38 38 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
39 39 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
40 40 # my-clone = /home/jdoe/jdoes-clone
41 41
42 42 [ui]
43 43 # name and email (local to this repository, optional), e.g.
44 44 # username = Jane Doe <jdoe@example.com>
45 45 $ hg paths
46 46 default = $TESTTMP/foo%bar (glob)
47 47 $ hg showconfig
48 48 bundle.mainreporoot=$TESTTMP/foobar (glob)
49 49 extensions.chgserver= (?)
50 50 paths.default=$TESTTMP/foo%bar (glob)
51 51 $ cd ..
52 52
53 53 issue1829: wrong indentation
54 54
55 55 $ echo '[foo]' > $HGRC
56 56 $ echo ' x = y' >> $HGRC
57 57 $ hg version
58 58 hg: parse error at $TESTTMP/hgrc:2: x = y
59 59 unexpected leading whitespace
60 60 [255]
61 61
62 62 $ $PYTHON -c "print '[foo]\nbar = a\n b\n c \n de\n fg \nbaz = bif cb \n'" \
63 63 > > $HGRC
64 64 $ hg showconfig foo
65 65 foo.bar=a\nb\nc\nde\nfg
66 66 foo.baz=bif cb
67 67
68 68 $ FAKEPATH=/path/to/nowhere
69 69 $ export FAKEPATH
70 70 $ echo '%include $FAKEPATH/no-such-file' > $HGRC
71 71 $ hg version
72 72 Mercurial Distributed SCM (version *) (glob)
73 73 (see https://mercurial-scm.org for more information)
74 74
75 75 Copyright (C) 2005-2016 Matt Mackall and others
76 76 This is free software; see the source for copying conditions. There is NO
77 77 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
78 78 $ unset FAKEPATH
79 79
80 80 make sure global options given on the cmdline take precedence
81 81
82 82 $ hg showconfig --config ui.verbose=True --quiet
83 83 bundle.mainreporoot=$TESTTMP
84 84 extensions.chgserver= (?)
85 85 ui.verbose=False
86 86 ui.debug=False
87 87 ui.quiet=True
88 88
89 89 $ touch foobar/untracked
90 90 $ cat >> foobar/.hg/hgrc <<EOF
91 91 > [ui]
92 92 > verbose=True
93 93 > EOF
94 94 $ hg -R foobar st -q
95 95
96 96 username expansion
97 97
98 98 $ olduser=$HGUSER
99 99 $ unset HGUSER
100 100
101 101 $ FAKEUSER='John Doe'
102 102 $ export FAKEUSER
103 103 $ echo '[ui]' > $HGRC
104 104 $ echo 'username = $FAKEUSER' >> $HGRC
105 105
106 106 $ hg init usertest
107 107 $ cd usertest
108 108 $ touch bar
109 109 $ hg commit --addremove --quiet -m "added bar"
110 110 $ hg log --template "{author}\n"
111 111 John Doe
112 112 $ cd ..
113 113
114 114 $ hg showconfig
115 115 bundle.mainreporoot=$TESTTMP
116 116 extensions.chgserver= (?)
117 117 ui.username=$FAKEUSER
118 118
119 119 $ unset FAKEUSER
120 120 $ HGUSER=$olduser
121 121 $ export HGUSER
122 122
123 123 showconfig with multiple arguments
124 124
125 125 $ echo "[alias]" > $HGRC
126 126 $ echo "log = log -g" >> $HGRC
127 127 $ echo "[defaults]" >> $HGRC
128 128 $ echo "identify = -n" >> $HGRC
129 129 $ hg showconfig alias defaults
130 130 alias.log=log -g
131 131 defaults.identify=-n
132 132 $ hg showconfig alias defaults.identify
133 133 abort: only one config item permitted
134 134 [255]
135 135 $ hg showconfig alias.log defaults.identify
136 136 abort: only one config item permitted
137 137 [255]
138 138
139 139 HGPLAIN
140 140
141 141 $ echo "[ui]" > $HGRC
142 142 $ echo "debug=true" >> $HGRC
143 143 $ echo "fallbackencoding=ASCII" >> $HGRC
144 144 $ echo "quiet=true" >> $HGRC
145 145 $ echo "slash=true" >> $HGRC
146 146 $ echo "traceback=true" >> $HGRC
147 147 $ echo "verbose=true" >> $HGRC
148 148 $ echo "style=~/.hgstyle" >> $HGRC
149 149 $ echo "logtemplate={node}" >> $HGRC
150 150 $ echo "[defaults]" >> $HGRC
151 151 $ echo "identify=-n" >> $HGRC
152 152 $ echo "[alias]" >> $HGRC
153 153 $ echo "log=log -g" >> $HGRC
154 154
155 155 customized hgrc
156 156
157 157 $ hg showconfig
158 158 read config from: $TESTTMP/hgrc
159 159 $TESTTMP/hgrc:13: alias.log=log -g
160 160 repo: bundle.mainreporoot=$TESTTMP
161 161 $TESTTMP/hgrc:11: defaults.identify=-n
162 162 --config: extensions.chgserver= (?)
163 163 $TESTTMP/hgrc:2: ui.debug=true
164 164 $TESTTMP/hgrc:3: ui.fallbackencoding=ASCII
165 165 $TESTTMP/hgrc:4: ui.quiet=true
166 166 $TESTTMP/hgrc:5: ui.slash=true
167 167 $TESTTMP/hgrc:6: ui.traceback=true
168 168 $TESTTMP/hgrc:7: ui.verbose=true
169 169 $TESTTMP/hgrc:8: ui.style=~/.hgstyle
170 170 $TESTTMP/hgrc:9: ui.logtemplate={node}
171 171
172 172 plain hgrc
173 173
174 174 $ HGPLAIN=; export HGPLAIN
175 175 $ hg showconfig --config ui.traceback=True --debug
176 176 read config from: $TESTTMP/hgrc
177 177 repo: bundle.mainreporoot=$TESTTMP
178 178 --config: extensions.chgserver= (?)
179 179 --config: ui.traceback=True
180 180 --verbose: ui.verbose=False
181 181 --debug: ui.debug=True
182 182 --quiet: ui.quiet=False
183 183
184 184 plain mode with exceptions
185 185
186 186 $ cat > plain.py <<EOF
187 187 > from mercurial import commands, extensions
188 188 > def _config(orig, ui, repo, *values, **opts):
189 189 > ui.write('plain: %r\n' % ui.plain())
190 190 > return orig(ui, repo, *values, **opts)
191 191 > def uisetup(ui):
192 192 > extensions.wrapcommand(commands.table, 'config', _config)
193 193 > EOF
194 194 $ echo "[extensions]" >> $HGRC
195 195 $ echo "plain=./plain.py" >> $HGRC
196 196 $ HGPLAINEXCEPT=; export HGPLAINEXCEPT
197 197 $ hg showconfig --config ui.traceback=True --debug
198 198 plain: True
199 199 read config from: $TESTTMP/hgrc
200 200 repo: bundle.mainreporoot=$TESTTMP
201 201 $TESTTMP/hgrc:15: extensions.plain=./plain.py
202 202 --config: extensions.chgserver= (?)
203 203 --config: ui.traceback=True
204 204 --verbose: ui.verbose=False
205 205 --debug: ui.debug=True
206 206 --quiet: ui.quiet=False
207 207 $ unset HGPLAIN
208 208 $ hg showconfig --config ui.traceback=True --debug
209 209 plain: True
210 210 read config from: $TESTTMP/hgrc
211 211 repo: bundle.mainreporoot=$TESTTMP
212 212 $TESTTMP/hgrc:15: extensions.plain=./plain.py
213 213 --config: extensions.chgserver= (?)
214 214 --config: ui.traceback=True
215 215 --verbose: ui.verbose=False
216 216 --debug: ui.debug=True
217 217 --quiet: ui.quiet=False
218 218 $ HGPLAINEXCEPT=i18n; export HGPLAINEXCEPT
219 219 $ hg showconfig --config ui.traceback=True --debug
220 220 plain: True
221 221 read config from: $TESTTMP/hgrc
222 222 repo: bundle.mainreporoot=$TESTTMP
223 223 $TESTTMP/hgrc:15: extensions.plain=./plain.py
224 224 --config: extensions.chgserver= (?)
225 225 --config: ui.traceback=True
226 226 --verbose: ui.verbose=False
227 227 --debug: ui.debug=True
228 228 --quiet: ui.quiet=False
229 229
230 230 source of paths is not mangled
231 231
232 232 $ cat >> $HGRCPATH <<EOF
233 233 > [paths]
234 234 > foo = bar
235 235 > EOF
236 236 $ hg showconfig --debug paths
237 237 plain: True
238 238 read config from: $TESTTMP/hgrc
239 239 $TESTTMP/hgrc:17: paths.foo=$TESTTMP/bar (glob)
@@ -1,80 +1,80
1 1 #require killdaemons
2 2
3 3 $ hg init test
4 4 $ cd test
5 5 $ echo a > a
6 6 $ hg ci -Ama
7 7 adding a
8 8 $ cd ..
9 9 $ hg clone test test2
10 10 updating to branch default
11 11 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
12 12 $ cd test2
13 13 $ echo a >> a
14 14 $ hg ci -mb
15 15
16 16 Cloning with a password in the URL should not save the password in .hg/hgrc:
17 17
18 18 $ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
19 19 $ cat hg.pid >> $DAEMON_PIDS
20 20 $ hg clone http://foo:xyzzy@localhost:$HGPORT/ test3
21 21 requesting all changes
22 22 adding changesets
23 23 adding manifests
24 24 adding file changes
25 25 added 2 changesets with 2 changes to 1 files
26 26 updating to branch default
27 27 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
28 28 $ cat test3/.hg/hgrc
29 # example repository config (see "hg help config" for more info)
29 # example repository config (see 'hg help config' for more info)
30 30 [paths]
31 31 default = http://foo@localhost:$HGPORT/
32 32
33 33 # path aliases to other clones of this repo in URLs or filesystem paths
34 # (see "hg help config.paths" for more info)
34 # (see 'hg help config.paths' for more info)
35 35 #
36 36 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
37 37 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
38 38 # my-clone = /home/jdoe/jdoes-clone
39 39
40 40 [ui]
41 41 # name and email (local to this repository, optional), e.g.
42 42 # username = Jane Doe <jdoe@example.com>
43 43 $ killdaemons.py
44 44
45 45 expect error, cloning not allowed
46 46
47 47 $ echo '[web]' > .hg/hgrc
48 48 $ echo 'allowpull = false' >> .hg/hgrc
49 49 $ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
50 50 $ cat hg.pid >> $DAEMON_PIDS
51 51 $ hg clone http://localhost:$HGPORT/ test4 # bundle2+
52 52 requesting all changes
53 53 abort: authorization failed
54 54 [255]
55 55 $ hg clone http://localhost:$HGPORT/ test4 --config devel.legacy.exchange=bundle1
56 56 abort: authorization failed
57 57 [255]
58 58 $ killdaemons.py
59 59
60 60 serve errors
61 61
62 62 $ cat errors.log
63 63 $ req() {
64 64 > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
65 65 > cat hg.pid >> $DAEMON_PIDS
66 66 > hg --cwd ../test pull http://localhost:$HGPORT/
67 67 > killdaemons.py hg.pid
68 68 > echo % serve errors
69 69 > cat errors.log
70 70 > }
71 71
72 72 expect error, pulling not allowed
73 73
74 74 $ req
75 75 pulling from http://localhost:$HGPORT/
76 76 searching for changes
77 77 abort: authorization failed
78 78 % serve errors
79 79
80 80 $ cd ..
@@ -1,116 +1,116
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [alias]
3 3 > tlog = log --template "{rev}:{node|short}: '{desc}' {branches}\n"
4 4 > tglog = tlog -G
5 5 > tout = out --template "{rev}:{node|short}: '{desc}' {branches}\n"
6 6 > EOF
7 7
8 8 $ hg init a
9 9 $ cd a
10 10
11 11 $ echo a > a
12 12 $ hg ci -Aqm0
13 13
14 14 $ echo foo >> a
15 15 $ hg ci -Aqm1
16 16
17 17 $ hg up -q 0
18 18
19 19 $ hg branch stable
20 20 marked working directory as branch stable
21 21 (branches are permanent and global, did you want a bookmark?)
22 22 $ echo bar >> a
23 23 $ hg ci -qm2
24 24
25 25 $ hg tglog
26 26 @ 2:7bee6c3bea3a: '2' stable
27 27 |
28 28 | o 1:3560197d8331: '1'
29 29 |/
30 30 o 0:f7b1eb17ad24: '0'
31 31
32 32
33 33 $ cd ..
34 34
35 35 $ hg clone -q a#stable b
36 36
37 37 $ cd b
38 38 $ cat .hg/hgrc
39 # example repository config (see "hg help config" for more info)
39 # example repository config (see 'hg help config' for more info)
40 40 [paths]
41 41 default = $TESTTMP/a#stable (glob)
42 42
43 43 # path aliases to other clones of this repo in URLs or filesystem paths
44 # (see "hg help config.paths" for more info)
44 # (see 'hg help config.paths' for more info)
45 45 #
46 46 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
47 47 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
48 48 # my-clone = /home/jdoe/jdoes-clone
49 49
50 50 [ui]
51 51 # name and email (local to this repository, optional), e.g.
52 52 # username = Jane Doe <jdoe@example.com>
53 53
54 54 $ echo red >> a
55 55 $ hg ci -qm3
56 56
57 57 $ hg up -q default
58 58
59 59 $ echo blue >> a
60 60 $ hg ci -qm4
61 61
62 62 $ hg tglog
63 63 @ 3:f0461977a3db: '4'
64 64 |
65 65 | o 2:1d4099801a4e: '3' stable
66 66 | |
67 67 | o 1:7bee6c3bea3a: '2' stable
68 68 |/
69 69 o 0:f7b1eb17ad24: '0'
70 70
71 71
72 72 $ hg tout
73 73 comparing with $TESTTMP/a (glob)
74 74 searching for changes
75 75 2:1d4099801a4e: '3' stable
76 76
77 77 $ hg tlog -r 'outgoing()'
78 78 2:1d4099801a4e: '3' stable
79 79
80 80 $ hg tout ../a#default
81 81 comparing with ../a
82 82 searching for changes
83 83 3:f0461977a3db: '4'
84 84
85 85 $ hg tlog -r 'outgoing("../a#default")'
86 86 3:f0461977a3db: '4'
87 87
88 88 $ echo "green = ../a#default" >> .hg/hgrc
89 89
90 90 $ cat .hg/hgrc
91 # example repository config (see "hg help config" for more info)
91 # example repository config (see 'hg help config' for more info)
92 92 [paths]
93 93 default = $TESTTMP/a#stable (glob)
94 94
95 95 # path aliases to other clones of this repo in URLs or filesystem paths
96 # (see "hg help config.paths" for more info)
96 # (see 'hg help config.paths' for more info)
97 97 #
98 98 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
99 99 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
100 100 # my-clone = /home/jdoe/jdoes-clone
101 101
102 102 [ui]
103 103 # name and email (local to this repository, optional), e.g.
104 104 # username = Jane Doe <jdoe@example.com>
105 105 green = ../a#default
106 106
107 107 $ hg tout green
108 108 comparing with green
109 109 abort: repository green not found!
110 110 [255]
111 111
112 112 $ hg tlog -r 'outgoing("green")'
113 113 abort: repository green not found!
114 114 [255]
115 115
116 116 $ cd ..
@@ -1,1097 +1,1097
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extdiff]
3 3 > # for portability:
4 4 > pdiff = sh "$RUNTESTDIR/pdiff"
5 5 > [progress]
6 6 > disable=False
7 7 > assume-tty = 1
8 8 > delay = 0
9 9 > # set changedelay really large so we don't see nested topics
10 10 > changedelay = 30000
11 11 > format = topic bar number
12 12 > refresh = 0
13 13 > width = 60
14 14 > EOF
15 15
16 16 Preparing the subrepository 'sub2'
17 17
18 18 $ hg init sub2
19 19 $ echo sub2 > sub2/sub2
20 20 $ hg add -R sub2
21 21 adding sub2/sub2 (glob)
22 22 $ hg commit -R sub2 -m "sub2 import"
23 23
24 24 Preparing the 'sub1' repo which depends on the subrepo 'sub2'
25 25
26 26 $ hg init sub1
27 27 $ echo sub1 > sub1/sub1
28 28 $ echo "sub2 = ../sub2" > sub1/.hgsub
29 29 $ hg clone sub2 sub1/sub2
30 30 \r (no-eol) (esc)
31 31 linking [ <=> ] 1\r (no-eol) (esc)
32 32 linking [ <=> ] 2\r (no-eol) (esc)
33 33 linking [ <=> ] 3\r (no-eol) (esc)
34 34 linking [ <=> ] 4\r (no-eol) (esc)
35 35 linking [ <=> ] 5\r (no-eol) (esc)
36 36 linking [ <=> ] 6\r (no-eol) (esc)
37 37 \r (no-eol) (esc)
38 38 \r (no-eol) (esc)
39 39 updating [===========================================>] 1/1\r (no-eol) (esc)
40 40 \r (no-eol) (esc)
41 41 updating to branch default
42 42 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
43 43 $ hg add -R sub1
44 44 adding sub1/.hgsub (glob)
45 45 adding sub1/sub1 (glob)
46 46 $ hg commit -R sub1 -m "sub1 import"
47 47
48 48 Preparing the 'main' repo which depends on the subrepo 'sub1'
49 49
50 50 $ hg init main
51 51 $ echo main > main/main
52 52 $ echo "sub1 = ../sub1" > main/.hgsub
53 53 $ hg clone sub1 main/sub1
54 54 \r (no-eol) (esc)
55 55 linking [ <=> ] 1\r (no-eol) (esc)
56 56 linking [ <=> ] 2\r (no-eol) (esc)
57 57 linking [ <=> ] 3\r (no-eol) (esc)
58 58 linking [ <=> ] 4\r (no-eol) (esc)
59 59 linking [ <=> ] 5\r (no-eol) (esc)
60 60 linking [ <=> ] 6\r (no-eol) (esc)
61 61 linking [ <=> ] 7\r (no-eol) (esc)
62 62 linking [ <=> ] 8\r (no-eol) (esc)
63 63 \r (no-eol) (esc)
64 64 \r (no-eol) (esc)
65 65 updating [===========================================>] 3/3\r (no-eol) (esc)
66 66 updating [===========================================>] 1/1\r (no-eol) (esc)
67 67 \r (no-eol) (esc)
68 68 updating to branch default
69 69 cloning subrepo sub2 from $TESTTMP/sub2
70 70 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
71 71 $ hg add -R main
72 72 adding main/.hgsub (glob)
73 73 adding main/main (glob)
74 74 $ hg commit -R main -m "main import"
75 75
76 76 Cleaning both repositories, just as a clone -U
77 77
78 78 $ hg up -C -R sub2 null
79 79 \r (no-eol) (esc)
80 80 updating [===========================================>] 1/1\r (no-eol) (esc)
81 81 \r (no-eol) (esc)
82 82 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
83 83 $ hg up -C -R sub1 null
84 84 \r (no-eol) (esc)
85 85 updating [===========================================>] 1/1\r (no-eol) (esc)
86 86 \r (no-eol) (esc)
87 87 \r (no-eol) (esc)
88 88 updating [===========================================>] 3/3\r (no-eol) (esc)
89 89 \r (no-eol) (esc)
90 90 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
91 91 $ hg up -C -R main null
92 92 \r (no-eol) (esc)
93 93 updating [===========================================>] 1/1\r (no-eol) (esc)
94 94 \r (no-eol) (esc)
95 95 \r (no-eol) (esc)
96 96 updating [===========================================>] 3/3\r (no-eol) (esc)
97 97 \r (no-eol) (esc)
98 98 \r (no-eol) (esc)
99 99 updating [===========================================>] 3/3\r (no-eol) (esc)
100 100 \r (no-eol) (esc)
101 101 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
102 102 $ rm -rf main/sub1
103 103 $ rm -rf sub1/sub2
104 104
105 105 Clone main
106 106
107 107 $ hg --config extensions.largefiles= clone main cloned
108 108 \r (no-eol) (esc)
109 109 linking [ <=> ] 1\r (no-eol) (esc)
110 110 linking [ <=> ] 2\r (no-eol) (esc)
111 111 linking [ <=> ] 3\r (no-eol) (esc)
112 112 linking [ <=> ] 4\r (no-eol) (esc)
113 113 linking [ <=> ] 5\r (no-eol) (esc)
114 114 linking [ <=> ] 6\r (no-eol) (esc)
115 115 linking [ <=> ] 7\r (no-eol) (esc)
116 116 linking [ <=> ] 8\r (no-eol) (esc)
117 117 \r (no-eol) (esc)
118 118 \r (no-eol) (esc)
119 119 updating [===========================================>] 3/3\r (no-eol) (esc)
120 120 updating [===========================================>] 3/3\r (no-eol) (esc)
121 121 updating [===========================================>] 1/1\r (no-eol) (esc)
122 122 \r (no-eol) (esc)
123 123 updating to branch default
124 124 cloning subrepo sub1 from $TESTTMP/sub1
125 125 cloning subrepo sub1/sub2 from $TESTTMP/sub2 (glob)
126 126 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
127 127
128 128 Largefiles is NOT enabled in the clone if the source repo doesn't require it
129 129 $ cat cloned/.hg/hgrc
130 # example repository config (see "hg help config" for more info)
130 # example repository config (see 'hg help config' for more info)
131 131 [paths]
132 132 default = $TESTTMP/main (glob)
133 133
134 134 # path aliases to other clones of this repo in URLs or filesystem paths
135 # (see "hg help config.paths" for more info)
135 # (see 'hg help config.paths' for more info)
136 136 #
137 137 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
138 138 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
139 139 # my-clone = /home/jdoe/jdoes-clone
140 140
141 141 [ui]
142 142 # name and email (local to this repository, optional), e.g.
143 143 # username = Jane Doe <jdoe@example.com>
144 144
145 145 Checking cloned repo ids
146 146
147 147 $ printf "cloned " ; hg id -R cloned
148 148 cloned 7f491f53a367 tip
149 149 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
150 150 cloned/sub1 fc3b4ce2696f tip
151 151 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
152 152 cloned/sub1/sub2 c57a0840e3ba tip
153 153
154 154 debugsub output for main and sub1
155 155
156 156 $ hg debugsub -R cloned
157 157 path sub1
158 158 source ../sub1
159 159 revision fc3b4ce2696f7741438c79207583768f2ce6b0dd
160 160 $ hg debugsub -R cloned/sub1
161 161 path sub2
162 162 source ../sub2
163 163 revision c57a0840e3badd667ef3c3ef65471609acb2ba3c
164 164
165 165 Modifying deeply nested 'sub2'
166 166
167 167 $ echo modified > cloned/sub1/sub2/sub2
168 168 $ hg commit --subrepos -m "deep nested modif should trigger a commit" -R cloned
169 169 committing subrepository sub1
170 170 committing subrepository sub1/sub2 (glob)
171 171
172 172 Checking modified node ids
173 173
174 174 $ printf "cloned " ; hg id -R cloned
175 175 cloned ffe6649062fe tip
176 176 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
177 177 cloned/sub1 2ecb03bf44a9 tip
178 178 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
179 179 cloned/sub1/sub2 53dd3430bcaf tip
180 180
181 181 debugsub output for main and sub1
182 182
183 183 $ hg debugsub -R cloned
184 184 path sub1
185 185 source ../sub1
186 186 revision 2ecb03bf44a94e749e8669481dd9069526ce7cb9
187 187 $ hg debugsub -R cloned/sub1
188 188 path sub2
189 189 source ../sub2
190 190 revision 53dd3430bcaf5ab4a7c48262bcad6d441f510487
191 191
192 192 Check that deep archiving works
193 193
194 194 $ cd cloned
195 195 $ echo 'test' > sub1/sub2/test.txt
196 196 $ hg --config extensions.largefiles=! add sub1/sub2/test.txt
197 197 $ mkdir sub1/sub2/folder
198 198 $ echo 'subfolder' > sub1/sub2/folder/test.txt
199 199 $ hg ci -ASm "add test.txt"
200 200 adding sub1/sub2/folder/test.txt
201 201 committing subrepository sub1
202 202 committing subrepository sub1/sub2 (glob)
203 203
204 204 .. but first take a detour through some deep removal testing
205 205
206 206 $ hg remove -S -I 're:.*.txt' .
207 207 \r (no-eol) (esc)
208 208 searching [==========================================>] 1/1\r (no-eol) (esc)
209 209 searching [==========================================>] 1/1\r (no-eol) (esc)
210 210 \r (no-eol) (esc)
211 211 \r (no-eol) (esc)
212 212 deleting [=====================> ] 1/2\r (no-eol) (esc)
213 213 \r (no-eol) (esc)
214 214 \r (no-eol) (esc)
215 215 deleting [===========================================>] 2/2\r (no-eol) (esc)
216 216 \r (no-eol) (esc)
217 217 removing sub1/sub2/folder/test.txt (glob)
218 218 removing sub1/sub2/test.txt (glob)
219 219 $ hg status -S
220 220 R sub1/sub2/folder/test.txt
221 221 R sub1/sub2/test.txt
222 222 $ hg update -Cq
223 223 $ hg remove -I 're:.*.txt' sub1
224 224 \r (no-eol) (esc)
225 225 searching [==========================================>] 1/1\r (no-eol) (esc)
226 226 \r (no-eol) (esc)
227 227 \r (no-eol) (esc)
228 228 deleting [===========================================>] 1/1\r (no-eol) (esc)
229 229 \r (no-eol) (esc)
230 230 $ hg status -S
231 231 $ hg remove sub1/sub2/folder/test.txt
232 232 \r (no-eol) (esc)
233 233 searching [==========================================>] 1/1\r (no-eol) (esc)
234 234 searching [==========================================>] 1/1\r (no-eol) (esc)
235 235 \r (no-eol) (esc)
236 236 \r (no-eol) (esc)
237 237 deleting [===========================================>] 1/1\r (no-eol) (esc)
238 238 \r (no-eol) (esc)
239 239 \r (no-eol) (esc)
240 240 deleting [===========================================>] 1/1\r (no-eol) (esc)
241 241 \r (no-eol) (esc)
242 242 \r (no-eol) (esc)
243 243 deleting [===========================================>] 1/1\r (no-eol) (esc)
244 244 \r (no-eol) (esc)
245 245 $ hg remove sub1/.hgsubstate
246 246 \r (no-eol) (esc)
247 247 searching [==========================================>] 1/1\r (no-eol) (esc)
248 248 \r (no-eol) (esc)
249 249 \r (no-eol) (esc)
250 250 deleting [===========================================>] 1/1\r (no-eol) (esc)
251 251 \r (no-eol) (esc)
252 252 \r (no-eol) (esc)
253 253 deleting [===========================================>] 1/1\r (no-eol) (esc)
254 254 \r (no-eol) (esc)
255 255 $ mv sub1/.hgsub sub1/x.hgsub
256 256 $ hg status -S
257 257 warning: subrepo spec file 'sub1/.hgsub' not found
258 258 R sub1/.hgsubstate
259 259 R sub1/sub2/folder/test.txt
260 260 ! sub1/.hgsub
261 261 ? sub1/x.hgsub
262 262 $ mv sub1/x.hgsub sub1/.hgsub
263 263 $ hg update -Cq
264 264 $ touch sub1/foo
265 265 $ hg forget sub1/sub2/folder/test.txt
266 266 $ rm sub1/sub2/test.txt
267 267
268 268 Test relative path printing + subrepos
269 269 $ mkdir -p foo/bar
270 270 $ cd foo
271 271 $ touch bar/abc
272 272 $ hg addremove -S ..
273 273 \r (no-eol) (esc)
274 274 searching for exact renames [ ] 0/1\r (no-eol) (esc)
275 275 \r (no-eol) (esc)
276 276 adding ../sub1/sub2/folder/test.txt (glob)
277 277 removing ../sub1/sub2/test.txt (glob)
278 278 adding ../sub1/foo (glob)
279 279 adding bar/abc (glob)
280 280 $ cd ..
281 281 $ hg status -S
282 282 A foo/bar/abc
283 283 A sub1/foo
284 284 R sub1/sub2/test.txt
285 285
286 286 Archive wdir() with subrepos
287 287 $ hg rm main
288 288 \r (no-eol) (esc)
289 289 deleting [===========================================>] 1/1\r (no-eol) (esc)
290 290 \r (no-eol) (esc)
291 291 $ hg archive -S -r 'wdir()' ../wdir
292 292 \r (no-eol) (esc)
293 293 archiving [ ] 0/3\r (no-eol) (esc)
294 294 archiving [=============> ] 1/3\r (no-eol) (esc)
295 295 archiving [===========================> ] 2/3\r (no-eol) (esc)
296 296 archiving [==========================================>] 3/3\r (no-eol) (esc)
297 297 \r (no-eol) (esc)
298 298 \r (no-eol) (esc)
299 299 archiving (sub1) [ ] 0/4\r (no-eol) (esc)
300 300 archiving (sub1) [========> ] 1/4\r (no-eol) (esc)
301 301 archiving (sub1) [=================> ] 2/4\r (no-eol) (esc)
302 302 archiving (sub1) [==========================> ] 3/4\r (no-eol) (esc)
303 303 archiving (sub1) [===================================>] 4/4\r (no-eol) (esc)
304 304 \r (no-eol) (esc)
305 305 \r (no-eol) (esc)
306 306 archiving (sub1/sub2) [ ] 0/2\r (no-eol) (glob) (esc)
307 307 archiving (sub1/sub2) [==============> ] 1/2\r (no-eol) (glob) (esc)
308 308 archiving (sub1/sub2) [==============================>] 2/2\r (no-eol) (glob) (esc)
309 309 \r (no-eol) (esc)
310 310 $ diff -r . ../wdir | egrep -v '\.hg$|^Common subdirectories:'
311 311 Only in ../wdir: .hg_archival.txt
312 312
313 313 $ find ../wdir -type f | sort
314 314 ../wdir/.hg_archival.txt
315 315 ../wdir/.hgsub
316 316 ../wdir/.hgsubstate
317 317 ../wdir/foo/bar/abc
318 318 ../wdir/sub1/.hgsub
319 319 ../wdir/sub1/.hgsubstate
320 320 ../wdir/sub1/foo
321 321 ../wdir/sub1/sub1
322 322 ../wdir/sub1/sub2/folder/test.txt
323 323 ../wdir/sub1/sub2/sub2
324 324
325 325 $ cat ../wdir/.hg_archival.txt
326 326 repo: 7f491f53a367861f47ee64a80eb997d1f341b77a
327 327 node: 9bb10eebee29dc0f1201dcf5977b811a540255fd+
328 328 branch: default
329 329 latesttag: null
330 330 latesttagdistance: 4
331 331 changessincelatesttag: 4
332 332
333 333 Attempting to archive 'wdir()' with a missing file is handled gracefully
334 334 $ rm sub1/sub1
335 335 $ rm -r ../wdir
336 336 $ hg archive -v -S -r 'wdir()' ../wdir
337 337 \r (no-eol) (esc)
338 338 archiving [ ] 0/3\r (no-eol) (esc)
339 339 archiving [=============> ] 1/3\r (no-eol) (esc)
340 340 archiving [===========================> ] 2/3\r (no-eol) (esc)
341 341 archiving [==========================================>] 3/3\r (no-eol) (esc)
342 342 \r (no-eol) (esc)
343 343 \r (no-eol) (esc)
344 344 archiving (sub1) [ ] 0/3\r (no-eol) (esc)
345 345 archiving (sub1) [===========> ] 1/3\r (no-eol) (esc)
346 346 archiving (sub1) [=======================> ] 2/3\r (no-eol) (esc)
347 347 archiving (sub1) [===================================>] 3/3\r (no-eol) (esc)
348 348 \r (no-eol) (esc)
349 349 \r (no-eol) (esc)
350 350 archiving (sub1/sub2) [ ] 0/2\r (no-eol) (glob) (esc)
351 351 archiving (sub1/sub2) [==============> ] 1/2\r (no-eol) (glob) (esc)
352 352 archiving (sub1/sub2) [==============================>] 2/2\r (no-eol) (glob) (esc)
353 353 \r (no-eol) (esc)
354 354 $ find ../wdir -type f | sort
355 355 ../wdir/.hg_archival.txt
356 356 ../wdir/.hgsub
357 357 ../wdir/.hgsubstate
358 358 ../wdir/foo/bar/abc
359 359 ../wdir/sub1/.hgsub
360 360 ../wdir/sub1/.hgsubstate
361 361 ../wdir/sub1/foo
362 362 ../wdir/sub1/sub2/folder/test.txt
363 363 ../wdir/sub1/sub2/sub2
364 364
365 365 Continue relative path printing + subrepos
366 366 $ hg update -Cq
367 367 $ rm -r ../wdir
368 368 $ hg archive -S -r 'wdir()' ../wdir
369 369 \r (no-eol) (esc)
370 370 archiving [ ] 0/3\r (no-eol) (esc)
371 371 archiving [=============> ] 1/3\r (no-eol) (esc)
372 372 archiving [===========================> ] 2/3\r (no-eol) (esc)
373 373 archiving [==========================================>] 3/3\r (no-eol) (esc)
374 374 \r (no-eol) (esc)
375 375 \r (no-eol) (esc)
376 376 archiving (sub1) [ ] 0/3\r (no-eol) (esc)
377 377 archiving (sub1) [===========> ] 1/3\r (no-eol) (esc)
378 378 archiving (sub1) [=======================> ] 2/3\r (no-eol) (esc)
379 379 archiving (sub1) [===================================>] 3/3\r (no-eol) (esc)
380 380 \r (no-eol) (esc)
381 381 \r (no-eol) (esc)
382 382 archiving (sub1/sub2) [ ] 0/3\r (no-eol) (glob) (esc)
383 383 archiving (sub1/sub2) [=========> ] 1/3\r (no-eol) (glob) (esc)
384 384 archiving (sub1/sub2) [===================> ] 2/3\r (no-eol) (glob) (esc)
385 385 archiving (sub1/sub2) [==============================>] 3/3\r (no-eol) (glob) (esc)
386 386 \r (no-eol) (esc)
387 387 $ cat ../wdir/.hg_archival.txt
388 388 repo: 7f491f53a367861f47ee64a80eb997d1f341b77a
389 389 node: 9bb10eebee29dc0f1201dcf5977b811a540255fd
390 390 branch: default
391 391 latesttag: null
392 392 latesttagdistance: 4
393 393 changessincelatesttag: 4
394 394
395 395 $ touch sub1/sub2/folder/bar
396 396 $ hg addremove sub1/sub2
397 397 adding sub1/sub2/folder/bar (glob)
398 398 $ hg status -S
399 399 A sub1/sub2/folder/bar
400 400 ? foo/bar/abc
401 401 ? sub1/foo
402 402 $ hg update -Cq
403 403 $ hg addremove sub1
404 404 adding sub1/sub2/folder/bar (glob)
405 405 adding sub1/foo (glob)
406 406 $ hg update -Cq
407 407 $ rm sub1/sub2/folder/test.txt
408 408 $ rm sub1/sub2/test.txt
409 409 $ hg ci -ASm "remove test.txt"
410 410 adding sub1/sub2/folder/bar
411 411 removing sub1/sub2/folder/test.txt
412 412 removing sub1/sub2/test.txt
413 413 adding sub1/foo
414 414 adding foo/bar/abc
415 415 committing subrepository sub1
416 416 committing subrepository sub1/sub2 (glob)
417 417
418 418 $ hg forget sub1/sub2/sub2
419 419 $ echo x > sub1/sub2/x.txt
420 420 $ hg add sub1/sub2/x.txt
421 421
422 422 Files sees uncommitted adds and removes in subrepos
423 423 $ hg files -S
424 424 .hgsub
425 425 .hgsubstate
426 426 foo/bar/abc (glob)
427 427 main
428 428 sub1/.hgsub (glob)
429 429 sub1/.hgsubstate (glob)
430 430 sub1/foo (glob)
431 431 sub1/sub1 (glob)
432 432 sub1/sub2/folder/bar (glob)
433 433 sub1/sub2/x.txt (glob)
434 434
435 435 $ hg files -S "set:eol('dos') or eol('unix') or size('<= 0')"
436 436 .hgsub
437 437 .hgsubstate
438 438 foo/bar/abc (glob)
439 439 main
440 440 sub1/.hgsub (glob)
441 441 sub1/.hgsubstate (glob)
442 442 sub1/foo (glob)
443 443 sub1/sub1 (glob)
444 444 sub1/sub2/folder/bar (glob)
445 445 sub1/sub2/x.txt (glob)
446 446
447 447 $ hg files -r '.^' -S "set:eol('dos') or eol('unix')"
448 448 .hgsub
449 449 .hgsubstate
450 450 main
451 451 sub1/.hgsub (glob)
452 452 sub1/.hgsubstate (glob)
453 453 sub1/sub1 (glob)
454 454 sub1/sub2/folder/test.txt (glob)
455 455 sub1/sub2/sub2 (glob)
456 456 sub1/sub2/test.txt (glob)
457 457
458 458 $ hg files sub1
459 459 sub1/.hgsub (glob)
460 460 sub1/.hgsubstate (glob)
461 461 sub1/foo (glob)
462 462 sub1/sub1 (glob)
463 463 sub1/sub2/folder/bar (glob)
464 464 sub1/sub2/x.txt (glob)
465 465
466 466 $ hg files sub1/sub2
467 467 sub1/sub2/folder/bar (glob)
468 468 sub1/sub2/x.txt (glob)
469 469
470 470 $ hg files
471 471 .hgsub
472 472 .hgsubstate
473 473 foo/bar/abc (glob)
474 474 main
475 475
476 476 $ hg files -S -r '.^' sub1/sub2/folder
477 477 sub1/sub2/folder/test.txt (glob)
478 478
479 479 $ hg files -S -r '.^' sub1/sub2/missing
480 480 sub1/sub2/missing: no such file in rev 78026e779ea6 (glob)
481 481 [1]
482 482
483 483 $ hg files -r '.^' sub1/
484 484 sub1/.hgsub (glob)
485 485 sub1/.hgsubstate (glob)
486 486 sub1/sub1 (glob)
487 487 sub1/sub2/folder/test.txt (glob)
488 488 sub1/sub2/sub2 (glob)
489 489 sub1/sub2/test.txt (glob)
490 490
491 491 $ hg files -r '.^' sub1/sub2
492 492 sub1/sub2/folder/test.txt (glob)
493 493 sub1/sub2/sub2 (glob)
494 494 sub1/sub2/test.txt (glob)
495 495
496 496 $ hg rollback -q
497 497 $ hg up -Cq
498 498
499 499 $ hg --config extensions.largefiles=! archive -S ../archive_all
500 500 \r (no-eol) (esc)
501 501 archiving [ ] 0/3\r (no-eol) (esc)
502 502 archiving [=============> ] 1/3\r (no-eol) (esc)
503 503 archiving [===========================> ] 2/3\r (no-eol) (esc)
504 504 archiving [==========================================>] 3/3\r (no-eol) (esc)
505 505 \r (no-eol) (esc)
506 506 \r (no-eol) (esc)
507 507 archiving (sub1) [ ] 0/3\r (no-eol) (esc)
508 508 archiving (sub1) [===========> ] 1/3\r (no-eol) (esc)
509 509 archiving (sub1) [=======================> ] 2/3\r (no-eol) (esc)
510 510 archiving (sub1) [===================================>] 3/3\r (no-eol) (esc)
511 511 \r (no-eol) (esc)
512 512 \r (no-eol) (esc)
513 513 archiving (sub1/sub2) [ ] 0/3\r (no-eol) (glob) (esc)
514 514 archiving (sub1/sub2) [=========> ] 1/3\r (no-eol) (glob) (esc)
515 515 archiving (sub1/sub2) [===================> ] 2/3\r (no-eol) (glob) (esc)
516 516 archiving (sub1/sub2) [==============================>] 3/3\r (no-eol) (glob) (esc)
517 517 \r (no-eol) (esc)
518 518 $ find ../archive_all | sort
519 519 ../archive_all
520 520 ../archive_all/.hg_archival.txt
521 521 ../archive_all/.hgsub
522 522 ../archive_all/.hgsubstate
523 523 ../archive_all/main
524 524 ../archive_all/sub1
525 525 ../archive_all/sub1/.hgsub
526 526 ../archive_all/sub1/.hgsubstate
527 527 ../archive_all/sub1/sub1
528 528 ../archive_all/sub1/sub2
529 529 ../archive_all/sub1/sub2/folder
530 530 ../archive_all/sub1/sub2/folder/test.txt
531 531 ../archive_all/sub1/sub2/sub2
532 532 ../archive_all/sub1/sub2/test.txt
533 533
534 534 Check that archive -X works in deep subrepos
535 535
536 536 $ hg --config extensions.largefiles=! archive -S -X '**test*' ../archive_exclude
537 537 \r (no-eol) (esc)
538 538 archiving [ ] 0/3\r (no-eol) (esc)
539 539 archiving [=============> ] 1/3\r (no-eol) (esc)
540 540 archiving [===========================> ] 2/3\r (no-eol) (esc)
541 541 archiving [==========================================>] 3/3\r (no-eol) (esc)
542 542 \r (no-eol) (esc)
543 543 \r (no-eol) (esc)
544 544 archiving (sub1) [ ] 0/3\r (no-eol) (esc)
545 545 archiving (sub1) [===========> ] 1/3\r (no-eol) (esc)
546 546 archiving (sub1) [=======================> ] 2/3\r (no-eol) (esc)
547 547 archiving (sub1) [===================================>] 3/3\r (no-eol) (esc)
548 548 \r (no-eol) (esc)
549 549 \r (no-eol) (esc)
550 550 archiving (sub1/sub2) [ ] 0/1\r (no-eol) (glob) (esc)
551 551 archiving (sub1/sub2) [==============================>] 1/1\r (no-eol) (glob) (esc)
552 552 \r (no-eol) (esc)
553 553 $ find ../archive_exclude | sort
554 554 ../archive_exclude
555 555 ../archive_exclude/.hg_archival.txt
556 556 ../archive_exclude/.hgsub
557 557 ../archive_exclude/.hgsubstate
558 558 ../archive_exclude/main
559 559 ../archive_exclude/sub1
560 560 ../archive_exclude/sub1/.hgsub
561 561 ../archive_exclude/sub1/.hgsubstate
562 562 ../archive_exclude/sub1/sub1
563 563 ../archive_exclude/sub1/sub2
564 564 ../archive_exclude/sub1/sub2/sub2
565 565
566 566 $ hg --config extensions.largefiles=! archive -S -I '**test*' ../archive_include
567 567 \r (no-eol) (esc)
568 568 archiving (sub1) [ <=> ] 0\r (no-eol) (esc)
569 569 \r (no-eol) (esc)
570 570 \r (no-eol) (esc)
571 571 archiving (sub1/sub2) [ ] 0/2\r (no-eol) (glob) (esc)
572 572 archiving (sub1/sub2) [==============> ] 1/2\r (no-eol) (glob) (esc)
573 573 archiving (sub1/sub2) [==============================>] 2/2\r (no-eol) (glob) (esc)
574 574 \r (no-eol) (esc)
575 575 $ find ../archive_include | sort
576 576 ../archive_include
577 577 ../archive_include/sub1
578 578 ../archive_include/sub1/sub2
579 579 ../archive_include/sub1/sub2/folder
580 580 ../archive_include/sub1/sub2/folder/test.txt
581 581 ../archive_include/sub1/sub2/test.txt
582 582
583 583 Check that deep archive works with largefiles (which overrides hgsubrepo impl)
584 584 This also tests the repo.ui regression in 43fb170a23bd, and that lf subrepo
585 585 subrepos are archived properly.
586 586 Note that add --large through a subrepo currently adds the file as a normal file
587 587
588 588 $ echo "large" > sub1/sub2/large.bin
589 589 $ hg --config extensions.largefiles= add --large -R sub1/sub2 sub1/sub2/large.bin
590 590 $ echo "large" > large.bin
591 591 $ hg --config extensions.largefiles= add --large large.bin
592 592 $ hg --config extensions.largefiles= ci -S -m "add large files"
593 593 committing subrepository sub1
594 594 committing subrepository sub1/sub2 (glob)
595 595
596 596 $ hg --config extensions.largefiles= archive -S ../archive_lf
597 597 $ find ../archive_lf | sort
598 598 ../archive_lf
599 599 ../archive_lf/.hg_archival.txt
600 600 ../archive_lf/.hgsub
601 601 ../archive_lf/.hgsubstate
602 602 ../archive_lf/large.bin
603 603 ../archive_lf/main
604 604 ../archive_lf/sub1
605 605 ../archive_lf/sub1/.hgsub
606 606 ../archive_lf/sub1/.hgsubstate
607 607 ../archive_lf/sub1/sub1
608 608 ../archive_lf/sub1/sub2
609 609 ../archive_lf/sub1/sub2/folder
610 610 ../archive_lf/sub1/sub2/folder/test.txt
611 611 ../archive_lf/sub1/sub2/large.bin
612 612 ../archive_lf/sub1/sub2/sub2
613 613 ../archive_lf/sub1/sub2/test.txt
614 614 $ rm -rf ../archive_lf
615 615
616 616 Exclude large files from main and sub-sub repo
617 617
618 618 $ hg --config extensions.largefiles= archive -S -X '**.bin' ../archive_lf
619 619 $ find ../archive_lf | sort
620 620 ../archive_lf
621 621 ../archive_lf/.hg_archival.txt
622 622 ../archive_lf/.hgsub
623 623 ../archive_lf/.hgsubstate
624 624 ../archive_lf/main
625 625 ../archive_lf/sub1
626 626 ../archive_lf/sub1/.hgsub
627 627 ../archive_lf/sub1/.hgsubstate
628 628 ../archive_lf/sub1/sub1
629 629 ../archive_lf/sub1/sub2
630 630 ../archive_lf/sub1/sub2/folder
631 631 ../archive_lf/sub1/sub2/folder/test.txt
632 632 ../archive_lf/sub1/sub2/sub2
633 633 ../archive_lf/sub1/sub2/test.txt
634 634 $ rm -rf ../archive_lf
635 635
636 636 Exclude normal files from main and sub-sub repo
637 637
638 638 $ hg --config extensions.largefiles= archive -S -X '**.txt' -p '.' ../archive_lf.tgz
639 639 $ tar -tzf ../archive_lf.tgz | sort
640 640 .hgsub
641 641 .hgsubstate
642 642 large.bin
643 643 main
644 644 sub1/.hgsub
645 645 sub1/.hgsubstate
646 646 sub1/sub1
647 647 sub1/sub2/large.bin
648 648 sub1/sub2/sub2
649 649
650 650 Include normal files from within a largefiles subrepo
651 651
652 652 $ hg --config extensions.largefiles= archive -S -I '**.txt' ../archive_lf
653 653 $ find ../archive_lf | sort
654 654 ../archive_lf
655 655 ../archive_lf/.hg_archival.txt
656 656 ../archive_lf/sub1
657 657 ../archive_lf/sub1/sub2
658 658 ../archive_lf/sub1/sub2/folder
659 659 ../archive_lf/sub1/sub2/folder/test.txt
660 660 ../archive_lf/sub1/sub2/test.txt
661 661 $ rm -rf ../archive_lf
662 662
663 663 Include large files from within a largefiles subrepo
664 664
665 665 $ hg --config extensions.largefiles= archive -S -I '**.bin' ../archive_lf
666 666 $ find ../archive_lf | sort
667 667 ../archive_lf
668 668 ../archive_lf/large.bin
669 669 ../archive_lf/sub1
670 670 ../archive_lf/sub1/sub2
671 671 ../archive_lf/sub1/sub2/large.bin
672 672 $ rm -rf ../archive_lf
673 673
674 674 Find an exact largefile match in a largefiles subrepo
675 675
676 676 $ hg --config extensions.largefiles= archive -S -I 'sub1/sub2/large.bin' ../archive_lf
677 677 $ find ../archive_lf | sort
678 678 ../archive_lf
679 679 ../archive_lf/sub1
680 680 ../archive_lf/sub1/sub2
681 681 ../archive_lf/sub1/sub2/large.bin
682 682 $ rm -rf ../archive_lf
683 683
684 684 The local repo enables largefiles if a largefiles repo is cloned
685 685 $ hg showconfig extensions
686 686 abort: repository requires features unknown to this Mercurial: largefiles!
687 687 (see https://mercurial-scm.org/wiki/MissingRequirement for more information)
688 688 [255]
689 689 $ hg --config extensions.largefiles= clone -qU . ../lfclone
690 690 $ cat ../lfclone/.hg/hgrc
691 # example repository config (see "hg help config" for more info)
691 # example repository config (see 'hg help config' for more info)
692 692 [paths]
693 693 default = $TESTTMP/cloned (glob)
694 694
695 695 # path aliases to other clones of this repo in URLs or filesystem paths
696 # (see "hg help config.paths" for more info)
696 # (see 'hg help config.paths' for more info)
697 697 #
698 698 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
699 699 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
700 700 # my-clone = /home/jdoe/jdoes-clone
701 701
702 702 [ui]
703 703 # name and email (local to this repository, optional), e.g.
704 704 # username = Jane Doe <jdoe@example.com>
705 705
706 706 [extensions]
707 707 largefiles=
708 708
709 709 Find an exact match to a standin (should archive nothing)
710 710 $ hg --config extensions.largefiles= archive -S -I 'sub/sub2/.hglf/large.bin' ../archive_lf
711 711 $ find ../archive_lf 2> /dev/null | sort
712 712
713 713 $ cat >> $HGRCPATH <<EOF
714 714 > [extensions]
715 715 > largefiles=
716 716 > [largefiles]
717 717 > patterns=glob:**.dat
718 718 > EOF
719 719
720 720 Test forget through a deep subrepo with the largefiles extension, both a
721 721 largefile and a normal file. Then a largefile that hasn't been committed yet.
722 722 $ touch sub1/sub2/untracked.txt
723 723 $ touch sub1/sub2/large.dat
724 724 $ hg forget sub1/sub2/large.bin sub1/sub2/test.txt sub1/sub2/untracked.txt
725 725 not removing sub1/sub2/untracked.txt: file is already untracked (glob)
726 726 [1]
727 727 $ hg add --large --dry-run -v sub1/sub2/untracked.txt
728 728 adding sub1/sub2/untracked.txt as a largefile (glob)
729 729 $ hg add --large -v sub1/sub2/untracked.txt
730 730 adding sub1/sub2/untracked.txt as a largefile (glob)
731 731 $ hg add --normal -v sub1/sub2/large.dat
732 732 adding sub1/sub2/large.dat (glob)
733 733 $ hg forget -v sub1/sub2/untracked.txt
734 734 removing sub1/sub2/untracked.txt (glob)
735 735 $ hg status -S
736 736 A sub1/sub2/large.dat
737 737 R sub1/sub2/large.bin
738 738 R sub1/sub2/test.txt
739 739 ? foo/bar/abc
740 740 ? sub1/sub2/untracked.txt
741 741 ? sub1/sub2/x.txt
742 742 $ hg add sub1/sub2
743 743
744 744 $ hg archive -S -r 'wdir()' ../wdir2
745 745 $ diff -r . ../wdir2 | egrep -v '\.hg$|^Common subdirectories:'
746 746 Only in ../wdir2: .hg_archival.txt
747 747 Only in .: .hglf
748 748 Only in .: foo
749 749 Only in ./sub1/sub2: large.bin
750 750 Only in ./sub1/sub2: test.txt
751 751 Only in ./sub1/sub2: untracked.txt
752 752 Only in ./sub1/sub2: x.txt
753 753 $ find ../wdir2 -type f | sort
754 754 ../wdir2/.hg_archival.txt
755 755 ../wdir2/.hgsub
756 756 ../wdir2/.hgsubstate
757 757 ../wdir2/large.bin
758 758 ../wdir2/main
759 759 ../wdir2/sub1/.hgsub
760 760 ../wdir2/sub1/.hgsubstate
761 761 ../wdir2/sub1/sub1
762 762 ../wdir2/sub1/sub2/folder/test.txt
763 763 ../wdir2/sub1/sub2/large.dat
764 764 ../wdir2/sub1/sub2/sub2
765 765 $ hg status -S -mac -n | sort
766 766 .hgsub
767 767 .hgsubstate
768 768 large.bin
769 769 main
770 770 sub1/.hgsub
771 771 sub1/.hgsubstate
772 772 sub1/sub1
773 773 sub1/sub2/folder/test.txt
774 774 sub1/sub2/large.dat
775 775 sub1/sub2/sub2
776 776
777 777 $ hg ci -Sqm 'forget testing'
778 778
779 779 Test 'wdir()' modified file archiving with largefiles
780 780 $ echo 'mod' > main
781 781 $ echo 'mod' > large.bin
782 782 $ echo 'mod' > sub1/sub2/large.dat
783 783 $ hg archive -S -r 'wdir()' ../wdir3
784 784 $ diff -r . ../wdir3 | egrep -v '\.hg$|^Common subdirectories'
785 785 Only in ../wdir3: .hg_archival.txt
786 786 Only in .: .hglf
787 787 Only in .: foo
788 788 Only in ./sub1/sub2: large.bin
789 789 Only in ./sub1/sub2: test.txt
790 790 Only in ./sub1/sub2: untracked.txt
791 791 Only in ./sub1/sub2: x.txt
792 792 $ find ../wdir3 -type f | sort
793 793 ../wdir3/.hg_archival.txt
794 794 ../wdir3/.hgsub
795 795 ../wdir3/.hgsubstate
796 796 ../wdir3/large.bin
797 797 ../wdir3/main
798 798 ../wdir3/sub1/.hgsub
799 799 ../wdir3/sub1/.hgsubstate
800 800 ../wdir3/sub1/sub1
801 801 ../wdir3/sub1/sub2/folder/test.txt
802 802 ../wdir3/sub1/sub2/large.dat
803 803 ../wdir3/sub1/sub2/sub2
804 804 $ hg up -Cq
805 805
806 806 Test issue4330: commit a directory where only normal files have changed
807 807 $ touch foo/bar/large.dat
808 808 $ hg add --large foo/bar/large.dat
809 809 $ hg ci -m 'add foo/bar/large.dat'
810 810 $ touch a.txt
811 811 $ touch a.dat
812 812 $ hg add -v foo/bar/abc a.txt a.dat
813 813 adding a.dat as a largefile
814 814 adding a.txt
815 815 adding foo/bar/abc (glob)
816 816 $ hg ci -m 'dir commit with only normal file deltas' foo/bar
817 817 $ hg status
818 818 A a.dat
819 819 A a.txt
820 820
821 821 Test a directory commit with a changed largefile and a changed normal file
822 822 $ echo changed > foo/bar/large.dat
823 823 $ echo changed > foo/bar/abc
824 824 $ hg ci -m 'dir commit with normal and lf file deltas' foo
825 825 $ hg status
826 826 A a.dat
827 827 A a.txt
828 828
829 829 $ hg ci -m "add a.*"
830 830 $ hg mv a.dat b.dat
831 831 $ hg mv foo/bar/abc foo/bar/def
832 832 $ hg status -C
833 833 A b.dat
834 834 a.dat
835 835 A foo/bar/def
836 836 foo/bar/abc
837 837 R a.dat
838 838 R foo/bar/abc
839 839
840 840 $ hg ci -m "move large and normal"
841 841 $ hg status -C --rev '.^' --rev .
842 842 A b.dat
843 843 a.dat
844 844 A foo/bar/def
845 845 foo/bar/abc
846 846 R a.dat
847 847 R foo/bar/abc
848 848
849 849
850 850 $ echo foo > main
851 851 $ hg ci -m "mod parent only"
852 852 $ hg init sub3
853 853 $ echo "sub3 = sub3" >> .hgsub
854 854 $ echo xyz > sub3/a.txt
855 855 $ hg add sub3/a.txt
856 856 $ hg ci -Sm "add sub3"
857 857 committing subrepository sub3
858 858 $ cat .hgsub | grep -v sub3 > .hgsub1
859 859 $ mv .hgsub1 .hgsub
860 860 $ hg ci -m "remove sub3"
861 861
862 862 $ hg log -r "subrepo()" --style compact
863 863 0 7f491f53a367 1970-01-01 00:00 +0000 test
864 864 main import
865 865
866 866 1 ffe6649062fe 1970-01-01 00:00 +0000 test
867 867 deep nested modif should trigger a commit
868 868
869 869 2 9bb10eebee29 1970-01-01 00:00 +0000 test
870 870 add test.txt
871 871
872 872 3 7c64f035294f 1970-01-01 00:00 +0000 test
873 873 add large files
874 874
875 875 4 f734a59e2e35 1970-01-01 00:00 +0000 test
876 876 forget testing
877 877
878 878 11 9685a22af5db 1970-01-01 00:00 +0000 test
879 879 add sub3
880 880
881 881 12[tip] 2e0485b475b9 1970-01-01 00:00 +0000 test
882 882 remove sub3
883 883
884 884 $ hg log -r "subrepo('sub3')" --style compact
885 885 11 9685a22af5db 1970-01-01 00:00 +0000 test
886 886 add sub3
887 887
888 888 12[tip] 2e0485b475b9 1970-01-01 00:00 +0000 test
889 889 remove sub3
890 890
891 891 $ hg log -r "subrepo('bogus')" --style compact
892 892
893 893
894 894 Test .hgsubstate in the R state
895 895
896 896 $ hg rm .hgsub .hgsubstate
897 897 \r (no-eol) (esc)
898 898 deleting [=====================> ] 1/2\r (no-eol) (esc)
899 899 deleting [===========================================>] 2/2\r (no-eol) (esc)
900 900 \r (no-eol) (esc)
901 901 $ hg ci -m 'trash subrepo tracking'
902 902
903 903 $ hg log -r "subrepo('re:sub\d+')" --style compact
904 904 0 7f491f53a367 1970-01-01 00:00 +0000 test
905 905 main import
906 906
907 907 1 ffe6649062fe 1970-01-01 00:00 +0000 test
908 908 deep nested modif should trigger a commit
909 909
910 910 2 9bb10eebee29 1970-01-01 00:00 +0000 test
911 911 add test.txt
912 912
913 913 3 7c64f035294f 1970-01-01 00:00 +0000 test
914 914 add large files
915 915
916 916 4 f734a59e2e35 1970-01-01 00:00 +0000 test
917 917 forget testing
918 918
919 919 11 9685a22af5db 1970-01-01 00:00 +0000 test
920 920 add sub3
921 921
922 922 12 2e0485b475b9 1970-01-01 00:00 +0000 test
923 923 remove sub3
924 924
925 925 13[tip] a68b2c361653 1970-01-01 00:00 +0000 test
926 926 trash subrepo tracking
927 927
928 928
929 929 Restore the trashed subrepo tracking
930 930
931 931 $ hg rollback -q
932 932 $ hg update -Cq .
933 933
934 934 Interaction with extdiff, largefiles and subrepos
935 935
936 936 $ hg --config extensions.extdiff= pdiff -S
937 937
938 938 $ hg --config extensions.extdiff= pdiff -r '.^' -S
939 939 \r (no-eol) (esc)
940 940 archiving [ ] 0/2\r (no-eol) (esc)
941 941 archiving [====================> ] 1/2\r (no-eol) (esc)
942 942 archiving [==========================================>] 2/2\r (no-eol) (esc)
943 943 \r (no-eol) (esc)
944 944 \r (no-eol) (esc)
945 945 archiving (sub1) [ <=> ] 0\r (no-eol) (esc)
946 946 \r (no-eol) (esc)
947 947 \r (no-eol) (esc)
948 948 archiving (sub1/sub2) [ <=> ] 0\r (no-eol) (glob) (esc)
949 949 \r (no-eol) (esc)
950 950 \r (no-eol) (esc)
951 951 archiving (sub3) [ <=> ] 0\r (no-eol) (esc)
952 952 \r (no-eol) (esc)
953 953 \r (no-eol) (esc)
954 954 archiving [ ] 0/2\r (no-eol) (esc)
955 955 archiving [====================> ] 1/2\r (no-eol) (esc)
956 956 archiving [==========================================>] 2/2\r (no-eol) (esc)
957 957 \r (no-eol) (esc)
958 958 \r (no-eol) (esc)
959 959 archiving (sub1) [ <=> ] 0\r (no-eol) (esc)
960 960 \r (no-eol) (esc)
961 961 \r (no-eol) (esc)
962 962 archiving (sub1/sub2) [ <=> ] 0\r (no-eol) (glob) (esc)
963 963 \r (no-eol) (esc)
964 964 diff -Nru cloned.*/.hgsub cloned/.hgsub (glob)
965 965 --- cloned.*/.hgsub * (glob)
966 966 +++ cloned/.hgsub * (glob)
967 967 @@ -1,2 +1* @@ (glob)
968 968 sub1 = ../sub1
969 969 -sub3 = sub3
970 970 diff -Nru cloned.*/.hgsubstate cloned/.hgsubstate (glob)
971 971 --- cloned.*/.hgsubstate * (glob)
972 972 +++ cloned/.hgsubstate * (glob)
973 973 @@ -1,2 +1* @@ (glob)
974 974 7a36fa02b66e61f27f3d4a822809f159479b8ab2 sub1
975 975 -b1a26de6f2a045a9f079323693614ee322f1ff7e sub3
976 976 [1]
977 977
978 978 $ hg --config extensions.extdiff= pdiff -r 0 -r '.^' -S
979 979 \r (no-eol) (esc)
980 980 archiving [ ] 0/3\r (no-eol) (esc)
981 981 archiving [=============> ] 1/3\r (no-eol) (esc)
982 982 archiving [===========================> ] 2/3\r (no-eol) (esc)
983 983 archiving [==========================================>] 3/3\r (no-eol) (esc)
984 984 \r (no-eol) (esc)
985 985 \r (no-eol) (esc)
986 986 archiving (sub1) [ ] 0/1\r (no-eol) (esc)
987 987 archiving (sub1) [===================================>] 1/1\r (no-eol) (esc)
988 988 \r (no-eol) (esc)
989 989 \r (no-eol) (esc)
990 990 archiving (sub1/sub2) [ ] 0/1\r (no-eol) (glob) (esc)
991 991 archiving (sub1/sub2) [==============================>] 1/1\r (no-eol) (glob) (esc)
992 992 \r (no-eol) (esc)
993 993 \r (no-eol) (esc)
994 994 archiving [ ] 0/8\r (no-eol) (esc)
995 995 archiving [====> ] 1/8\r (no-eol) (esc)
996 996 archiving [=========> ] 2/8\r (no-eol) (esc)
997 997 archiving [===============> ] 3/8\r (no-eol) (esc)
998 998 archiving [====================> ] 4/8\r (no-eol) (esc)
999 999 archiving [=========================> ] 5/8\r (no-eol) (esc)
1000 1000 archiving [===============================> ] 6/8\r (no-eol) (esc)
1001 1001 archiving [====================================> ] 7/8\r (no-eol) (esc)
1002 1002 archiving [==========================================>] 8/8\r (no-eol) (esc)
1003 1003 \r (no-eol) (esc)
1004 1004 \r (no-eol) (esc)
1005 1005 archiving (sub1) [ ] 0/1\r (no-eol) (esc)
1006 1006 archiving (sub1) [===================================>] 1/1\r (no-eol) (esc)
1007 1007 \r (no-eol) (esc)
1008 1008 \r (no-eol) (esc)
1009 1009 archiving (sub1/sub2) [ ] 0/3\r (no-eol) (glob) (esc)
1010 1010 archiving (sub1/sub2) [=========> ] 1/3\r (no-eol) (glob) (esc)
1011 1011 archiving (sub1/sub2) [===================> ] 2/3\r (no-eol) (glob) (esc)
1012 1012 archiving (sub1/sub2) [==============================>] 3/3\r (no-eol) (glob) (esc)
1013 1013 \r (no-eol) (esc)
1014 1014 \r (no-eol) (esc)
1015 1015 archiving (sub3) [ ] 0/1\r (no-eol) (esc)
1016 1016 archiving (sub3) [===================================>] 1/1\r (no-eol) (esc)
1017 1017 \r (no-eol) (esc)
1018 1018 diff -Nru cloned.*/.hglf/b.dat cloned.*/.hglf/b.dat (glob)
1019 1019 --- cloned.*/.hglf/b.dat * (glob)
1020 1020 +++ cloned.*/.hglf/b.dat * (glob)
1021 1021 @@ -*,0 +1* @@ (glob)
1022 1022 +da39a3ee5e6b4b0d3255bfef95601890afd80709
1023 1023 diff -Nru cloned.*/.hglf/foo/bar/large.dat cloned.*/.hglf/foo/bar/large.dat (glob)
1024 1024 --- cloned.*/.hglf/foo/bar/large.dat * (glob)
1025 1025 +++ cloned.*/.hglf/foo/bar/large.dat * (glob)
1026 1026 @@ -*,0 +1* @@ (glob)
1027 1027 +2f6933b5ee0f5fdd823d9717d8729f3c2523811b
1028 1028 diff -Nru cloned.*/.hglf/large.bin cloned.*/.hglf/large.bin (glob)
1029 1029 --- cloned.*/.hglf/large.bin * (glob)
1030 1030 +++ cloned.*/.hglf/large.bin * (glob)
1031 1031 @@ -*,0 +1* @@ (glob)
1032 1032 +7f7097b041ccf68cc5561e9600da4655d21c6d18
1033 1033 diff -Nru cloned.*/.hgsub cloned.*/.hgsub (glob)
1034 1034 --- cloned.*/.hgsub * (glob)
1035 1035 +++ cloned.*/.hgsub * (glob)
1036 1036 @@ -1* +1,2 @@ (glob)
1037 1037 sub1 = ../sub1
1038 1038 +sub3 = sub3
1039 1039 diff -Nru cloned.*/.hgsubstate cloned.*/.hgsubstate (glob)
1040 1040 --- cloned.*/.hgsubstate * (glob)
1041 1041 +++ cloned.*/.hgsubstate * (glob)
1042 1042 @@ -1* +1,2 @@ (glob)
1043 1043 -fc3b4ce2696f7741438c79207583768f2ce6b0dd sub1
1044 1044 +7a36fa02b66e61f27f3d4a822809f159479b8ab2 sub1
1045 1045 +b1a26de6f2a045a9f079323693614ee322f1ff7e sub3
1046 1046 diff -Nru cloned.*/foo/bar/def cloned.*/foo/bar/def (glob)
1047 1047 --- cloned.*/foo/bar/def * (glob)
1048 1048 +++ cloned.*/foo/bar/def * (glob)
1049 1049 @@ -*,0 +1* @@ (glob)
1050 1050 +changed
1051 1051 diff -Nru cloned.*/main cloned.*/main (glob)
1052 1052 --- cloned.*/main * (glob)
1053 1053 +++ cloned.*/main * (glob)
1054 1054 @@ -1* +1* @@ (glob)
1055 1055 -main
1056 1056 +foo
1057 1057 diff -Nru cloned.*/sub1/.hgsubstate cloned.*/sub1/.hgsubstate (glob)
1058 1058 --- cloned.*/sub1/.hgsubstate * (glob)
1059 1059 +++ cloned.*/sub1/.hgsubstate * (glob)
1060 1060 @@ -1* +1* @@ (glob)
1061 1061 -c57a0840e3badd667ef3c3ef65471609acb2ba3c sub2
1062 1062 +c77908c81ccea3794a896c79e98b0e004aee2e9e sub2
1063 1063 diff -Nru cloned.*/sub1/sub2/folder/test.txt cloned.*/sub1/sub2/folder/test.txt (glob)
1064 1064 --- cloned.*/sub1/sub2/folder/test.txt * (glob)
1065 1065 +++ cloned.*/sub1/sub2/folder/test.txt * (glob)
1066 1066 @@ -*,0 +1* @@ (glob)
1067 1067 +subfolder
1068 1068 diff -Nru cloned.*/sub1/sub2/sub2 cloned.*/sub1/sub2/sub2 (glob)
1069 1069 --- cloned.*/sub1/sub2/sub2 * (glob)
1070 1070 +++ cloned.*/sub1/sub2/sub2 * (glob)
1071 1071 @@ -1* +1* @@ (glob)
1072 1072 -sub2
1073 1073 +modified
1074 1074 diff -Nru cloned.*/sub3/a.txt cloned.*/sub3/a.txt (glob)
1075 1075 --- cloned.*/sub3/a.txt * (glob)
1076 1076 +++ cloned.*/sub3/a.txt * (glob)
1077 1077 @@ -*,0 +1* @@ (glob)
1078 1078 +xyz
1079 1079 [1]
1080 1080
1081 1081 $ echo mod > sub1/sub2/sub2
1082 1082 $ hg --config extensions.extdiff= pdiff -S
1083 1083 \r (no-eol) (esc)
1084 1084 archiving (sub1) [ <=> ] 0\r (no-eol) (esc)
1085 1085 \r (no-eol) (esc)
1086 1086 \r (no-eol) (esc)
1087 1087 archiving (sub1/sub2) [ ] 0/1\r (no-eol) (glob) (esc)
1088 1088 archiving (sub1/sub2) [==============================>] 1/1\r (no-eol) (glob) (esc)
1089 1089 \r (no-eol) (esc)
1090 1090 --- */cloned.*/sub1/sub2/sub2 * (glob)
1091 1091 +++ */cloned/sub1/sub2/sub2 * (glob)
1092 1092 @@ -1* +1* @@ (glob)
1093 1093 -modified
1094 1094 +mod
1095 1095 [1]
1096 1096
1097 1097 $ cd ..
@@ -1,322 +1,322
1 1 Test basic functionality of url#rev syntax
2 2
3 3 $ hg init repo
4 4 $ cd repo
5 5 $ echo a > a
6 6 $ hg ci -qAm 'add a'
7 7 $ hg branch foo
8 8 marked working directory as branch foo
9 9 (branches are permanent and global, did you want a bookmark?)
10 10 $ echo >> a
11 11 $ hg ci -m 'change a'
12 12 $ cd ..
13 13
14 14 $ hg clone 'repo#foo' clone
15 15 adding changesets
16 16 adding manifests
17 17 adding file changes
18 18 added 2 changesets with 2 changes to 1 files
19 19 updating to branch foo
20 20 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 21
22 22 $ hg --cwd clone heads
23 23 changeset: 1:cd2a86ecc814
24 24 branch: foo
25 25 tag: tip
26 26 user: test
27 27 date: Thu Jan 01 00:00:00 1970 +0000
28 28 summary: change a
29 29
30 30 changeset: 0:1f0dee641bb7
31 31 user: test
32 32 date: Thu Jan 01 00:00:00 1970 +0000
33 33 summary: add a
34 34
35 35 $ hg --cwd clone parents
36 36 changeset: 1:cd2a86ecc814
37 37 branch: foo
38 38 tag: tip
39 39 user: test
40 40 date: Thu Jan 01 00:00:00 1970 +0000
41 41 summary: change a
42 42
43 43 $ cat clone/.hg/hgrc
44 # example repository config (see "hg help config" for more info)
44 # example repository config (see 'hg help config' for more info)
45 45 [paths]
46 46 default = $TESTTMP/repo#foo (glob)
47 47
48 48 # path aliases to other clones of this repo in URLs or filesystem paths
49 # (see "hg help config.paths" for more info)
49 # (see 'hg help config.paths' for more info)
50 50 #
51 51 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
52 52 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
53 53 # my-clone = /home/jdoe/jdoes-clone
54 54
55 55 [ui]
56 56 # name and email (local to this repository, optional), e.g.
57 57 # username = Jane Doe <jdoe@example.com>
58 58
59 59 Changing original repo:
60 60
61 61 $ cd repo
62 62
63 63 $ echo >> a
64 64 $ hg ci -m 'new head of branch foo'
65 65
66 66 $ hg up -qC default
67 67 $ echo bar > bar
68 68 $ hg ci -qAm 'add bar'
69 69
70 70 $ hg log
71 71 changeset: 3:4cd725637392
72 72 tag: tip
73 73 parent: 0:1f0dee641bb7
74 74 user: test
75 75 date: Thu Jan 01 00:00:00 1970 +0000
76 76 summary: add bar
77 77
78 78 changeset: 2:faba9097cad4
79 79 branch: foo
80 80 user: test
81 81 date: Thu Jan 01 00:00:00 1970 +0000
82 82 summary: new head of branch foo
83 83
84 84 changeset: 1:cd2a86ecc814
85 85 branch: foo
86 86 user: test
87 87 date: Thu Jan 01 00:00:00 1970 +0000
88 88 summary: change a
89 89
90 90 changeset: 0:1f0dee641bb7
91 91 user: test
92 92 date: Thu Jan 01 00:00:00 1970 +0000
93 93 summary: add a
94 94
95 95 $ hg -q outgoing '../clone'
96 96 2:faba9097cad4
97 97 3:4cd725637392
98 98 $ hg summary --remote --config paths.default='../clone'
99 99 parent: 3:4cd725637392 tip
100 100 add bar
101 101 branch: default
102 102 commit: (clean)
103 103 update: (current)
104 104 phases: 4 draft
105 105 remote: 2 outgoing
106 106 $ hg -q outgoing '../clone#foo'
107 107 2:faba9097cad4
108 108 $ hg summary --remote --config paths.default='../clone#foo'
109 109 parent: 3:4cd725637392 tip
110 110 add bar
111 111 branch: default
112 112 commit: (clean)
113 113 update: (current)
114 114 phases: 4 draft
115 115 remote: 1 outgoing
116 116
117 117 $ hg -q --cwd ../clone incoming '../repo#foo'
118 118 2:faba9097cad4
119 119 $ hg --cwd ../clone summary --remote --config paths.default='../repo#foo'
120 120 parent: 1:cd2a86ecc814 tip
121 121 change a
122 122 branch: foo
123 123 commit: (clean)
124 124 update: (current)
125 125 remote: 1 or more incoming
126 126
127 127 $ hg -q push '../clone#foo'
128 128
129 129 $ hg --cwd ../clone heads
130 130 changeset: 2:faba9097cad4
131 131 branch: foo
132 132 tag: tip
133 133 user: test
134 134 date: Thu Jan 01 00:00:00 1970 +0000
135 135 summary: new head of branch foo
136 136
137 137 changeset: 0:1f0dee641bb7
138 138 user: test
139 139 date: Thu Jan 01 00:00:00 1970 +0000
140 140 summary: add a
141 141
142 142 $ hg -q --cwd ../clone incoming '../repo#foo'
143 143 [1]
144 144 $ hg --cwd ../clone summary --remote --config paths.default='../repo#foo'
145 145 parent: 1:cd2a86ecc814
146 146 change a
147 147 branch: foo
148 148 commit: (clean)
149 149 update: 1 new changesets (update)
150 150 remote: (synced)
151 151
152 152 $ cd ..
153 153
154 154 $ cd clone
155 155 $ hg rollback
156 156 repository tip rolled back to revision 1 (undo push)
157 157
158 158 $ hg -q incoming
159 159 2:faba9097cad4
160 160
161 161 $ hg -q pull
162 162
163 163 $ hg heads
164 164 changeset: 2:faba9097cad4
165 165 branch: foo
166 166 tag: tip
167 167 user: test
168 168 date: Thu Jan 01 00:00:00 1970 +0000
169 169 summary: new head of branch foo
170 170
171 171 changeset: 0:1f0dee641bb7
172 172 user: test
173 173 date: Thu Jan 01 00:00:00 1970 +0000
174 174 summary: add a
175 175
176 176 Pull should not have updated:
177 177
178 178 $ hg parents -q
179 179 1:cd2a86ecc814
180 180
181 181 Going back to the default branch:
182 182
183 183 $ hg up -C 0
184 184 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
185 185
186 186 $ hg parents
187 187 changeset: 0:1f0dee641bb7
188 188 user: test
189 189 date: Thu Jan 01 00:00:00 1970 +0000
190 190 summary: add a
191 191
192 192 No new revs, no update:
193 193
194 194 $ hg pull -qu
195 195
196 196 $ hg parents -q
197 197 0:1f0dee641bb7
198 198
199 199 $ hg rollback
200 200 repository tip rolled back to revision 1 (undo pull)
201 201
202 202 $ hg parents -q
203 203 0:1f0dee641bb7
204 204
205 205 Pull -u takes us back to branch foo:
206 206
207 207 $ hg pull -qu
208 208
209 209 $ hg parents
210 210 changeset: 2:faba9097cad4
211 211 branch: foo
212 212 tag: tip
213 213 user: test
214 214 date: Thu Jan 01 00:00:00 1970 +0000
215 215 summary: new head of branch foo
216 216
217 217 $ hg rollback
218 218 repository tip rolled back to revision 1 (undo pull)
219 219 working directory now based on revision 0
220 220
221 221 $ hg up -C 0
222 222 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
223 223
224 224 $ hg parents -q
225 225 0:1f0dee641bb7
226 226
227 227 $ hg heads -q
228 228 1:cd2a86ecc814
229 229 0:1f0dee641bb7
230 230
231 231 $ hg pull -qur default default
232 232
233 233 $ hg parents
234 234 changeset: 3:4cd725637392
235 235 tag: tip
236 236 parent: 0:1f0dee641bb7
237 237 user: test
238 238 date: Thu Jan 01 00:00:00 1970 +0000
239 239 summary: add bar
240 240
241 241 $ hg heads
242 242 changeset: 3:4cd725637392
243 243 tag: tip
244 244 parent: 0:1f0dee641bb7
245 245 user: test
246 246 date: Thu Jan 01 00:00:00 1970 +0000
247 247 summary: add bar
248 248
249 249 changeset: 2:faba9097cad4
250 250 branch: foo
251 251 user: test
252 252 date: Thu Jan 01 00:00:00 1970 +0000
253 253 summary: new head of branch foo
254 254
255 255 Test handling of invalid urls
256 256
257 257 $ hg id http://foo/?bar
258 258 abort: unsupported URL component: "bar"
259 259 [255]
260 260
261 261 $ cd ..
262 262
263 263 Test handling common incoming revisions between "default" and
264 264 "default-push"
265 265
266 266 $ hg -R clone rollback
267 267 repository tip rolled back to revision 1 (undo pull)
268 268 working directory now based on revision 0
269 269
270 270 $ cd repo
271 271
272 272 $ hg update -q -C default
273 273 $ echo modified >> bar
274 274 $ hg commit -m "new head to push current default head"
275 275 $ hg -q push -r ".^1" '../clone'
276 276
277 277 $ hg -q outgoing '../clone'
278 278 2:faba9097cad4
279 279 4:d515801a8f3d
280 280
281 281 $ hg summary --remote --config paths.default='../clone#default' --config paths.default-push='../clone#foo'
282 282 parent: 4:d515801a8f3d tip
283 283 new head to push current default head
284 284 branch: default
285 285 commit: (clean)
286 286 update: (current)
287 287 phases: 1 draft
288 288 remote: 1 outgoing
289 289
290 290 $ hg summary --remote --config paths.default='../clone#foo' --config paths.default-push='../clone'
291 291 parent: 4:d515801a8f3d tip
292 292 new head to push current default head
293 293 branch: default
294 294 commit: (clean)
295 295 update: (current)
296 296 phases: 1 draft
297 297 remote: 2 outgoing
298 298
299 299 $ hg summary --remote --config paths.default='../clone' --config paths.default-push='../clone#foo'
300 300 parent: 4:d515801a8f3d tip
301 301 new head to push current default head
302 302 branch: default
303 303 commit: (clean)
304 304 update: (current)
305 305 phases: 1 draft
306 306 remote: 1 outgoing
307 307
308 308 $ hg clone -q -r 0 . ../another
309 309 $ hg -q outgoing '../another#default'
310 310 3:4cd725637392
311 311 4:d515801a8f3d
312 312
313 313 $ hg summary --remote --config paths.default='../another#default' --config paths.default-push='../clone#default'
314 314 parent: 4:d515801a8f3d tip
315 315 new head to push current default head
316 316 branch: default
317 317 commit: (clean)
318 318 update: (current)
319 319 phases: 1 draft
320 320 remote: 1 outgoing
321 321
322 322 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now