mercurial/util.py
author Dan Villiom Podlaski Christiansen <danchr@gmail.com>
Mon, 13 Feb 2017 14:05:24 +0100
changeset 31133 23080c03a604
parent 31108 3f8f53190d6a
child 31141 b4cd912d7704
permissions -rw-r--r--
share: add --relative flag to store a relative path to the source Storing a relative path the source repository is useful when exporting repositories over the network or when they're located on external drives where the mountpoint isn't always fixed. Currently, Mercurial interprets paths in `.hg/shared` relative to $PWD. I suspect this is very much unintentional, and you have to manually edit `.hg/shared` in order to trigger this behaviour. However, on the off chance that someone might rely on it, I added a new capability called 'relshared'. In addition, this makes earlier versions of Mercurial fail with a graceful error. I should note that I haven't tested this patch on Windows.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
17515
b5b38d21fe99 spelling: specific
timeless@mozdev.org
parents: 17237
diff changeset
     1
# util.py - Mercurial utility functions and platform specific implementations
8226
8b2cd04a6e97 put license and copyright info into comment blocks
Martin Geisler <mg@lazybytes.net>
parents: 8225
diff changeset
     2
#
8b2cd04a6e97 put license and copyright info into comment blocks
Martin Geisler <mg@lazybytes.net>
parents: 8225
diff changeset
     3
#  Copyright 2005 K. Thananchayan <thananck@yahoo.com>
8b2cd04a6e97 put license and copyright info into comment blocks
Martin Geisler <mg@lazybytes.net>
parents: 8225
diff changeset
     4
#  Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
8b2cd04a6e97 put license and copyright info into comment blocks
Martin Geisler <mg@lazybytes.net>
parents: 8225
diff changeset
     5
#  Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
8b2cd04a6e97 put license and copyright info into comment blocks
Martin Geisler <mg@lazybytes.net>
parents: 8225
diff changeset
     6
#
8b2cd04a6e97 put license and copyright info into comment blocks
Martin Geisler <mg@lazybytes.net>
parents: 8225
diff changeset
     7
# This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 9996
diff changeset
     8
# GNU General Public License version 2 or any later version.
1082
ce96e316278a Update util.py docstrings, fix walk test
mpm@selenic.com
parents: 1081
diff changeset
     9
17515
b5b38d21fe99 spelling: specific
timeless@mozdev.org
parents: 17237
diff changeset
    10
"""Mercurial utility functions and platform specific implementations.
1082
ce96e316278a Update util.py docstrings, fix walk test
mpm@selenic.com
parents: 1081
diff changeset
    11
8227
0a9542703300 turn some comments back into module docstrings
Martin Geisler <mg@lazybytes.net>
parents: 8226
diff changeset
    12
This contains helper routines that are independent of the SCM core and
0a9542703300 turn some comments back into module docstrings
Martin Geisler <mg@lazybytes.net>
parents: 8226
diff changeset
    13
hide platform-specific details from the core.
1082
ce96e316278a Update util.py docstrings, fix walk test
mpm@selenic.com
parents: 1081
diff changeset
    14
"""
419
28511fc21073 [PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
diff changeset
    15
27358
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    16
from __future__ import absolute_import
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    17
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    18
import bz2
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    19
import calendar
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    20
import collections
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    21
import datetime
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    22
import errno
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    23
import gc
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    24
import hashlib
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    25
import imp
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    26
import os
30418
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
    27
import platform as pyplatform
21907
7e5dfa00e3c2 util: rename 're' to 'remod'
Siddharth Agarwal <sid0@fb.com>
parents: 21857
diff changeset
    28
import re as remod
27358
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    29
import shutil
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    30
import signal
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    31
import socket
30418
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
    32
import stat
30054
8b89521a69ba util: use string.hexdigits instead of defining it ourselves
Augie Fackler <augie@google.com>
parents: 30053
diff changeset
    33
import string
27358
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    34
import subprocess
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    35
import sys
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    36
import tempfile
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    37
import textwrap
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    38
import time
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    39
import traceback
26266
1e042e31bd0c changegroup: move all compressions utilities in util
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26201
diff changeset
    40
import zlib
3769
96095d9ff1f8 Add encoding detection
Matt Mackall <mpm@selenic.com>
parents: 3767
diff changeset
    41
27358
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    42
from . import (
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    43
    encoding,
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    44
    error,
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    45
    i18n,
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    46
    osutil,
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    47
    parsers,
28818
6041fb8f2da8 pycompat: add empty and queue to handle py3 divergence
timeless <timeless@mozdev.org>
parents: 28497
diff changeset
    48
    pycompat,
27358
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    49
)
3769
96095d9ff1f8 Add encoding detection
Matt Mackall <mpm@selenic.com>
parents: 3767
diff changeset
    50
30471
00c9ac4ce816 util: rewrite pycompat imports to make pyflakes always happy
Yuya Nishihara <yuya@tcha.org>
parents: 30442
diff changeset
    51
empty = pycompat.empty
00c9ac4ce816 util: rewrite pycompat imports to make pyflakes always happy
Yuya Nishihara <yuya@tcha.org>
parents: 30442
diff changeset
    52
httplib = pycompat.httplib
00c9ac4ce816 util: rewrite pycompat imports to make pyflakes always happy
Yuya Nishihara <yuya@tcha.org>
parents: 30442
diff changeset
    53
httpserver = pycompat.httpserver
00c9ac4ce816 util: rewrite pycompat imports to make pyflakes always happy
Yuya Nishihara <yuya@tcha.org>
parents: 30442
diff changeset
    54
pickle = pycompat.pickle
00c9ac4ce816 util: rewrite pycompat imports to make pyflakes always happy
Yuya Nishihara <yuya@tcha.org>
parents: 30442
diff changeset
    55
queue = pycompat.queue
00c9ac4ce816 util: rewrite pycompat imports to make pyflakes always happy
Yuya Nishihara <yuya@tcha.org>
parents: 30442
diff changeset
    56
socketserver = pycompat.socketserver
30472
277f4fe6d01a py3: provide bytes stdin/out/err through util module
Yuya Nishihara <yuya@tcha.org>
parents: 30471
diff changeset
    57
stderr = pycompat.stderr
277f4fe6d01a py3: provide bytes stdin/out/err through util module
Yuya Nishihara <yuya@tcha.org>
parents: 30471
diff changeset
    58
stdin = pycompat.stdin
277f4fe6d01a py3: provide bytes stdin/out/err through util module
Yuya Nishihara <yuya@tcha.org>
parents: 30471
diff changeset
    59
stdout = pycompat.stdout
30471
00c9ac4ce816 util: rewrite pycompat imports to make pyflakes always happy
Yuya Nishihara <yuya@tcha.org>
parents: 30442
diff changeset
    60
stringio = pycompat.stringio
00c9ac4ce816 util: rewrite pycompat imports to make pyflakes always happy
Yuya Nishihara <yuya@tcha.org>
parents: 30442
diff changeset
    61
urlerr = pycompat.urlerr
00c9ac4ce816 util: rewrite pycompat imports to make pyflakes always happy
Yuya Nishihara <yuya@tcha.org>
parents: 30442
diff changeset
    62
urlparse = pycompat.urlparse
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28882
diff changeset
    63
urlreq = pycompat.urlreq
30471
00c9ac4ce816 util: rewrite pycompat imports to make pyflakes always happy
Yuya Nishihara <yuya@tcha.org>
parents: 30442
diff changeset
    64
xmlrpclib = pycompat.xmlrpclib
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28882
diff changeset
    65
30876
3a4c0905f357 util: always force line buffered stdout when stdout is a tty (BC)
Simon Farnsworth <simonfar@fb.com>
parents: 30854
diff changeset
    66
def isatty(fp):
3a4c0905f357 util: always force line buffered stdout when stdout is a tty (BC)
Simon Farnsworth <simonfar@fb.com>
parents: 30854
diff changeset
    67
    try:
3a4c0905f357 util: always force line buffered stdout when stdout is a tty (BC)
Simon Farnsworth <simonfar@fb.com>
parents: 30854
diff changeset
    68
        return fp.isatty()
3a4c0905f357 util: always force line buffered stdout when stdout is a tty (BC)
Simon Farnsworth <simonfar@fb.com>
parents: 30854
diff changeset
    69
    except AttributeError:
3a4c0905f357 util: always force line buffered stdout when stdout is a tty (BC)
Simon Farnsworth <simonfar@fb.com>
parents: 30854
diff changeset
    70
        return False
3a4c0905f357 util: always force line buffered stdout when stdout is a tty (BC)
Simon Farnsworth <simonfar@fb.com>
parents: 30854
diff changeset
    71
3a4c0905f357 util: always force line buffered stdout when stdout is a tty (BC)
Simon Farnsworth <simonfar@fb.com>
parents: 30854
diff changeset
    72
# glibc determines buffering on first write to stdout - if we replace a TTY
3a4c0905f357 util: always force line buffered stdout when stdout is a tty (BC)
Simon Farnsworth <simonfar@fb.com>
parents: 30854
diff changeset
    73
# destined stdout with a pipe destined stdout (e.g. pager), we want line
3a4c0905f357 util: always force line buffered stdout when stdout is a tty (BC)
Simon Farnsworth <simonfar@fb.com>
parents: 30854
diff changeset
    74
# buffering
3a4c0905f357 util: always force line buffered stdout when stdout is a tty (BC)
Simon Farnsworth <simonfar@fb.com>
parents: 30854
diff changeset
    75
if isatty(stdout):
30988
d194f0dba7ac py3: convert the mode argument of os.fdopen to unicodes
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30975
diff changeset
    76
    stdout = os.fdopen(stdout.fileno(), pycompat.sysstr('wb'), 1)
30876
3a4c0905f357 util: always force line buffered stdout when stdout is a tty (BC)
Simon Farnsworth <simonfar@fb.com>
parents: 30854
diff changeset
    77
30639
d524c88511a7 py3: replace os.name with pycompat.osname (part 1 of 2)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30637
diff changeset
    78
if pycompat.osname == 'nt':
27358
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    79
    from . import windows as platform
30876
3a4c0905f357 util: always force line buffered stdout when stdout is a tty (BC)
Simon Farnsworth <simonfar@fb.com>
parents: 30854
diff changeset
    80
    stdout = platform.winstdout(stdout)
14912
ec46a7da9f2c util: move windows and posix wildcard imports to begin of file
Adrian Buehlmann <adrian@cadifra.com>
parents: 14911
diff changeset
    81
else:
27358
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    82
    from . import posix as platform
14926
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
    83
27358
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
    84
_ = i18n._
14926
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
    85
29530
3239e2fdd2e2 chgserver: extract utility to bind unix domain socket to long path
Yuya Nishihara <yuya@tcha.org>
parents: 29455
diff changeset
    86
bindunixsocket = platform.bindunixsocket
14927
2aa3e07b2f07 posix, windows: introduce cachestat
Idan Kamara <idankk86@gmail.com>
parents: 14926
diff changeset
    87
cachestat = platform.cachestat
14926
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
    88
checkexec = platform.checkexec
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
    89
checklink = platform.checklink
15011
5e44e4b3a0a3 util: move copymode into posix.py and windows.py
Adrian Buehlmann <adrian@cadifra.com>
parents: 15010
diff changeset
    90
copymode = platform.copymode
14926
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
    91
executablepath = platform.executablepath
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
    92
expandglobs = platform.expandglobs
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
    93
explainexit = platform.explainexit
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
    94
findexe = platform.findexe
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
    95
gethgcmd = platform.gethgcmd
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
    96
getuser = platform.getuser
28027
14033c5dd261 util: enable getpid to be replaced
timeless <timeless@mozdev.org>
parents: 27785
diff changeset
    97
getpid = os.getpid
14926
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
    98
groupmembers = platform.groupmembers
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
    99
groupname = platform.groupname
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   100
hidewindow = platform.hidewindow
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   101
isexec = platform.isexec
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   102
isowner = platform.isowner
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   103
localpath = platform.localpath
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   104
lookupreg = platform.lookupreg
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   105
makedir = platform.makedir
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   106
nlinks = platform.nlinks
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   107
normpath = platform.normpath
15488
6eff984d8e76 dirstate: fix case-folding identity for traditional Unix
Matt Mackall <mpm@selenic.com>
parents: 15392
diff changeset
   108
normcase = platform.normcase
24605
98744856b7d3 util: add normcase spec and fallback
Siddharth Agarwal <sid0@fb.com>
parents: 24439
diff changeset
   109
normcasespec = platform.normcasespec
98744856b7d3 util: add normcase spec and fallback
Siddharth Agarwal <sid0@fb.com>
parents: 24439
diff changeset
   110
normcasefallback = platform.normcasefallback
14926
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   111
openhardlinks = platform.openhardlinks
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   112
oslink = platform.oslink
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   113
parsepatchoutput = platform.parsepatchoutput
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   114
pconvert = platform.pconvert
25420
c2ec81891502 util: add a simple poll utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25406
diff changeset
   115
poll = platform.poll
14926
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   116
popen = platform.popen
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   117
posixfile = platform.posixfile
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   118
quotecommand = platform.quotecommand
22245
234e4c24b980 platform: implement readpipe()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 21914
diff changeset
   119
readpipe = platform.readpipe
14926
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   120
rename = platform.rename
24692
144883a8d0d4 util: add removedirs as platform depending function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 24635
diff changeset
   121
removedirs = platform.removedirs
14926
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   122
samedevice = platform.samedevice
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   123
samefile = platform.samefile
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   124
samestat = platform.samestat
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   125
setbinary = platform.setbinary
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   126
setflags = platform.setflags
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   127
setsignalhandler = platform.setsignalhandler
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   128
shellquote = platform.shellquote
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   129
spawndetached = platform.spawndetached
17560
9ee25d7b1aed util: implement a faster os.path.split for posix systems
Bryan O'Sullivan <bryano@fb.com>
parents: 17537
diff changeset
   130
split = platform.split
14926
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   131
sshargs = platform.sshargs
18026
ddc0323db78b osutil: write a C implementation of statfiles for unix
Bryan O'Sullivan <bryano@fb.com>
parents: 18013
diff changeset
   132
statfiles = getattr(osutil, 'statfiles', platform.statfiles)
18868
cafa447a7d3b util: add functions to check symlink/exec bits
Bryan O'Sullivan <bryano@fb.com>
parents: 18775
diff changeset
   133
statisexec = platform.statisexec
cafa447a7d3b util: add functions to check symlink/exec bits
Bryan O'Sullivan <bryano@fb.com>
parents: 18775
diff changeset
   134
statislink = platform.statislink
14926
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   135
testpid = platform.testpid
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   136
umask = platform.umask
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   137
unlink = platform.unlink
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   138
unlinkpath = platform.unlinkpath
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
   139
username = platform.username
14912
ec46a7da9f2c util: move windows and posix wildcard imports to begin of file
Adrian Buehlmann <adrian@cadifra.com>
parents: 14911
diff changeset
   140
6470
ac0bcd951c2c python 2.6 compatibility: compatibility wrappers for hash functions
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6339
diff changeset
   141
# Python compatibility
3769
96095d9ff1f8 Add encoding detection
Matt Mackall <mpm@selenic.com>
parents: 3767
diff changeset
   142
15656
4f5a78fa4917 util: clean up function ordering
Matt Mackall <mpm@selenic.com>
parents: 15611
diff changeset
   143
_notset = object()
4f5a78fa4917 util: clean up function ordering
Matt Mackall <mpm@selenic.com>
parents: 15611
diff changeset
   144
27015
341cb90ffd18 util: disable floating point stat times (issue4836)
Matt Mackall <mpm@selenic.com>
parents: 26847
diff changeset
   145
# disable Python's problematic floating point timestamps (issue4836)
341cb90ffd18 util: disable floating point stat times (issue4836)
Matt Mackall <mpm@selenic.com>
parents: 26847
diff changeset
   146
# (Python hypocritically says you shouldn't change this behavior in
341cb90ffd18 util: disable floating point stat times (issue4836)
Matt Mackall <mpm@selenic.com>
parents: 26847
diff changeset
   147
# libraries, and sure enough Mercurial is not a library.)
341cb90ffd18 util: disable floating point stat times (issue4836)
Matt Mackall <mpm@selenic.com>
parents: 26847
diff changeset
   148
os.stat_float_times(False)
341cb90ffd18 util: disable floating point stat times (issue4836)
Matt Mackall <mpm@selenic.com>
parents: 26847
diff changeset
   149
15656
4f5a78fa4917 util: clean up function ordering
Matt Mackall <mpm@selenic.com>
parents: 15611
diff changeset
   150
def safehasattr(thing, attr):
4f5a78fa4917 util: clean up function ordering
Matt Mackall <mpm@selenic.com>
parents: 15611
diff changeset
   151
    return getattr(thing, attr, _notset) is not _notset
4f5a78fa4917 util: clean up function ordering
Matt Mackall <mpm@selenic.com>
parents: 15611
diff changeset
   152
30745
c1b7b2285522 revlog: flag processor
Remi Chaintron <remi@fb.com>
parents: 30736
diff changeset
   153
def bitsfrom(container):
c1b7b2285522 revlog: flag processor
Remi Chaintron <remi@fb.com>
parents: 30736
diff changeset
   154
    bits = 0
c1b7b2285522 revlog: flag processor
Remi Chaintron <remi@fb.com>
parents: 30736
diff changeset
   155
    for bit in container:
c1b7b2285522 revlog: flag processor
Remi Chaintron <remi@fb.com>
parents: 30736
diff changeset
   156
        bits |= bit
c1b7b2285522 revlog: flag processor
Remi Chaintron <remi@fb.com>
parents: 30736
diff changeset
   157
    return bits
c1b7b2285522 revlog: flag processor
Remi Chaintron <remi@fb.com>
parents: 30736
diff changeset
   158
22962
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   159
DIGESTS = {
29342
c27dc3c31222 util: drop local aliases for md5, sha1, sha256, and sha512
Augie Fackler <raf@durin42.com>
parents: 29324
diff changeset
   160
    'md5': hashlib.md5,
c27dc3c31222 util: drop local aliases for md5, sha1, sha256, and sha512
Augie Fackler <raf@durin42.com>
parents: 29324
diff changeset
   161
    'sha1': hashlib.sha1,
c27dc3c31222 util: drop local aliases for md5, sha1, sha256, and sha512
Augie Fackler <raf@durin42.com>
parents: 29324
diff changeset
   162
    'sha512': hashlib.sha512,
22962
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   163
}
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   164
# List of digest types from strongest to weakest
27357
7f5a0bd4c9aa util: make hashlib import unconditional
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27112
diff changeset
   165
DIGESTS_BY_STRENGTH = ['sha512', 'sha1', 'md5']
22962
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   166
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   167
for k in DIGESTS_BY_STRENGTH:
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   168
    assert k in DIGESTS
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   169
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   170
class digester(object):
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   171
    """helper to compute digests.
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   172
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   173
    This helper can be used to compute one or more digests given their name.
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   174
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   175
    >>> d = digester(['md5', 'sha1'])
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   176
    >>> d.update('foo')
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   177
    >>> [k for k in sorted(d)]
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   178
    ['md5', 'sha1']
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   179
    >>> d['md5']
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   180
    'acbd18db4cc2f85cedef654fccc4a4d8'
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   181
    >>> d['sha1']
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   182
    '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33'
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   183
    >>> digester.preferred(['md5', 'sha1'])
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   184
    'sha1'
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   185
    """
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   186
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   187
    def __init__(self, digests, s=''):
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   188
        self._hashes = {}
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   189
        for k in digests:
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   190
            if k not in DIGESTS:
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   191
                raise Abort(_('unknown digest type: %s') % k)
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   192
            self._hashes[k] = DIGESTS[k]()
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   193
        if s:
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   194
            self.update(s)
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   195
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   196
    def update(self, data):
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   197
        for h in self._hashes.values():
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   198
            h.update(data)
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   199
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   200
    def __getitem__(self, key):
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   201
        if key not in DIGESTS:
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   202
            raise Abort(_('unknown digest type: %s') % k)
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   203
        return self._hashes[key].hexdigest()
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   204
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   205
    def __iter__(self):
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   206
        return iter(self._hashes)
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   207
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   208
    @staticmethod
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   209
    def preferred(supported):
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   210
        """returns the strongest digest type in both supported and DIGESTS."""
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   211
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   212
        for k in DIGESTS_BY_STRENGTH:
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   213
            if k in supported:
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   214
                return k
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   215
        return None
4d58f4083148 util: add a helper class to compute digests
Mike Hommey <mh@glandium.org>
parents: 22958
diff changeset
   216
22963
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   217
class digestchecker(object):
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   218
    """file handle wrapper that additionally checks content against a given
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   219
    size and digests.
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   220
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   221
        d = digestchecker(fh, size, {'md5': '...'})
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   222
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   223
    When multiple digests are given, all of them are validated.
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   224
    """
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   225
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   226
    def __init__(self, fh, size, digests):
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   227
        self._fh = fh
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   228
        self._size = size
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   229
        self._got = 0
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   230
        self._digests = dict(digests)
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   231
        self._digester = digester(self._digests.keys())
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   232
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   233
    def read(self, length=-1):
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   234
        content = self._fh.read(length)
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   235
        self._digester.update(content)
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   236
        self._got += len(content)
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   237
        return content
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   238
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   239
    def validate(self):
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   240
        if self._size != self._got:
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   241
            raise Abort(_('size mismatch: expected %d, got %d') %
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   242
                (self._size, self._got))
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   243
        for k, v in self._digests.items():
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   244
            if v != self._digester[k]:
23076
c312ef382033 i18n: add hint to digest mismatch message
Wagner Bruna <wbruna@softwareexpress.com.br>
parents: 23030
diff changeset
   245
                # i18n: first parameter is a digest name
22963
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   246
                raise Abort(_('%s mismatch: expected %s, got %s') %
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   247
                    (k, v, self._digester[k]))
56e04741bbf1 util: add a file handle wrapper class that does hash digest validation
Mike Hommey <mh@glandium.org>
parents: 22962
diff changeset
   248
11565
7546d4a272c8 util: improved the check for the existence of the 'buffer' builtin
Renato Cunha <renatoc@gmail.com>
parents: 11469
diff changeset
   249
try:
15657
d976b1ef6760 util: don't mess with builtins to emulate buffer()
Matt Mackall <mpm@selenic.com>
parents: 15656
diff changeset
   250
    buffer = buffer
11565
7546d4a272c8 util: improved the check for the existence of the 'buffer' builtin
Renato Cunha <renatoc@gmail.com>
parents: 11469
diff changeset
   251
except NameError:
30030
0f6d6fdd3c2a pycompat: provide 'ispy3' constant
Yuya Nishihara <yuya@tcha.org>
parents: 29977
diff changeset
   252
    if not pycompat.ispy3:
30821
7005c03f7387 util: add length argument to util.buffer()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30798
diff changeset
   253
        def buffer(sliceable, offset=0, length=None):
7005c03f7387 util: add length argument to util.buffer()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30798
diff changeset
   254
            if length is not None:
7005c03f7387 util: add length argument to util.buffer()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30798
diff changeset
   255
                return sliceable[offset:offset + length]
15657
d976b1ef6760 util: don't mess with builtins to emulate buffer()
Matt Mackall <mpm@selenic.com>
parents: 15656
diff changeset
   256
            return sliceable[offset:]
d976b1ef6760 util: don't mess with builtins to emulate buffer()
Matt Mackall <mpm@selenic.com>
parents: 15656
diff changeset
   257
    else:
30821
7005c03f7387 util: add length argument to util.buffer()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30798
diff changeset
   258
        def buffer(sliceable, offset=0, length=None):
7005c03f7387 util: add length argument to util.buffer()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30798
diff changeset
   259
            if length is not None:
7005c03f7387 util: add length argument to util.buffer()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30798
diff changeset
   260
                return memoryview(sliceable)[offset:offset + length]
15657
d976b1ef6760 util: don't mess with builtins to emulate buffer()
Matt Mackall <mpm@selenic.com>
parents: 15656
diff changeset
   261
            return memoryview(sliceable)[offset:]
10756
cb681cc59a8d util: fake the builtin buffer if it's missing (jython)
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 10487
diff changeset
   262
30639
d524c88511a7 py3: replace os.name with pycompat.osname (part 1 of 2)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30637
diff changeset
   263
closefds = pycompat.osname == 'posix'
10197
29e3c4a7699b subrepo: normalize svn output line-endings
Patrick Mezard <pmezard@gmail.com>
parents: 9996
diff changeset
   264
25406
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   265
_chunksize = 4096
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   266
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   267
class bufferedinputpipe(object):
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   268
    """a manually buffered input pipe
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   269
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   270
    Python will not let us use buffered IO and lazy reading with 'polling' at
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   271
    the same time. We cannot probe the buffer state and select will not detect
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   272
    that data are ready to read if they are already buffered.
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   273
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   274
    This class let us work around that by implementing its own buffering
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   275
    (allowing efficient readline) while offering a way to know if the buffer is
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   276
    empty from the output (allowing collaboration of the buffer with polling).
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   277
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   278
    This class lives in the 'util' module because it makes use of the 'os'
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   279
    module from the python stdlib.
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   280
    """
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   281
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   282
    def __init__(self, input):
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   283
        self._input = input
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   284
        self._buffer = []
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   285
        self._eof = False
25672
050dc6eabc92 bufferedinputpipe: remove N^2 computation of buffer length (issue4735)
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25671
diff changeset
   286
        self._lenbuf = 0
25406
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   287
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   288
    @property
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   289
    def hasbuffer(self):
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   290
        """True is any data is currently buffered
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   291
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   292
        This will be used externally a pre-step for polling IO. If there is
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   293
        already data then no polling should be set in place."""
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   294
        return bool(self._buffer)
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   295
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   296
    @property
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   297
    def closed(self):
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   298
        return self._input.closed
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   299
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   300
    def fileno(self):
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   301
        return self._input.fileno()
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   302
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   303
    def close(self):
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   304
        return self._input.close()
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   305
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   306
    def read(self, size):
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   307
        while (not self._eof) and (self._lenbuf < size):
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   308
            self._fillbuffer()
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   309
        return self._frombuffer(size)
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   310
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   311
    def readline(self, *args, **kwargs):
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   312
        if 1 < len(self._buffer):
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   313
            # this should not happen because both read and readline end with a
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   314
            # _frombuffer call that collapse it.
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   315
            self._buffer = [''.join(self._buffer)]
25672
050dc6eabc92 bufferedinputpipe: remove N^2 computation of buffer length (issue4735)
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25671
diff changeset
   316
            self._lenbuf = len(self._buffer[0])
25406
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   317
        lfi = -1
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   318
        if self._buffer:
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   319
            lfi = self._buffer[-1].find('\n')
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   320
        while (not self._eof) and lfi < 0:
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   321
            self._fillbuffer()
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   322
            if self._buffer:
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   323
                lfi = self._buffer[-1].find('\n')
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   324
        size = lfi + 1
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   325
        if lfi < 0: # end of file
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   326
            size = self._lenbuf
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   327
        elif 1 < len(self._buffer):
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   328
            # we need to take previous chunks into account
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   329
            size += self._lenbuf - len(self._buffer[-1])
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   330
        return self._frombuffer(size)
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   331
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   332
    def _frombuffer(self, size):
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   333
        """return at most 'size' data from the buffer
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   334
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   335
        The data are removed from the buffer."""
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   336
        if size == 0 or not self._buffer:
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   337
            return ''
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   338
        buf = self._buffer[0]
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   339
        if 1 < len(self._buffer):
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   340
            buf = ''.join(self._buffer)
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   341
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   342
        data = buf[:size]
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   343
        buf = buf[len(data):]
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   344
        if buf:
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   345
            self._buffer = [buf]
25672
050dc6eabc92 bufferedinputpipe: remove N^2 computation of buffer length (issue4735)
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25671
diff changeset
   346
            self._lenbuf = len(buf)
25406
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   347
        else:
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   348
            self._buffer = []
25672
050dc6eabc92 bufferedinputpipe: remove N^2 computation of buffer length (issue4735)
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25671
diff changeset
   349
            self._lenbuf = 0
25406
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   350
        return data
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   351
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   352
    def _fillbuffer(self):
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   353
        """read data to the buffer"""
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   354
        data = os.read(self._input.fileno(), _chunksize)
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   355
        if not data:
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   356
            self._eof = True
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   357
        else:
25672
050dc6eabc92 bufferedinputpipe: remove N^2 computation of buffer length (issue4735)
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25671
diff changeset
   358
            self._lenbuf += len(data)
25406
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   359
            self._buffer.append(data)
be930f16a52a util: introduce a bufferedinputpipe utility
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25245
diff changeset
   360
10199
c2e2a5e6c36b subrepo: force en_US.UTF-8 locale when calling svn
Patrick Mezard <pmezard@gmail.com>
parents: 10197
diff changeset
   361
def popen2(cmd, env=None, newlines=False):
9089
8ec39725d966 util: remove unused bufsize argument
Martin Geisler <mg@lazybytes.net>
parents: 9084
diff changeset
   362
    # Setting bufsize to -1 lets the system decide the buffer size.
8ec39725d966 util: remove unused bufsize argument
Martin Geisler <mg@lazybytes.net>
parents: 9084
diff changeset
   363
    # The default for bufsize is 0, meaning unbuffered. This leads to
8ec39725d966 util: remove unused bufsize argument
Martin Geisler <mg@lazybytes.net>
parents: 9084
diff changeset
   364
    # poor performance on Mac OS X: http://bugs.python.org/issue4194
8ec39725d966 util: remove unused bufsize argument
Martin Geisler <mg@lazybytes.net>
parents: 9084
diff changeset
   365
    p = subprocess.Popen(cmd, shell=True, bufsize=-1,
9083
ec171737aaf1 Backed out changeset fce065538bcf: it caused a 5x performance regression on OS X
Bryan O'Sullivan <bos@serpentine.com>
parents: 8340
diff changeset
   366
                         close_fds=closefds,
10197
29e3c4a7699b subrepo: normalize svn output line-endings
Patrick Mezard <pmezard@gmail.com>
parents: 9996
diff changeset
   367
                         stdin=subprocess.PIPE, stdout=subprocess.PIPE,
10199
c2e2a5e6c36b subrepo: force en_US.UTF-8 locale when calling svn
Patrick Mezard <pmezard@gmail.com>
parents: 10197
diff changeset
   368
                         universal_newlines=newlines,
c2e2a5e6c36b subrepo: force en_US.UTF-8 locale when calling svn
Patrick Mezard <pmezard@gmail.com>
parents: 10197
diff changeset
   369
                         env=env)
8280
0b02d98d44d0 util: always use subprocess
Martin Geisler <mg@lazybytes.net>
parents: 8257
diff changeset
   370
    return p.stdin, p.stdout
10197
29e3c4a7699b subrepo: normalize svn output line-endings
Patrick Mezard <pmezard@gmail.com>
parents: 9996
diff changeset
   371
10199
c2e2a5e6c36b subrepo: force en_US.UTF-8 locale when calling svn
Patrick Mezard <pmezard@gmail.com>
parents: 10197
diff changeset
   372
def popen3(cmd, env=None, newlines=False):
18759
9baf4330d88f sshpeer: store subprocess so it cleans up correctly
Durham Goode <durham@fb.com>
parents: 18736
diff changeset
   373
    stdin, stdout, stderr, p = popen4(cmd, env, newlines)
9baf4330d88f sshpeer: store subprocess so it cleans up correctly
Durham Goode <durham@fb.com>
parents: 18736
diff changeset
   374
    return stdin, stdout, stderr
9baf4330d88f sshpeer: store subprocess so it cleans up correctly
Durham Goode <durham@fb.com>
parents: 18736
diff changeset
   375
25245
504ef9c49f4a util: allow to specify buffer size in popen4
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25211
diff changeset
   376
def popen4(cmd, env=None, newlines=False, bufsize=-1):
504ef9c49f4a util: allow to specify buffer size in popen4
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25211
diff changeset
   377
    p = subprocess.Popen(cmd, shell=True, bufsize=bufsize,
9083
ec171737aaf1 Backed out changeset fce065538bcf: it caused a 5x performance regression on OS X
Bryan O'Sullivan <bos@serpentine.com>
parents: 8340
diff changeset
   378
                         close_fds=closefds,
8280
0b02d98d44d0 util: always use subprocess
Martin Geisler <mg@lazybytes.net>
parents: 8257
diff changeset
   379
                         stdin=subprocess.PIPE, stdout=subprocess.PIPE,
10197
29e3c4a7699b subrepo: normalize svn output line-endings
Patrick Mezard <pmezard@gmail.com>
parents: 9996
diff changeset
   380
                         stderr=subprocess.PIPE,
10199
c2e2a5e6c36b subrepo: force en_US.UTF-8 locale when calling svn
Patrick Mezard <pmezard@gmail.com>
parents: 10197
diff changeset
   381
                         universal_newlines=newlines,
c2e2a5e6c36b subrepo: force en_US.UTF-8 locale when calling svn
Patrick Mezard <pmezard@gmail.com>
parents: 10197
diff changeset
   382
                         env=env)
18759
9baf4330d88f sshpeer: store subprocess so it cleans up correctly
Durham Goode <durham@fb.com>
parents: 18736
diff changeset
   383
    return p.stdin, p.stdout, p.stderr, p
7106
4674706b5b95 python2.6: use subprocess if available
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6884
diff changeset
   384
7632
9626819b2e3d refactor version code
Matt Mackall <mpm@selenic.com>
parents: 7559
diff changeset
   385
def version():
9626819b2e3d refactor version code
Matt Mackall <mpm@selenic.com>
parents: 7559
diff changeset
   386
    """Return version information if available."""
9626819b2e3d refactor version code
Matt Mackall <mpm@selenic.com>
parents: 7559
diff changeset
   387
    try:
27358
ac839ee45b6a util: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27357
diff changeset
   388
        from . import __version__
7632
9626819b2e3d refactor version code
Matt Mackall <mpm@selenic.com>
parents: 7559
diff changeset
   389
        return __version__.version
9626819b2e3d refactor version code
Matt Mackall <mpm@selenic.com>
parents: 7559
diff changeset
   390
    except ImportError:
9626819b2e3d refactor version code
Matt Mackall <mpm@selenic.com>
parents: 7559
diff changeset
   391
        return 'unknown'
9626819b2e3d refactor version code
Matt Mackall <mpm@selenic.com>
parents: 7559
diff changeset
   392
27112
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   393
def versiontuple(v=None, n=4):
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   394
    """Parses a Mercurial version string into an N-tuple.
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   395
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   396
    The version string to be parsed is specified with the ``v`` argument.
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   397
    If it isn't defined, the current Mercurial version string will be parsed.
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   398
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   399
    ``n`` can be 2, 3, or 4. Here is how some version strings map to
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   400
    returned values:
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   401
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   402
    >>> v = '3.6.1+190-df9b73d2d444'
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   403
    >>> versiontuple(v, 2)
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   404
    (3, 6)
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   405
    >>> versiontuple(v, 3)
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   406
    (3, 6, 1)
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   407
    >>> versiontuple(v, 4)
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   408
    (3, 6, 1, '190-df9b73d2d444')
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   409
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   410
    >>> versiontuple('3.6.1+190-df9b73d2d444+20151118')
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   411
    (3, 6, 1, '190-df9b73d2d444+20151118')
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   412
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   413
    >>> v = '3.6'
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   414
    >>> versiontuple(v, 2)
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   415
    (3, 6)
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   416
    >>> versiontuple(v, 3)
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   417
    (3, 6, None)
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   418
    >>> versiontuple(v, 4)
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   419
    (3, 6, None, None)
29613
616cbcb59e05 util: better handle '-' in version string (issue5302)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29592
diff changeset
   420
616cbcb59e05 util: better handle '-' in version string (issue5302)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29592
diff changeset
   421
    >>> v = '3.9-rc'
616cbcb59e05 util: better handle '-' in version string (issue5302)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29592
diff changeset
   422
    >>> versiontuple(v, 2)
616cbcb59e05 util: better handle '-' in version string (issue5302)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29592
diff changeset
   423
    (3, 9)
616cbcb59e05 util: better handle '-' in version string (issue5302)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29592
diff changeset
   424
    >>> versiontuple(v, 3)
616cbcb59e05 util: better handle '-' in version string (issue5302)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29592
diff changeset
   425
    (3, 9, None)
616cbcb59e05 util: better handle '-' in version string (issue5302)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29592
diff changeset
   426
    >>> versiontuple(v, 4)
616cbcb59e05 util: better handle '-' in version string (issue5302)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29592
diff changeset
   427
    (3, 9, None, 'rc')
616cbcb59e05 util: better handle '-' in version string (issue5302)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29592
diff changeset
   428
616cbcb59e05 util: better handle '-' in version string (issue5302)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29592
diff changeset
   429
    >>> v = '3.9-rc+2-02a8fea4289b'
616cbcb59e05 util: better handle '-' in version string (issue5302)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29592
diff changeset
   430
    >>> versiontuple(v, 2)
616cbcb59e05 util: better handle '-' in version string (issue5302)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29592
diff changeset
   431
    (3, 9)
616cbcb59e05 util: better handle '-' in version string (issue5302)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29592
diff changeset
   432
    >>> versiontuple(v, 3)
616cbcb59e05 util: better handle '-' in version string (issue5302)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29592
diff changeset
   433
    (3, 9, None)
616cbcb59e05 util: better handle '-' in version string (issue5302)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29592
diff changeset
   434
    >>> versiontuple(v, 4)
616cbcb59e05 util: better handle '-' in version string (issue5302)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29592
diff changeset
   435
    (3, 9, None, 'rc+2-02a8fea4289b')
27112
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   436
    """
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   437
    if not v:
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   438
        v = version()
29613
616cbcb59e05 util: better handle '-' in version string (issue5302)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29592
diff changeset
   439
    parts = remod.split('[\+-]', v, 1)
27112
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   440
    if len(parts) == 1:
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   441
        vparts, extra = parts[0], None
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   442
    else:
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   443
        vparts, extra = parts
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   444
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   445
    vints = []
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   446
    for i in vparts.split('.'):
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   447
        try:
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   448
            vints.append(int(i))
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   449
        except ValueError:
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   450
            break
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   451
    # (3, 6) -> (3, 6, None)
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   452
    while len(vints) < 3:
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   453
        vints.append(None)
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   454
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   455
    if n == 2:
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   456
        return (vints[0], vints[1])
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   457
    if n == 3:
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   458
        return (vints[0], vints[1], vints[2])
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   459
    if n == 4:
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   460
        return (vints[0], vints[1], vints[2], extra)
39c14e89b881 util: add versiontuple() for returning parsed version information
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27066
diff changeset
   461
2609
6c5b1b5cc160 util.parsedate should understand dates from hg export
Chris Mason <mason@suse.com>
parents: 2601
diff changeset
   462
# used by parsedate
3808
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   463
defaultdateformats = (
29638
491ee264b9f6 date: accept broader range of ISO 8601 time specs
Matt Mackall <mpm@selenic.com>
parents: 29637
diff changeset
   464
    '%Y-%m-%dT%H:%M:%S', # the 'real' ISO8601
491ee264b9f6 date: accept broader range of ISO 8601 time specs
Matt Mackall <mpm@selenic.com>
parents: 29637
diff changeset
   465
    '%Y-%m-%dT%H:%M',    #   without seconds
491ee264b9f6 date: accept broader range of ISO 8601 time specs
Matt Mackall <mpm@selenic.com>
parents: 29637
diff changeset
   466
    '%Y-%m-%dT%H%M%S',   # another awful but legal variant without :
491ee264b9f6 date: accept broader range of ISO 8601 time specs
Matt Mackall <mpm@selenic.com>
parents: 29637
diff changeset
   467
    '%Y-%m-%dT%H%M',     #   without seconds
491ee264b9f6 date: accept broader range of ISO 8601 time specs
Matt Mackall <mpm@selenic.com>
parents: 29637
diff changeset
   468
    '%Y-%m-%d %H:%M:%S', # our common legal variant
491ee264b9f6 date: accept broader range of ISO 8601 time specs
Matt Mackall <mpm@selenic.com>
parents: 29637
diff changeset
   469
    '%Y-%m-%d %H:%M',    #   without seconds
491ee264b9f6 date: accept broader range of ISO 8601 time specs
Matt Mackall <mpm@selenic.com>
parents: 29637
diff changeset
   470
    '%Y-%m-%d %H%M%S',   # without :
491ee264b9f6 date: accept broader range of ISO 8601 time specs
Matt Mackall <mpm@selenic.com>
parents: 29637
diff changeset
   471
    '%Y-%m-%d %H%M',     #   without seconds
3808
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   472
    '%Y-%m-%d %I:%M:%S%p',
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   473
    '%Y-%m-%d %H:%M',
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   474
    '%Y-%m-%d %I:%M%p',
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   475
    '%Y-%m-%d',
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   476
    '%m-%d',
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   477
    '%m/%d',
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   478
    '%m/%d/%y',
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   479
    '%m/%d/%Y',
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   480
    '%a %b %d %H:%M:%S %Y',
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   481
    '%a %b %d %I:%M:%S%p %Y',
4708
01f9ee4de1ad Add support for RFC2822 to util.parsedate().
Markus F.X.J. Oberhumer <markus@oberhumer.com>
parents: 4686
diff changeset
   482
    '%a, %d %b %Y %H:%M:%S',        #  GNU coreutils "/bin/date --rfc-2822"
3808
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   483
    '%b %d %H:%M:%S %Y',
3812
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
   484
    '%b %d %I:%M:%S%p %Y',
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
   485
    '%b %d %H:%M:%S',
3808
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   486
    '%b %d %I:%M:%S%p',
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   487
    '%b %d %H:%M',
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   488
    '%b %d %I:%M%p',
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   489
    '%b %d %Y',
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   490
    '%b %d',
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   491
    '%H:%M:%S',
9383
7116494c48ab util: Fix date format for 12-hour time.
Carey Evans <carey@carey.geek.nz>
parents: 9097
diff changeset
   492
    '%I:%M:%S%p',
3808
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   493
    '%H:%M',
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   494
    '%I:%M%p',
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
   495
)
2609
6c5b1b5cc160 util.parsedate should understand dates from hg export
Chris Mason <mason@suse.com>
parents: 2601
diff changeset
   496
3812
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
   497
extendeddateformats = defaultdateformats + (
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
   498
    "%Y",
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
   499
    "%Y-%m",
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
   500
    "%b",
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
   501
    "%b %Y",
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
   502
    )
2609
6c5b1b5cc160 util.parsedate should understand dates from hg export
Chris Mason <mason@suse.com>
parents: 2601
diff changeset
   503
3145
e4ea47c21480 Add cachefunc to abstract function call cache
Brendan Cully <brendan@kublai.com>
parents: 3131
diff changeset
   504
def cachefunc(func):
e4ea47c21480 Add cachefunc to abstract function call cache
Brendan Cully <brendan@kublai.com>
parents: 3131
diff changeset
   505
    '''cache the result of function calls'''
3147
97420a49188d add comments in cachefunc
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3145
diff changeset
   506
    # XXX doesn't handle keywords args
28832
f5ff10f6fa6b util: use __code__ (available since py2.6)
timeless <timeless@mozdev.org>
parents: 28826
diff changeset
   507
    if func.__code__.co_argcount == 0:
20835
0e8417131a29 util: add the code path to "cachefunc()" for the function taking no arguments
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20679
diff changeset
   508
        cache = []
0e8417131a29 util: add the code path to "cachefunc()" for the function taking no arguments
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20679
diff changeset
   509
        def f():
0e8417131a29 util: add the code path to "cachefunc()" for the function taking no arguments
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20679
diff changeset
   510
            if len(cache) == 0:
0e8417131a29 util: add the code path to "cachefunc()" for the function taking no arguments
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20679
diff changeset
   511
                cache.append(func())
0e8417131a29 util: add the code path to "cachefunc()" for the function taking no arguments
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20679
diff changeset
   512
            return cache[0]
0e8417131a29 util: add the code path to "cachefunc()" for the function taking no arguments
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 20679
diff changeset
   513
        return f
3145
e4ea47c21480 Add cachefunc to abstract function call cache
Brendan Cully <brendan@kublai.com>
parents: 3131
diff changeset
   514
    cache = {}
28832
f5ff10f6fa6b util: use __code__ (available since py2.6)
timeless <timeless@mozdev.org>
parents: 28826
diff changeset
   515
    if func.__code__.co_argcount == 1:
3147
97420a49188d add comments in cachefunc
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3145
diff changeset
   516
        # we gain a small amount of time because
97420a49188d add comments in cachefunc
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 3145
diff changeset
   517
        # we don't need to pack/unpack the list
3145
e4ea47c21480 Add cachefunc to abstract function call cache
Brendan Cully <brendan@kublai.com>
parents: 3131
diff changeset
   518
        def f(arg):
e4ea47c21480 Add cachefunc to abstract function call cache
Brendan Cully <brendan@kublai.com>
parents: 3131
diff changeset
   519
            if arg not in cache:
e4ea47c21480 Add cachefunc to abstract function call cache
Brendan Cully <brendan@kublai.com>
parents: 3131
diff changeset
   520
                cache[arg] = func(arg)
e4ea47c21480 Add cachefunc to abstract function call cache
Brendan Cully <brendan@kublai.com>
parents: 3131
diff changeset
   521
            return cache[arg]
e4ea47c21480 Add cachefunc to abstract function call cache
Brendan Cully <brendan@kublai.com>
parents: 3131
diff changeset
   522
    else:
e4ea47c21480 Add cachefunc to abstract function call cache
Brendan Cully <brendan@kublai.com>
parents: 3131
diff changeset
   523
        def f(*args):
e4ea47c21480 Add cachefunc to abstract function call cache
Brendan Cully <brendan@kublai.com>
parents: 3131
diff changeset
   524
            if args not in cache:
e4ea47c21480 Add cachefunc to abstract function call cache
Brendan Cully <brendan@kublai.com>
parents: 3131
diff changeset
   525
                cache[args] = func(*args)
e4ea47c21480 Add cachefunc to abstract function call cache
Brendan Cully <brendan@kublai.com>
parents: 3131
diff changeset
   526
            return cache[args]
e4ea47c21480 Add cachefunc to abstract function call cache
Brendan Cully <brendan@kublai.com>
parents: 3131
diff changeset
   527
e4ea47c21480 Add cachefunc to abstract function call cache
Brendan Cully <brendan@kublai.com>
parents: 3131
diff changeset
   528
    return f
e4ea47c21480 Add cachefunc to abstract function call cache
Brendan Cully <brendan@kublai.com>
parents: 3131
diff changeset
   529
21813
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   530
class sortdict(dict):
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   531
    '''a simple sorted dictionary'''
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   532
    def __init__(self, data=None):
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   533
        self._list = []
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   534
        if data:
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   535
            self.update(data)
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   536
    def copy(self):
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   537
        return sortdict(self)
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   538
    def __setitem__(self, key, val):
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   539
        if key in self:
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   540
            self._list.remove(key)
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   541
        self._list.append(key)
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   542
        dict.__setitem__(self, key, val)
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   543
    def __iter__(self):
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   544
        return self._list.__iter__()
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   545
    def update(self, src):
24236
de14c3972c2f sortdict: have update() accept either dict or iterable of key/value pairs
Yuya Nishihara <yuya@tcha.org>
parents: 24188
diff changeset
   546
        if isinstance(src, dict):
de14c3972c2f sortdict: have update() accept either dict or iterable of key/value pairs
Yuya Nishihara <yuya@tcha.org>
parents: 24188
diff changeset
   547
            src = src.iteritems()
de14c3972c2f sortdict: have update() accept either dict or iterable of key/value pairs
Yuya Nishihara <yuya@tcha.org>
parents: 24188
diff changeset
   548
        for k, v in src:
de14c3972c2f sortdict: have update() accept either dict or iterable of key/value pairs
Yuya Nishihara <yuya@tcha.org>
parents: 24188
diff changeset
   549
            self[k] = v
21813
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   550
    def clear(self):
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   551
        dict.clear(self)
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   552
        self._list = []
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   553
    def items(self):
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   554
        return [(k, self[k]) for k in self._list]
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   555
    def __delitem__(self, key):
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   556
        dict.__delitem__(self, key)
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   557
        self._list.remove(key)
22643
3b1c0e1ede4c util: fix sorteddict.pop
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 22638
diff changeset
   558
    def pop(self, key, *args, **kwargs):
3b1c0e1ede4c util: fix sorteddict.pop
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 22638
diff changeset
   559
        dict.pop(self, key, *args, **kwargs)
3b1c0e1ede4c util: fix sorteddict.pop
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 22638
diff changeset
   560
        try:
3b1c0e1ede4c util: fix sorteddict.pop
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 22638
diff changeset
   561
            self._list.remove(key)
3b1c0e1ede4c util: fix sorteddict.pop
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 22638
diff changeset
   562
        except ValueError:
3b1c0e1ede4c util: fix sorteddict.pop
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 22638
diff changeset
   563
            pass
21813
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   564
    def keys(self):
30854
0126e422450e util: make sortdict.keys() return a copy
Martin von Zweigbergk <martinvonz@google.com>
parents: 30821
diff changeset
   565
        return self._list[:]
21813
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   566
    def iterkeys(self):
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   567
        return self._list.__iter__()
23260
565f97e71ce3 sortdict: add iteritems method
Sean Farley <sean.michael.farley@gmail.com>
parents: 23139
diff changeset
   568
    def iteritems(self):
565f97e71ce3 sortdict: add iteritems method
Sean Farley <sean.michael.farley@gmail.com>
parents: 23139
diff changeset
   569
        for k in self._list:
565f97e71ce3 sortdict: add iteritems method
Sean Farley <sean.michael.farley@gmail.com>
parents: 23139
diff changeset
   570
            yield k, self[k]
23261
79858e66a7ce sortdict: add insert method
Sean Farley <sean.michael.farley@gmail.com>
parents: 23260
diff changeset
   571
    def insert(self, index, key, val):
79858e66a7ce sortdict: add insert method
Sean Farley <sean.michael.farley@gmail.com>
parents: 23260
diff changeset
   572
        self._list.insert(index, key)
79858e66a7ce sortdict: add insert method
Sean Farley <sean.michael.farley@gmail.com>
parents: 23260
diff changeset
   573
        dict.__setitem__(self, key, val)
29592
37cccad55410 util: implement a deterministic __repr__ on sortdict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29566
diff changeset
   574
    def __repr__(self):
37cccad55410 util: implement a deterministic __repr__ on sortdict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29566
diff changeset
   575
        if not self:
37cccad55410 util: implement a deterministic __repr__ on sortdict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29566
diff changeset
   576
            return '%s()' % self.__class__.__name__
37cccad55410 util: implement a deterministic __repr__ on sortdict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29566
diff changeset
   577
        return '%s(%r)' % (self.__class__.__name__, self.items())
21813
c2262004c2e2 config: move config.sortdict class into util
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 21046
diff changeset
   578
27371
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   579
class _lrucachenode(object):
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   580
    """A node in a doubly linked list.
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   581
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   582
    Holds a reference to nodes on either side as well as a key-value
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   583
    pair for the dictionary entry.
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   584
    """
30038
42ead5b3aa7b py3: use unicodes in __slots__
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30036
diff changeset
   585
    __slots__ = (u'next', u'prev', u'key', u'value')
27371
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   586
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   587
    def __init__(self):
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   588
        self.next = None
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   589
        self.prev = None
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   590
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   591
        self.key = _notset
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   592
        self.value = None
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   593
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   594
    def markempty(self):
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   595
        """Mark the node as emptied."""
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   596
        self.key = _notset
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   597
18603
2251b3184e6e util: add an LRU cache dict
Siddharth Agarwal <sid0@fb.com>
parents: 18537
diff changeset
   598
class lrucachedict(object):
27371
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   599
    """Dict that caches most recent accesses and sets.
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   600
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   601
    The dict consists of an actual backing dict - indexed by original
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   602
    key - and a doubly linked circular list defining the order of entries in
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   603
    the cache.
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   604
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   605
    The head node is the newest entry in the cache. If the cache is full,
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   606
    we recycle head.prev and make it the new head. Cache accesses result in
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   607
    the node being moved to before the existing head and being marked as the
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   608
    new head node.
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   609
    """
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   610
    def __init__(self, max):
18603
2251b3184e6e util: add an LRU cache dict
Siddharth Agarwal <sid0@fb.com>
parents: 18537
diff changeset
   611
        self._cache = {}
27371
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   612
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   613
        self._head = head = _lrucachenode()
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   614
        head.prev = head
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   615
        head.next = head
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   616
        self._size = 1
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   617
        self._capacity = max
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   618
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   619
    def __len__(self):
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   620
        return len(self._cache)
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   621
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   622
    def __contains__(self, k):
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   623
        return k in self._cache
18603
2251b3184e6e util: add an LRU cache dict
Siddharth Agarwal <sid0@fb.com>
parents: 18537
diff changeset
   624
27371
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   625
    def __iter__(self):
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   626
        # We don't have to iterate in cache order, but why not.
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   627
        n = self._head
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   628
        for i in range(len(self._cache)):
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   629
            yield n.key
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   630
            n = n.next
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   631
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   632
    def __getitem__(self, k):
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   633
        node = self._cache[k]
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   634
        self._movetohead(node)
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   635
        return node.value
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   636
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   637
    def __setitem__(self, k, v):
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   638
        node = self._cache.get(k)
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   639
        # Replace existing value and mark as newest.
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   640
        if node is not None:
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   641
            node.value = v
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   642
            self._movetohead(node)
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   643
            return
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   644
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   645
        if self._size < self._capacity:
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   646
            node = self._addcapacity()
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   647
        else:
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   648
            # Grab the last/oldest item.
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   649
            node = self._head.prev
18603
2251b3184e6e util: add an LRU cache dict
Siddharth Agarwal <sid0@fb.com>
parents: 18537
diff changeset
   650
27371
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   651
        # At capacity. Kill the old entry.
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   652
        if node.key is not _notset:
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   653
            del self._cache[node.key]
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   654
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   655
        node.key = k
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   656
        node.value = v
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   657
        self._cache[k] = node
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   658
        # And mark it as newest entry. No need to adjust order since it
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   659
        # is already self._head.prev.
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   660
        self._head = node
18603
2251b3184e6e util: add an LRU cache dict
Siddharth Agarwal <sid0@fb.com>
parents: 18537
diff changeset
   661
27371
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   662
    def __delitem__(self, k):
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   663
        node = self._cache.pop(k)
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   664
        node.markempty()
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   665
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   666
        # Temporarily mark as newest item before re-adjusting head to make
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   667
        # this node the oldest item.
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   668
        self._movetohead(node)
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   669
        self._head = node.next
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   670
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   671
    # Additional dict methods.
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   672
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   673
    def get(self, k, default=None):
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   674
        try:
29828
79add5a4e857 util: properly implement lrucachedict.get()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 29776
diff changeset
   675
            return self._cache[k].value
27371
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   676
        except KeyError:
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   677
            return default
18603
2251b3184e6e util: add an LRU cache dict
Siddharth Agarwal <sid0@fb.com>
parents: 18537
diff changeset
   678
19710
887ffa22fd0d lrucachedict: implement clear()
Siddharth Agarwal <sid0@fb.com>
parents: 19461
diff changeset
   679
    def clear(self):
27371
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   680
        n = self._head
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   681
        while n.key is not _notset:
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   682
            n.markempty()
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   683
            n = n.next
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   684
19710
887ffa22fd0d lrucachedict: implement clear()
Siddharth Agarwal <sid0@fb.com>
parents: 19461
diff changeset
   685
        self._cache.clear()
27371
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   686
27576
6cd3044985c2 lrucachedict: add copy method
Eric Sumner <ericsumner@fb.com>
parents: 27391
diff changeset
   687
    def copy(self):
6cd3044985c2 lrucachedict: add copy method
Eric Sumner <ericsumner@fb.com>
parents: 27391
diff changeset
   688
        result = lrucachedict(self._capacity)
6cd3044985c2 lrucachedict: add copy method
Eric Sumner <ericsumner@fb.com>
parents: 27391
diff changeset
   689
        n = self._head.prev
6cd3044985c2 lrucachedict: add copy method
Eric Sumner <ericsumner@fb.com>
parents: 27391
diff changeset
   690
        # Iterate in oldest-to-newest order, so the copy has the right ordering
6cd3044985c2 lrucachedict: add copy method
Eric Sumner <ericsumner@fb.com>
parents: 27391
diff changeset
   691
        for i in range(len(self._cache)):
6cd3044985c2 lrucachedict: add copy method
Eric Sumner <ericsumner@fb.com>
parents: 27391
diff changeset
   692
            result[n.key] = n.value
6cd3044985c2 lrucachedict: add copy method
Eric Sumner <ericsumner@fb.com>
parents: 27391
diff changeset
   693
            n = n.prev
6cd3044985c2 lrucachedict: add copy method
Eric Sumner <ericsumner@fb.com>
parents: 27391
diff changeset
   694
        return result
6cd3044985c2 lrucachedict: add copy method
Eric Sumner <ericsumner@fb.com>
parents: 27391
diff changeset
   695
27371
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   696
    def _movetohead(self, node):
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   697
        """Mark a node as the newest, making it the new head.
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   698
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   699
        When a node is accessed, it becomes the freshest entry in the LRU
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   700
        list, which is denoted by self._head.
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   701
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   702
        Visually, let's make ``N`` the new head node (* denotes head):
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   703
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   704
            previous/oldest <-> head <-> next/next newest
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   705
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   706
            ----<->--- A* ---<->-----
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   707
            |                       |
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   708
            E <-> D <-> N <-> C <-> B
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   709
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   710
        To:
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   711
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   712
            ----<->--- N* ---<->-----
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   713
            |                       |
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   714
            E <-> D <-> C <-> B <-> A
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   715
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   716
        This requires the following moves:
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   717
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   718
           C.next = D  (node.prev.next = node.next)
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   719
           D.prev = C  (node.next.prev = node.prev)
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   720
           E.next = N  (head.prev.next = node)
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   721
           N.prev = E  (node.prev = head.prev)
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   722
           N.next = A  (node.next = head)
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   723
           A.prev = N  (head.prev = node)
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   724
        """
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   725
        head = self._head
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   726
        # C.next = D
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   727
        node.prev.next = node.next
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   728
        # D.prev = C
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   729
        node.next.prev = node.prev
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   730
        # N.prev = E
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   731
        node.prev = head.prev
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   732
        # N.next = A
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   733
        # It is tempting to do just "head" here, however if node is
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   734
        # adjacent to head, this will do bad things.
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   735
        node.next = head.prev.next
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   736
        # E.next = N
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   737
        node.next.prev = node
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   738
        # A.prev = N
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   739
        node.prev.next = node
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   740
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   741
        self._head = node
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   742
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   743
    def _addcapacity(self):
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   744
        """Add a node to the circular linked list.
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   745
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   746
        The new node is inserted before the head node.
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   747
        """
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   748
        head = self._head
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   749
        node = _lrucachenode()
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   750
        head.prev.next = node
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   751
        node.prev = head.prev
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   752
        node.next = head
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   753
        head.prev = node
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   754
        self._size += 1
45d996a566d7 util: reimplement lrucachedict
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27363
diff changeset
   755
        return node
19710
887ffa22fd0d lrucachedict: implement clear()
Siddharth Agarwal <sid0@fb.com>
parents: 19461
diff changeset
   756
9097
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   757
def lrucachefunc(func):
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   758
    '''cache most recent results of function calls'''
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   759
    cache = {}
25113
0ca8410ea345 util: drop alias for collections.deque
Martin von Zweigbergk <martinvonz@google.com>
parents: 25112
diff changeset
   760
    order = collections.deque()
28832
f5ff10f6fa6b util: use __code__ (available since py2.6)
timeless <timeless@mozdev.org>
parents: 28826
diff changeset
   761
    if func.__code__.co_argcount == 1:
9097
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   762
        def f(arg):
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   763
            if arg not in cache:
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   764
                if len(cache) > 20:
16803
107a3270a24a cleanup: use the deque type where appropriate
Bryan O'Sullivan <bryano@fb.com>
parents: 16769
diff changeset
   765
                    del cache[order.popleft()]
9097
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   766
                cache[arg] = func(arg)
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   767
            else:
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   768
                order.remove(arg)
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   769
            order.append(arg)
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   770
            return cache[arg]
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   771
    else:
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   772
        def f(*args):
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   773
            if args not in cache:
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   774
                if len(cache) > 20:
16803
107a3270a24a cleanup: use the deque type where appropriate
Bryan O'Sullivan <bryano@fb.com>
parents: 16769
diff changeset
   775
                    del cache[order.popleft()]
9097
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   776
                cache[args] = func(*args)
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   777
            else:
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   778
                order.remove(args)
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   779
            order.append(args)
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   780
            return cache[args]
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   781
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   782
    return f
431462bd8478 fix memory usage of revlog caches by limiting cache size [issue1639]
Matt Mackall <mpm@selenic.com>
parents: 9089
diff changeset
   783
8207
dd8d5be57d65 util: take propertycache from context.py
Matt Mackall <mpm@selenic.com>
parents: 8181
diff changeset
   784
class propertycache(object):
dd8d5be57d65 util: take propertycache from context.py
Matt Mackall <mpm@selenic.com>
parents: 8181
diff changeset
   785
    def __init__(self, func):
dd8d5be57d65 util: take propertycache from context.py
Matt Mackall <mpm@selenic.com>
parents: 8181
diff changeset
   786
        self.func = func
dd8d5be57d65 util: take propertycache from context.py
Matt Mackall <mpm@selenic.com>
parents: 8181
diff changeset
   787
        self.name = func.__name__
dd8d5be57d65 util: take propertycache from context.py
Matt Mackall <mpm@selenic.com>
parents: 8181
diff changeset
   788
    def __get__(self, obj, type=None):
dd8d5be57d65 util: take propertycache from context.py
Matt Mackall <mpm@selenic.com>
parents: 8181
diff changeset
   789
        result = self.func(obj)
18013
98c867ac1330 clfilter: add a propertycache that must be unfiltered
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 17962
diff changeset
   790
        self.cachevalue(obj, result)
8207
dd8d5be57d65 util: take propertycache from context.py
Matt Mackall <mpm@selenic.com>
parents: 8181
diff changeset
   791
        return result
dd8d5be57d65 util: take propertycache from context.py
Matt Mackall <mpm@selenic.com>
parents: 8181
diff changeset
   792
18013
98c867ac1330 clfilter: add a propertycache that must be unfiltered
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 17962
diff changeset
   793
    def cachevalue(self, obj, value):
19951
d51c4d85ec23 spelling: random spell checker fixes
Mads Kiilerich <madski@unity3d.com>
parents: 19852
diff changeset
   794
        # __dict__ assignment required to bypass __setattr__ (eg: repoview)
19845
a1237a4b437d repoview: make propertycache.setcache compatible with repoview
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 19461
diff changeset
   795
        obj.__dict__[self.name] = value
18013
98c867ac1330 clfilter: add a propertycache that must be unfiltered
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents: 17962
diff changeset
   796
1293
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   797
def pipefilter(s, cmd):
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   798
    '''filter string S through command CMD, returning its output'''
8302
d2ad8c066676 util: simplify pipefilter and avoid subprocess race
Martin Geisler <mg@lazybytes.net>
parents: 8299
diff changeset
   799
    p = subprocess.Popen(cmd, shell=True, close_fds=closefds,
d2ad8c066676 util: simplify pipefilter and avoid subprocess race
Martin Geisler <mg@lazybytes.net>
parents: 8299
diff changeset
   800
                         stdin=subprocess.PIPE, stdout=subprocess.PIPE)
d2ad8c066676 util: simplify pipefilter and avoid subprocess race
Martin Geisler <mg@lazybytes.net>
parents: 8299
diff changeset
   801
    pout, perr = p.communicate(s)
d2ad8c066676 util: simplify pipefilter and avoid subprocess race
Martin Geisler <mg@lazybytes.net>
parents: 8299
diff changeset
   802
    return pout
419
28511fc21073 [PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
diff changeset
   803
1293
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   804
def tempfilter(s, cmd):
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   805
    '''filter string S through a pair of temporary files with CMD.
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   806
    CMD is used as a template to create the real command to be run,
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   807
    with the strings INFILE and OUTFILE replaced by the real names of
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   808
    the temporary files generated.'''
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   809
    inname, outname = None, None
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   810
    try:
2165
d821918e3bee Use better names (hg-{usage}-{random}.{suffix}) for temporary files.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 2153
diff changeset
   811
        infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
30925
82f1ef8b4477 py3: convert the mode argument of os.fdopen to unicodes (2 of 2)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30876
diff changeset
   812
        fp = os.fdopen(infd, pycompat.sysstr('wb'))
1293
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   813
        fp.write(s)
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   814
        fp.close()
2165
d821918e3bee Use better names (hg-{usage}-{random}.{suffix}) for temporary files.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 2153
diff changeset
   815
        outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
1293
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   816
        os.close(outfd)
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   817
        cmd = cmd.replace('INFILE', inname)
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   818
        cmd = cmd.replace('OUTFILE', outname)
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   819
        code = os.system(cmd)
30642
e995f00a9e9a py3: replace sys.platform with pycompat.sysplatform (part 2 of 2)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30639
diff changeset
   820
        if pycompat.sysplatform == 'OpenVMS' and code & 1:
4720
72fb6f10fac1 OpenVMS patches
Jean-Francois PIERONNE <jf.pieronne@laposte.net>
parents: 4708
diff changeset
   821
            code = 0
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
   822
        if code:
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
   823
            raise Abort(_("command '%s' failed: %s") %
14234
600e64004eb5 rename explain_exit to explainexit
Adrian Buehlmann <adrian@cadifra.com>
parents: 14230
diff changeset
   824
                        (cmd, explainexit(code)))
27768
5ef99738a562 util: replace file I/O with readfile
Bryan O'Sullivan <bryano@fb.com>
parents: 27766
diff changeset
   825
        return readfile(outname)
1293
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   826
    finally:
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   827
        try:
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
   828
            if inname:
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
   829
                os.unlink(inname)
14004
97ed99d1f419 eliminate various naked except clauses
Idan Kamara <idankk86@gmail.com>
parents: 13985
diff changeset
   830
        except OSError:
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
   831
            pass
1293
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   832
        try:
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
   833
            if outname:
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
   834
                os.unlink(outname)
14004
97ed99d1f419 eliminate various naked except clauses
Idan Kamara <idankk86@gmail.com>
parents: 13985
diff changeset
   835
        except OSError:
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
   836
            pass
1293
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   837
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   838
filtertable = {
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   839
    'tempfile:': tempfilter,
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   840
    'pipe:': pipefilter,
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   841
    }
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   842
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   843
def filter(s, cmd):
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   844
    "filter a string through a command that transforms its input to its output"
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   845
    for name, fn in filtertable.iteritems():
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   846
        if cmd.startswith(name):
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   847
            return fn(s, cmd[len(name):].lstrip())
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   848
    return pipefilter(s, cmd)
a6ffcebd3315 Enhance the file filtering capabilities.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1292
diff changeset
   849
1015
22571b8d35d3 Add automatic binary file detection to diff and export
mpm@selenic.com
parents: 917
diff changeset
   850
def binary(s):
6507
9699864de219 Let util.binary check entire data for \0 (issue1066, issue1079)
Christian Ebert <blacktrash@gmx.net>
parents: 6501
diff changeset
   851
    """return true if a string is binary data"""
8118
35f7fda52c92 util: return boolean result directly in util.binary
Martin Geisler <mg@lazybytes.net>
parents: 8011
diff changeset
   852
    return bool(s and '\0' in s)
6762
f67d1468ac50 util: add sort helper
Matt Mackall <mpm@selenic.com>
parents: 6746
diff changeset
   853
7396
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   854
def increasingchunks(source, min=1024, max=65536):
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   855
    '''return no less than min bytes per chunk while data remains,
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   856
    doubling min after each chunk until it reaches max'''
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   857
    def log2(x):
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   858
        if not x:
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   859
            return 0
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   860
        i = 0
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   861
        while x:
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   862
            x >>= 1
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   863
            i += 1
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   864
        return i - 1
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   865
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   866
    buf = []
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   867
    blen = 0
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   868
    for chunk in source:
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   869
        buf.append(chunk)
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   870
        blen += len(chunk)
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   871
        if blen >= min:
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   872
            if min < max:
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   873
                min = min << 1
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   874
                nmin = 1 << log2(blen)
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   875
                if nmin > min:
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   876
                    min = nmin
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   877
                if min > max:
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   878
                    min = max
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   879
            yield ''.join(buf)
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   880
            blen = 0
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   881
            buf = []
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   882
    if buf:
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   883
        yield ''.join(buf)
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7301
diff changeset
   884
7947
a454eeb1b827 move util.Abort to error.py
Matt Mackall <mpm@selenic.com>
parents: 7913
diff changeset
   885
Abort = error.Abort
508
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
   886
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
   887
def always(fn):
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
   888
    return True
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
   889
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
   890
def never(fn):
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
   891
    return False
724
1c0c413cccdd Get add and locate to use new repo and dirstate walk code.
Bryan O'Sullivan <bos@serpentine.com>
parents: 705
diff changeset
   892
23495
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   893
def nogc(func):
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   894
    """disable garbage collector
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   895
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   896
    Python's garbage collector triggers a GC each time a certain number of
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   897
    container objects (the number being defined by gc.get_threshold()) are
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   898
    allocated even when marked not to be tracked by the collector. Tracking has
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   899
    no effect on when GCs are triggered, only on what objects the GC looks
23543
4dd8a6a1240d spelling: fixes from proofreading of spell checker issues
Mads Kiilerich <madski@unity3d.com>
parents: 23495
diff changeset
   900
    into. As a workaround, disable GC while building complex (huge)
23495
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   901
    containers.
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   902
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   903
    This garbage collector issue have been fixed in 2.7.
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   904
    """
30053
dbcef8918bbd util: correct check of sys.version_info
Augie Fackler <augie@google.com>
parents: 30039
diff changeset
   905
    if sys.version_info >= (2, 7):
29776
279cd80059d4 performance: disable workaround for an old bug of Python gc
Maciej Fijalkowski <fijall@gmail.com>
parents: 29730
diff changeset
   906
        return func
23495
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   907
    def wrapper(*args, **kwargs):
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   908
        gcenabled = gc.isenabled()
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   909
        gc.disable()
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   910
        try:
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   911
            return func(*args, **kwargs)
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   912
        finally:
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   913
            if gcenabled:
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   914
                gc.enable()
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   915
    return wrapper
b25f07cb5399 util: add a 'nogc' decorator to disable the garbage collection
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23370
diff changeset
   916
4229
24c22a3f2ef8 pass repo.root to util.pathto() in preparation for the next patch
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4129
diff changeset
   917
def pathto(root, n1, n2):
886
509de8ab6f31 Fix walk path handling on Windows
Bryan O'Sullivan <bos@serpentine.com>
parents: 884
diff changeset
   918
    '''return the relative path from one place to another.
4229
24c22a3f2ef8 pass repo.root to util.pathto() in preparation for the next patch
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4129
diff changeset
   919
    root should use os.sep to separate directories
3669
48768b1ab23c fix util.pathto
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3629
diff changeset
   920
    n1 should use os.sep to separate directories
48768b1ab23c fix util.pathto
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3629
diff changeset
   921
    n2 should use "/" to separate directories
48768b1ab23c fix util.pathto
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3629
diff changeset
   922
    returns an os.sep-separated path.
4229
24c22a3f2ef8 pass repo.root to util.pathto() in preparation for the next patch
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4129
diff changeset
   923
24c22a3f2ef8 pass repo.root to util.pathto() in preparation for the next patch
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4129
diff changeset
   924
    If n1 is a relative path, it's assumed it's
24c22a3f2ef8 pass repo.root to util.pathto() in preparation for the next patch
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4129
diff changeset
   925
    relative to root.
24c22a3f2ef8 pass repo.root to util.pathto() in preparation for the next patch
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4129
diff changeset
   926
    n2 should always be relative to root.
3669
48768b1ab23c fix util.pathto
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3629
diff changeset
   927
    '''
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
   928
    if not n1:
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
   929
        return localpath(n2)
4230
c93562fb12cc Fix handling of paths when run outside the repo.
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4229
diff changeset
   930
    if os.path.isabs(n1):
c93562fb12cc Fix handling of paths when run outside the repo.
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4229
diff changeset
   931
        if os.path.splitdrive(root)[0] != os.path.splitdrive(n1)[0]:
c93562fb12cc Fix handling of paths when run outside the repo.
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4229
diff changeset
   932
            return os.path.join(root, localpath(n2))
c93562fb12cc Fix handling of paths when run outside the repo.
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4229
diff changeset
   933
        n2 = '/'.join((pconvert(root), n2))
5844
07d8eb78dd68 Add util.splitpath() and use it instead of using os.sep directly.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents: 5843
diff changeset
   934
    a, b = splitpath(n1), n2.split('/')
1541
bf4e7ef08741 fixed some stuff pychecker shows, marked unclear/wrong stuff with XXX
twaldmann@thinkmo.de
parents: 1528
diff changeset
   935
    a.reverse()
bf4e7ef08741 fixed some stuff pychecker shows, marked unclear/wrong stuff with XXX
twaldmann@thinkmo.de
parents: 1528
diff changeset
   936
    b.reverse()
884
087771ebe2e6 Fix walk code for files that do not exist anywhere, and unhandled types.
Bryan O'Sullivan <bos@serpentine.com>
parents: 878
diff changeset
   937
    while a and b and a[-1] == b[-1]:
1541
bf4e7ef08741 fixed some stuff pychecker shows, marked unclear/wrong stuff with XXX
twaldmann@thinkmo.de
parents: 1528
diff changeset
   938
        a.pop()
bf4e7ef08741 fixed some stuff pychecker shows, marked unclear/wrong stuff with XXX
twaldmann@thinkmo.de
parents: 1528
diff changeset
   939
        b.pop()
884
087771ebe2e6 Fix walk code for files that do not exist anywhere, and unhandled types.
Bryan O'Sullivan <bos@serpentine.com>
parents: 878
diff changeset
   940
    b.reverse()
30613
1112ff99d965 py3: replace os.sep with pycompat.ossep (part 1 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30536
diff changeset
   941
    return pycompat.ossep.join((['..'] * len(a)) + b) or '.'
884
087771ebe2e6 Fix walk code for files that do not exist anywhere, and unhandled types.
Bryan O'Sullivan <bos@serpentine.com>
parents: 878
diff changeset
   942
14228
116de1da2154 rename util.main_is_frozen to mainfrozen
Adrian Buehlmann <adrian@cadifra.com>
parents: 14167
diff changeset
   943
def mainfrozen():
6499
479847ccabe0 Added hgexecutable support for py2exe/frozen scripts
"Paul Moore <p.f.moore@gmail.com>"
parents: 5659
diff changeset
   944
    """return True if we are a frozen executable.
479847ccabe0 Added hgexecutable support for py2exe/frozen scripts
"Paul Moore <p.f.moore@gmail.com>"
parents: 5659
diff changeset
   945
479847ccabe0 Added hgexecutable support for py2exe/frozen scripts
"Paul Moore <p.f.moore@gmail.com>"
parents: 5659
diff changeset
   946
    The code supports py2exe (most common, Windows only) and tools/freeze
479847ccabe0 Added hgexecutable support for py2exe/frozen scripts
"Paul Moore <p.f.moore@gmail.com>"
parents: 5659
diff changeset
   947
    (portable, not much used).
479847ccabe0 Added hgexecutable support for py2exe/frozen scripts
"Paul Moore <p.f.moore@gmail.com>"
parents: 5659
diff changeset
   948
    """
14968
b7dbe957585c util: use safehasattr or getattr instead of hasattr
Augie Fackler <durin42@gmail.com>
parents: 14942
diff changeset
   949
    return (safehasattr(sys, "frozen") or # new py2exe
b7dbe957585c util: use safehasattr or getattr instead of hasattr
Augie Fackler <durin42@gmail.com>
parents: 14942
diff changeset
   950
            safehasattr(sys, "importers") or # old py2exe
30039
ff7697b436ab py3: use unicode in is_frozen()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30038
diff changeset
   951
            imp.is_frozen(u"__main__")) # tools/freeze
6499
479847ccabe0 Added hgexecutable support for py2exe/frozen scripts
"Paul Moore <p.f.moore@gmail.com>"
parents: 5659
diff changeset
   952
22633
92b54547ac5d util: introduce datapath for getting the location of supporting data files
Mads Kiilerich <madski@unity3d.com>
parents: 22632
diff changeset
   953
# the location of data files matching the source code
27764
dd0c5f4d1b53 util: adjust 'datapath' to be correct in a frozen OS X package
Matt Harbison <matt_harbison@yahoo.com>
parents: 27755
diff changeset
   954
if mainfrozen() and getattr(sys, 'frozen', None) != 'macosx_app':
22633
92b54547ac5d util: introduce datapath for getting the location of supporting data files
Mads Kiilerich <madski@unity3d.com>
parents: 22632
diff changeset
   955
    # executable version (py2exe) doesn't support __file__
30669
10b17ed9b591 py3: replace sys.executable with pycompat.sysexecutable
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30642
diff changeset
   956
    datapath = os.path.dirname(pycompat.sysexecutable)
22633
92b54547ac5d util: introduce datapath for getting the location of supporting data files
Mads Kiilerich <madski@unity3d.com>
parents: 22632
diff changeset
   957
else:
31074
2912b06905dc py3: use pycompat.fsencode() to convert __file__ to bytes
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30988
diff changeset
   958
    datapath = os.path.dirname(pycompat.fsencode(__file__))
30301
8321b083a83d py3: make util.datapath a bytes variable
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30265
diff changeset
   959
22638
0d0350cfc7ab i18n: use datapath for i18n like for templates and help
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
   960
i18n.setdatapath(datapath)
0d0350cfc7ab i18n: use datapath for i18n like for templates and help
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
   961
22632
db15bb2d6323 util: move _hgexecutable a few lines, closer to where it is used
Mads Kiilerich <madski@unity3d.com>
parents: 22245
diff changeset
   962
_hgexecutable = None
db15bb2d6323 util: move _hgexecutable a few lines, closer to where it is used
Mads Kiilerich <madski@unity3d.com>
parents: 22245
diff changeset
   963
5062
3d35c8cb5eb4 Simplify/correct finding the hg executable (fixes issue644)
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4832
diff changeset
   964
def hgexecutable():
3d35c8cb5eb4 Simplify/correct finding the hg executable (fixes issue644)
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4832
diff changeset
   965
    """return location of the 'hg' executable.
3d35c8cb5eb4 Simplify/correct finding the hg executable (fixes issue644)
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4832
diff changeset
   966
3d35c8cb5eb4 Simplify/correct finding the hg executable (fixes issue644)
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4832
diff changeset
   967
    Defaults to $HG or 'hg' in the search path.
3d35c8cb5eb4 Simplify/correct finding the hg executable (fixes issue644)
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4832
diff changeset
   968
    """
3d35c8cb5eb4 Simplify/correct finding the hg executable (fixes issue644)
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4832
diff changeset
   969
    if _hgexecutable is None:
30637
344e68882cd3 py3: replace os.environ with encoding.environ (part 4 of 5)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30625
diff changeset
   970
        hg = encoding.environ.get('HG')
15106
76cd1964519c util: fix finding of hgexecutable
Simon Heimberg <simohe@besonet.ch>
parents: 15081
diff changeset
   971
        mainmod = sys.modules['__main__']
6500
a3175cd7dbec Tidy code, fix typo
Bryan O'Sullivan <bos@serpentine.com>
parents: 6499
diff changeset
   972
        if hg:
14229
85fd8402cbc4 rename util.set_hgexecutable to _sethgexecutable
Adrian Buehlmann <adrian@cadifra.com>
parents: 14228
diff changeset
   973
            _sethgexecutable(hg)
14228
116de1da2154 rename util.main_is_frozen to mainfrozen
Adrian Buehlmann <adrian@cadifra.com>
parents: 14167
diff changeset
   974
        elif mainfrozen():
27765
f1fb93eebb1d util: adjust hgexecutable() to handle frozen Mercurial on OS X
Matt Harbison <matt_harbison@yahoo.com>
parents: 27764
diff changeset
   975
            if getattr(sys, 'frozen', None) == 'macosx_app':
f1fb93eebb1d util: adjust hgexecutable() to handle frozen Mercurial on OS X
Matt Harbison <matt_harbison@yahoo.com>
parents: 27764
diff changeset
   976
                # Env variable set by py2app
30637
344e68882cd3 py3: replace os.environ with encoding.environ (part 4 of 5)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30625
diff changeset
   977
                _sethgexecutable(encoding.environ['EXECUTABLEPATH'])
27765
f1fb93eebb1d util: adjust hgexecutable() to handle frozen Mercurial on OS X
Matt Harbison <matt_harbison@yahoo.com>
parents: 27764
diff changeset
   978
            else:
30669
10b17ed9b591 py3: replace sys.executable with pycompat.sysexecutable
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30642
diff changeset
   979
                _sethgexecutable(pycompat.sysexecutable)
31074
2912b06905dc py3: use pycompat.fsencode() to convert __file__ to bytes
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30988
diff changeset
   980
        elif (os.path.basename(
2912b06905dc py3: use pycompat.fsencode() to convert __file__ to bytes
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30988
diff changeset
   981
            pycompat.fsencode(getattr(mainmod, '__file__', ''))) == 'hg'):
2912b06905dc py3: use pycompat.fsencode() to convert __file__ to bytes
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30988
diff changeset
   982
            _sethgexecutable(pycompat.fsencode(mainmod.__file__))
6499
479847ccabe0 Added hgexecutable support for py2exe/frozen scripts
"Paul Moore <p.f.moore@gmail.com>"
parents: 5659
diff changeset
   983
        else:
14271
4030630fb59c rename util.find_exe to findexe
Adrian Buehlmann <adrian@cadifra.com>
parents: 14262
diff changeset
   984
            exe = findexe('hg') or os.path.basename(sys.argv[0])
14229
85fd8402cbc4 rename util.set_hgexecutable to _sethgexecutable
Adrian Buehlmann <adrian@cadifra.com>
parents: 14228
diff changeset
   985
            _sethgexecutable(exe)
5062
3d35c8cb5eb4 Simplify/correct finding the hg executable (fixes issue644)
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4832
diff changeset
   986
    return _hgexecutable
4686
849f011dbf79 Remember path to 'hg' executable and pass to external tools and hooks as $HG.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4673
diff changeset
   987
14229
85fd8402cbc4 rename util.set_hgexecutable to _sethgexecutable
Adrian Buehlmann <adrian@cadifra.com>
parents: 14228
diff changeset
   988
def _sethgexecutable(path):
5062
3d35c8cb5eb4 Simplify/correct finding the hg executable (fixes issue644)
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4832
diff changeset
   989
    """set location of the 'hg' executable"""
4686
849f011dbf79 Remember path to 'hg' executable and pass to external tools and hooks as $HG.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4673
diff changeset
   990
    global _hgexecutable
5062
3d35c8cb5eb4 Simplify/correct finding the hg executable (fixes issue644)
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4832
diff changeset
   991
    _hgexecutable = path
4686
849f011dbf79 Remember path to 'hg' executable and pass to external tools and hooks as $HG.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4673
diff changeset
   992
26450
1138e1d05207 util.system: compare fileno to see if it needs stdout redirection
Yuya Nishihara <yuya@tcha.org>
parents: 26392
diff changeset
   993
def _isstdout(f):
1138e1d05207 util.system: compare fileno to see if it needs stdout redirection
Yuya Nishihara <yuya@tcha.org>
parents: 26392
diff changeset
   994
    fileno = getattr(f, 'fileno', None)
1138e1d05207 util.system: compare fileno to see if it needs stdout redirection
Yuya Nishihara <yuya@tcha.org>
parents: 26392
diff changeset
   995
    return fileno and fileno() == sys.__stdout__.fileno()
1138e1d05207 util.system: compare fileno to see if it needs stdout redirection
Yuya Nishihara <yuya@tcha.org>
parents: 26392
diff changeset
   996
30736
d9e5b0aeeb90 util: extract the logic calculating environment variables
Jun Wu <quark@fb.com>
parents: 30669
diff changeset
   997
def shellenviron(environ=None):
d9e5b0aeeb90 util: extract the logic calculating environment variables
Jun Wu <quark@fb.com>
parents: 30669
diff changeset
   998
    """return environ with optional override, useful for shelling out"""
d9e5b0aeeb90 util: extract the logic calculating environment variables
Jun Wu <quark@fb.com>
parents: 30669
diff changeset
   999
    def py2shell(val):
d9e5b0aeeb90 util: extract the logic calculating environment variables
Jun Wu <quark@fb.com>
parents: 30669
diff changeset
  1000
        'convert python object into string that is useful to shell'
d9e5b0aeeb90 util: extract the logic calculating environment variables
Jun Wu <quark@fb.com>
parents: 30669
diff changeset
  1001
        if val is None or val is False:
d9e5b0aeeb90 util: extract the logic calculating environment variables
Jun Wu <quark@fb.com>
parents: 30669
diff changeset
  1002
            return '0'
d9e5b0aeeb90 util: extract the logic calculating environment variables
Jun Wu <quark@fb.com>
parents: 30669
diff changeset
  1003
        if val is True:
d9e5b0aeeb90 util: extract the logic calculating environment variables
Jun Wu <quark@fb.com>
parents: 30669
diff changeset
  1004
            return '1'
d9e5b0aeeb90 util: extract the logic calculating environment variables
Jun Wu <quark@fb.com>
parents: 30669
diff changeset
  1005
        return str(val)
d9e5b0aeeb90 util: extract the logic calculating environment variables
Jun Wu <quark@fb.com>
parents: 30669
diff changeset
  1006
    env = dict(encoding.environ)
d9e5b0aeeb90 util: extract the logic calculating environment variables
Jun Wu <quark@fb.com>
parents: 30669
diff changeset
  1007
    if environ:
d9e5b0aeeb90 util: extract the logic calculating environment variables
Jun Wu <quark@fb.com>
parents: 30669
diff changeset
  1008
        env.update((k, py2shell(v)) for k, v in environ.iteritems())
d9e5b0aeeb90 util: extract the logic calculating environment variables
Jun Wu <quark@fb.com>
parents: 30669
diff changeset
  1009
    env['HG'] = hgexecutable()
d9e5b0aeeb90 util: extract the logic calculating environment variables
Jun Wu <quark@fb.com>
parents: 30669
diff changeset
  1010
    return env
d9e5b0aeeb90 util: extract the logic calculating environment variables
Jun Wu <quark@fb.com>
parents: 30669
diff changeset
  1011
31108
3f8f53190d6a chg: deduplicate error handling of ui.system()
Yuya Nishihara <yuya@tcha.org>
parents: 31074
diff changeset
  1012
def system(cmd, environ=None, cwd=None, out=None):
1882
c0320567931f merge util.esystem and util.system.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1880
diff changeset
  1013
    '''enhanced shell command execution.
c0320567931f merge util.esystem and util.system.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1880
diff changeset
  1014
    run with environment maybe modified, maybe in different dir.
508
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
  1015
11469
c37f35d7f2f5 http: deliver hook output to client
Maxim Khitrov <mkhitrov@gmail.com>
parents: 11297
diff changeset
  1016
    if out is specified, it is assumed to be a file-like object that has a
c37f35d7f2f5 http: deliver hook output to client
Maxim Khitrov <mkhitrov@gmail.com>
parents: 11297
diff changeset
  1017
    write() method. stdout and stderr will be redirected to out.'''
13439
d724a69309e0 util: flush stdout before calling external processes
Mads Kiilerich <mads@kiilerich.com>
parents: 13400
diff changeset
  1018
    try:
30473
39d13b8c101d py3: bulk replace sys.stdin/out/err by util's
Yuya Nishihara <yuya@tcha.org>
parents: 30472
diff changeset
  1019
        stdout.flush()
13439
d724a69309e0 util: flush stdout before calling external processes
Mads Kiilerich <mads@kiilerich.com>
parents: 13400
diff changeset
  1020
    except Exception:
d724a69309e0 util: flush stdout before calling external processes
Mads Kiilerich <mads@kiilerich.com>
parents: 13400
diff changeset
  1021
        pass
13188
6c9345f9edca util: concentrate quoting knowledge to windows.py quotecommand()
Steve Borho <steve@borho.org>
parents: 13128
diff changeset
  1022
    cmd = quotecommand(cmd)
30642
e995f00a9e9a py3: replace sys.platform with pycompat.sysplatform (part 2 of 2)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30639
diff changeset
  1023
    if pycompat.sysplatform == 'plan9' and (sys.version_info[0] == 2
19729
dfefb719eb92 plan9: update util.py for cpython 2.7 build
Jeff Sickel <jas@corpus-callosum.com>
parents: 19710
diff changeset
  1024
                                    and sys.version_info[1] < 7):
16383
f5dd179bfa4a plan9: initial support for plan 9 from bell labs
Steven Stallion <sstallion@gmail.com>
parents: 16360
diff changeset
  1025
        # subprocess kludge to work around issues in half-baked Python
f5dd179bfa4a plan9: initial support for plan 9 from bell labs
Steven Stallion <sstallion@gmail.com>
parents: 16360
diff changeset
  1026
        # ports, notably bichued/python:
f5dd179bfa4a plan9: initial support for plan 9 from bell labs
Steven Stallion <sstallion@gmail.com>
parents: 16360
diff changeset
  1027
        if not cwd is None:
f5dd179bfa4a plan9: initial support for plan 9 from bell labs
Steven Stallion <sstallion@gmail.com>
parents: 16360
diff changeset
  1028
            os.chdir(cwd)
f5dd179bfa4a plan9: initial support for plan 9 from bell labs
Steven Stallion <sstallion@gmail.com>
parents: 16360
diff changeset
  1029
        rc = os.system(cmd)
11469
c37f35d7f2f5 http: deliver hook output to client
Maxim Khitrov <mkhitrov@gmail.com>
parents: 11297
diff changeset
  1030
    else:
30736
d9e5b0aeeb90 util: extract the logic calculating environment variables
Jun Wu <quark@fb.com>
parents: 30669
diff changeset
  1031
        env = shellenviron(environ)
26450
1138e1d05207 util.system: compare fileno to see if it needs stdout redirection
Yuya Nishihara <yuya@tcha.org>
parents: 26392
diff changeset
  1032
        if out is None or _isstdout(out):
16383
f5dd179bfa4a plan9: initial support for plan 9 from bell labs
Steven Stallion <sstallion@gmail.com>
parents: 16360
diff changeset
  1033
            rc = subprocess.call(cmd, shell=True, close_fds=closefds,
f5dd179bfa4a plan9: initial support for plan 9 from bell labs
Steven Stallion <sstallion@gmail.com>
parents: 16360
diff changeset
  1034
                                 env=env, cwd=cwd)
f5dd179bfa4a plan9: initial support for plan 9 from bell labs
Steven Stallion <sstallion@gmail.com>
parents: 16360
diff changeset
  1035
        else:
f5dd179bfa4a plan9: initial support for plan 9 from bell labs
Steven Stallion <sstallion@gmail.com>
parents: 16360
diff changeset
  1036
            proc = subprocess.Popen(cmd, shell=True, close_fds=closefds,
f5dd179bfa4a plan9: initial support for plan 9 from bell labs
Steven Stallion <sstallion@gmail.com>
parents: 16360
diff changeset
  1037
                                    env=env, cwd=cwd, stdout=subprocess.PIPE,
f5dd179bfa4a plan9: initial support for plan 9 from bell labs
Steven Stallion <sstallion@gmail.com>
parents: 16360
diff changeset
  1038
                                    stderr=subprocess.STDOUT)
29730
4d23cd6e2219 util: use `iter(callable, sentinel)` instead of while True
Augie Fackler <augie@google.com>
parents: 29638
diff changeset
  1039
            for line in iter(proc.stdout.readline, ''):
16383
f5dd179bfa4a plan9: initial support for plan 9 from bell labs
Steven Stallion <sstallion@gmail.com>
parents: 16360
diff changeset
  1040
                out.write(line)
f5dd179bfa4a plan9: initial support for plan 9 from bell labs
Steven Stallion <sstallion@gmail.com>
parents: 16360
diff changeset
  1041
            proc.wait()
f5dd179bfa4a plan9: initial support for plan 9 from bell labs
Steven Stallion <sstallion@gmail.com>
parents: 16360
diff changeset
  1042
            rc = proc.returncode
30642
e995f00a9e9a py3: replace sys.platform with pycompat.sysplatform (part 2 of 2)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30639
diff changeset
  1043
        if pycompat.sysplatform == 'OpenVMS' and rc & 1:
16383
f5dd179bfa4a plan9: initial support for plan 9 from bell labs
Steven Stallion <sstallion@gmail.com>
parents: 16360
diff changeset
  1044
            rc = 0
9517
4368f582c806 util.system: Use subprocess instead of os.system
Mads Kiilerich <mads@kiilerich.com>
parents: 9508
diff changeset
  1045
    return rc
1880
05c7d75be925 fix broken environment save/restore when a hook runs.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1877
diff changeset
  1046
7388
5751631246de dispatch: generalize signature checking for extension command wrapping
Matt Mackall <mpm@selenic.com>
parents: 7301
diff changeset
  1047
def checksignature(func):
5751631246de dispatch: generalize signature checking for extension command wrapping
Matt Mackall <mpm@selenic.com>
parents: 7301
diff changeset
  1048
    '''wrap a function with code to check for calling errors'''
5751631246de dispatch: generalize signature checking for extension command wrapping
Matt Mackall <mpm@selenic.com>
parents: 7301
diff changeset
  1049
    def check(*args, **kwargs):
5751631246de dispatch: generalize signature checking for extension command wrapping
Matt Mackall <mpm@selenic.com>
parents: 7301
diff changeset
  1050
        try:
5751631246de dispatch: generalize signature checking for extension command wrapping
Matt Mackall <mpm@selenic.com>
parents: 7301
diff changeset
  1051
            return func(*args, **kwargs)
5751631246de dispatch: generalize signature checking for extension command wrapping
Matt Mackall <mpm@selenic.com>
parents: 7301
diff changeset
  1052
        except TypeError:
5751631246de dispatch: generalize signature checking for extension command wrapping
Matt Mackall <mpm@selenic.com>
parents: 7301
diff changeset
  1053
            if len(traceback.extract_tb(sys.exc_info()[2])) == 1:
7646
e62a456b8dc5 error: move SignatureError
Matt Mackall <mpm@selenic.com>
parents: 7644
diff changeset
  1054
                raise error.SignatureError
7388
5751631246de dispatch: generalize signature checking for extension command wrapping
Matt Mackall <mpm@selenic.com>
parents: 7301
diff changeset
  1055
            raise
5751631246de dispatch: generalize signature checking for extension command wrapping
Matt Mackall <mpm@selenic.com>
parents: 7301
diff changeset
  1056
5751631246de dispatch: generalize signature checking for extension command wrapping
Matt Mackall <mpm@selenic.com>
parents: 7301
diff changeset
  1057
    return check
5751631246de dispatch: generalize signature checking for extension command wrapping
Matt Mackall <mpm@selenic.com>
parents: 7301
diff changeset
  1058
29204
ce2d81aafbae util: make copyfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29201
diff changeset
  1059
def copyfile(src, dest, hardlink=False, copystat=False, checkambig=False):
27369
c48ecc0b5bc9 copyfile: add an optional parameter to copy other stat data
Siddharth Agarwal <sid0@fb.com>
parents: 26665
diff changeset
  1060
    '''copy a file, preserving mode and optionally other stat info like
29367
4e6e280e238f doc: describe detail about checkambig optional argument
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29342
diff changeset
  1061
    atime/mtime
4e6e280e238f doc: describe detail about checkambig optional argument
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29342
diff changeset
  1062
4e6e280e238f doc: describe detail about checkambig optional argument
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29342
diff changeset
  1063
    checkambig argument is used with filestat, and is useful only if
4e6e280e238f doc: describe detail about checkambig optional argument
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29342
diff changeset
  1064
    destination file is guarded by any lock (e.g. repo.lock or
4e6e280e238f doc: describe detail about checkambig optional argument
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29342
diff changeset
  1065
    repo.wlock).
4e6e280e238f doc: describe detail about checkambig optional argument
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29342
diff changeset
  1066
4e6e280e238f doc: describe detail about checkambig optional argument
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29342
diff changeset
  1067
    copystat and checkambig should be exclusive.
4e6e280e238f doc: describe detail about checkambig optional argument
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29342
diff changeset
  1068
    '''
29204
ce2d81aafbae util: make copyfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29201
diff changeset
  1069
    assert not (copystat and checkambig)
ce2d81aafbae util: make copyfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29201
diff changeset
  1070
    oldstat = None
18326
614f769e6aa7 util: copyfile: remove dest before copying
Mads Kiilerich <mads@kiilerich.com>
parents: 18026
diff changeset
  1071
    if os.path.lexists(dest):
29204
ce2d81aafbae util: make copyfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29201
diff changeset
  1072
        if checkambig:
ce2d81aafbae util: make copyfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29201
diff changeset
  1073
            oldstat = checkambig and filestat(dest)
18326
614f769e6aa7 util: copyfile: remove dest before copying
Mads Kiilerich <mads@kiilerich.com>
parents: 18026
diff changeset
  1074
        unlink(dest)
24155
e5ce49a30146 transaction: disable hardlink backups (issue4546)
Matt Mackall <mpm@selenic.com>
parents: 23917
diff changeset
  1075
    # hardlinks are problematic on CIFS, quietly ignore this flag
e5ce49a30146 transaction: disable hardlink backups (issue4546)
Matt Mackall <mpm@selenic.com>
parents: 23917
diff changeset
  1076
    # until we find a way to work around it cleanly (issue4546)
24164
07a92bbd02e5 transaction: really disable hardlink backups (issue4546)
Matt Harbison <matt_harbison@yahoo.com>
parents: 24155
diff changeset
  1077
    if False and hardlink:
23899
4e451d1359de copyfile: allow optional hardlinking
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23864
diff changeset
  1078
        try:
4e451d1359de copyfile: allow optional hardlinking
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23864
diff changeset
  1079
            oslink(src, dest)
4e451d1359de copyfile: allow optional hardlinking
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23864
diff changeset
  1080
            return
4e451d1359de copyfile: allow optional hardlinking
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23864
diff changeset
  1081
        except (IOError, OSError):
4e451d1359de copyfile: allow optional hardlinking
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 23864
diff changeset
  1082
            pass # fall back to normal copy
4271
1eaa8d90c689 fix util.copyfile to deal with symlinks
Eric St-Jean <esj@wwd.ca>
parents: 4256
diff changeset
  1083
    if os.path.islink(src):
1eaa8d90c689 fix util.copyfile to deal with symlinks
Eric St-Jean <esj@wwd.ca>
parents: 4256
diff changeset
  1084
        os.symlink(os.readlink(src), dest)
27369
c48ecc0b5bc9 copyfile: add an optional parameter to copy other stat data
Siddharth Agarwal <sid0@fb.com>
parents: 26665
diff changeset
  1085
        # copytime is ignored for symlinks, but in general copytime isn't needed
c48ecc0b5bc9 copyfile: add an optional parameter to copy other stat data
Siddharth Agarwal <sid0@fb.com>
parents: 26665
diff changeset
  1086
        # for them anyway
4271
1eaa8d90c689 fix util.copyfile to deal with symlinks
Eric St-Jean <esj@wwd.ca>
parents: 4256
diff changeset
  1087
    else:
1eaa8d90c689 fix util.copyfile to deal with symlinks
Eric St-Jean <esj@wwd.ca>
parents: 4256
diff changeset
  1088
        try:
1eaa8d90c689 fix util.copyfile to deal with symlinks
Eric St-Jean <esj@wwd.ca>
parents: 4256
diff changeset
  1089
            shutil.copyfile(src, dest)
27369
c48ecc0b5bc9 copyfile: add an optional parameter to copy other stat data
Siddharth Agarwal <sid0@fb.com>
parents: 26665
diff changeset
  1090
            if copystat:
c48ecc0b5bc9 copyfile: add an optional parameter to copy other stat data
Siddharth Agarwal <sid0@fb.com>
parents: 26665
diff changeset
  1091
                # copystat also copies mode
c48ecc0b5bc9 copyfile: add an optional parameter to copy other stat data
Siddharth Agarwal <sid0@fb.com>
parents: 26665
diff changeset
  1092
                shutil.copystat(src, dest)
c48ecc0b5bc9 copyfile: add an optional parameter to copy other stat data
Siddharth Agarwal <sid0@fb.com>
parents: 26665
diff changeset
  1093
            else:
c48ecc0b5bc9 copyfile: add an optional parameter to copy other stat data
Siddharth Agarwal <sid0@fb.com>
parents: 26665
diff changeset
  1094
                shutil.copymode(src, dest)
29204
ce2d81aafbae util: make copyfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29201
diff changeset
  1095
                if oldstat and oldstat.stat:
ce2d81aafbae util: make copyfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29201
diff changeset
  1096
                    newstat = filestat(dest)
ce2d81aafbae util: make copyfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29201
diff changeset
  1097
                    if newstat.isambig(oldstat):
ce2d81aafbae util: make copyfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29201
diff changeset
  1098
                        # stat of copied file is ambiguous to original one
ce2d81aafbae util: make copyfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29201
diff changeset
  1099
                        advanced = (oldstat.stat.st_mtime + 1) & 0x7fffffff
ce2d81aafbae util: make copyfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29201
diff changeset
  1100
                        os.utime(dest, (advanced, advanced))
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25420
diff changeset
  1101
        except shutil.Error as inst:
4271
1eaa8d90c689 fix util.copyfile to deal with symlinks
Eric St-Jean <esj@wwd.ca>
parents: 4256
diff changeset
  1102
            raise Abort(str(inst))
3629
4cfb72bcb978 util: add copyfile function
Matt Mackall <mpm@selenic.com>
parents: 3568
diff changeset
  1103
24439
2ddfac2f163e util: add progress callback support to copyfiles
Augie Fackler <augie@google.com>
parents: 24236
diff changeset
  1104
def copyfiles(src, dst, hardlink=None, progress=lambda t, pos: None):
2ddfac2f163e util: add progress callback support to copyfiles
Augie Fackler <augie@google.com>
parents: 24236
diff changeset
  1105
    """Copy a directory tree using hardlinks if possible."""
2ddfac2f163e util: add progress callback support to copyfiles
Augie Fackler <augie@google.com>
parents: 24236
diff changeset
  1106
    num = 0
1241
3b4f05ff3130 Add support for cloning with hardlinks on windows.
Stephen Darnell
parents: 1207
diff changeset
  1107
3b4f05ff3130 Add support for cloning with hardlinks on windows.
Stephen Darnell
parents: 1207
diff changeset
  1108
    if hardlink is None:
3b4f05ff3130 Add support for cloning with hardlinks on windows.
Stephen Darnell
parents: 1207
diff changeset
  1109
        hardlink = (os.stat(src).st_dev ==
3b4f05ff3130 Add support for cloning with hardlinks on windows.
Stephen Darnell
parents: 1207
diff changeset
  1110
                    os.stat(os.path.dirname(dst)).st_dev)
24439
2ddfac2f163e util: add progress callback support to copyfiles
Augie Fackler <augie@google.com>
parents: 24236
diff changeset
  1111
    if hardlink:
2ddfac2f163e util: add progress callback support to copyfiles
Augie Fackler <augie@google.com>
parents: 24236
diff changeset
  1112
        topic = _('linking')
2ddfac2f163e util: add progress callback support to copyfiles
Augie Fackler <augie@google.com>
parents: 24236
diff changeset
  1113
    else:
2ddfac2f163e util: add progress callback support to copyfiles
Augie Fackler <augie@google.com>
parents: 24236
diff changeset
  1114
        topic = _('copying')
698
df78d8ccac4c Use python function instead of external 'cp' command when cloning repos.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 667
diff changeset
  1115
1207
a7b8812973d9 Rewrite copytree as copyfiles
mpm@selenic.com
parents: 1200
diff changeset
  1116
    if os.path.isdir(src):
a7b8812973d9 Rewrite copytree as copyfiles
mpm@selenic.com
parents: 1200
diff changeset
  1117
        os.mkdir(dst)
5396
5105b119edd2 Add osutil module, containing a listdir function.
Bryan O'Sullivan <bos@serpentine.com>
parents: 5360
diff changeset
  1118
        for name, kind in osutil.listdir(src):
1207
a7b8812973d9 Rewrite copytree as copyfiles
mpm@selenic.com
parents: 1200
diff changeset
  1119
            srcname = os.path.join(src, name)
a7b8812973d9 Rewrite copytree as copyfiles
mpm@selenic.com
parents: 1200
diff changeset
  1120
            dstname = os.path.join(dst, name)
24439
2ddfac2f163e util: add progress callback support to copyfiles
Augie Fackler <augie@google.com>
parents: 24236
diff changeset
  1121
            def nprog(t, pos):
2ddfac2f163e util: add progress callback support to copyfiles
Augie Fackler <augie@google.com>
parents: 24236
diff changeset
  1122
                if pos is not None:
2ddfac2f163e util: add progress callback support to copyfiles
Augie Fackler <augie@google.com>
parents: 24236
diff changeset
  1123
                    return progress(t, pos + num)
2ddfac2f163e util: add progress callback support to copyfiles
Augie Fackler <augie@google.com>
parents: 24236
diff changeset
  1124
            hardlink, n = copyfiles(srcname, dstname, hardlink, progress=nprog)
11251
c61442f6d106 clone: print number of linked/copied files on --debug
Adrian Buehlmann <adrian@cadifra.com>
parents: 11232
diff changeset
  1125
            num += n
1207
a7b8812973d9 Rewrite copytree as copyfiles
mpm@selenic.com
parents: 1200
diff changeset
  1126
    else:
1241
3b4f05ff3130 Add support for cloning with hardlinks on windows.
Stephen Darnell
parents: 1207
diff changeset
  1127
        if hardlink:
3b4f05ff3130 Add support for cloning with hardlinks on windows.
Stephen Darnell
parents: 1207
diff changeset
  1128
            try:
14235
b9e1b041744f rename util.os_link to oslink
Adrian Buehlmann <adrian@cadifra.com>
parents: 14234
diff changeset
  1129
                oslink(src, dst)
2050
e49d0fa38176 util.copyfiles: only switch to copy if hardlink raises IOError or OSError.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2026
diff changeset
  1130
            except (IOError, OSError):
1241
3b4f05ff3130 Add support for cloning with hardlinks on windows.
Stephen Darnell
parents: 1207
diff changeset
  1131
                hardlink = False
1591
5a3229cf1492 do not copy atime and mtime in util.copyfiles
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 1585
diff changeset
  1132
                shutil.copy(src, dst)
1241
3b4f05ff3130 Add support for cloning with hardlinks on windows.
Stephen Darnell
parents: 1207
diff changeset
  1133
        else:
1591
5a3229cf1492 do not copy atime and mtime in util.copyfiles
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 1585
diff changeset
  1134
            shutil.copy(src, dst)
11251
c61442f6d106 clone: print number of linked/copied files on --debug
Adrian Buehlmann <adrian@cadifra.com>
parents: 11232
diff changeset
  1135
        num += 1
24439
2ddfac2f163e util: add progress callback support to copyfiles
Augie Fackler <augie@google.com>
parents: 24236
diff changeset
  1136
        progress(topic, num)
2ddfac2f163e util: add progress callback support to copyfiles
Augie Fackler <augie@google.com>
parents: 24236
diff changeset
  1137
    progress(topic, None)
698
df78d8ccac4c Use python function instead of external 'cp' command when cloning repos.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 667
diff changeset
  1138
11251
c61442f6d106 clone: print number of linked/copied files on --debug
Adrian Buehlmann <adrian@cadifra.com>
parents: 11232
diff changeset
  1139
    return hardlink, num
11254
640d419725d0 util.copyfiles: don't try os_link() again if it failed before
Adrian Buehlmann <adrian@cadifra.com>
parents: 11010
diff changeset
  1140
14262
23cd7eeff678 util: rename _windows_reserved_filenames and _windows_reserved_chars
Adrian Buehlmann <adrian@cadifra.com>
parents: 14250
diff changeset
  1141
_winreservednames = '''con prn aux nul
13916
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1142
    com1 com2 com3 com4 com5 com6 com7 com8 com9
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1143
    lpt1 lpt2 lpt3 lpt4 lpt5 lpt6 lpt7 lpt8 lpt9'''.split()
14262
23cd7eeff678 util: rename _windows_reserved_filenames and _windows_reserved_chars
Adrian Buehlmann <adrian@cadifra.com>
parents: 14250
diff changeset
  1144
_winreservedchars = ':*?"<>|'
13916
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1145
def checkwinfilename(path):
20000
0849d280663e util: warn when adding paths ending with \
Mads Kiilerich <madski@unity3d.com>
parents: 19951
diff changeset
  1146
    r'''Check that the base-relative path is a valid filename on Windows.
13916
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1147
    Returns None if the path is ok, or a UI string describing the problem.
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1148
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1149
    >>> checkwinfilename("just/a/normal/path")
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1150
    >>> checkwinfilename("foo/bar/con.xml")
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1151
    "filename contains 'con', which is reserved on Windows"
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1152
    >>> checkwinfilename("foo/con.xml/bar")
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1153
    "filename contains 'con', which is reserved on Windows"
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1154
    >>> checkwinfilename("foo/bar/xml.con")
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1155
    >>> checkwinfilename("foo/bar/AUX/bla.txt")
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1156
    "filename contains 'AUX', which is reserved on Windows"
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1157
    >>> checkwinfilename("foo/bar/bla:.txt")
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1158
    "filename contains ':', which is reserved on Windows"
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1159
    >>> checkwinfilename("foo/bar/b\07la.txt")
20000
0849d280663e util: warn when adding paths ending with \
Mads Kiilerich <madski@unity3d.com>
parents: 19951
diff changeset
  1160
    "filename contains '\\x07', which is invalid on Windows"
13916
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1161
    >>> checkwinfilename("foo/bar/bla ")
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1162
    "filename ends with ' ', which is not allowed on Windows"
15358
a347b3614bae util: don't complain about '..' in path components not working on Windows
Matt Mackall <mpm@selenic.com>
parents: 15159
diff changeset
  1163
    >>> checkwinfilename("../bar")
20000
0849d280663e util: warn when adding paths ending with \
Mads Kiilerich <madski@unity3d.com>
parents: 19951
diff changeset
  1164
    >>> checkwinfilename("foo\\")
0849d280663e util: warn when adding paths ending with \
Mads Kiilerich <madski@unity3d.com>
parents: 19951
diff changeset
  1165
    "filename ends with '\\', which is invalid on Windows"
0849d280663e util: warn when adding paths ending with \
Mads Kiilerich <madski@unity3d.com>
parents: 19951
diff changeset
  1166
    >>> checkwinfilename("foo\\/bar")
0849d280663e util: warn when adding paths ending with \
Mads Kiilerich <madski@unity3d.com>
parents: 19951
diff changeset
  1167
    "directory name ends with '\\', which is invalid on Windows"
13916
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1168
    '''
20000
0849d280663e util: warn when adding paths ending with \
Mads Kiilerich <madski@unity3d.com>
parents: 19951
diff changeset
  1169
    if path.endswith('\\'):
0849d280663e util: warn when adding paths ending with \
Mads Kiilerich <madski@unity3d.com>
parents: 19951
diff changeset
  1170
        return _("filename ends with '\\', which is invalid on Windows")
0849d280663e util: warn when adding paths ending with \
Mads Kiilerich <madski@unity3d.com>
parents: 19951
diff changeset
  1171
    if '\\/' in path:
0849d280663e util: warn when adding paths ending with \
Mads Kiilerich <madski@unity3d.com>
parents: 19951
diff changeset
  1172
        return _("directory name ends with '\\', which is invalid on Windows")
13916
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1173
    for n in path.replace('\\', '/').split('/'):
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1174
        if not n:
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1175
            continue
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1176
        for c in n:
14262
23cd7eeff678 util: rename _windows_reserved_filenames and _windows_reserved_chars
Adrian Buehlmann <adrian@cadifra.com>
parents: 14250
diff changeset
  1177
            if c in _winreservedchars:
13916
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1178
                return _("filename contains '%s', which is reserved "
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1179
                         "on Windows") % c
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1180
            if ord(c) <= 31:
13947
d2d1ef6a5238 checkwinfilename: use %r in format string
Adrian Buehlmann <adrian@cadifra.com>
parents: 13944
diff changeset
  1181
                return _("filename contains %r, which is invalid "
13916
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1182
                         "on Windows") % c
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1183
        base = n.split('.')[0]
14262
23cd7eeff678 util: rename _windows_reserved_filenames and _windows_reserved_chars
Adrian Buehlmann <adrian@cadifra.com>
parents: 14250
diff changeset
  1184
        if base and base.lower() in _winreservednames:
13916
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1185
            return _("filename contains '%s', which is reserved "
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1186
                     "on Windows") % base
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1187
        t = n[-1]
15358
a347b3614bae util: don't complain about '..' in path components not working on Windows
Matt Mackall <mpm@selenic.com>
parents: 15159
diff changeset
  1188
        if t in '. ' and n not in '..':
13916
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1189
            return _("filename ends with '%s', which is not allowed "
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1190
                     "on Windows") % t
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1191
30639
d524c88511a7 py3: replace os.name with pycompat.osname (part 1 of 2)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30637
diff changeset
  1192
if pycompat.osname == 'nt':
13916
98ee3dd5bab4 path_auditor: check filenames for basic platform validity (issue2755)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13910
diff changeset
  1193
    checkosfilename = checkwinfilename
30974
ae5d60bb70c9 util: introduce timer()
Simon Farnsworth <simonfar@fb.com>
parents: 30925
diff changeset
  1194
    timer = time.clock
7890
e710f0f592b2 util: split out posix, windows, and win32 modules
Matt Mackall <mpm@selenic.com>
parents: 7879
diff changeset
  1195
else:
14926
4e7e63fc685a util: eliminate wildcard imports
Adrian Buehlmann <adrian@cadifra.com>
parents: 14918
diff changeset
  1196
    checkosfilename = platform.checkosfilename
30974
ae5d60bb70c9 util: introduce timer()
Simon Farnsworth <simonfar@fb.com>
parents: 30925
diff changeset
  1197
    timer = time.time
ae5d60bb70c9 util: introduce timer()
Simon Farnsworth <simonfar@fb.com>
parents: 30925
diff changeset
  1198
ae5d60bb70c9 util: introduce timer()
Simon Farnsworth <simonfar@fb.com>
parents: 30925
diff changeset
  1199
if safehasattr(time, "perf_counter"):
ae5d60bb70c9 util: introduce timer()
Simon Farnsworth <simonfar@fb.com>
parents: 30925
diff changeset
  1200
    timer = time.perf_counter
7890
e710f0f592b2 util: split out posix, windows, and win32 modules
Matt Mackall <mpm@selenic.com>
parents: 7879
diff changeset
  1201
e710f0f592b2 util: split out posix, windows, and win32 modules
Matt Mackall <mpm@selenic.com>
parents: 7879
diff changeset
  1202
def makelock(info, pathname):
e710f0f592b2 util: split out posix, windows, and win32 modules
Matt Mackall <mpm@selenic.com>
parents: 7879
diff changeset
  1203
    try:
e710f0f592b2 util: split out posix, windows, and win32 modules
Matt Mackall <mpm@selenic.com>
parents: 7879
diff changeset
  1204
        return os.symlink(info, pathname)
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25420
diff changeset
  1205
    except OSError as why:
7890
e710f0f592b2 util: split out posix, windows, and win32 modules
Matt Mackall <mpm@selenic.com>
parents: 7879
diff changeset
  1206
        if why.errno == errno.EEXIST:
e710f0f592b2 util: split out posix, windows, and win32 modules
Matt Mackall <mpm@selenic.com>
parents: 7879
diff changeset
  1207
            raise
e710f0f592b2 util: split out posix, windows, and win32 modules
Matt Mackall <mpm@selenic.com>
parents: 7879
diff changeset
  1208
    except AttributeError: # no symlink in os
e710f0f592b2 util: split out posix, windows, and win32 modules
Matt Mackall <mpm@selenic.com>
parents: 7879
diff changeset
  1209
        pass
e710f0f592b2 util: split out posix, windows, and win32 modules
Matt Mackall <mpm@selenic.com>
parents: 7879
diff changeset
  1210
704
5ca319a641e1 Make makelock and readlock work on filesystems without symlink support.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 698
diff changeset
  1211
    ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
5ca319a641e1 Make makelock and readlock work on filesystems without symlink support.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 698
diff changeset
  1212
    os.write(ld, info)
5ca319a641e1 Make makelock and readlock work on filesystems without symlink support.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 698
diff changeset
  1213
    os.close(ld)
5ca319a641e1 Make makelock and readlock work on filesystems without symlink support.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 698
diff changeset
  1214
7890
e710f0f592b2 util: split out posix, windows, and win32 modules
Matt Mackall <mpm@selenic.com>
parents: 7879
diff changeset
  1215
def readlock(pathname):
e710f0f592b2 util: split out posix, windows, and win32 modules
Matt Mackall <mpm@selenic.com>
parents: 7879
diff changeset
  1216
    try:
e710f0f592b2 util: split out posix, windows, and win32 modules
Matt Mackall <mpm@selenic.com>
parents: 7879
diff changeset
  1217
        return os.readlink(pathname)
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25420
diff changeset
  1218
    except OSError as why:
7890
e710f0f592b2 util: split out posix, windows, and win32 modules
Matt Mackall <mpm@selenic.com>
parents: 7879
diff changeset
  1219
        if why.errno not in (errno.EINVAL, errno.ENOSYS):
e710f0f592b2 util: split out posix, windows, and win32 modules
Matt Mackall <mpm@selenic.com>
parents: 7879
diff changeset
  1220
            raise
e710f0f592b2 util: split out posix, windows, and win32 modules
Matt Mackall <mpm@selenic.com>
parents: 7879
diff changeset
  1221
    except AttributeError: # no symlink in os
e710f0f592b2 util: split out posix, windows, and win32 modules
Matt Mackall <mpm@selenic.com>
parents: 7879
diff changeset
  1222
        pass
13400
14f3795a5ed7 explicitly close files
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13392
diff changeset
  1223
    fp = posixfile(pathname)
14f3795a5ed7 explicitly close files
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13392
diff changeset
  1224
    r = fp.read()
14f3795a5ed7 explicitly close files
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13392
diff changeset
  1225
    fp.close()
14f3795a5ed7 explicitly close files
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13392
diff changeset
  1226
    return r
704
5ca319a641e1 Make makelock and readlock work on filesystems without symlink support.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 698
diff changeset
  1227
2176
9b42304d9896 fix file handling bugs on windows.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2117
diff changeset
  1228
def fstat(fp):
9b42304d9896 fix file handling bugs on windows.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2117
diff changeset
  1229
    '''stat file object that may not have fileno method.'''
9b42304d9896 fix file handling bugs on windows.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2117
diff changeset
  1230
    try:
9b42304d9896 fix file handling bugs on windows.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2117
diff changeset
  1231
        return os.fstat(fp.fileno())
9b42304d9896 fix file handling bugs on windows.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2117
diff changeset
  1232
    except AttributeError:
9b42304d9896 fix file handling bugs on windows.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2117
diff changeset
  1233
        return os.stat(fp.name)
9b42304d9896 fix file handling bugs on windows.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2117
diff changeset
  1234
3784
1427949b8f80 imported patch folding
Matt Mackall <mpm@selenic.com>
parents: 3770
diff changeset
  1235
# File system features
1427949b8f80 imported patch folding
Matt Mackall <mpm@selenic.com>
parents: 3770
diff changeset
  1236
29889
6f447b9ec263 util: rename checkcase() to fscasesensitive() (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 29832
diff changeset
  1237
def fscasesensitive(path):
3784
1427949b8f80 imported patch folding
Matt Mackall <mpm@selenic.com>
parents: 3770
diff changeset
  1238
    """
18911
451eb1c27c1b util: improve doc for checkcase
Mads Kiilerich <mads@kiilerich.com>
parents: 18868
diff changeset
  1239
    Return true if the given path is on a case-sensitive filesystem
3784
1427949b8f80 imported patch folding
Matt Mackall <mpm@selenic.com>
parents: 3770
diff changeset
  1240
1427949b8f80 imported patch folding
Matt Mackall <mpm@selenic.com>
parents: 3770
diff changeset
  1241
    Requires a path (like /foo/.hg) ending with a foldable final
1427949b8f80 imported patch folding
Matt Mackall <mpm@selenic.com>
parents: 3770
diff changeset
  1242
    directory component.
1427949b8f80 imported patch folding
Matt Mackall <mpm@selenic.com>
parents: 3770
diff changeset
  1243
    """
24902
986a5c23b1c1 util.checkcase: don't abort on broken symlinks
Siddharth Agarwal <sid0@fb.com>
parents: 24692
diff changeset
  1244
    s1 = os.lstat(path)
3784
1427949b8f80 imported patch folding
Matt Mackall <mpm@selenic.com>
parents: 3770
diff changeset
  1245
    d, b = os.path.split(path)
15667
eacfd851cb9e icasefs: consider as case sensitive if there is no counterevidence, for safety
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15609
diff changeset
  1246
    b2 = b.upper()
eacfd851cb9e icasefs: consider as case sensitive if there is no counterevidence, for safety
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15609
diff changeset
  1247
    if b == b2:
eacfd851cb9e icasefs: consider as case sensitive if there is no counterevidence, for safety
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15609
diff changeset
  1248
        b2 = b.lower()
eacfd851cb9e icasefs: consider as case sensitive if there is no counterevidence, for safety
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15609
diff changeset
  1249
        if b == b2:
eacfd851cb9e icasefs: consider as case sensitive if there is no counterevidence, for safety
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15609
diff changeset
  1250
            return True # no evidence against case sensitivity
eacfd851cb9e icasefs: consider as case sensitive if there is no counterevidence, for safety
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15609
diff changeset
  1251
    p2 = os.path.join(d, b2)
3784
1427949b8f80 imported patch folding
Matt Mackall <mpm@selenic.com>
parents: 3770
diff changeset
  1252
    try:
24902
986a5c23b1c1 util.checkcase: don't abort on broken symlinks
Siddharth Agarwal <sid0@fb.com>
parents: 24692
diff changeset
  1253
        s2 = os.lstat(p2)
3784
1427949b8f80 imported patch folding
Matt Mackall <mpm@selenic.com>
parents: 3770
diff changeset
  1254
        if s2 == s1:
1427949b8f80 imported patch folding
Matt Mackall <mpm@selenic.com>
parents: 3770
diff changeset
  1255
            return False
1427949b8f80 imported patch folding
Matt Mackall <mpm@selenic.com>
parents: 3770
diff changeset
  1256
        return True
14004
97ed99d1f419 eliminate various naked except clauses
Idan Kamara <idankk86@gmail.com>
parents: 13985
diff changeset
  1257
    except OSError:
3784
1427949b8f80 imported patch folding
Matt Mackall <mpm@selenic.com>
parents: 3770
diff changeset
  1258
        return True
1427949b8f80 imported patch folding
Matt Mackall <mpm@selenic.com>
parents: 3770
diff changeset
  1259
16943
8d08a28aa63e matcher: use re2 bindings if available
Bryan O'Sullivan <bryano@fb.com>
parents: 16873
diff changeset
  1260
try:
8d08a28aa63e matcher: use re2 bindings if available
Bryan O'Sullivan <bryano@fb.com>
parents: 16873
diff changeset
  1261
    import re2
8d08a28aa63e matcher: use re2 bindings if available
Bryan O'Sullivan <bryano@fb.com>
parents: 16873
diff changeset
  1262
    _re2 = None
8d08a28aa63e matcher: use re2 bindings if available
Bryan O'Sullivan <bryano@fb.com>
parents: 16873
diff changeset
  1263
except ImportError:
8d08a28aa63e matcher: use re2 bindings if available
Bryan O'Sullivan <bryano@fb.com>
parents: 16873
diff changeset
  1264
    _re2 = False
8d08a28aa63e matcher: use re2 bindings if available
Bryan O'Sullivan <bryano@fb.com>
parents: 16873
diff changeset
  1265
21908
cad9dadc9d26 util: move compilere to a class
Siddharth Agarwal <sid0@fb.com>
parents: 21907
diff changeset
  1266
class _re(object):
21913
50aad4609224 util.re: move check for re2 into a separate method
Siddharth Agarwal <sid0@fb.com>
parents: 21912
diff changeset
  1267
    def _checkre2(self):
50aad4609224 util.re: move check for re2 into a separate method
Siddharth Agarwal <sid0@fb.com>
parents: 21912
diff changeset
  1268
        global _re2
50aad4609224 util.re: move check for re2 into a separate method
Siddharth Agarwal <sid0@fb.com>
parents: 21912
diff changeset
  1269
        try:
50aad4609224 util.re: move check for re2 into a separate method
Siddharth Agarwal <sid0@fb.com>
parents: 21912
diff changeset
  1270
            # check if match works, see issue3964
50aad4609224 util.re: move check for re2 into a separate method
Siddharth Agarwal <sid0@fb.com>
parents: 21912
diff changeset
  1271
            _re2 = bool(re2.match(r'\[([^\[]+)\]', '[ui]'))
50aad4609224 util.re: move check for re2 into a separate method
Siddharth Agarwal <sid0@fb.com>
parents: 21912
diff changeset
  1272
        except ImportError:
50aad4609224 util.re: move check for re2 into a separate method
Siddharth Agarwal <sid0@fb.com>
parents: 21912
diff changeset
  1273
            _re2 = False
50aad4609224 util.re: move check for re2 into a separate method
Siddharth Agarwal <sid0@fb.com>
parents: 21912
diff changeset
  1274
21908
cad9dadc9d26 util: move compilere to a class
Siddharth Agarwal <sid0@fb.com>
parents: 21907
diff changeset
  1275
    def compile(self, pat, flags=0):
cad9dadc9d26 util: move compilere to a class
Siddharth Agarwal <sid0@fb.com>
parents: 21907
diff changeset
  1276
        '''Compile a regular expression, using re2 if possible
16943
8d08a28aa63e matcher: use re2 bindings if available
Bryan O'Sullivan <bryano@fb.com>
parents: 16873
diff changeset
  1277
21908
cad9dadc9d26 util: move compilere to a class
Siddharth Agarwal <sid0@fb.com>
parents: 21907
diff changeset
  1278
        For best performance, use only re2-compatible regexp features. The
cad9dadc9d26 util: move compilere to a class
Siddharth Agarwal <sid0@fb.com>
parents: 21907
diff changeset
  1279
        only flags from the re module that are re2-compatible are
cad9dadc9d26 util: move compilere to a class
Siddharth Agarwal <sid0@fb.com>
parents: 21907
diff changeset
  1280
        IGNORECASE and MULTILINE.'''
cad9dadc9d26 util: move compilere to a class
Siddharth Agarwal <sid0@fb.com>
parents: 21907
diff changeset
  1281
        if _re2 is None:
21913
50aad4609224 util.re: move check for re2 into a separate method
Siddharth Agarwal <sid0@fb.com>
parents: 21912
diff changeset
  1282
            self._checkre2()
21908
cad9dadc9d26 util: move compilere to a class
Siddharth Agarwal <sid0@fb.com>
parents: 21907
diff changeset
  1283
        if _re2 and (flags & ~(remod.IGNORECASE | remod.MULTILINE)) == 0:
cad9dadc9d26 util: move compilere to a class
Siddharth Agarwal <sid0@fb.com>
parents: 21907
diff changeset
  1284
            if flags & remod.IGNORECASE:
cad9dadc9d26 util: move compilere to a class
Siddharth Agarwal <sid0@fb.com>
parents: 21907
diff changeset
  1285
                pat = '(?i)' + pat
cad9dadc9d26 util: move compilere to a class
Siddharth Agarwal <sid0@fb.com>
parents: 21907
diff changeset
  1286
            if flags & remod.MULTILINE:
cad9dadc9d26 util: move compilere to a class
Siddharth Agarwal <sid0@fb.com>
parents: 21907
diff changeset
  1287
                pat = '(?m)' + pat
cad9dadc9d26 util: move compilere to a class
Siddharth Agarwal <sid0@fb.com>
parents: 21907
diff changeset
  1288
            try:
cad9dadc9d26 util: move compilere to a class
Siddharth Agarwal <sid0@fb.com>
parents: 21907
diff changeset
  1289
                return re2.compile(pat)
cad9dadc9d26 util: move compilere to a class
Siddharth Agarwal <sid0@fb.com>
parents: 21907
diff changeset
  1290
            except re2.error:
cad9dadc9d26 util: move compilere to a class
Siddharth Agarwal <sid0@fb.com>
parents: 21907
diff changeset
  1291
                pass
cad9dadc9d26 util: move compilere to a class
Siddharth Agarwal <sid0@fb.com>
parents: 21907
diff changeset
  1292
        return remod.compile(pat, flags)
cad9dadc9d26 util: move compilere to a class
Siddharth Agarwal <sid0@fb.com>
parents: 21907
diff changeset
  1293
21914
10e99839a7a4 util.re: add an escape method
Siddharth Agarwal <sid0@fb.com>
parents: 21913
diff changeset
  1294
    @propertycache
10e99839a7a4 util.re: add an escape method
Siddharth Agarwal <sid0@fb.com>
parents: 21913
diff changeset
  1295
    def escape(self):
10e99839a7a4 util.re: add an escape method
Siddharth Agarwal <sid0@fb.com>
parents: 21913
diff changeset
  1296
        '''Return the version of escape corresponding to self.compile.
10e99839a7a4 util.re: add an escape method
Siddharth Agarwal <sid0@fb.com>
parents: 21913
diff changeset
  1297
10e99839a7a4 util.re: add an escape method
Siddharth Agarwal <sid0@fb.com>
parents: 21913
diff changeset
  1298
        This is imperfect because whether re2 or re is used for a particular
10e99839a7a4 util.re: add an escape method
Siddharth Agarwal <sid0@fb.com>
parents: 21913
diff changeset
  1299
        function depends on the flags, etc, but it's the best we can do.
10e99839a7a4 util.re: add an escape method
Siddharth Agarwal <sid0@fb.com>
parents: 21913
diff changeset
  1300
        '''
10e99839a7a4 util.re: add an escape method
Siddharth Agarwal <sid0@fb.com>
parents: 21913
diff changeset
  1301
        global _re2
10e99839a7a4 util.re: add an escape method
Siddharth Agarwal <sid0@fb.com>
parents: 21913
diff changeset
  1302
        if _re2 is None:
10e99839a7a4 util.re: add an escape method
Siddharth Agarwal <sid0@fb.com>
parents: 21913
diff changeset
  1303
            self._checkre2()
10e99839a7a4 util.re: add an escape method
Siddharth Agarwal <sid0@fb.com>
parents: 21913
diff changeset
  1304
        if _re2:
10e99839a7a4 util.re: add an escape method
Siddharth Agarwal <sid0@fb.com>
parents: 21913
diff changeset
  1305
            return re2.escape
10e99839a7a4 util.re: add an escape method
Siddharth Agarwal <sid0@fb.com>
parents: 21913
diff changeset
  1306
        else:
10e99839a7a4 util.re: add an escape method
Siddharth Agarwal <sid0@fb.com>
parents: 21913
diff changeset
  1307
            return remod.escape
10e99839a7a4 util.re: add an escape method
Siddharth Agarwal <sid0@fb.com>
parents: 21913
diff changeset
  1308
21908
cad9dadc9d26 util: move compilere to a class
Siddharth Agarwal <sid0@fb.com>
parents: 21907
diff changeset
  1309
re = _re()
16943
8d08a28aa63e matcher: use re2 bindings if available
Bryan O'Sullivan <bryano@fb.com>
parents: 16873
diff changeset
  1310
6676
33045179d079 Add a new function, fspath
Paul Moore <p.f.moore@gmail.com>
parents: 6595
diff changeset
  1311
_fspathcache = {}
33045179d079 Add a new function, fspath
Paul Moore <p.f.moore@gmail.com>
parents: 6595
diff changeset
  1312
def fspath(name, root):
33045179d079 Add a new function, fspath
Paul Moore <p.f.moore@gmail.com>
parents: 6595
diff changeset
  1313
    '''Get name in the case stored in the filesystem
33045179d079 Add a new function, fspath
Paul Moore <p.f.moore@gmail.com>
parents: 6595
diff changeset
  1314
15710
f63e40047372 icasefs: avoid path-absoluteness/existance check in util.fspath() for efficiency
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15709
diff changeset
  1315
    The name should be relative to root, and be normcase-ed for efficiency.
f63e40047372 icasefs: avoid path-absoluteness/existance check in util.fspath() for efficiency
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15709
diff changeset
  1316
f63e40047372 icasefs: avoid path-absoluteness/existance check in util.fspath() for efficiency
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15709
diff changeset
  1317
    Note that this function is unnecessary, and should not be
6676
33045179d079 Add a new function, fspath
Paul Moore <p.f.moore@gmail.com>
parents: 6595
diff changeset
  1318
    called, for case-sensitive filesystems (simply because it's expensive).
15670
d6c19cfa03ce icasefs: avoid normcase()-ing in util.fspath() for efficiency
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15669
diff changeset
  1319
15710
f63e40047372 icasefs: avoid path-absoluteness/existance check in util.fspath() for efficiency
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15709
diff changeset
  1320
    The root should be normcase-ed, too.
6676
33045179d079 Add a new function, fspath
Paul Moore <p.f.moore@gmail.com>
parents: 6595
diff changeset
  1321
    '''
23097
30124c40d11f util.fspath: use a dict rather than a linear scan for lookups
Siddharth Agarwal <sid0@fb.com>
parents: 23076
diff changeset
  1322
    def _makefspathcacheentry(dir):
30124c40d11f util.fspath: use a dict rather than a linear scan for lookups
Siddharth Agarwal <sid0@fb.com>
parents: 23076
diff changeset
  1323
        return dict((normcase(n), n) for n in os.listdir(dir))
15709
a1f4bd47d18e icasefs: retry directory scan once for already invalidated cache
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15674
diff changeset
  1324
30613
1112ff99d965 py3: replace os.sep with pycompat.ossep (part 1 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30536
diff changeset
  1325
    seps = pycompat.ossep
30625
bcf4a975f93d py3: replace os.altsep with pycompat.altsep
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30613
diff changeset
  1326
    if pycompat.osaltsep:
bcf4a975f93d py3: replace os.altsep with pycompat.altsep
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30613
diff changeset
  1327
        seps = seps + pycompat.osaltsep
6676
33045179d079 Add a new function, fspath
Paul Moore <p.f.moore@gmail.com>
parents: 6595
diff changeset
  1328
    # Protect backslashes. This gets silly very quickly.
33045179d079 Add a new function, fspath
Paul Moore <p.f.moore@gmail.com>
parents: 6595
diff changeset
  1329
    seps.replace('\\','\\\\')
21907
7e5dfa00e3c2 util: rename 're' to 'remod'
Siddharth Agarwal <sid0@fb.com>
parents: 21857
diff changeset
  1330
    pattern = remod.compile(r'([^%s]+)|([%s]+)' % (seps, seps))
15669
390bcd01775a icasefs: use util.normcase() instead of lower() or os.path.normcase in fspath
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15667
diff changeset
  1331
    dir = os.path.normpath(root)
6676
33045179d079 Add a new function, fspath
Paul Moore <p.f.moore@gmail.com>
parents: 6595
diff changeset
  1332
    result = []
33045179d079 Add a new function, fspath
Paul Moore <p.f.moore@gmail.com>
parents: 6595
diff changeset
  1333
    for part, sep in pattern.findall(name):
33045179d079 Add a new function, fspath
Paul Moore <p.f.moore@gmail.com>
parents: 6595
diff changeset
  1334
        if sep:
33045179d079 Add a new function, fspath
Paul Moore <p.f.moore@gmail.com>
parents: 6595
diff changeset
  1335
            result.append(sep)
33045179d079 Add a new function, fspath
Paul Moore <p.f.moore@gmail.com>
parents: 6595
diff changeset
  1336
            continue
33045179d079 Add a new function, fspath
Paul Moore <p.f.moore@gmail.com>
parents: 6595
diff changeset
  1337
15719
1dd60426b061 icasefs: follow standard cache look up pattern
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15718
diff changeset
  1338
        if dir not in _fspathcache:
23097
30124c40d11f util.fspath: use a dict rather than a linear scan for lookups
Siddharth Agarwal <sid0@fb.com>
parents: 23076
diff changeset
  1339
            _fspathcache[dir] = _makefspathcacheentry(dir)
15719
1dd60426b061 icasefs: follow standard cache look up pattern
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15718
diff changeset
  1340
        contents = _fspathcache[dir]
6676
33045179d079 Add a new function, fspath
Paul Moore <p.f.moore@gmail.com>
parents: 6595
diff changeset
  1341
23097
30124c40d11f util.fspath: use a dict rather than a linear scan for lookups
Siddharth Agarwal <sid0@fb.com>
parents: 23076
diff changeset
  1342
        found = contents.get(part)
15709
a1f4bd47d18e icasefs: retry directory scan once for already invalidated cache
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15674
diff changeset
  1343
        if not found:
15720
3bcfea777efc icasefs: rewrite comment to explain situtation precisely
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15719
diff changeset
  1344
            # retry "once per directory" per "dirstate.walk" which
3bcfea777efc icasefs: rewrite comment to explain situtation precisely
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15719
diff changeset
  1345
            # may take place for each patches of "hg qpush", for example
23097
30124c40d11f util.fspath: use a dict rather than a linear scan for lookups
Siddharth Agarwal <sid0@fb.com>
parents: 23076
diff changeset
  1346
            _fspathcache[dir] = contents = _makefspathcacheentry(dir)
30124c40d11f util.fspath: use a dict rather than a linear scan for lookups
Siddharth Agarwal <sid0@fb.com>
parents: 23076
diff changeset
  1347
            found = contents.get(part)
15709
a1f4bd47d18e icasefs: retry directory scan once for already invalidated cache
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15674
diff changeset
  1348
a1f4bd47d18e icasefs: retry directory scan once for already invalidated cache
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15674
diff changeset
  1349
        result.append(found or part)
15669
390bcd01775a icasefs: use util.normcase() instead of lower() or os.path.normcase in fspath
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15667
diff changeset
  1350
        dir = os.path.join(dir, part)
6676
33045179d079 Add a new function, fspath
Paul Moore <p.f.moore@gmail.com>
parents: 6595
diff changeset
  1351
33045179d079 Add a new function, fspath
Paul Moore <p.f.moore@gmail.com>
parents: 6595
diff changeset
  1352
    return ''.join(result)
33045179d079 Add a new function, fspath
Paul Moore <p.f.moore@gmail.com>
parents: 6595
diff changeset
  1353
12938
bf826c0b9537 opener: check hardlink count reporting (issue1866)
Adrian Buehlmann <adrian@cadifra.com>
parents: 12927
diff changeset
  1354
def checknlink(testfile):
bf826c0b9537 opener: check hardlink count reporting (issue1866)
Adrian Buehlmann <adrian@cadifra.com>
parents: 12927
diff changeset
  1355
    '''check whether hardlink count reporting works properly'''
bf826c0b9537 opener: check hardlink count reporting (issue1866)
Adrian Buehlmann <adrian@cadifra.com>
parents: 12927
diff changeset
  1356
13204
5b83ab614dab checknlink: use two testfiles (issue2543)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13188
diff changeset
  1357
    # testfile may be open, so we need a separate file for checking to
5b83ab614dab checknlink: use two testfiles (issue2543)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13188
diff changeset
  1358
    # work around issue2543 (or testfile may get lost on Samba shares)
5b83ab614dab checknlink: use two testfiles (issue2543)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13188
diff changeset
  1359
    f1 = testfile + ".hgtmp1"
5b83ab614dab checknlink: use two testfiles (issue2543)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13188
diff changeset
  1360
    if os.path.lexists(f1):
5b83ab614dab checknlink: use two testfiles (issue2543)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13188
diff changeset
  1361
        return False
12938
bf826c0b9537 opener: check hardlink count reporting (issue1866)
Adrian Buehlmann <adrian@cadifra.com>
parents: 12927
diff changeset
  1362
    try:
13204
5b83ab614dab checknlink: use two testfiles (issue2543)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13188
diff changeset
  1363
        posixfile(f1, 'w').close()
5b83ab614dab checknlink: use two testfiles (issue2543)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13188
diff changeset
  1364
    except IOError:
29832
bac1829ec31f util: checknlink should remove file it creates if an exception occurs
Tony Tung <tonytung@merly.org>
parents: 29828
diff changeset
  1365
        try:
bac1829ec31f util: checknlink should remove file it creates if an exception occurs
Tony Tung <tonytung@merly.org>
parents: 29828
diff changeset
  1366
            os.unlink(f1)
bac1829ec31f util: checknlink should remove file it creates if an exception occurs
Tony Tung <tonytung@merly.org>
parents: 29828
diff changeset
  1367
        except OSError:
bac1829ec31f util: checknlink should remove file it creates if an exception occurs
Tony Tung <tonytung@merly.org>
parents: 29828
diff changeset
  1368
            pass
12938
bf826c0b9537 opener: check hardlink count reporting (issue1866)
Adrian Buehlmann <adrian@cadifra.com>
parents: 12927
diff changeset
  1369
        return False
bf826c0b9537 opener: check hardlink count reporting (issue1866)
Adrian Buehlmann <adrian@cadifra.com>
parents: 12927
diff changeset
  1370
13204
5b83ab614dab checknlink: use two testfiles (issue2543)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13188
diff changeset
  1371
    f2 = testfile + ".hgtmp2"
5b83ab614dab checknlink: use two testfiles (issue2543)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13188
diff changeset
  1372
    fd = None
12938
bf826c0b9537 opener: check hardlink count reporting (issue1866)
Adrian Buehlmann <adrian@cadifra.com>
parents: 12927
diff changeset
  1373
    try:
25088
754df8e932d3 util: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 24902
diff changeset
  1374
        oslink(f1, f2)
12938
bf826c0b9537 opener: check hardlink count reporting (issue1866)
Adrian Buehlmann <adrian@cadifra.com>
parents: 12927
diff changeset
  1375
        # nlinks() may behave differently for files on Windows shares if
bf826c0b9537 opener: check hardlink count reporting (issue1866)
Adrian Buehlmann <adrian@cadifra.com>
parents: 12927
diff changeset
  1376
        # the file is open.
13342
2dc7a2a96cfd opener: use posixfile to hold file open when calling nlinks()
Adrian Buehlmann <adrian@cadifra.com>
parents: 13316
diff changeset
  1377
        fd = posixfile(f2)
13204
5b83ab614dab checknlink: use two testfiles (issue2543)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13188
diff changeset
  1378
        return nlinks(f2) > 1
25088
754df8e932d3 util: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 24902
diff changeset
  1379
    except OSError:
754df8e932d3 util: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 24902
diff changeset
  1380
        return False
12938
bf826c0b9537 opener: check hardlink count reporting (issue1866)
Adrian Buehlmann <adrian@cadifra.com>
parents: 12927
diff changeset
  1381
    finally:
13204
5b83ab614dab checknlink: use two testfiles (issue2543)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13188
diff changeset
  1382
        if fd is not None:
5b83ab614dab checknlink: use two testfiles (issue2543)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13188
diff changeset
  1383
            fd.close()
5b83ab614dab checknlink: use two testfiles (issue2543)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13188
diff changeset
  1384
        for f in (f1, f2):
5b83ab614dab checknlink: use two testfiles (issue2543)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13188
diff changeset
  1385
            try:
5b83ab614dab checknlink: use two testfiles (issue2543)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13188
diff changeset
  1386
                os.unlink(f)
5b83ab614dab checknlink: use two testfiles (issue2543)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13188
diff changeset
  1387
            except OSError:
5b83ab614dab checknlink: use two testfiles (issue2543)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13188
diff changeset
  1388
                pass
12938
bf826c0b9537 opener: check hardlink count reporting (issue1866)
Adrian Buehlmann <adrian@cadifra.com>
parents: 12927
diff changeset
  1389
5843
83c354c4d529 Add endswithsep() and use it instead of using os.sep and os.altsep directly.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents: 5802
diff changeset
  1390
def endswithsep(path):
83c354c4d529 Add endswithsep() and use it instead of using os.sep and os.altsep directly.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents: 5802
diff changeset
  1391
    '''Check path ends with os.sep or os.altsep.'''
30613
1112ff99d965 py3: replace os.sep with pycompat.ossep (part 1 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30536
diff changeset
  1392
    return (path.endswith(pycompat.ossep)
30625
bcf4a975f93d py3: replace os.altsep with pycompat.altsep
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30613
diff changeset
  1393
            or pycompat.osaltsep and path.endswith(pycompat.osaltsep))
5843
83c354c4d529 Add endswithsep() and use it instead of using os.sep and os.altsep directly.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents: 5802
diff changeset
  1394
5844
07d8eb78dd68 Add util.splitpath() and use it instead of using os.sep directly.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents: 5843
diff changeset
  1395
def splitpath(path):
07d8eb78dd68 Add util.splitpath() and use it instead of using os.sep directly.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents: 5843
diff changeset
  1396
    '''Split path by os.sep.
07d8eb78dd68 Add util.splitpath() and use it instead of using os.sep directly.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents: 5843
diff changeset
  1397
    Note that this function does not use os.altsep because this is
07d8eb78dd68 Add util.splitpath() and use it instead of using os.sep directly.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents: 5843
diff changeset
  1398
    an alternative of simple "xxx.split(os.sep)".
07d8eb78dd68 Add util.splitpath() and use it instead of using os.sep directly.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents: 5843
diff changeset
  1399
    It is recommended to use os.path.normpath() before using this
07d8eb78dd68 Add util.splitpath() and use it instead of using os.sep directly.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents: 5843
diff changeset
  1400
    function if need.'''
30613
1112ff99d965 py3: replace os.sep with pycompat.ossep (part 1 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30536
diff changeset
  1401
    return path.split(pycompat.ossep)
5844
07d8eb78dd68 Add util.splitpath() and use it instead of using os.sep directly.
Shun-ichi GOTO <shunichi.goto@gmail.com>
parents: 5843
diff changeset
  1402
6007
090b1a665901 filemerge: add config item for GUI tools
Matt Mackall <mpm@selenic.com>
parents: 6006
diff changeset
  1403
def gui():
090b1a665901 filemerge: add config item for GUI tools
Matt Mackall <mpm@selenic.com>
parents: 6006
diff changeset
  1404
    '''Are we running in a GUI?'''
30642
e995f00a9e9a py3: replace sys.platform with pycompat.sysplatform (part 2 of 2)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30639
diff changeset
  1405
    if pycompat.sysplatform == 'darwin':
30637
344e68882cd3 py3: replace os.environ with encoding.environ (part 4 of 5)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30625
diff changeset
  1406
        if 'SSH_CONNECTION' in encoding.environ:
13734
16118b4859a1 util: add Mac-specific check whether we're in a GUI session (issue2553)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13439
diff changeset
  1407
            # handle SSH access to a box where the user is logged in
16118b4859a1 util: add Mac-specific check whether we're in a GUI session (issue2553)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13439
diff changeset
  1408
            return False
16118b4859a1 util: add Mac-specific check whether we're in a GUI session (issue2553)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13439
diff changeset
  1409
        elif getattr(osutil, 'isgui', None):
16118b4859a1 util: add Mac-specific check whether we're in a GUI session (issue2553)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13439
diff changeset
  1410
            # check if a CoreGraphics session is available
16118b4859a1 util: add Mac-specific check whether we're in a GUI session (issue2553)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13439
diff changeset
  1411
            return osutil.isgui()
16118b4859a1 util: add Mac-specific check whether we're in a GUI session (issue2553)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13439
diff changeset
  1412
        else:
16118b4859a1 util: add Mac-specific check whether we're in a GUI session (issue2553)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13439
diff changeset
  1413
            # pure build; use a safe default
16118b4859a1 util: add Mac-specific check whether we're in a GUI session (issue2553)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13439
diff changeset
  1414
            return True
16118b4859a1 util: add Mac-specific check whether we're in a GUI session (issue2553)
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13439
diff changeset
  1415
    else:
30639
d524c88511a7 py3: replace os.name with pycompat.osname (part 1 of 2)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30637
diff changeset
  1416
        return pycompat.osname == "nt" or encoding.environ.get("DISPLAY")
6007
090b1a665901 filemerge: add config item for GUI tools
Matt Mackall <mpm@selenic.com>
parents: 6006
diff changeset
  1417
6062
3c3b126e5619 Make files in .hg inherit the permissions from .hg/store
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 6007
diff changeset
  1418
def mktempcopy(name, emptyok=False, createmode=None):
4827
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1419
    """Create a temporary file with the same contents from name
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1420
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1421
    The permission bits are copied from the original file.
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1422
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1423
    If the temporary file is going to be truncated immediately, you
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1424
    can use emptyok=True as an optimization.
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1425
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1426
    Returns the name of the temporary file.
2176
9b42304d9896 fix file handling bugs on windows.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2117
diff changeset
  1427
    """
4827
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1428
    d, fn = os.path.split(name)
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1429
    fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1430
    os.close(fd)
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1431
    # Temporary files are created with mode 0600, which is usually not
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1432
    # what we want.  If the original file already exists, just copy
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1433
    # its mode.  Otherwise, manually obey umask.
15010
c3114acd8ea2 util: factor new function copymode out of mktempcopy
Adrian Buehlmann <adrian@cadifra.com>
parents: 14999
diff changeset
  1434
    copymode(name, temp, createmode)
4827
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1435
    if emptyok:
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1436
        return temp
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1437
    try:
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1438
        try:
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1439
            ifp = posixfile(name, "rb")
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25420
diff changeset
  1440
        except IOError as inst:
4827
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1441
            if inst.errno == errno.ENOENT:
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1442
                return temp
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1443
            if not getattr(inst, 'filename', None):
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1444
                inst.filename = name
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1445
            raise
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1446
        ofp = posixfile(temp, "wb")
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1447
        for chunk in filechunkiter(ifp):
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1448
            ofp.write(chunk)
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1449
        ifp.close()
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1450
        ofp.close()
16705
c2d9ef43ff6c check-code: ignore naked excepts with a "re-raise" comment
Brodie Rao <brodie@sf.io>
parents: 16703
diff changeset
  1451
    except: # re-raises
4827
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1452
        try: os.unlink(temp)
16703
7292a4618f46 cleanup: replace more naked excepts with more specific ones
Brodie Rao <brodie@sf.io>
parents: 16688
diff changeset
  1453
        except OSError: pass
4827
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1454
        raise
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1455
    return temp
2176
9b42304d9896 fix file handling bugs on windows.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2117
diff changeset
  1456
29200
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1457
class filestat(object):
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1458
    """help to exactly detect change of a file
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1459
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1460
    'stat' attribute is result of 'os.stat()' if specified 'path'
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1461
    exists. Otherwise, it is None. This can avoid preparative
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1462
    'exists()' examination on client side of this class.
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1463
    """
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1464
    def __init__(self, path):
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1465
        try:
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1466
            self.stat = os.stat(path)
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1467
        except OSError as err:
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1468
            if err.errno != errno.ENOENT:
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1469
                raise
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1470
            self.stat = None
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1471
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1472
    __hash__ = object.__hash__
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1473
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1474
    def __eq__(self, old):
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1475
        try:
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1476
            # if ambiguity between stat of new and old file is
30332
318a24b52eeb spelling: fixes of non-dictionary words
Mads Kiilerich <madski@unity3d.com>
parents: 30329
diff changeset
  1477
            # avoided, comparison of size, ctime and mtime is enough
29200
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1478
            # to exactly detect change of a file regardless of platform
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1479
            return (self.stat.st_size == old.stat.st_size and
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1480
                    self.stat.st_ctime == old.stat.st_ctime and
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1481
                    self.stat.st_mtime == old.stat.st_mtime)
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1482
        except AttributeError:
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1483
            return False
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1484
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1485
    def isambig(self, old):
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1486
        """Examine whether new (= self) stat is ambiguous against old one
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1487
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1488
        "S[N]" below means stat of a file at N-th change:
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1489
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1490
        - S[n-1].ctime  < S[n].ctime: can detect change of a file
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1491
        - S[n-1].ctime == S[n].ctime
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1492
          - S[n-1].ctime  < S[n].mtime: means natural advancing (*1)
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1493
          - S[n-1].ctime == S[n].mtime: is ambiguous (*2)
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1494
          - S[n-1].ctime  > S[n].mtime: never occurs naturally (don't care)
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1495
        - S[n-1].ctime  > S[n].ctime: never occurs naturally (don't care)
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1496
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1497
        Case (*2) above means that a file was changed twice or more at
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1498
        same time in sec (= S[n-1].ctime), and comparison of timestamp
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1499
        is ambiguous.
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1500
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1501
        Base idea to avoid such ambiguity is "advance mtime 1 sec, if
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1502
        timestamp is ambiguous".
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1503
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1504
        But advancing mtime only in case (*2) doesn't work as
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1505
        expected, because naturally advanced S[n].mtime in case (*1)
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1506
        might be equal to manually advanced S[n-1 or earlier].mtime.
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1507
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1508
        Therefore, all "S[n-1].ctime == S[n].ctime" cases should be
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1509
        treated as ambiguous regardless of mtime, to avoid overlooking
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1510
        by confliction between such mtime.
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1511
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1512
        Advancing mtime "if isambig(oldstat)" ensures "S[n-1].mtime !=
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1513
        S[n].mtime", even if size of a file isn't changed.
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1514
        """
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1515
        try:
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1516
            return (self.stat.st_ctime == old.stat.st_ctime)
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1517
        except AttributeError:
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1518
            return False
ca4065028e00 util: add filestat class to detect ambiguity of file stat
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29017
diff changeset
  1519
30319
b496a464399c util: add utility function to skip avoiding file stat ambiguity if EPERM
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 30181
diff changeset
  1520
    def avoidambig(self, path, old):
b496a464399c util: add utility function to skip avoiding file stat ambiguity if EPERM
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 30181
diff changeset
  1521
        """Change file stat of specified path to avoid ambiguity
b496a464399c util: add utility function to skip avoiding file stat ambiguity if EPERM
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 30181
diff changeset
  1522
b496a464399c util: add utility function to skip avoiding file stat ambiguity if EPERM
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 30181
diff changeset
  1523
        'old' should be previous filestat of 'path'.
b496a464399c util: add utility function to skip avoiding file stat ambiguity if EPERM
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 30181
diff changeset
  1524
b496a464399c util: add utility function to skip avoiding file stat ambiguity if EPERM
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 30181
diff changeset
  1525
        This skips avoiding ambiguity, if a process doesn't have
b496a464399c util: add utility function to skip avoiding file stat ambiguity if EPERM
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 30181
diff changeset
  1526
        appropriate privileges for 'path'.
b496a464399c util: add utility function to skip avoiding file stat ambiguity if EPERM
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 30181
diff changeset
  1527
        """
b496a464399c util: add utility function to skip avoiding file stat ambiguity if EPERM
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 30181
diff changeset
  1528
        advanced = (old.stat.st_mtime + 1) & 0x7fffffff
b496a464399c util: add utility function to skip avoiding file stat ambiguity if EPERM
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 30181
diff changeset
  1529
        try:
b496a464399c util: add utility function to skip avoiding file stat ambiguity if EPERM
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 30181
diff changeset
  1530
            os.utime(path, (advanced, advanced))
b496a464399c util: add utility function to skip avoiding file stat ambiguity if EPERM
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 30181
diff changeset
  1531
        except OSError as inst:
b496a464399c util: add utility function to skip avoiding file stat ambiguity if EPERM
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 30181
diff changeset
  1532
            if inst.errno == errno.EPERM:
b496a464399c util: add utility function to skip avoiding file stat ambiguity if EPERM
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 30181
diff changeset
  1533
                # utime() on the file created by another user causes EPERM,
b496a464399c util: add utility function to skip avoiding file stat ambiguity if EPERM
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 30181
diff changeset
  1534
                # if a process doesn't have appropriate privileges
b496a464399c util: add utility function to skip avoiding file stat ambiguity if EPERM
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 30181
diff changeset
  1535
                return
b496a464399c util: add utility function to skip avoiding file stat ambiguity if EPERM
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 30181
diff changeset
  1536
            raise
b496a464399c util: add utility function to skip avoiding file stat ambiguity if EPERM
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 30181
diff changeset
  1537
29298
82f6193ff2bc util: add __ne__ to filestat class for consistency
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29261
diff changeset
  1538
    def __ne__(self, other):
82f6193ff2bc util: add __ne__ to filestat class for consistency
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29261
diff changeset
  1539
        return not self == other
82f6193ff2bc util: add __ne__ to filestat class for consistency
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29261
diff changeset
  1540
8778
c5f36402daad use new style classes
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 8631
diff changeset
  1541
class atomictempfile(object):
17424
e7cfe3587ea4 fix trivial spelling errors
Mads Kiilerich <mads@kiilerich.com>
parents: 17391
diff changeset
  1542
    '''writable file object that atomically updates a file
4827
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1543
14008
da65edcac72a atomictempfile: rewrite docstring to clarify rename() vs. close().
Greg Ward <greg@gerg.ca>
parents: 14007
diff changeset
  1544
    All writes will go to a temporary copy of the original file. Call
15057
774da7121fc9 atomictempfile: make close() consistent with other file-like objects.
Greg Ward <greg@gerg.ca>
parents: 15050
diff changeset
  1545
    close() when you are done writing, and atomictempfile will rename
774da7121fc9 atomictempfile: make close() consistent with other file-like objects.
Greg Ward <greg@gerg.ca>
parents: 15050
diff changeset
  1546
    the temporary copy to the original name, making the changes
774da7121fc9 atomictempfile: make close() consistent with other file-like objects.
Greg Ward <greg@gerg.ca>
parents: 15050
diff changeset
  1547
    visible. If the object is destroyed without being closed, all your
774da7121fc9 atomictempfile: make close() consistent with other file-like objects.
Greg Ward <greg@gerg.ca>
parents: 15050
diff changeset
  1548
    writes are discarded.
29367
4e6e280e238f doc: describe detail about checkambig optional argument
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29342
diff changeset
  1549
4e6e280e238f doc: describe detail about checkambig optional argument
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29342
diff changeset
  1550
    checkambig argument of constructor is used with filestat, and is
4e6e280e238f doc: describe detail about checkambig optional argument
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29342
diff changeset
  1551
    useful only if target file is guarded by any lock (e.g. repo.lock
4e6e280e238f doc: describe detail about checkambig optional argument
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29342
diff changeset
  1552
    or repo.wlock).
14008
da65edcac72a atomictempfile: rewrite docstring to clarify rename() vs. close().
Greg Ward <greg@gerg.ca>
parents: 14007
diff changeset
  1553
    '''
29201
a109bf7e0dc2 util: make atomictempfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29200
diff changeset
  1554
    def __init__(self, name, mode='w+b', createmode=None, checkambig=False):
14007
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents: 14004
diff changeset
  1555
        self.__name = name      # permanent name
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents: 14004
diff changeset
  1556
        self._tempname = mktempcopy(name, emptyok=('w' in mode),
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents: 14004
diff changeset
  1557
                                    createmode=createmode)
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents: 14004
diff changeset
  1558
        self._fp = posixfile(self._tempname, mode)
29201
a109bf7e0dc2 util: make atomictempfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29200
diff changeset
  1559
        self._checkambig = checkambig
8327
aa25be1c2889 atomictempfile: delegate to posixfile instead of inheriting from it
Bryan O'Sullivan <bos@serpentine.com>
parents: 8312
diff changeset
  1560
14007
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents: 14004
diff changeset
  1561
        # delegated methods
29393
50269a4dce61 atomictempfile: add read to the supported file operations
Martijn Pieters <mjpieters@fb.com>
parents: 29367
diff changeset
  1562
        self.read = self._fp.read
14007
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents: 14004
diff changeset
  1563
        self.write = self._fp.write
17237
e73128535105 util: delegate seek and tell methods of atomictempfile
Bryan O'Sullivan <bryano@fb.com>
parents: 17203
diff changeset
  1564
        self.seek = self._fp.seek
e73128535105 util: delegate seek and tell methods of atomictempfile
Bryan O'Sullivan <bryano@fb.com>
parents: 17203
diff changeset
  1565
        self.tell = self._fp.tell
14007
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents: 14004
diff changeset
  1566
        self.fileno = self._fp.fileno
4827
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1567
15057
774da7121fc9 atomictempfile: make close() consistent with other file-like objects.
Greg Ward <greg@gerg.ca>
parents: 15050
diff changeset
  1568
    def close(self):
8785
7a9151bc5b37 atomictempfile: fix exception in __del__ if mktempcopy fails (self._fp is None)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 8778
diff changeset
  1569
        if not self._fp.closed:
8327
aa25be1c2889 atomictempfile: delegate to posixfile instead of inheriting from it
Bryan O'Sullivan <bos@serpentine.com>
parents: 8312
diff changeset
  1570
            self._fp.close()
29201
a109bf7e0dc2 util: make atomictempfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29200
diff changeset
  1571
            filename = localpath(self.__name)
a109bf7e0dc2 util: make atomictempfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29200
diff changeset
  1572
            oldstat = self._checkambig and filestat(filename)
a109bf7e0dc2 util: make atomictempfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29200
diff changeset
  1573
            if oldstat and oldstat.stat:
a109bf7e0dc2 util: make atomictempfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29200
diff changeset
  1574
                rename(self._tempname, filename)
a109bf7e0dc2 util: make atomictempfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29200
diff changeset
  1575
                newstat = filestat(filename)
a109bf7e0dc2 util: make atomictempfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29200
diff changeset
  1576
                if newstat.isambig(oldstat):
a109bf7e0dc2 util: make atomictempfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29200
diff changeset
  1577
                    # stat of changed file is ambiguous to original one
a109bf7e0dc2 util: make atomictempfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29200
diff changeset
  1578
                    advanced = (oldstat.stat.st_mtime + 1) & 0x7fffffff
a109bf7e0dc2 util: make atomictempfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29200
diff changeset
  1579
                    os.utime(filename, (advanced, advanced))
a109bf7e0dc2 util: make atomictempfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29200
diff changeset
  1580
            else:
a109bf7e0dc2 util: make atomictempfile avoid ambiguity of file stat if needed
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 29200
diff changeset
  1581
                rename(self._tempname, filename)
4827
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1582
15057
774da7121fc9 atomictempfile: make close() consistent with other file-like objects.
Greg Ward <greg@gerg.ca>
parents: 15050
diff changeset
  1583
    def discard(self):
8785
7a9151bc5b37 atomictempfile: fix exception in __del__ if mktempcopy fails (self._fp is None)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 8778
diff changeset
  1584
        if not self._fp.closed:
4827
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1585
            try:
14007
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents: 14004
diff changeset
  1586
                os.unlink(self._tempname)
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents: 14004
diff changeset
  1587
            except OSError:
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents: 14004
diff changeset
  1588
                pass
8327
aa25be1c2889 atomictempfile: delegate to posixfile instead of inheriting from it
Bryan O'Sullivan <bos@serpentine.com>
parents: 8312
diff changeset
  1589
            self._fp.close()
4827
89defeae88f3 turn util.opener into a class
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4803
diff changeset
  1590
13098
f7d6750dcd01 util: make atomicfiles closable
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13072
diff changeset
  1591
    def __del__(self):
14968
b7dbe957585c util: use safehasattr or getattr instead of hasattr
Augie Fackler <durin42@gmail.com>
parents: 14942
diff changeset
  1592
        if safehasattr(self, '_fp'): # constructor actually did something
15057
774da7121fc9 atomictempfile: make close() consistent with other file-like objects.
Greg Ward <greg@gerg.ca>
parents: 15050
diff changeset
  1593
            self.discard()
13098
f7d6750dcd01 util: make atomicfiles closable
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13072
diff changeset
  1594
29394
6d96658a22b0 atomictempfile: add context manager support
Martijn Pieters <mjpieters@fb.com>
parents: 29393
diff changeset
  1595
    def __enter__(self):
6d96658a22b0 atomictempfile: add context manager support
Martijn Pieters <mjpieters@fb.com>
parents: 29393
diff changeset
  1596
        return self
6d96658a22b0 atomictempfile: add context manager support
Martijn Pieters <mjpieters@fb.com>
parents: 29393
diff changeset
  1597
6d96658a22b0 atomictempfile: add context manager support
Martijn Pieters <mjpieters@fb.com>
parents: 29393
diff changeset
  1598
    def __exit__(self, exctype, excvalue, traceback):
6d96658a22b0 atomictempfile: add context manager support
Martijn Pieters <mjpieters@fb.com>
parents: 29393
diff changeset
  1599
        if exctype is not None:
6d96658a22b0 atomictempfile: add context manager support
Martijn Pieters <mjpieters@fb.com>
parents: 29393
diff changeset
  1600
            self.discard()
6d96658a22b0 atomictempfile: add context manager support
Martijn Pieters <mjpieters@fb.com>
parents: 29393
diff changeset
  1601
        else:
6d96658a22b0 atomictempfile: add context manager support
Martijn Pieters <mjpieters@fb.com>
parents: 29393
diff changeset
  1602
            self.close()
6d96658a22b0 atomictempfile: add context manager support
Martijn Pieters <mjpieters@fb.com>
parents: 29393
diff changeset
  1603
18938
e22107cff6bf util: add notindexed optional parameter to makedirs function
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 18930
diff changeset
  1604
def makedirs(name, mode=None, notindexed=False):
29017
07be86828e79 util: fix race in makedirs()
Adam Simpkins <simpkins@fb.com>
parents: 28883
diff changeset
  1605
    """recursive directory creation with parent mode inheritance
07be86828e79 util: fix race in makedirs()
Adam Simpkins <simpkins@fb.com>
parents: 28883
diff changeset
  1606
07be86828e79 util: fix race in makedirs()
Adam Simpkins <simpkins@fb.com>
parents: 28883
diff changeset
  1607
    Newly created directories are marked as "not to be indexed by
07be86828e79 util: fix race in makedirs()
Adam Simpkins <simpkins@fb.com>
parents: 28883
diff changeset
  1608
    the content indexing service", if ``notindexed`` is specified
07be86828e79 util: fix race in makedirs()
Adam Simpkins <simpkins@fb.com>
parents: 28883
diff changeset
  1609
    for "write" mode access.
07be86828e79 util: fix race in makedirs()
Adam Simpkins <simpkins@fb.com>
parents: 28883
diff changeset
  1610
    """
6062
3c3b126e5619 Make files in .hg inherit the permissions from .hg/store
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 6007
diff changeset
  1611
    try:
18938
e22107cff6bf util: add notindexed optional parameter to makedirs function
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 18930
diff changeset
  1612
        makedir(name, notindexed)
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25420
diff changeset
  1613
    except OSError as err:
6062
3c3b126e5619 Make files in .hg inherit the permissions from .hg/store
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 6007
diff changeset
  1614
        if err.errno == errno.EEXIST:
3c3b126e5619 Make files in .hg inherit the permissions from .hg/store
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 6007
diff changeset
  1615
            return
15058
81f33be0ea79 util: postpone and reorder parent calculation in makedirs
Adrian Buehlmann <adrian@cadifra.com>
parents: 15057
diff changeset
  1616
        if err.errno != errno.ENOENT or not name:
81f33be0ea79 util: postpone and reorder parent calculation in makedirs
Adrian Buehlmann <adrian@cadifra.com>
parents: 15057
diff changeset
  1617
            raise
81f33be0ea79 util: postpone and reorder parent calculation in makedirs
Adrian Buehlmann <adrian@cadifra.com>
parents: 15057
diff changeset
  1618
        parent = os.path.dirname(os.path.abspath(name))
81f33be0ea79 util: postpone and reorder parent calculation in makedirs
Adrian Buehlmann <adrian@cadifra.com>
parents: 15057
diff changeset
  1619
        if parent == name:
6062
3c3b126e5619 Make files in .hg inherit the permissions from .hg/store
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 6007
diff changeset
  1620
            raise
18938
e22107cff6bf util: add notindexed optional parameter to makedirs function
Angel Ezquerra <angel.ezquerra@gmail.com>
parents: 18930
diff changeset
  1621
        makedirs(parent, mode, notindexed)
29017
07be86828e79 util: fix race in makedirs()
Adam Simpkins <simpkins@fb.com>
parents: 28883
diff changeset
  1622
        try:
07be86828e79 util: fix race in makedirs()
Adam Simpkins <simpkins@fb.com>
parents: 28883
diff changeset
  1623
            makedir(name, notindexed)
07be86828e79 util: fix race in makedirs()
Adam Simpkins <simpkins@fb.com>
parents: 28883
diff changeset
  1624
        except OSError as err:
07be86828e79 util: fix race in makedirs()
Adam Simpkins <simpkins@fb.com>
parents: 28883
diff changeset
  1625
            # Catch EEXIST to handle races
07be86828e79 util: fix race in makedirs()
Adam Simpkins <simpkins@fb.com>
parents: 28883
diff changeset
  1626
            if err.errno == errno.EEXIST:
07be86828e79 util: fix race in makedirs()
Adam Simpkins <simpkins@fb.com>
parents: 28883
diff changeset
  1627
                return
07be86828e79 util: fix race in makedirs()
Adam Simpkins <simpkins@fb.com>
parents: 28883
diff changeset
  1628
            raise
18678
423eee0b0b14 util: make ensuredirs safer against races
Bryan O'Sullivan <bryano@fb.com>
parents: 18668
diff changeset
  1629
    if mode is not None:
423eee0b0b14 util: make ensuredirs safer against races
Bryan O'Sullivan <bryano@fb.com>
parents: 18668
diff changeset
  1630
        os.chmod(name, mode)
18668
4034b8d551b1 scmutil: create directories in a race-safe way during update
Bryan O'Sullivan <bryano@fb.com>
parents: 18614
diff changeset
  1631
14099
0824a0a3cefc util: add readfile() & writefile() helper functions
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 14077
diff changeset
  1632
def readfile(path):
27778
4d10600c3f08 util: simplify file I/O functions using context managers
Bryan O'Sullivan <bryano@fb.com>
parents: 27768
diff changeset
  1633
    with open(path, 'rb') as fp:
14100
3e9e02a41dfb util: really drop size from readfile
Matt Mackall <mpm@selenic.com>
parents: 14099
diff changeset
  1634
        return fp.read()
14099
0824a0a3cefc util: add readfile() & writefile() helper functions
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 14077
diff changeset
  1635
14167
0e4753807c93 util & scmutil: adapt read/write helpers as request by mpm
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 14147
diff changeset
  1636
def writefile(path, text):
27778
4d10600c3f08 util: simplify file I/O functions using context managers
Bryan O'Sullivan <bryano@fb.com>
parents: 27768
diff changeset
  1637
    with open(path, 'wb') as fp:
14167
0e4753807c93 util & scmutil: adapt read/write helpers as request by mpm
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 14147
diff changeset
  1638
        fp.write(text)
0e4753807c93 util & scmutil: adapt read/write helpers as request by mpm
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 14147
diff changeset
  1639
0e4753807c93 util & scmutil: adapt read/write helpers as request by mpm
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 14147
diff changeset
  1640
def appendfile(path, text):
27778
4d10600c3f08 util: simplify file I/O functions using context managers
Bryan O'Sullivan <bryano@fb.com>
parents: 27768
diff changeset
  1641
    with open(path, 'ab') as fp:
14099
0824a0a3cefc util: add readfile() & writefile() helper functions
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 14077
diff changeset
  1642
        fp.write(text)
0824a0a3cefc util: add readfile() & writefile() helper functions
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 14077
diff changeset
  1643
1199
78ceaf83f28f Created a class in util called chunkbuffer that buffers reads from an
Eric Hopper <hopper@omnifarious.org>
parents: 1169
diff changeset
  1644
class chunkbuffer(object):
78ceaf83f28f Created a class in util called chunkbuffer that buffers reads from an
Eric Hopper <hopper@omnifarious.org>
parents: 1169
diff changeset
  1645
    """Allow arbitrary sized chunks of data to be efficiently read from an
78ceaf83f28f Created a class in util called chunkbuffer that buffers reads from an
Eric Hopper <hopper@omnifarious.org>
parents: 1169
diff changeset
  1646
    iterator over chunks of arbitrary size."""
1200
333de1d53846 Minor cleanups.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1199
diff changeset
  1647
5446
fa836e050c50 chunkbuffer: removed unused method and arg
Matt Mackall <mpm@selenic.com>
parents: 5420
diff changeset
  1648
    def __init__(self, in_iter):
1199
78ceaf83f28f Created a class in util called chunkbuffer that buffers reads from an
Eric Hopper <hopper@omnifarious.org>
parents: 1169
diff changeset
  1649
        """in_iter is the iterator that's iterating over the input chunks.
78ceaf83f28f Created a class in util called chunkbuffer that buffers reads from an
Eric Hopper <hopper@omnifarious.org>
parents: 1169
diff changeset
  1650
        targetsize is how big a buffer to try to maintain."""
11670
1b3b843e1100 chunkbuffer: split big strings directly in chunkbuffer
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 11668
diff changeset
  1651
        def splitbig(chunks):
1b3b843e1100 chunkbuffer: split big strings directly in chunkbuffer
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 11668
diff changeset
  1652
            for chunk in chunks:
1b3b843e1100 chunkbuffer: split big strings directly in chunkbuffer
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 11668
diff changeset
  1653
                if len(chunk) > 2**20:
1b3b843e1100 chunkbuffer: split big strings directly in chunkbuffer
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 11668
diff changeset
  1654
                    pos = 0
1b3b843e1100 chunkbuffer: split big strings directly in chunkbuffer
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 11668
diff changeset
  1655
                    while pos < len(chunk):
1b3b843e1100 chunkbuffer: split big strings directly in chunkbuffer
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 11668
diff changeset
  1656
                        end = pos + 2 ** 18
1b3b843e1100 chunkbuffer: split big strings directly in chunkbuffer
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 11668
diff changeset
  1657
                        yield chunk[pos:end]
1b3b843e1100 chunkbuffer: split big strings directly in chunkbuffer
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 11668
diff changeset
  1658
                        pos = end
1b3b843e1100 chunkbuffer: split big strings directly in chunkbuffer
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 11668
diff changeset
  1659
                else:
1b3b843e1100 chunkbuffer: split big strings directly in chunkbuffer
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 11668
diff changeset
  1660
                    yield chunk
1b3b843e1100 chunkbuffer: split big strings directly in chunkbuffer
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 11668
diff changeset
  1661
        self.iter = splitbig(in_iter)
25113
0ca8410ea345 util: drop alias for collections.deque
Martin von Zweigbergk <martinvonz@google.com>
parents: 25112
diff changeset
  1662
        self._queue = collections.deque()
26480
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1663
        self._chunkoffset = 0
1200
333de1d53846 Minor cleanups.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1199
diff changeset
  1664
21018
c848bfd02366 util: support None size in chunkbuffer.read()
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20835
diff changeset
  1665
    def read(self, l=None):
1200
333de1d53846 Minor cleanups.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1199
diff changeset
  1666
        """Read L bytes of data from the iterator of chunks of data.
21018
c848bfd02366 util: support None size in chunkbuffer.read()
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20835
diff changeset
  1667
        Returns less than L bytes if the iterator runs dry.
c848bfd02366 util: support None size in chunkbuffer.read()
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20835
diff changeset
  1668
23139
e53f6b72a0e4 spelling: fixes from proofreading of spell checker issues
Mads Kiilerich <madski@unity3d.com>
parents: 23097
diff changeset
  1669
        If size parameter is omitted, read everything"""
26478
a3f7e5461dbd util.chunkbuffer: special case reading everything
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26450
diff changeset
  1670
        if l is None:
a3f7e5461dbd util.chunkbuffer: special case reading everything
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26450
diff changeset
  1671
            return ''.join(self.iter)
a3f7e5461dbd util.chunkbuffer: special case reading everything
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26450
diff changeset
  1672
11758
a79214972da2 chunkbuffer: use += rather than cStringIO to reduce memory footprint
Matt Mackall <mpm@selenic.com>
parents: 11469
diff changeset
  1673
        left = l
17962
4c29668ca316 util: make chunkbuffer non-quadratic on Windows
Matt Mackall <mpm@selenic.com>
parents: 17560
diff changeset
  1674
        buf = []
16873
37e081609828 util: simplify queue management in chunkbuffer
Bryan O'Sullivan <bryano@fb.com>
parents: 16834
diff changeset
  1675
        queue = self._queue
26478
a3f7e5461dbd util.chunkbuffer: special case reading everything
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26450
diff changeset
  1676
        while left > 0:
11758
a79214972da2 chunkbuffer: use += rather than cStringIO to reduce memory footprint
Matt Mackall <mpm@selenic.com>
parents: 11469
diff changeset
  1677
            # refill the queue
a79214972da2 chunkbuffer: use += rather than cStringIO to reduce memory footprint
Matt Mackall <mpm@selenic.com>
parents: 11469
diff changeset
  1678
            if not queue:
a79214972da2 chunkbuffer: use += rather than cStringIO to reduce memory footprint
Matt Mackall <mpm@selenic.com>
parents: 11469
diff changeset
  1679
                target = 2**18
a79214972da2 chunkbuffer: use += rather than cStringIO to reduce memory footprint
Matt Mackall <mpm@selenic.com>
parents: 11469
diff changeset
  1680
                for chunk in self.iter:
a79214972da2 chunkbuffer: use += rather than cStringIO to reduce memory footprint
Matt Mackall <mpm@selenic.com>
parents: 11469
diff changeset
  1681
                    queue.append(chunk)
a79214972da2 chunkbuffer: use += rather than cStringIO to reduce memory footprint
Matt Mackall <mpm@selenic.com>
parents: 11469
diff changeset
  1682
                    target -= len(chunk)
a79214972da2 chunkbuffer: use += rather than cStringIO to reduce memory footprint
Matt Mackall <mpm@selenic.com>
parents: 11469
diff changeset
  1683
                    if target <= 0:
a79214972da2 chunkbuffer: use += rather than cStringIO to reduce memory footprint
Matt Mackall <mpm@selenic.com>
parents: 11469
diff changeset
  1684
                        break
a79214972da2 chunkbuffer: use += rather than cStringIO to reduce memory footprint
Matt Mackall <mpm@selenic.com>
parents: 11469
diff changeset
  1685
                if not queue:
1199
78ceaf83f28f Created a class in util called chunkbuffer that buffers reads from an
Eric Hopper <hopper@omnifarious.org>
parents: 1169
diff changeset
  1686
                    break
11758
a79214972da2 chunkbuffer: use += rather than cStringIO to reduce memory footprint
Matt Mackall <mpm@selenic.com>
parents: 11469
diff changeset
  1687
26480
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1688
            # The easy way to do this would be to queue.popleft(), modify the
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1689
            # chunk (if necessary), then queue.appendleft(). However, for cases
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1690
            # where we read partial chunk content, this incurs 2 dequeue
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1691
            # mutations and creates a new str for the remaining chunk in the
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1692
            # queue. Our code below avoids this overhead.
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1693
26479
46143f31290e util.chunkbuffer: refactor chunk handling logic
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26478
diff changeset
  1694
            chunk = queue[0]
46143f31290e util.chunkbuffer: refactor chunk handling logic
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26478
diff changeset
  1695
            chunkl = len(chunk)
26480
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1696
            offset = self._chunkoffset
26479
46143f31290e util.chunkbuffer: refactor chunk handling logic
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26478
diff changeset
  1697
46143f31290e util.chunkbuffer: refactor chunk handling logic
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26478
diff changeset
  1698
            # Use full chunk.
26480
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1699
            if offset == 0 and left >= chunkl:
26479
46143f31290e util.chunkbuffer: refactor chunk handling logic
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26478
diff changeset
  1700
                left -= chunkl
46143f31290e util.chunkbuffer: refactor chunk handling logic
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26478
diff changeset
  1701
                queue.popleft()
46143f31290e util.chunkbuffer: refactor chunk handling logic
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26478
diff changeset
  1702
                buf.append(chunk)
26480
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1703
                # self._chunkoffset remains at 0.
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1704
                continue
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1705
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1706
            chunkremaining = chunkl - offset
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1707
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1708
            # Use all of unconsumed part of chunk.
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1709
            if left >= chunkremaining:
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1710
                left -= chunkremaining
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1711
                queue.popleft()
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1712
                # offset == 0 is enabled by block above, so this won't merely
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1713
                # copy via ``chunk[0:]``.
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1714
                buf.append(chunk[offset:])
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1715
                self._chunkoffset = 0
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1716
26479
46143f31290e util.chunkbuffer: refactor chunk handling logic
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26478
diff changeset
  1717
            # Partial chunk needed.
46143f31290e util.chunkbuffer: refactor chunk handling logic
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26478
diff changeset
  1718
            else:
26480
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1719
                buf.append(chunk[offset:offset + left])
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1720
                self._chunkoffset += left
6ae14d1ca3aa util.chunkbuffer: avoid extra mutations when reading partial chunks
Gregory Szorc <gregory.szorc@gmail.com>
parents: 26479
diff changeset
  1721
                left -= chunkremaining
11758
a79214972da2 chunkbuffer: use += rather than cStringIO to reduce memory footprint
Matt Mackall <mpm@selenic.com>
parents: 11469
diff changeset
  1722
17962
4c29668ca316 util: make chunkbuffer non-quadratic on Windows
Matt Mackall <mpm@selenic.com>
parents: 17560
diff changeset
  1723
        return ''.join(buf)
11758
a79214972da2 chunkbuffer: use += rather than cStringIO to reduce memory footprint
Matt Mackall <mpm@selenic.com>
parents: 11469
diff changeset
  1724
30181
7356e6b1f5b8 util: increase filechunkiter size to 128k
Mads Kiilerich <madski@unity3d.com>
parents: 30087
diff changeset
  1725
def filechunkiter(f, size=131072, limit=None):
2462
d610bcfd66a8 util: add limit to amount filechunkiter will read
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2448
diff changeset
  1726
    """Create a generator that produces the data in the file size
30181
7356e6b1f5b8 util: increase filechunkiter size to 128k
Mads Kiilerich <madski@unity3d.com>
parents: 30087
diff changeset
  1727
    (default 131072) bytes at a time, up to optional limit (default is
2462
d610bcfd66a8 util: add limit to amount filechunkiter will read
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2448
diff changeset
  1728
    to read all data).  Chunks may be less than size bytes if the
d610bcfd66a8 util: add limit to amount filechunkiter will read
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2448
diff changeset
  1729
    chunk is the last chunk in the file, or the file is a socket or
d610bcfd66a8 util: add limit to amount filechunkiter will read
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2448
diff changeset
  1730
    some other type of file that sometimes reads less data than is
d610bcfd66a8 util: add limit to amount filechunkiter will read
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2448
diff changeset
  1731
    requested."""
d610bcfd66a8 util: add limit to amount filechunkiter will read
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2448
diff changeset
  1732
    assert size >= 0
d610bcfd66a8 util: add limit to amount filechunkiter will read
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2448
diff changeset
  1733
    assert limit is None or limit >= 0
d610bcfd66a8 util: add limit to amount filechunkiter will read
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2448
diff changeset
  1734
    while True:
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1735
        if limit is None:
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1736
            nbytes = size
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1737
        else:
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1738
            nbytes = min(limit, size)
2462
d610bcfd66a8 util: add limit to amount filechunkiter will read
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2448
diff changeset
  1739
        s = nbytes and f.read(nbytes)
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1740
        if not s:
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1741
            break
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1742
        if limit:
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  1743
            limit -= len(s)
1199
78ceaf83f28f Created a class in util called chunkbuffer that buffers reads from an
Eric Hopper <hopper@omnifarious.org>
parents: 1169
diff changeset
  1744
        yield s
1320
5f277e73778f Fix up representation of dates in hgweb.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1312
diff changeset
  1745
19287
8b04e1344111 util: add an optional timestamp parameter to makedate
Bryan O'Sullivan <bryano@fb.com>
parents: 19286
diff changeset
  1746
def makedate(timestamp=None):
8b04e1344111 util: add an optional timestamp parameter to makedate
Bryan O'Sullivan <bryano@fb.com>
parents: 19286
diff changeset
  1747
    '''Return a unix timestamp (or the current time) as a (unixtime,
8b04e1344111 util: add an optional timestamp parameter to makedate
Bryan O'Sullivan <bryano@fb.com>
parents: 19286
diff changeset
  1748
    offset) tuple based off the local timezone.'''
8b04e1344111 util: add an optional timestamp parameter to makedate
Bryan O'Sullivan <bryano@fb.com>
parents: 19286
diff changeset
  1749
    if timestamp is None:
8b04e1344111 util: add an optional timestamp parameter to makedate
Bryan O'Sullivan <bryano@fb.com>
parents: 19286
diff changeset
  1750
        timestamp = time.time()
19286
78501209488a util: rename ct variable in makedate to timestamp
Bryan O'Sullivan <bryano@fb.com>
parents: 19211
diff changeset
  1751
    if timestamp < 0:
13063
e98581d44f0b makedate: abort on negative timestamps (issue2513)
Adrian Buehlmann <adrian@cadifra.com>
parents: 13062
diff changeset
  1752
        hint = _("check your clock")
19286
78501209488a util: rename ct variable in makedate to timestamp
Bryan O'Sullivan <bryano@fb.com>
parents: 19211
diff changeset
  1753
        raise Abort(_("negative timestamp: %d") % timestamp, hint=hint)
78501209488a util: rename ct variable in makedate to timestamp
Bryan O'Sullivan <bryano@fb.com>
parents: 19211
diff changeset
  1754
    delta = (datetime.datetime.utcfromtimestamp(timestamp) -
78501209488a util: rename ct variable in makedate to timestamp
Bryan O'Sullivan <bryano@fb.com>
parents: 19211
diff changeset
  1755
             datetime.datetime.fromtimestamp(timestamp))
15505
ae04af1ce78d makedate: wrong timezone offset if DST rules changed this year (issue2511)
Dmitry Panov <dop@itoolabs.com>
parents: 15496
diff changeset
  1756
    tz = delta.days * 86400 + delta.seconds
19286
78501209488a util: rename ct variable in makedate to timestamp
Bryan O'Sullivan <bryano@fb.com>
parents: 19211
diff changeset
  1757
    return timestamp, tz
1329
8f06817bf266 Allow files to be opened in text mode, even on Windows.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1321
diff changeset
  1758
6229
c3182eeb70ea dates: improve timezone handling
Matt Mackall <mpm@selenic.com>
parents: 6224
diff changeset
  1759
def datestr(date=None, format='%a %b %d %H:%M:%S %Y %1%2'):
1321
b47f96a178a3 Clean up date and timezone handling.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1320
diff changeset
  1760
    """represent a (unixtime, offset) tuple as a localized time.
b47f96a178a3 Clean up date and timezone handling.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1320
diff changeset
  1761
    unixtime is seconds since the epoch, and offset is the time zone's
28865
16255662446d util: add doctest to datestr()
Adrian Buehlmann <adrian@cadifra.com>
parents: 28864
diff changeset
  1762
    number of seconds away from UTC.
16255662446d util: add doctest to datestr()
Adrian Buehlmann <adrian@cadifra.com>
parents: 28864
diff changeset
  1763
16255662446d util: add doctest to datestr()
Adrian Buehlmann <adrian@cadifra.com>
parents: 28864
diff changeset
  1764
    >>> datestr((0, 0))
16255662446d util: add doctest to datestr()
Adrian Buehlmann <adrian@cadifra.com>
parents: 28864
diff changeset
  1765
    'Thu Jan 01 00:00:00 1970 +0000'
16255662446d util: add doctest to datestr()
Adrian Buehlmann <adrian@cadifra.com>
parents: 28864
diff changeset
  1766
    >>> datestr((42, 0))
16255662446d util: add doctest to datestr()
Adrian Buehlmann <adrian@cadifra.com>
parents: 28864
diff changeset
  1767
    'Thu Jan 01 00:00:42 1970 +0000'
16255662446d util: add doctest to datestr()
Adrian Buehlmann <adrian@cadifra.com>
parents: 28864
diff changeset
  1768
    >>> datestr((-42, 0))
16255662446d util: add doctest to datestr()
Adrian Buehlmann <adrian@cadifra.com>
parents: 28864
diff changeset
  1769
    'Wed Dec 31 23:59:18 1969 +0000'
16255662446d util: add doctest to datestr()
Adrian Buehlmann <adrian@cadifra.com>
parents: 28864
diff changeset
  1770
    >>> datestr((0x7fffffff, 0))
16255662446d util: add doctest to datestr()
Adrian Buehlmann <adrian@cadifra.com>
parents: 28864
diff changeset
  1771
    'Tue Jan 19 03:14:07 2038 +0000'
16255662446d util: add doctest to datestr()
Adrian Buehlmann <adrian@cadifra.com>
parents: 28864
diff changeset
  1772
    >>> datestr((-0x80000000, 0))
16255662446d util: add doctest to datestr()
Adrian Buehlmann <adrian@cadifra.com>
parents: 28864
diff changeset
  1773
    'Fri Dec 13 20:45:52 1901 +0000'
16255662446d util: add doctest to datestr()
Adrian Buehlmann <adrian@cadifra.com>
parents: 28864
diff changeset
  1774
    """
1321
b47f96a178a3 Clean up date and timezone handling.
Bryan O'Sullivan <bos@serpentine.com>
parents: 1320
diff changeset
  1775
    t, tz = date or makedate()
19989
c38c3fdc8b93 date: allow %z in format (issue4040)
Matt Mackall <mpm@selenic.com>
parents: 19951
diff changeset
  1776
    if "%1" in format or "%2" in format or "%z" in format:
6229
c3182eeb70ea dates: improve timezone handling
Matt Mackall <mpm@selenic.com>
parents: 6224
diff changeset
  1777
        sign = (tz > 0) and "-" or "+"
9029
0001e49f1c11 compat: use // for integer division
Alejandro Santos <alejolp@alejolp.com>
parents: 8938
diff changeset
  1778
        minutes = abs(tz) // 60
27066
6f1f8e88f036 util.datestr: use divmod()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27016
diff changeset
  1779
        q, r = divmod(minutes, 60)
19989
c38c3fdc8b93 date: allow %z in format (issue4040)
Matt Mackall <mpm@selenic.com>
parents: 19951
diff changeset
  1780
        format = format.replace("%z", "%1%2")
27066
6f1f8e88f036 util.datestr: use divmod()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27016
diff changeset
  1781
        format = format.replace("%1", "%c%02d" % (sign, q))
6f1f8e88f036 util.datestr: use divmod()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27016
diff changeset
  1782
        format = format.replace("%2", "%02d" % r)
28825
87c6ad2251d8 date: reallow negative timestamp, fix for Windows buggy gmtime() (issue2513)
Florent Gallaire <fgallaire@gmail.com>
parents: 28818
diff changeset
  1783
    d = t - tz
87c6ad2251d8 date: reallow negative timestamp, fix for Windows buggy gmtime() (issue2513)
Florent Gallaire <fgallaire@gmail.com>
parents: 28818
diff changeset
  1784
    if d > 0x7fffffff:
87c6ad2251d8 date: reallow negative timestamp, fix for Windows buggy gmtime() (issue2513)
Florent Gallaire <fgallaire@gmail.com>
parents: 28818
diff changeset
  1785
        d = 0x7fffffff
28864
b0811a9fe67c date: fix boundary check of negative integer
Florent Gallaire <fgallaire@gmail.com>
parents: 28835
diff changeset
  1786
    elif d < -0x80000000:
b0811a9fe67c date: fix boundary check of negative integer
Florent Gallaire <fgallaire@gmail.com>
parents: 28835
diff changeset
  1787
        d = -0x80000000
28825
87c6ad2251d8 date: reallow negative timestamp, fix for Windows buggy gmtime() (issue2513)
Florent Gallaire <fgallaire@gmail.com>
parents: 28818
diff changeset
  1788
    # Never use time.gmtime() and datetime.datetime.fromtimestamp()
87c6ad2251d8 date: reallow negative timestamp, fix for Windows buggy gmtime() (issue2513)
Florent Gallaire <fgallaire@gmail.com>
parents: 28818
diff changeset
  1789
    # because they use the gmtime() system call which is buggy on Windows
87c6ad2251d8 date: reallow negative timestamp, fix for Windows buggy gmtime() (issue2513)
Florent Gallaire <fgallaire@gmail.com>
parents: 28818
diff changeset
  1790
    # for negative values.
87c6ad2251d8 date: reallow negative timestamp, fix for Windows buggy gmtime() (issue2513)
Florent Gallaire <fgallaire@gmail.com>
parents: 28818
diff changeset
  1791
    t = datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=d)
87c6ad2251d8 date: reallow negative timestamp, fix for Windows buggy gmtime() (issue2513)
Florent Gallaire <fgallaire@gmail.com>
parents: 28818
diff changeset
  1792
    s = t.strftime(format)
1987
04c17fc39c84 add changelog style to command line template.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1976
diff changeset
  1793
    return s
1829
b0f6af327fd4 hgwebdir: export collections of repos
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1635
diff changeset
  1794
6134
7b937b26adf7 Make annotae/grep print short dates with -q/--quiet.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 6111
diff changeset
  1795
def shortdate(date=None):
7b937b26adf7 Make annotae/grep print short dates with -q/--quiet.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 6111
diff changeset
  1796
    """turn (timestamp, tzoff) tuple into iso 8631 date."""
6229
c3182eeb70ea dates: improve timezone handling
Matt Mackall <mpm@selenic.com>
parents: 6224
diff changeset
  1797
    return datestr(date, format='%Y-%m-%d')
6134
7b937b26adf7 Make annotae/grep print short dates with -q/--quiet.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 6111
diff changeset
  1798
29636
84ef4517de03 date: refactor timezone parsing
Matt Mackall <mpm@selenic.com>
parents: 29613
diff changeset
  1799
def parsetimezone(s):
84ef4517de03 date: refactor timezone parsing
Matt Mackall <mpm@selenic.com>
parents: 29613
diff changeset
  1800
    """find a trailing timezone, if any, in string, and return a
84ef4517de03 date: refactor timezone parsing
Matt Mackall <mpm@selenic.com>
parents: 29613
diff changeset
  1801
       (offset, remainder) pair"""
84ef4517de03 date: refactor timezone parsing
Matt Mackall <mpm@selenic.com>
parents: 29613
diff changeset
  1802
84ef4517de03 date: refactor timezone parsing
Matt Mackall <mpm@selenic.com>
parents: 29613
diff changeset
  1803
    if s.endswith("GMT") or s.endswith("UTC"):
84ef4517de03 date: refactor timezone parsing
Matt Mackall <mpm@selenic.com>
parents: 29613
diff changeset
  1804
        return 0, s[:-3].rstrip()
84ef4517de03 date: refactor timezone parsing
Matt Mackall <mpm@selenic.com>
parents: 29613
diff changeset
  1805
84ef4517de03 date: refactor timezone parsing
Matt Mackall <mpm@selenic.com>
parents: 29613
diff changeset
  1806
    # Unix-style timezones [+-]hhmm
84ef4517de03 date: refactor timezone parsing
Matt Mackall <mpm@selenic.com>
parents: 29613
diff changeset
  1807
    if len(s) >= 5 and s[-5] in "+-" and s[-4:].isdigit():
84ef4517de03 date: refactor timezone parsing
Matt Mackall <mpm@selenic.com>
parents: 29613
diff changeset
  1808
        sign = (s[-5] == "+") and 1 or -1
84ef4517de03 date: refactor timezone parsing
Matt Mackall <mpm@selenic.com>
parents: 29613
diff changeset
  1809
        hours = int(s[-4:-2])
84ef4517de03 date: refactor timezone parsing
Matt Mackall <mpm@selenic.com>
parents: 29613
diff changeset
  1810
        minutes = int(s[-2:])
84ef4517de03 date: refactor timezone parsing
Matt Mackall <mpm@selenic.com>
parents: 29613
diff changeset
  1811
        return -sign * (hours * 60 + minutes) * 60, s[:-5].rstrip()
84ef4517de03 date: refactor timezone parsing
Matt Mackall <mpm@selenic.com>
parents: 29613
diff changeset
  1812
29637
46b2ccce7fde date: parse ISO-style Z and +hh:mm timezone specs
Matt Mackall <mpm@selenic.com>
parents: 29636
diff changeset
  1813
    # ISO8601 trailing Z
46b2ccce7fde date: parse ISO-style Z and +hh:mm timezone specs
Matt Mackall <mpm@selenic.com>
parents: 29636
diff changeset
  1814
    if s.endswith("Z") and s[-2:-1].isdigit():
46b2ccce7fde date: parse ISO-style Z and +hh:mm timezone specs
Matt Mackall <mpm@selenic.com>
parents: 29636
diff changeset
  1815
        return 0, s[:-1]
46b2ccce7fde date: parse ISO-style Z and +hh:mm timezone specs
Matt Mackall <mpm@selenic.com>
parents: 29636
diff changeset
  1816
46b2ccce7fde date: parse ISO-style Z and +hh:mm timezone specs
Matt Mackall <mpm@selenic.com>
parents: 29636
diff changeset
  1817
    # ISO8601-style [+-]hh:mm
46b2ccce7fde date: parse ISO-style Z and +hh:mm timezone specs
Matt Mackall <mpm@selenic.com>
parents: 29636
diff changeset
  1818
    if (len(s) >= 6 and s[-6] in "+-" and s[-3] == ":" and
46b2ccce7fde date: parse ISO-style Z and +hh:mm timezone specs
Matt Mackall <mpm@selenic.com>
parents: 29636
diff changeset
  1819
        s[-5:-3].isdigit() and s[-2:].isdigit()):
46b2ccce7fde date: parse ISO-style Z and +hh:mm timezone specs
Matt Mackall <mpm@selenic.com>
parents: 29636
diff changeset
  1820
        sign = (s[-6] == "+") and 1 or -1
46b2ccce7fde date: parse ISO-style Z and +hh:mm timezone specs
Matt Mackall <mpm@selenic.com>
parents: 29636
diff changeset
  1821
        hours = int(s[-5:-3])
46b2ccce7fde date: parse ISO-style Z and +hh:mm timezone specs
Matt Mackall <mpm@selenic.com>
parents: 29636
diff changeset
  1822
        minutes = int(s[-2:])
46b2ccce7fde date: parse ISO-style Z and +hh:mm timezone specs
Matt Mackall <mpm@selenic.com>
parents: 29636
diff changeset
  1823
        return -sign * (hours * 60 + minutes) * 60, s[:-6]
46b2ccce7fde date: parse ISO-style Z and +hh:mm timezone specs
Matt Mackall <mpm@selenic.com>
parents: 29636
diff changeset
  1824
29636
84ef4517de03 date: refactor timezone parsing
Matt Mackall <mpm@selenic.com>
parents: 29613
diff changeset
  1825
    return None, s
26126
7b625baed995 util: extract function that parses timezone string
Yuya Nishihara <yuya@tcha.org>
parents: 26098
diff changeset
  1826
5357
c6adf2be6069 util: add default argument to strdate
Bryan O'Sullivan <bos@serpentine.com>
parents: 5293
diff changeset
  1827
def strdate(string, format, defaults=[]):
2522
85f796baab10 Allow the use of human readable dates (issue 251)
Jose M. Prieto <jmprieto@gmx.net>
parents: 2480
diff changeset
  1828
    """parse a localized time string and return a (unixtime, offset) tuple.
85f796baab10 Allow the use of human readable dates (issue 251)
Jose M. Prieto <jmprieto@gmx.net>
parents: 2480
diff changeset
  1829
    if the string cannot be parsed, ValueError is raised."""
3255
e96d2956eb4a util.strdate: compute timestamp using UTC, not local timezone
Jose M. Prieto <jmprieto@gmx.net>
parents: 3176
diff changeset
  1830
    # NOTE: unixtime = localunixtime + offset
29636
84ef4517de03 date: refactor timezone parsing
Matt Mackall <mpm@selenic.com>
parents: 29613
diff changeset
  1831
    offset, date = parsetimezone(string)
3808
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
  1832
3812
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1833
    # add missing elements from defaults
13212
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1834
    usenow = False # default to using biased defaults
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1835
    for part in ("S", "M", "HI", "d", "mb", "yY"): # decreasing specificity
3812
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1836
        found = [True for p in part if ("%"+p) in format]
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1837
        if not found:
13212
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1838
            date += "@" + defaults[part][usenow]
3812
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1839
            format += "@%" + part[0]
13212
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1840
        else:
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1841
            # We've found a specific time element, less specific time
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1842
            # elements are relative to today
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1843
            usenow = True
3808
d6529582942a improve date parsing for numerous new date formats
Matt Mackall <mpm@selenic.com>
parents: 3807
diff changeset
  1844
3256
e5c9a084ffe3 util.strdate: assume local time when no timezone specified
Jose M. Prieto <jmprieto@gmx.net>
parents: 3255
diff changeset
  1845
    timetuple = time.strptime(date, format)
e5c9a084ffe3 util.strdate: assume local time when no timezone specified
Jose M. Prieto <jmprieto@gmx.net>
parents: 3255
diff changeset
  1846
    localunixtime = int(calendar.timegm(timetuple))
e5c9a084ffe3 util.strdate: assume local time when no timezone specified
Jose M. Prieto <jmprieto@gmx.net>
parents: 3255
diff changeset
  1847
    if offset is None:
e5c9a084ffe3 util.strdate: assume local time when no timezone specified
Jose M. Prieto <jmprieto@gmx.net>
parents: 3255
diff changeset
  1848
        # local timezone
e5c9a084ffe3 util.strdate: assume local time when no timezone specified
Jose M. Prieto <jmprieto@gmx.net>
parents: 3255
diff changeset
  1849
        unixtime = int(time.mktime(timetuple))
e5c9a084ffe3 util.strdate: assume local time when no timezone specified
Jose M. Prieto <jmprieto@gmx.net>
parents: 3255
diff changeset
  1850
        offset = unixtime - localunixtime
e5c9a084ffe3 util.strdate: assume local time when no timezone specified
Jose M. Prieto <jmprieto@gmx.net>
parents: 3255
diff changeset
  1851
    else:
e5c9a084ffe3 util.strdate: assume local time when no timezone specified
Jose M. Prieto <jmprieto@gmx.net>
parents: 3255
diff changeset
  1852
        unixtime = localunixtime + offset
3255
e96d2956eb4a util.strdate: compute timestamp using UTC, not local timezone
Jose M. Prieto <jmprieto@gmx.net>
parents: 3176
diff changeset
  1853
    return unixtime, offset
2522
85f796baab10 Allow the use of human readable dates (issue 251)
Jose M. Prieto <jmprieto@gmx.net>
parents: 2480
diff changeset
  1854
26311
60dd8e3977f0 util: avoid mutable default arguments
Siddharth Agarwal <sid0@fb.com>
parents: 26267
diff changeset
  1855
def parsedate(date, formats=None, bias=None):
13212
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1856
    """parse a localized date/time and return a (unixtime, offset) tuple.
6139
989467e8e3a9 Fix bad behaviour when specifying an invalid date (issue700)
Thomas Arendsen Hein <thomas@intevation.de>
parents: 6135
diff changeset
  1857
2522
85f796baab10 Allow the use of human readable dates (issue 251)
Jose M. Prieto <jmprieto@gmx.net>
parents: 2480
diff changeset
  1858
    The date may be a "unixtime offset" string or in one of the specified
6139
989467e8e3a9 Fix bad behaviour when specifying an invalid date (issue700)
Thomas Arendsen Hein <thomas@intevation.de>
parents: 6135
diff changeset
  1859
    formats. If the date already is a (unixtime, offset) tuple, it is returned.
18537
ae60735e37d2 dates: support 'today' and 'yesterday' in parsedate (issue3764)
Paul Cavallaro <ptc@fb.com>
parents: 18326
diff changeset
  1860
ae60735e37d2 dates: support 'today' and 'yesterday' in parsedate (issue3764)
Paul Cavallaro <ptc@fb.com>
parents: 18326
diff changeset
  1861
    >>> parsedate(' today ') == parsedate(\
ae60735e37d2 dates: support 'today' and 'yesterday' in parsedate (issue3764)
Paul Cavallaro <ptc@fb.com>
parents: 18326
diff changeset
  1862
                                  datetime.date.today().strftime('%b %d'))
ae60735e37d2 dates: support 'today' and 'yesterday' in parsedate (issue3764)
Paul Cavallaro <ptc@fb.com>
parents: 18326
diff changeset
  1863
    True
ae60735e37d2 dates: support 'today' and 'yesterday' in parsedate (issue3764)
Paul Cavallaro <ptc@fb.com>
parents: 18326
diff changeset
  1864
    >>> parsedate( 'yesterday ') == parsedate((datetime.date.today() -\
ae60735e37d2 dates: support 'today' and 'yesterday' in parsedate (issue3764)
Paul Cavallaro <ptc@fb.com>
parents: 18326
diff changeset
  1865
                                               datetime.timedelta(days=1)\
ae60735e37d2 dates: support 'today' and 'yesterday' in parsedate (issue3764)
Paul Cavallaro <ptc@fb.com>
parents: 18326
diff changeset
  1866
                                              ).strftime('%b %d'))
ae60735e37d2 dates: support 'today' and 'yesterday' in parsedate (issue3764)
Paul Cavallaro <ptc@fb.com>
parents: 18326
diff changeset
  1867
    True
18614
b2586e2cc67a parsedate: understand "now" as a shortcut for the current time
Augie Fackler <raf@durin42.com>
parents: 18603
diff changeset
  1868
    >>> now, tz = makedate()
b2586e2cc67a parsedate: understand "now" as a shortcut for the current time
Augie Fackler <raf@durin42.com>
parents: 18603
diff changeset
  1869
    >>> strnow, strtz = parsedate('now')
b2586e2cc67a parsedate: understand "now" as a shortcut for the current time
Augie Fackler <raf@durin42.com>
parents: 18603
diff changeset
  1870
    >>> (strnow - now) < 1
b2586e2cc67a parsedate: understand "now" as a shortcut for the current time
Augie Fackler <raf@durin42.com>
parents: 18603
diff changeset
  1871
    True
b2586e2cc67a parsedate: understand "now" as a shortcut for the current time
Augie Fackler <raf@durin42.com>
parents: 18603
diff changeset
  1872
    >>> tz == strtz
b2586e2cc67a parsedate: understand "now" as a shortcut for the current time
Augie Fackler <raf@durin42.com>
parents: 18603
diff changeset
  1873
    True
6139
989467e8e3a9 Fix bad behaviour when specifying an invalid date (issue700)
Thomas Arendsen Hein <thomas@intevation.de>
parents: 6135
diff changeset
  1874
    """
26311
60dd8e3977f0 util: avoid mutable default arguments
Siddharth Agarwal <sid0@fb.com>
parents: 26267
diff changeset
  1875
    if bias is None:
60dd8e3977f0 util: avoid mutable default arguments
Siddharth Agarwal <sid0@fb.com>
parents: 26267
diff changeset
  1876
        bias = {}
6139
989467e8e3a9 Fix bad behaviour when specifying an invalid date (issue700)
Thomas Arendsen Hein <thomas@intevation.de>
parents: 6135
diff changeset
  1877
    if not date:
3807
e43b48f0f718 parsedate: allow '' for epoch
Matt Mackall <mpm@selenic.com>
parents: 3806
diff changeset
  1878
        return 0, 0
6230
c7253d1a774e dates: Fix bare times to be relative to "today"
Matt Mackall <mpm@selenic.com>
parents: 6229
diff changeset
  1879
    if isinstance(date, tuple) and len(date) == 2:
6139
989467e8e3a9 Fix bad behaviour when specifying an invalid date (issue700)
Thomas Arendsen Hein <thomas@intevation.de>
parents: 6135
diff changeset
  1880
        return date
2609
6c5b1b5cc160 util.parsedate should understand dates from hg export
Chris Mason <mason@suse.com>
parents: 2601
diff changeset
  1881
    if not formats:
6c5b1b5cc160 util.parsedate should understand dates from hg export
Chris Mason <mason@suse.com>
parents: 2601
diff changeset
  1882
        formats = defaultdateformats
6139
989467e8e3a9 Fix bad behaviour when specifying an invalid date (issue700)
Thomas Arendsen Hein <thomas@intevation.de>
parents: 6135
diff changeset
  1883
    date = date.strip()
18537
ae60735e37d2 dates: support 'today' and 'yesterday' in parsedate (issue3764)
Paul Cavallaro <ptc@fb.com>
parents: 18326
diff changeset
  1884
24188
5a7920c4d2ea util: accept "now, today, yesterday" for dates even the locale is not english
André Klitzing <aklitzing@gmail.com>
parents: 24164
diff changeset
  1885
    if date == 'now' or date == _('now'):
18614
b2586e2cc67a parsedate: understand "now" as a shortcut for the current time
Augie Fackler <raf@durin42.com>
parents: 18603
diff changeset
  1886
        return makedate()
24188
5a7920c4d2ea util: accept "now, today, yesterday" for dates even the locale is not english
André Klitzing <aklitzing@gmail.com>
parents: 24164
diff changeset
  1887
    if date == 'today' or date == _('today'):
18537
ae60735e37d2 dates: support 'today' and 'yesterday' in parsedate (issue3764)
Paul Cavallaro <ptc@fb.com>
parents: 18326
diff changeset
  1888
        date = datetime.date.today().strftime('%b %d')
24188
5a7920c4d2ea util: accept "now, today, yesterday" for dates even the locale is not english
André Klitzing <aklitzing@gmail.com>
parents: 24164
diff changeset
  1889
    elif date == 'yesterday' or date == _('yesterday'):
18537
ae60735e37d2 dates: support 'today' and 'yesterday' in parsedate (issue3764)
Paul Cavallaro <ptc@fb.com>
parents: 18326
diff changeset
  1890
        date = (datetime.date.today() -
ae60735e37d2 dates: support 'today' and 'yesterday' in parsedate (issue3764)
Paul Cavallaro <ptc@fb.com>
parents: 18326
diff changeset
  1891
                datetime.timedelta(days=1)).strftime('%b %d')
ae60735e37d2 dates: support 'today' and 'yesterday' in parsedate (issue3764)
Paul Cavallaro <ptc@fb.com>
parents: 18326
diff changeset
  1892
2522
85f796baab10 Allow the use of human readable dates (issue 251)
Jose M. Prieto <jmprieto@gmx.net>
parents: 2480
diff changeset
  1893
    try:
6139
989467e8e3a9 Fix bad behaviour when specifying an invalid date (issue700)
Thomas Arendsen Hein <thomas@intevation.de>
parents: 6135
diff changeset
  1894
        when, offset = map(int, date.split(' '))
2523
4ab59a3acd16 validate the resulting date in parsedate
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2522
diff changeset
  1895
    except ValueError:
3812
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1896
        # fill out defaults
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1897
        now = makedate()
13212
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1898
        defaults = {}
13200
6f011cf52f9a avoid .split() in for loops and use tuples instead
David Soria Parra <dsp@php.net>
parents: 13197
diff changeset
  1899
        for part in ("d", "mb", "yY", "HI", "M", "S"):
13212
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1900
            # this piece is for rounding the specific end of unknowns
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1901
            b = bias.get(part)
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1902
            if b is None:
3812
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1903
                if part[0] in "HMS":
13212
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1904
                    b = "00"
3812
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1905
                else:
13212
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1906
                    b = "0"
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1907
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1908
            # this piece is for matching the generic end to today's date
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1909
            n = datestr(now, "%" + part[0])
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1910
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1911
            defaults[part] = (b, n)
3812
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1912
2523
4ab59a3acd16 validate the resulting date in parsedate
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2522
diff changeset
  1913
        for format in formats:
4ab59a3acd16 validate the resulting date in parsedate
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2522
diff changeset
  1914
            try:
6139
989467e8e3a9 Fix bad behaviour when specifying an invalid date (issue700)
Thomas Arendsen Hein <thomas@intevation.de>
parents: 6135
diff changeset
  1915
                when, offset = strdate(date, format, defaults)
6087
12856a1742dc better handle errors with date parsing (issue983)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5917
diff changeset
  1916
            except (ValueError, OverflowError):
2523
4ab59a3acd16 validate the resulting date in parsedate
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2522
diff changeset
  1917
                pass
4ab59a3acd16 validate the resulting date in parsedate
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2522
diff changeset
  1918
            else:
4ab59a3acd16 validate the resulting date in parsedate
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2522
diff changeset
  1919
                break
4ab59a3acd16 validate the resulting date in parsedate
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2522
diff changeset
  1920
        else:
12105
6f58430dfdd0 util: get rid of extra trailing whitespace in parsedate abort message
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 12088
diff changeset
  1921
            raise Abort(_('invalid date: %r') % date)
2523
4ab59a3acd16 validate the resulting date in parsedate
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2522
diff changeset
  1922
    # validate explicit (probably user-specified) date and
4ab59a3acd16 validate the resulting date in parsedate
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2522
diff changeset
  1923
    # time zone offset. values must fit in signed 32 bits for
4ab59a3acd16 validate the resulting date in parsedate
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2522
diff changeset
  1924
    # current 32-bit linux runtimes. timezones go from UTC-12
4ab59a3acd16 validate the resulting date in parsedate
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2522
diff changeset
  1925
    # to UTC+14
28864
b0811a9fe67c date: fix boundary check of negative integer
Florent Gallaire <fgallaire@gmail.com>
parents: 28835
diff changeset
  1926
    if when < -0x80000000 or when > 0x7fffffff:
3806
92a3532a01d9 parsedate: use Abort rather than ValueError
Matt Mackall <mpm@selenic.com>
parents: 3784
diff changeset
  1927
        raise Abort(_('date exceeds 32 bits: %d') % when)
2523
4ab59a3acd16 validate the resulting date in parsedate
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2522
diff changeset
  1928
    if offset < -50400 or offset > 43200:
3806
92a3532a01d9 parsedate: use Abort rather than ValueError
Matt Mackall <mpm@selenic.com>
parents: 3784
diff changeset
  1929
        raise Abort(_('impossible time zone offset: %d') % offset)
2523
4ab59a3acd16 validate the resulting date in parsedate
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 2522
diff changeset
  1930
    return when, offset
2522
85f796baab10 Allow the use of human readable dates (issue 251)
Jose M. Prieto <jmprieto@gmx.net>
parents: 2480
diff changeset
  1931
3812
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1932
def matchdate(date):
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1933
    """Return a function that matches a given date match specifier
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1934
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1935
    Formats include:
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1936
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1937
    '{date}' match a given date to the accuracy provided
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1938
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1939
    '<{date}' on or before a given date
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1940
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1941
    '>{date}' on or after a given date
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1942
13212
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1943
    >>> p1 = parsedate("10:29:59")
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1944
    >>> p2 = parsedate("10:30:00")
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1945
    >>> p3 = parsedate("10:30:59")
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1946
    >>> p4 = parsedate("10:31:00")
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1947
    >>> p5 = parsedate("Sep 15 10:30:00 1999")
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1948
    >>> f = matchdate("10:30")
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1949
    >>> f(p1[0])
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1950
    False
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1951
    >>> f(p2[0])
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1952
    True
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1953
    >>> f(p3[0])
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1954
    True
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1955
    >>> f(p4[0])
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1956
    False
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1957
    >>> f(p5[0])
5d0a30fad7de date: fix matching of underspecified date ranges
Matt Mackall <mpm@selenic.com>
parents: 13204
diff changeset
  1958
    False
3812
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1959
    """
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1960
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1961
    def lower(date):
20679
0916f829eb8d util: move from dict() construction to {} literals
Augie Fackler <raf@durin42.com>
parents: 20542
diff changeset
  1962
        d = {'mb': "1", 'd': "1"}
6230
c7253d1a774e dates: Fix bare times to be relative to "today"
Matt Mackall <mpm@selenic.com>
parents: 6229
diff changeset
  1963
        return parsedate(date, extendeddateformats, d)[0]
3812
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1964
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1965
    def upper(date):
20679
0916f829eb8d util: move from dict() construction to {} literals
Augie Fackler <raf@durin42.com>
parents: 20542
diff changeset
  1966
        d = {'mb': "12", 'HI': "23", 'M': "59", 'S': "59"}
13200
6f011cf52f9a avoid .split() in for loops and use tuples instead
David Soria Parra <dsp@php.net>
parents: 13197
diff changeset
  1967
        for days in ("31", "30", "29"):
3812
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1968
            try:
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1969
                d["d"] = days
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1970
                return parsedate(date, extendeddateformats, d)[0]
16688
cfb6682961b8 cleanup: replace naked excepts with more specific ones
Brodie Rao <brodie@sf.io>
parents: 16397
diff changeset
  1971
            except Abort:
3812
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1972
                pass
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1973
        d["d"] = "28"
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1974
        return parsedate(date, extendeddateformats, d)[0]
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1975
7953
8c6f823efcc9 Correct a bug on date formats with '>' or '<' accompanied by space characters.
Justin Peng <justin.peng.sw@gmail.com>
parents: 7948
diff changeset
  1976
    date = date.strip()
13780
bc7b5d1c1999 util: dates cannot consist entirely of whitespace (issue2732)
Idan Kamara <idankk86@gmail.com>
parents: 13734
diff changeset
  1977
bc7b5d1c1999 util: dates cannot consist entirely of whitespace (issue2732)
Idan Kamara <idankk86@gmail.com>
parents: 13734
diff changeset
  1978
    if not date:
bc7b5d1c1999 util: dates cannot consist entirely of whitespace (issue2732)
Idan Kamara <idankk86@gmail.com>
parents: 13734
diff changeset
  1979
        raise Abort(_("dates cannot consist entirely of whitespace"))
bc7b5d1c1999 util: dates cannot consist entirely of whitespace (issue2732)
Idan Kamara <idankk86@gmail.com>
parents: 13734
diff changeset
  1980
    elif date[0] == "<":
13869
b470894c33f8 date: fixup breakage from ">" fix
Matt Mackall <mpm@selenic.com>
parents: 13867
diff changeset
  1981
        if not date[1:]:
13886
fe48c57390f2 help/dates: use DATE as place-holder in help and abort texts
Martin Geisler <mg@aragost.com>
parents: 13879
diff changeset
  1982
            raise Abort(_("invalid day spec, use '<DATE'"))
3812
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1983
        when = upper(date[1:])
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1984
        return lambda x: x <= when
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1985
    elif date[0] == ">":
13869
b470894c33f8 date: fixup breakage from ">" fix
Matt Mackall <mpm@selenic.com>
parents: 13867
diff changeset
  1986
        if not date[1:]:
13886
fe48c57390f2 help/dates: use DATE as place-holder in help and abort texts
Martin Geisler <mg@aragost.com>
parents: 13879
diff changeset
  1987
            raise Abort(_("invalid day spec, use '>DATE'"))
3812
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1988
        when = lower(date[1:])
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1989
        return lambda x: x >= when
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1990
    elif date[0] == "-":
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1991
        try:
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1992
            days = int(date[1:])
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1993
        except ValueError:
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1994
            raise Abort(_("invalid day spec: %s") % date[1:])
13889
9a96efc4af8a util: make 'hg log -d --2' abort (issue2734)
Yun Lee <yunlee.bj@gmail.com>
parents: 13886
diff changeset
  1995
        if days < 0:
29977
73b1c328a7da util: use single quotes in use warning
timeless <timeless@mozdev.org>
parents: 29889
diff changeset
  1996
            raise Abort(_("%s must be nonnegative (see 'hg help dates')")
13889
9a96efc4af8a util: make 'hg log -d --2' abort (issue2734)
Yun Lee <yunlee.bj@gmail.com>
parents: 13886
diff changeset
  1997
                % date[1:])
3812
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  1998
        when = makedate()[0] - days * 3600 * 24
3813
fc5ba0ab7f45 Add --date support to log
Matt Mackall <mpm@selenic.com>
parents: 3812
diff changeset
  1999
        return lambda x: x >= when
3812
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  2000
    elif " to " in date:
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  2001
        a, b = date.split(" to ")
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  2002
        start, stop = lower(a), upper(b)
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  2003
        return lambda x: x >= start and x <= stop
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  2004
    else:
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  2005
        start, stop = lower(date), upper(date)
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  2006
        return lambda x: x >= start and x <= stop
bf6ab30559e6 Add date matching support
Matt Mackall <mpm@selenic.com>
parents: 3809
diff changeset
  2007
30773
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2008
def stringmatcher(pattern, casesensitive=True):
26481
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2009
    """
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2010
    accepts a string, possibly starting with 're:' or 'literal:' prefix.
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2011
    returns the matcher name, pattern, and matcher function.
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2012
    missing or unknown prefixes are treated as literal matches.
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2013
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2014
    helper for tests:
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2015
    >>> def test(pattern, *tests):
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2016
    ...     kind, pattern, matcher = stringmatcher(pattern)
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2017
    ...     return (kind, pattern, [bool(matcher(t)) for t in tests])
30773
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2018
    >>> def itest(pattern, *tests):
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2019
    ...     kind, pattern, matcher = stringmatcher(pattern, casesensitive=False)
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2020
    ...     return (kind, pattern, [bool(matcher(t)) for t in tests])
26481
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2021
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2022
    exact matching (no prefix):
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2023
    >>> test('abcdefg', 'abc', 'def', 'abcdefg')
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2024
    ('literal', 'abcdefg', [False, False, True])
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2025
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2026
    regex matching ('re:' prefix)
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2027
    >>> test('re:a.+b', 'nomatch', 'fooadef', 'fooadefbar')
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2028
    ('re', 'a.+b', [False, False, True])
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2029
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2030
    force exact matches ('literal:' prefix)
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2031
    >>> test('literal:re:foobar', 'foobar', 're:foobar')
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2032
    ('literal', 're:foobar', [False, True])
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2033
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2034
    unknown prefixes are ignored and treated as literals
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2035
    >>> test('foo:bar', 'foo', 'bar', 'foo:bar')
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2036
    ('literal', 'foo:bar', [False, False, True])
30773
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2037
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2038
    case insensitive regex matches
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2039
    >>> itest('re:A.+b', 'nomatch', 'fooadef', 'fooadefBar')
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2040
    ('re', 'A.+b', [False, False, True])
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2041
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2042
    case insensitive literal matches
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2043
    >>> itest('ABCDEFG', 'abc', 'def', 'abcdefg')
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2044
    ('literal', 'ABCDEFG', [False, False, True])
26481
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2045
    """
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2046
    if pattern.startswith('re:'):
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2047
        pattern = pattern[3:]
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2048
        try:
30773
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2049
            flags = 0
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2050
            if not casesensitive:
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2051
                flags = remod.I
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2052
            regex = remod.compile(pattern, flags)
26481
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2053
        except remod.error as e:
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2054
            raise error.ParseError(_('invalid regular expression: %s')
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2055
                                   % e)
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2056
        return 're', pattern, regex.search
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2057
    elif pattern.startswith('literal:'):
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2058
        pattern = pattern[8:]
30773
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2059
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2060
    match = pattern.__eq__
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2061
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2062
    if not casesensitive:
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2063
        ipat = encoding.lower(pattern)
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2064
        match = lambda s: ipat == encoding.lower(s)
c390b40fe1d7 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com>
parents: 30761
diff changeset
  2065
    return 'literal', pattern, match
26481
7d132557e44a util: extract stringmatcher() from revset
Matt Harbison <matt_harbison@yahoo.com>
parents: 26480
diff changeset
  2066
1903
e4abeafd6eb1 move shortuser into util module.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1635
diff changeset
  2067
def shortuser(user):
e4abeafd6eb1 move shortuser into util module.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1635
diff changeset
  2068
    """Return a short representation of a user name or email address."""
e4abeafd6eb1 move shortuser into util module.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1635
diff changeset
  2069
    f = user.find('@')
e4abeafd6eb1 move shortuser into util module.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1635
diff changeset
  2070
    if f >= 0:
e4abeafd6eb1 move shortuser into util module.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1635
diff changeset
  2071
        user = user[:f]
e4abeafd6eb1 move shortuser into util module.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1635
diff changeset
  2072
    f = user.find('<')
e4abeafd6eb1 move shortuser into util module.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1635
diff changeset
  2073
    if f >= 0:
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  2074
        user = user[f + 1:]
3176
7492b33bdd9f shortuser should stop before the first space character.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 3147
diff changeset
  2075
    f = user.find(' ')
7492b33bdd9f shortuser should stop before the first space character.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 3147
diff changeset
  2076
    if f >= 0:
7492b33bdd9f shortuser should stop before the first space character.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 3147
diff changeset
  2077
        user = user[:f]
3533
bb44489b901f shortname: truncate at '.' too
Matt Mackall <mpm@selenic.com>
parents: 3466
diff changeset
  2078
    f = user.find('.')
bb44489b901f shortname: truncate at '.' too
Matt Mackall <mpm@selenic.com>
parents: 3466
diff changeset
  2079
    if f >= 0:
bb44489b901f shortname: truncate at '.' too
Matt Mackall <mpm@selenic.com>
parents: 3466
diff changeset
  2080
        user = user[:f]
1903
e4abeafd6eb1 move shortuser into util module.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1635
diff changeset
  2081
    return user
1920
b7cc0f323a4c merge with crew.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1903 1882
diff changeset
  2082
16360
e5788269741a templates/filters: extracting the user portion of an email address
Matteo Capobianco <m.capobianco@gmail.com>
parents: 15720
diff changeset
  2083
def emailuser(user):
e5788269741a templates/filters: extracting the user portion of an email address
Matteo Capobianco <m.capobianco@gmail.com>
parents: 15720
diff changeset
  2084
    """Return the user portion of an email address."""
e5788269741a templates/filters: extracting the user portion of an email address
Matteo Capobianco <m.capobianco@gmail.com>
parents: 15720
diff changeset
  2085
    f = user.find('@')
e5788269741a templates/filters: extracting the user portion of an email address
Matteo Capobianco <m.capobianco@gmail.com>
parents: 15720
diff changeset
  2086
    if f >= 0:
e5788269741a templates/filters: extracting the user portion of an email address
Matteo Capobianco <m.capobianco@gmail.com>
parents: 15720
diff changeset
  2087
        user = user[:f]
e5788269741a templates/filters: extracting the user portion of an email address
Matteo Capobianco <m.capobianco@gmail.com>
parents: 15720
diff changeset
  2088
    f = user.find('<')
e5788269741a templates/filters: extracting the user portion of an email address
Matteo Capobianco <m.capobianco@gmail.com>
parents: 15720
diff changeset
  2089
    if f >= 0:
e5788269741a templates/filters: extracting the user portion of an email address
Matteo Capobianco <m.capobianco@gmail.com>
parents: 15720
diff changeset
  2090
        user = user[f + 1:]
e5788269741a templates/filters: extracting the user portion of an email address
Matteo Capobianco <m.capobianco@gmail.com>
parents: 15720
diff changeset
  2091
    return user
e5788269741a templates/filters: extracting the user portion of an email address
Matteo Capobianco <m.capobianco@gmail.com>
parents: 15720
diff changeset
  2092
5975
75d9fe70c654 templater: move email function to util
Matt Mackall <mpm@selenic.com>
parents: 5949
diff changeset
  2093
def email(author):
75d9fe70c654 templater: move email function to util
Matt Mackall <mpm@selenic.com>
parents: 5949
diff changeset
  2094
    '''get email of author.'''
75d9fe70c654 templater: move email function to util
Matt Mackall <mpm@selenic.com>
parents: 5949
diff changeset
  2095
    r = author.find('>')
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  2096
    if r == -1:
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  2097
        r = None
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10264
diff changeset
  2098
    return author[author.find('<') + 1:r]
5975
75d9fe70c654 templater: move email function to util
Matt Mackall <mpm@selenic.com>
parents: 5949
diff changeset
  2099
3767
1861fa38a6a7 Move ellipsis code to util.ellipsis() and improve maxlength handling.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 3721
diff changeset
  2100
def ellipsis(text, maxlength=400):
21857
86c2d792a4b7 util: replace 'ellipsis' implementation by 'encoding.trim'
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 21813
diff changeset
  2101
    """Trim string to at most maxlength (default: 400) columns in display."""
86c2d792a4b7 util: replace 'ellipsis' implementation by 'encoding.trim'
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 21813
diff changeset
  2102
    return encoding.trim(text, maxlength, ellipsis='...')
3767
1861fa38a6a7 Move ellipsis code to util.ellipsis() and improve maxlength handling.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 3721
diff changeset
  2103
18735
716cad930691 util: generalize bytecount to unitcountfn
Bryan O'Sullivan <bryano@fb.com>
parents: 18678
diff changeset
  2104
def unitcountfn(*unittable):
716cad930691 util: generalize bytecount to unitcountfn
Bryan O'Sullivan <bryano@fb.com>
parents: 18678
diff changeset
  2105
    '''return a function that renders a readable count of some quantity'''
716cad930691 util: generalize bytecount to unitcountfn
Bryan O'Sullivan <bryano@fb.com>
parents: 18678
diff changeset
  2106
716cad930691 util: generalize bytecount to unitcountfn
Bryan O'Sullivan <bryano@fb.com>
parents: 18678
diff changeset
  2107
    def go(count):
716cad930691 util: generalize bytecount to unitcountfn
Bryan O'Sullivan <bryano@fb.com>
parents: 18678
diff changeset
  2108
        for multiplier, divisor, format in unittable:
716cad930691 util: generalize bytecount to unitcountfn
Bryan O'Sullivan <bryano@fb.com>
parents: 18678
diff changeset
  2109
            if count >= divisor * multiplier:
716cad930691 util: generalize bytecount to unitcountfn
Bryan O'Sullivan <bryano@fb.com>
parents: 18678
diff changeset
  2110
                return format % (count / float(divisor))
716cad930691 util: generalize bytecount to unitcountfn
Bryan O'Sullivan <bryano@fb.com>
parents: 18678
diff changeset
  2111
        return unittable[-1][2] % count
716cad930691 util: generalize bytecount to unitcountfn
Bryan O'Sullivan <bryano@fb.com>
parents: 18678
diff changeset
  2112
716cad930691 util: generalize bytecount to unitcountfn
Bryan O'Sullivan <bryano@fb.com>
parents: 18678
diff changeset
  2113
    return go
716cad930691 util: generalize bytecount to unitcountfn
Bryan O'Sullivan <bryano@fb.com>
parents: 18678
diff changeset
  2114
716cad930691 util: generalize bytecount to unitcountfn
Bryan O'Sullivan <bryano@fb.com>
parents: 18678
diff changeset
  2115
bytecount = unitcountfn(
16397
f0f7f3fab315 util: create bytecount array just once
Matt Mackall <mpm@selenic.com>
parents: 16383
diff changeset
  2116
    (100, 1 << 30, _('%.0f GB')),
f0f7f3fab315 util: create bytecount array just once
Matt Mackall <mpm@selenic.com>
parents: 16383
diff changeset
  2117
    (10, 1 << 30, _('%.1f GB')),
f0f7f3fab315 util: create bytecount array just once
Matt Mackall <mpm@selenic.com>
parents: 16383
diff changeset
  2118
    (1, 1 << 30, _('%.2f GB')),
f0f7f3fab315 util: create bytecount array just once
Matt Mackall <mpm@selenic.com>
parents: 16383
diff changeset
  2119
    (100, 1 << 20, _('%.0f MB')),
f0f7f3fab315 util: create bytecount array just once
Matt Mackall <mpm@selenic.com>
parents: 16383
diff changeset
  2120
    (10, 1 << 20, _('%.1f MB')),
f0f7f3fab315 util: create bytecount array just once
Matt Mackall <mpm@selenic.com>
parents: 16383
diff changeset
  2121
    (1, 1 << 20, _('%.2f MB')),
f0f7f3fab315 util: create bytecount array just once
Matt Mackall <mpm@selenic.com>
parents: 16383
diff changeset
  2122
    (100, 1 << 10, _('%.0f KB')),
f0f7f3fab315 util: create bytecount array just once
Matt Mackall <mpm@selenic.com>
parents: 16383
diff changeset
  2123
    (10, 1 << 10, _('%.1f KB')),
f0f7f3fab315 util: create bytecount array just once
Matt Mackall <mpm@selenic.com>
parents: 16383
diff changeset
  2124
    (1, 1 << 10, _('%.2f KB')),
f0f7f3fab315 util: create bytecount array just once
Matt Mackall <mpm@selenic.com>
parents: 16383
diff changeset
  2125
    (1, 1, _('%.0f bytes')),
f0f7f3fab315 util: create bytecount array just once
Matt Mackall <mpm@selenic.com>
parents: 16383
diff changeset
  2126
    )
f0f7f3fab315 util: create bytecount array just once
Matt Mackall <mpm@selenic.com>
parents: 16383
diff changeset
  2127
5291
23651848d638 extdiff: avoid repr() doubling paths backslashes under Windows
Patrick Mezard <pmezard@gmail.com>
parents: 5213
diff changeset
  2128
def uirepr(s):
23651848d638 extdiff: avoid repr() doubling paths backslashes under Windows
Patrick Mezard <pmezard@gmail.com>
parents: 5213
diff changeset
  2129
    # Avoid double backslash in Windows path repr()
23651848d638 extdiff: avoid repr() doubling paths backslashes under Windows
Patrick Mezard <pmezard@gmail.com>
parents: 5213
diff changeset
  2130
    return repr(s).replace('\\\\', '\\')
7547
4949729ee9ee python implementation of diffstat
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7537
diff changeset
  2131
13316
d119403fd266 util: delay loading of textwrap
Matt Mackall <mpm@selenic.com>
parents: 13313
diff changeset
  2132
# delay import of textwrap
d119403fd266 util: delay loading of textwrap
Matt Mackall <mpm@selenic.com>
parents: 13313
diff changeset
  2133
def MBTextWrapper(**kwargs):
d119403fd266 util: delay loading of textwrap
Matt Mackall <mpm@selenic.com>
parents: 13313
diff changeset
  2134
    class tw(textwrap.TextWrapper):
d119403fd266 util: delay loading of textwrap
Matt Mackall <mpm@selenic.com>
parents: 13313
diff changeset
  2135
        """
15066
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2136
        Extend TextWrapper for width-awareness.
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2137
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2138
        Neither number of 'bytes' in any encoding nor 'characters' is
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2139
        appropriate to calculate terminal columns for specified string.
12957
9f2ac318b92e util: clarify purpose of MBTextWrapper class
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 12938
diff changeset
  2140
15066
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2141
        Original TextWrapper implementation uses built-in 'len()' directly,
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2142
        so overriding is needed to use width information of each characters.
12957
9f2ac318b92e util: clarify purpose of MBTextWrapper class
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 12938
diff changeset
  2143
15066
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2144
        In addition, characters classified into 'ambiguous' width are
17424
e7cfe3587ea4 fix trivial spelling errors
Mads Kiilerich <mads@kiilerich.com>
parents: 17391
diff changeset
  2145
        treated as wide in East Asian area, but as narrow in other.
15066
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2146
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2147
        This requires use decision to determine width of such characters.
13316
d119403fd266 util: delay loading of textwrap
Matt Mackall <mpm@selenic.com>
parents: 13313
diff changeset
  2148
        """
15065
24a6c3f903bb util: wrap lines with multi-byte characters correctly (issue2943)
Mads Kiilerich <mads@kiilerich.com>
parents: 15024
diff changeset
  2149
        def _cutdown(self, ucstr, space_left):
13316
d119403fd266 util: delay loading of textwrap
Matt Mackall <mpm@selenic.com>
parents: 13313
diff changeset
  2150
            l = 0
15066
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2151
            colwidth = encoding.ucolwidth
13316
d119403fd266 util: delay loading of textwrap
Matt Mackall <mpm@selenic.com>
parents: 13313
diff changeset
  2152
            for i in xrange(len(ucstr)):
15066
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2153
                l += colwidth(ucstr[i])
13316
d119403fd266 util: delay loading of textwrap
Matt Mackall <mpm@selenic.com>
parents: 13313
diff changeset
  2154
                if space_left < l:
15065
24a6c3f903bb util: wrap lines with multi-byte characters correctly (issue2943)
Mads Kiilerich <mads@kiilerich.com>
parents: 15024
diff changeset
  2155
                    return (ucstr[:i], ucstr[i:])
24a6c3f903bb util: wrap lines with multi-byte characters correctly (issue2943)
Mads Kiilerich <mads@kiilerich.com>
parents: 15024
diff changeset
  2156
            return ucstr, ''
11297
d320e70442a5 replace Python standard textwrap by MBCS sensitive one for i18n text
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 11256
diff changeset
  2157
13316
d119403fd266 util: delay loading of textwrap
Matt Mackall <mpm@selenic.com>
parents: 13313
diff changeset
  2158
        # overriding of base class
d119403fd266 util: delay loading of textwrap
Matt Mackall <mpm@selenic.com>
parents: 13313
diff changeset
  2159
        def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
d119403fd266 util: delay loading of textwrap
Matt Mackall <mpm@selenic.com>
parents: 13313
diff changeset
  2160
            space_left = max(width - cur_len, 1)
11297
d320e70442a5 replace Python standard textwrap by MBCS sensitive one for i18n text
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 11256
diff changeset
  2161
13316
d119403fd266 util: delay loading of textwrap
Matt Mackall <mpm@selenic.com>
parents: 13313
diff changeset
  2162
            if self.break_long_words:
d119403fd266 util: delay loading of textwrap
Matt Mackall <mpm@selenic.com>
parents: 13313
diff changeset
  2163
                cut, res = self._cutdown(reversed_chunks[-1], space_left)
d119403fd266 util: delay loading of textwrap
Matt Mackall <mpm@selenic.com>
parents: 13313
diff changeset
  2164
                cur_line.append(cut)
d119403fd266 util: delay loading of textwrap
Matt Mackall <mpm@selenic.com>
parents: 13313
diff changeset
  2165
                reversed_chunks[-1] = res
d119403fd266 util: delay loading of textwrap
Matt Mackall <mpm@selenic.com>
parents: 13313
diff changeset
  2166
            elif not cur_line:
d119403fd266 util: delay loading of textwrap
Matt Mackall <mpm@selenic.com>
parents: 13313
diff changeset
  2167
                cur_line.append(reversed_chunks.pop())
11297
d320e70442a5 replace Python standard textwrap by MBCS sensitive one for i18n text
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 11256
diff changeset
  2168
26201
c5b2074ae8c0 util: capitalize Python in MBTextWrapper._wrap_chunks comment
timeless@mozdev.org
parents: 26126
diff changeset
  2169
        # this overriding code is imported from TextWrapper of Python 2.6
15066
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2170
        # to calculate columns of string by 'encoding.ucolwidth()'
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2171
        def _wrap_chunks(self, chunks):
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2172
            colwidth = encoding.ucolwidth
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2173
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2174
            lines = []
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2175
            if self.width <= 0:
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2176
                raise ValueError("invalid width %r (must be > 0)" % self.width)
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2177
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2178
            # Arrange in reverse order so items can be efficiently popped
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2179
            # from a stack of chucks.
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2180
            chunks.reverse()
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2181
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2182
            while chunks:
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2183
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2184
                # Start the list of chunks that will make up the current line.
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2185
                # cur_len is just the length of all the chunks in cur_line.
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2186
                cur_line = []
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2187
                cur_len = 0
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2188
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2189
                # Figure out which static string will prefix this line.
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2190
                if lines:
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2191
                    indent = self.subsequent_indent
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2192
                else:
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2193
                    indent = self.initial_indent
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2194
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2195
                # Maximum width for this line.
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2196
                width = self.width - len(indent)
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2197
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2198
                # First chunk on line is whitespace -- drop it, unless this
17424
e7cfe3587ea4 fix trivial spelling errors
Mads Kiilerich <mads@kiilerich.com>
parents: 17391
diff changeset
  2199
                # is the very beginning of the text (i.e. no lines started yet).
15066
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2200
                if self.drop_whitespace and chunks[-1].strip() == '' and lines:
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2201
                    del chunks[-1]
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2202
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2203
                while chunks:
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2204
                    l = colwidth(chunks[-1])
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2205
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2206
                    # Can at least squeeze this chunk onto the current line.
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2207
                    if cur_len + l <= width:
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2208
                        cur_line.append(chunks.pop())
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2209
                        cur_len += l
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2210
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2211
                    # Nope, this line is full.
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2212
                    else:
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2213
                        break
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2214
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2215
                # The current line is full, and the next chunk is too big to
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2216
                # fit on *any* line (not just this one).
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2217
                if chunks and colwidth(chunks[-1]) > width:
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2218
                    self._handle_long_word(chunks, cur_line, cur_len, width)
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2219
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2220
                # If the last chunk on this line is all whitespace, drop it.
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2221
                if (self.drop_whitespace and
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2222
                    cur_line and cur_line[-1].strip() == ''):
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2223
                    del cur_line[-1]
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2224
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2225
                # Convert current line back to a string and store it in list
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2226
                # of all lines (return value).
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2227
                if cur_line:
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2228
                    lines.append(indent + ''.join(cur_line))
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2229
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2230
            return lines
24efa83d81cb i18n: calculate terminal columns by width information of each characters
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 15065
diff changeset
  2231
13316
d119403fd266 util: delay loading of textwrap
Matt Mackall <mpm@selenic.com>
parents: 13313
diff changeset
  2232
    global MBTextWrapper
d119403fd266 util: delay loading of textwrap
Matt Mackall <mpm@selenic.com>
parents: 13313
diff changeset
  2233
    MBTextWrapper = tw
d119403fd266 util: delay loading of textwrap
Matt Mackall <mpm@selenic.com>
parents: 13313
diff changeset
  2234
    return tw(**kwargs)
11297
d320e70442a5 replace Python standard textwrap by MBCS sensitive one for i18n text
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 11256
diff changeset
  2235
12698
7aef77e74cf3 util: make wrap() require a width argument
Matt Mackall <mpm@selenic.com>
parents: 12689
diff changeset
  2236
def wrap(line, width, initindent='', hangindent=''):
11297
d320e70442a5 replace Python standard textwrap by MBCS sensitive one for i18n text
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 11256
diff changeset
  2237
    maxindent = max(len(hangindent), len(initindent))
d320e70442a5 replace Python standard textwrap by MBCS sensitive one for i18n text
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 11256
diff changeset
  2238
    if width <= maxindent:
9417
4c3fb45123e5 util, minirst: do not crash with COLUMNS=0
Martin Geisler <mg@lazybytes.net>
parents: 9397
diff changeset
  2239
        # adjust for weird terminal size
11297
d320e70442a5 replace Python standard textwrap by MBCS sensitive one for i18n text
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 11256
diff changeset
  2240
        width = max(78, maxindent + 1)
15065
24a6c3f903bb util: wrap lines with multi-byte characters correctly (issue2943)
Mads Kiilerich <mads@kiilerich.com>
parents: 15024
diff changeset
  2241
    line = line.decode(encoding.encoding, encoding.encodingmode)
24a6c3f903bb util: wrap lines with multi-byte characters correctly (issue2943)
Mads Kiilerich <mads@kiilerich.com>
parents: 15024
diff changeset
  2242
    initindent = initindent.decode(encoding.encoding, encoding.encodingmode)
24a6c3f903bb util: wrap lines with multi-byte characters correctly (issue2943)
Mads Kiilerich <mads@kiilerich.com>
parents: 15024
diff changeset
  2243
    hangindent = hangindent.decode(encoding.encoding, encoding.encodingmode)
11297
d320e70442a5 replace Python standard textwrap by MBCS sensitive one for i18n text
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 11256
diff changeset
  2244
    wrapper = MBTextWrapper(width=width,
d320e70442a5 replace Python standard textwrap by MBCS sensitive one for i18n text
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 11256
diff changeset
  2245
                            initial_indent=initindent,
d320e70442a5 replace Python standard textwrap by MBCS sensitive one for i18n text
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 11256
diff changeset
  2246
                            subsequent_indent=hangindent)
15065
24a6c3f903bb util: wrap lines with multi-byte characters correctly (issue2943)
Mads Kiilerich <mads@kiilerich.com>
parents: 15024
diff changeset
  2247
    return wrapper.fill(line).encode(encoding.encoding)
8938
9b8c9266c59d commands: wrap short descriptions in 'hg help'
Martin Geisler <mg@lazybytes.net>
parents: 8785
diff changeset
  2248
30418
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2249
if (pyplatform.python_implementation() == 'CPython' and
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2250
    sys.version_info < (3, 0)):
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2251
    # There is an issue in CPython that some IO methods do not handle EINTR
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2252
    # correctly. The following table shows what CPython version (and functions)
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2253
    # are affected (buggy: has the EINTR bug, okay: otherwise):
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2254
    #
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2255
    #                | < 2.7.4 | 2.7.4 to 2.7.12 | >= 3.0
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2256
    #   --------------------------------------------------
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2257
    #    fp.__iter__ | buggy   | buggy           | okay
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2258
    #    fp.read*    | buggy   | okay [1]        | okay
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2259
    #
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2260
    # [1]: fixed by changeset 67dc99a989cd in the cpython hg repo.
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2261
    #
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2262
    # Here we workaround the EINTR issue for fileobj.__iter__. Other methods
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2263
    # like "read*" are ignored for now, as Python < 2.7.4 is a minority.
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2264
    #
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2265
    # Although we can workaround the EINTR issue for fp.__iter__, it is slower:
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2266
    # "for x in fp" is 4x faster than "for x in iter(fp.readline, '')" in
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2267
    # CPython 2, because CPython 2 maintains an internal readahead buffer for
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2268
    # fp.__iter__ but not other fp.read* methods.
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2269
    #
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2270
    # On modern systems like Linux, the "read" syscall cannot be interrupted
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2271
    # when reading "fast" files like on-disk files. So the EINTR issue only
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2272
    # affects things like pipes, sockets, ttys etc. We treat "normal" (S_ISREG)
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2273
    # files approximately as "fast" files and use the fast (unsafe) code path,
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2274
    # to minimize the performance impact.
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2275
    if sys.version_info >= (2, 7, 4):
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2276
        # fp.readline deals with EINTR correctly, use it as a workaround.
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2277
        def _safeiterfile(fp):
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2278
            return iter(fp.readline, '')
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2279
    else:
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2280
        # fp.read* are broken too, manually deal with EINTR in a stupid way.
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2281
        # note: this may block longer than necessary because of bufsize.
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2282
        def _safeiterfile(fp, bufsize=4096):
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2283
            fd = fp.fileno()
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2284
            line = ''
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2285
            while True:
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2286
                try:
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2287
                    buf = os.read(fd, bufsize)
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2288
                except OSError as ex:
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2289
                    # os.read only raises EINTR before any data is read
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2290
                    if ex.errno == errno.EINTR:
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2291
                        continue
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2292
                    else:
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2293
                        raise
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2294
                line += buf
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2295
                if '\n' in buf:
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2296
                    splitted = line.splitlines(True)
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2297
                    line = ''
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2298
                    for l in splitted:
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2299
                        if l[-1] == '\n':
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2300
                            yield l
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2301
                        else:
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2302
                            line = l
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2303
                if not buf:
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2304
                    break
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2305
            if line:
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2306
                yield line
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2307
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2308
    def iterfile(fp):
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2309
        fastpath = True
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2310
        if type(fp) is file:
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2311
            fastpath = stat.S_ISREG(os.fstat(fp.fileno()).st_mode)
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2312
        if fastpath:
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2313
            return fp
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2314
        else:
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2315
            return _safeiterfile(fp)
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2316
else:
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2317
    # PyPy and CPython 3 do not have the EINTR issue thus no workaround needed.
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2318
    def iterfile(fp):
1156ec81f709 util: improve iterfile so it chooses code path wisely
Jun Wu <quark@fb.com>
parents: 30417
diff changeset
  2319
        return fp
30395
10514a92860e util: add iterfile to workaround a fileobj.__iter__ issue with EINTR
Jun Wu <quark@fb.com>
parents: 30359
diff changeset
  2320
7879
5c4026a289a4 templater: ability to display diffstat for log-like commands
Alexander Solovyov <piranha at piranha.org.ua>
parents: 7875
diff changeset
  2321
def iterlines(iterator):
5c4026a289a4 templater: ability to display diffstat for log-like commands
Alexander Solovyov <piranha at piranha.org.ua>
parents: 7875
diff changeset
  2322
    for chunk in iterator:
5c4026a289a4 templater: ability to display diffstat for log-like commands
Alexander Solovyov <piranha at piranha.org.ua>
parents: 7875
diff changeset
  2323
        for line in chunk.splitlines():
5c4026a289a4 templater: ability to display diffstat for log-like commands
Alexander Solovyov <piranha at piranha.org.ua>
parents: 7875
diff changeset
  2324
            yield line
9610
d78fe60f6bda make path expanding more consistent
Alexander Solovyov <piranha@piranha.org.ua>
parents: 9569
diff changeset
  2325
d78fe60f6bda make path expanding more consistent
Alexander Solovyov <piranha@piranha.org.ua>
parents: 9569
diff changeset
  2326
def expandpath(path):
d78fe60f6bda make path expanding more consistent
Alexander Solovyov <piranha@piranha.org.ua>
parents: 9569
diff changeset
  2327
    return os.path.expanduser(os.path.expandvars(path))
10239
8e4be44a676f Find right hg command for detached process
Patrick Mezard <pmezard@gmail.com>
parents: 10199
diff changeset
  2328
8e4be44a676f Find right hg command for detached process
Patrick Mezard <pmezard@gmail.com>
parents: 10199
diff changeset
  2329
def hgcmd():
8e4be44a676f Find right hg command for detached process
Patrick Mezard <pmezard@gmail.com>
parents: 10199
diff changeset
  2330
    """Return the command used to execute current hg
8e4be44a676f Find right hg command for detached process
Patrick Mezard <pmezard@gmail.com>
parents: 10199
diff changeset
  2331
8e4be44a676f Find right hg command for detached process
Patrick Mezard <pmezard@gmail.com>
parents: 10199
diff changeset
  2332
    This is different from hgexecutable() because on Windows we want
8e4be44a676f Find right hg command for detached process
Patrick Mezard <pmezard@gmail.com>
parents: 10199
diff changeset
  2333
    to avoid things opening new shell windows like batch files, so we
8e4be44a676f Find right hg command for detached process
Patrick Mezard <pmezard@gmail.com>
parents: 10199
diff changeset
  2334
    get either the python call or current executable.
8e4be44a676f Find right hg command for detached process
Patrick Mezard <pmezard@gmail.com>
parents: 10199
diff changeset
  2335
    """
14228
116de1da2154 rename util.main_is_frozen to mainfrozen
Adrian Buehlmann <adrian@cadifra.com>
parents: 14167
diff changeset
  2336
    if mainfrozen():
27766
198f78a52a2f util: adjust hgcmd() to handle frozen Mercurial on OS X
Matt Harbison <matt_harbison@yahoo.com>
parents: 27765
diff changeset
  2337
        if getattr(sys, 'frozen', None) == 'macosx_app':
198f78a52a2f util: adjust hgcmd() to handle frozen Mercurial on OS X
Matt Harbison <matt_harbison@yahoo.com>
parents: 27765
diff changeset
  2338
            # Env variable set by py2app
30637
344e68882cd3 py3: replace os.environ with encoding.environ (part 4 of 5)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30625
diff changeset
  2339
            return [encoding.environ['EXECUTABLEPATH']]
27766
198f78a52a2f util: adjust hgcmd() to handle frozen Mercurial on OS X
Matt Harbison <matt_harbison@yahoo.com>
parents: 27765
diff changeset
  2340
        else:
30669
10b17ed9b591 py3: replace sys.executable with pycompat.sysexecutable
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30642
diff changeset
  2341
            return [pycompat.sysexecutable]
10239
8e4be44a676f Find right hg command for detached process
Patrick Mezard <pmezard@gmail.com>
parents: 10199
diff changeset
  2342
    return gethgcmd()
10344
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2343
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2344
def rundetached(args, condfn):
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2345
    """Execute the argument list in a detached process.
10422
600142e7a028 util: fix trailing whitespace found by check-code
Augie Fackler <durin42@gmail.com>
parents: 10344
diff changeset
  2346
10344
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2347
    condfn is a callable which is called repeatedly and should return
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2348
    True once the child process is known to have started successfully.
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2349
    At this point, the child process PID is returned. If the child
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2350
    process fails to start or finishes before condfn() evaluates to
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2351
    True, return -1.
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2352
    """
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2353
    # Windows case is easier because the child process is either
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2354
    # successfully starting and validating the condition or exiting
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2355
    # on failure. We just poll on its PID. On Unix, if the child
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2356
    # process fails to start, it will be left in a zombie state until
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2357
    # the parent wait on it, which we cannot do since we expect a long
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2358
    # running process on success. Instead we listen for SIGCHLD telling
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2359
    # us our child process terminated.
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2360
    terminated = set()
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2361
    def handler(signum, frame):
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2362
        terminated.add(os.wait())
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2363
    prevhandler = None
14968
b7dbe957585c util: use safehasattr or getattr instead of hasattr
Augie Fackler <durin42@gmail.com>
parents: 14942
diff changeset
  2364
    SIGCHLD = getattr(signal, 'SIGCHLD', None)
b7dbe957585c util: use safehasattr or getattr instead of hasattr
Augie Fackler <durin42@gmail.com>
parents: 14942
diff changeset
  2365
    if SIGCHLD is not None:
b7dbe957585c util: use safehasattr or getattr instead of hasattr
Augie Fackler <durin42@gmail.com>
parents: 14942
diff changeset
  2366
        prevhandler = signal.signal(SIGCHLD, handler)
10344
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2367
    try:
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2368
        pid = spawndetached(args)
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2369
        while not condfn():
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2370
            if ((pid in terminated or not testpid(pid))
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2371
                and not condfn()):
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2372
                return -1
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2373
            time.sleep(0.1)
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2374
        return pid
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2375
    finally:
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2376
        if prevhandler is not None:
9501cde4c034 util: make spawndetached() handle subprocess early terminations
Patrick Mezard <pmezard@gmail.com>
parents: 10282
diff changeset
  2377
            signal.signal(signal.SIGCHLD, prevhandler)
10438
e6dc44147234 util: add any() and all() functions for Python 2.4 compatibility
Steve Losh <steve@stevelosh.com>
parents: 10422
diff changeset
  2378
13392
777cef34a890 dispatch: support for $ escaping in shell-alias definition
Roman Sokolov <sokolov.r.v@gmail.com>
parents: 13375
diff changeset
  2379
def interpolate(prefix, mapping, s, fn=None, escape_prefix=False):
11988
8380ed691df8 util: add an interpolate() function to for replacing multiple values
Steve Losh <steve@stevelosh.com>
parents: 11946
diff changeset
  2380
    """Return the result of interpolating items in the mapping into string s.
8380ed691df8 util: add an interpolate() function to for replacing multiple values
Steve Losh <steve@stevelosh.com>
parents: 11946
diff changeset
  2381
8380ed691df8 util: add an interpolate() function to for replacing multiple values
Steve Losh <steve@stevelosh.com>
parents: 11946
diff changeset
  2382
    prefix is a single character string, or a two character string with
8380ed691df8 util: add an interpolate() function to for replacing multiple values
Steve Losh <steve@stevelosh.com>
parents: 11946
diff changeset
  2383
    a backslash as the first character if the prefix needs to be escaped in
8380ed691df8 util: add an interpolate() function to for replacing multiple values
Steve Losh <steve@stevelosh.com>
parents: 11946
diff changeset
  2384
    a regular expression.
8380ed691df8 util: add an interpolate() function to for replacing multiple values
Steve Losh <steve@stevelosh.com>
parents: 11946
diff changeset
  2385
8380ed691df8 util: add an interpolate() function to for replacing multiple values
Steve Losh <steve@stevelosh.com>
parents: 11946
diff changeset
  2386
    fn is an optional function that will be applied to the replacement text
8380ed691df8 util: add an interpolate() function to for replacing multiple values
Steve Losh <steve@stevelosh.com>
parents: 11946
diff changeset
  2387
    just before replacement.
13392
777cef34a890 dispatch: support for $ escaping in shell-alias definition
Roman Sokolov <sokolov.r.v@gmail.com>
parents: 13375
diff changeset
  2388
777cef34a890 dispatch: support for $ escaping in shell-alias definition
Roman Sokolov <sokolov.r.v@gmail.com>
parents: 13375
diff changeset
  2389
    escape_prefix is an optional flag that allows using doubled prefix for
777cef34a890 dispatch: support for $ escaping in shell-alias definition
Roman Sokolov <sokolov.r.v@gmail.com>
parents: 13375
diff changeset
  2390
    its escaping.
11988
8380ed691df8 util: add an interpolate() function to for replacing multiple values
Steve Losh <steve@stevelosh.com>
parents: 11946
diff changeset
  2391
    """
8380ed691df8 util: add an interpolate() function to for replacing multiple values
Steve Losh <steve@stevelosh.com>
parents: 11946
diff changeset
  2392
    fn = fn or (lambda s: s)
13392
777cef34a890 dispatch: support for $ escaping in shell-alias definition
Roman Sokolov <sokolov.r.v@gmail.com>
parents: 13375
diff changeset
  2393
    patterns = '|'.join(mapping.keys())
777cef34a890 dispatch: support for $ escaping in shell-alias definition
Roman Sokolov <sokolov.r.v@gmail.com>
parents: 13375
diff changeset
  2394
    if escape_prefix:
777cef34a890 dispatch: support for $ escaping in shell-alias definition
Roman Sokolov <sokolov.r.v@gmail.com>
parents: 13375
diff changeset
  2395
        patterns += '|' + prefix
777cef34a890 dispatch: support for $ escaping in shell-alias definition
Roman Sokolov <sokolov.r.v@gmail.com>
parents: 13375
diff changeset
  2396
        if len(prefix) > 1:
777cef34a890 dispatch: support for $ escaping in shell-alias definition
Roman Sokolov <sokolov.r.v@gmail.com>
parents: 13375
diff changeset
  2397
            prefix_char = prefix[1:]
777cef34a890 dispatch: support for $ escaping in shell-alias definition
Roman Sokolov <sokolov.r.v@gmail.com>
parents: 13375
diff changeset
  2398
        else:
777cef34a890 dispatch: support for $ escaping in shell-alias definition
Roman Sokolov <sokolov.r.v@gmail.com>
parents: 13375
diff changeset
  2399
            prefix_char = prefix
777cef34a890 dispatch: support for $ escaping in shell-alias definition
Roman Sokolov <sokolov.r.v@gmail.com>
parents: 13375
diff changeset
  2400
        mapping[prefix_char] = prefix_char
21907
7e5dfa00e3c2 util: rename 're' to 'remod'
Siddharth Agarwal <sid0@fb.com>
parents: 21857
diff changeset
  2401
    r = remod.compile(r'%s(%s)' % (prefix, patterns))
11988
8380ed691df8 util: add an interpolate() function to for replacing multiple values
Steve Losh <steve@stevelosh.com>
parents: 11946
diff changeset
  2402
    return r.sub(lambda x: fn(mapping[x.group()[1:]]), s)
8380ed691df8 util: add an interpolate() function to for replacing multiple values
Steve Losh <steve@stevelosh.com>
parents: 11946
diff changeset
  2403
12076
49463314c24f mail/hgweb: support service names for ports (issue2350)
Brodie Rao <brodie@bitheap.org>
parents: 12054
diff changeset
  2404
def getport(port):
49463314c24f mail/hgweb: support service names for ports (issue2350)
Brodie Rao <brodie@bitheap.org>
parents: 12054
diff changeset
  2405
    """Return the port for a given network service.
49463314c24f mail/hgweb: support service names for ports (issue2350)
Brodie Rao <brodie@bitheap.org>
parents: 12054
diff changeset
  2406
49463314c24f mail/hgweb: support service names for ports (issue2350)
Brodie Rao <brodie@bitheap.org>
parents: 12054
diff changeset
  2407
    If port is an integer, it's returned as is. If it's a string, it's
49463314c24f mail/hgweb: support service names for ports (issue2350)
Brodie Rao <brodie@bitheap.org>
parents: 12054
diff changeset
  2408
    looked up using socket.getservbyname(). If there's no matching
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26493
diff changeset
  2409
    service, error.Abort is raised.
12076
49463314c24f mail/hgweb: support service names for ports (issue2350)
Brodie Rao <brodie@bitheap.org>
parents: 12054
diff changeset
  2410
    """
49463314c24f mail/hgweb: support service names for ports (issue2350)
Brodie Rao <brodie@bitheap.org>
parents: 12054
diff changeset
  2411
    try:
49463314c24f mail/hgweb: support service names for ports (issue2350)
Brodie Rao <brodie@bitheap.org>
parents: 12054
diff changeset
  2412
        return int(port)
49463314c24f mail/hgweb: support service names for ports (issue2350)
Brodie Rao <brodie@bitheap.org>
parents: 12054
diff changeset
  2413
    except ValueError:
49463314c24f mail/hgweb: support service names for ports (issue2350)
Brodie Rao <brodie@bitheap.org>
parents: 12054
diff changeset
  2414
        pass
49463314c24f mail/hgweb: support service names for ports (issue2350)
Brodie Rao <brodie@bitheap.org>
parents: 12054
diff changeset
  2415
49463314c24f mail/hgweb: support service names for ports (issue2350)
Brodie Rao <brodie@bitheap.org>
parents: 12054
diff changeset
  2416
    try:
49463314c24f mail/hgweb: support service names for ports (issue2350)
Brodie Rao <brodie@bitheap.org>
parents: 12054
diff changeset
  2417
        return socket.getservbyname(port)
49463314c24f mail/hgweb: support service names for ports (issue2350)
Brodie Rao <brodie@bitheap.org>
parents: 12054
diff changeset
  2418
    except socket.error:
49463314c24f mail/hgweb: support service names for ports (issue2350)
Brodie Rao <brodie@bitheap.org>
parents: 12054
diff changeset
  2419
        raise Abort(_("no port number associated with service '%s'") % port)
12087
a88a4720c2f0 parsebool: create new function and use it for config parsing
Augie Fackler <durin42@gmail.com>
parents: 12086
diff changeset
  2420
12088
1f71dffabc53 parsebool: accept always as true and never as false
Augie Fackler <durin42@gmail.com>
parents: 12087
diff changeset
  2421
_booleans = {'1': True, 'yes': True, 'true': True, 'on': True, 'always': True,
1f71dffabc53 parsebool: accept always as true and never as false
Augie Fackler <durin42@gmail.com>
parents: 12087
diff changeset
  2422
             '0': False, 'no': False, 'false': False, 'off': False,
1f71dffabc53 parsebool: accept always as true and never as false
Augie Fackler <durin42@gmail.com>
parents: 12087
diff changeset
  2423
             'never': False}
12087
a88a4720c2f0 parsebool: create new function and use it for config parsing
Augie Fackler <durin42@gmail.com>
parents: 12086
diff changeset
  2424
a88a4720c2f0 parsebool: create new function and use it for config parsing
Augie Fackler <durin42@gmail.com>
parents: 12086
diff changeset
  2425
def parsebool(s):
a88a4720c2f0 parsebool: create new function and use it for config parsing
Augie Fackler <durin42@gmail.com>
parents: 12086
diff changeset
  2426
    """Parse s into a boolean.
a88a4720c2f0 parsebool: create new function and use it for config parsing
Augie Fackler <durin42@gmail.com>
parents: 12086
diff changeset
  2427
a88a4720c2f0 parsebool: create new function and use it for config parsing
Augie Fackler <durin42@gmail.com>
parents: 12086
diff changeset
  2428
    If s is not a valid boolean, returns None.
a88a4720c2f0 parsebool: create new function and use it for config parsing
Augie Fackler <durin42@gmail.com>
parents: 12086
diff changeset
  2429
    """
a88a4720c2f0 parsebool: create new function and use it for config parsing
Augie Fackler <durin42@gmail.com>
parents: 12086
diff changeset
  2430
    return _booleans.get(s.lower(), None)
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2431
14077
c285bdb0572a util.url: copy urllib.unquote() into util to improve startup times
Brodie Rao <brodie@bitheap.org>
parents: 14076
diff changeset
  2432
_hextochr = dict((a + b, chr(int(a + b, 16)))
30054
8b89521a69ba util: use string.hexdigits instead of defining it ourselves
Augie Fackler <augie@google.com>
parents: 30053
diff changeset
  2433
                 for a in string.hexdigits for b in string.hexdigits)
14077
c285bdb0572a util.url: copy urllib.unquote() into util to improve startup times
Brodie Rao <brodie@bitheap.org>
parents: 14076
diff changeset
  2434
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2435
class url(object):
14146
1618c4f6f15b tests: use raw string for url tests of '\' handling
Mads Kiilerich <mads@kiilerich.com>
parents: 14100
diff changeset
  2436
    r"""Reliable URL parser.
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2437
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2438
    This parses URLs and provides attributes for the following
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2439
    components:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2440
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2441
    <scheme>://<user>:<passwd>@<host>:<port>/<path>?<query>#<fragment>
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2442
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2443
    Missing components are set to None. The only exception is
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2444
    fragment, which is set to '' if present but empty.
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2445
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2446
    If parsefragment is False, fragment is included in query. If
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2447
    parsequery is False, query is included in path. If both are
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2448
    False, both fragment and query are included in path.
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2449
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2450
    See http://www.ietf.org/rfc/rfc2396.txt for more information.
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2451
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2452
    Note that for backward compatibility reasons, bundle URLs do not
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2453
    take host names. That means 'bundle://../' has a path of '../'.
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2454
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2455
    Examples:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2456
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2457
    >>> url('http://www.ietf.org/rfc/rfc2396.txt')
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2458
    <url scheme: 'http', host: 'www.ietf.org', path: 'rfc/rfc2396.txt'>
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2459
    >>> url('ssh://[::1]:2200//home/joe/repo')
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2460
    <url scheme: 'ssh', host: '[::1]', port: '2200', path: '/home/joe/repo'>
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2461
    >>> url('file:///home/joe/repo')
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2462
    <url scheme: 'file', path: '/home/joe/repo'>
14915
28edd65000d9 url: handle urls of the form file:///c:/foo/bar/ correctly
Matt Mackall <mpm@selenic.com>
parents: 14825
diff changeset
  2463
    >>> url('file:///c:/temp/foo/')
28edd65000d9 url: handle urls of the form file:///c:/foo/bar/ correctly
Matt Mackall <mpm@selenic.com>
parents: 14825
diff changeset
  2464
    <url scheme: 'file', path: 'c:/temp/foo/'>
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2465
    >>> url('bundle:foo')
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2466
    <url scheme: 'bundle', path: 'foo'>
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2467
    >>> url('bundle://../foo')
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2468
    <url scheme: 'bundle', path: '../foo'>
14146
1618c4f6f15b tests: use raw string for url tests of '\' handling
Mads Kiilerich <mads@kiilerich.com>
parents: 14100
diff changeset
  2469
    >>> url(r'c:\foo\bar')
1618c4f6f15b tests: use raw string for url tests of '\' handling
Mads Kiilerich <mads@kiilerich.com>
parents: 14100
diff changeset
  2470
    <url path: 'c:\\foo\\bar'>
14699
388af80c058b url: catch UNC paths as yet another Windows special case (issue2808)
Matt Mackall <mpm@selenic.com>
parents: 14640
diff changeset
  2471
    >>> url(r'\\blah\blah\blah')
388af80c058b url: catch UNC paths as yet another Windows special case (issue2808)
Matt Mackall <mpm@selenic.com>
parents: 14640
diff changeset
  2472
    <url path: '\\\\blah\\blah\\blah'>
15074
64fbd0de9773 url: parse fragments first (issue2997)
Matt Mackall <mpm@selenic.com>
parents: 15066
diff changeset
  2473
    >>> url(r'\\blah\blah\blah#baz')
64fbd0de9773 url: parse fragments first (issue2997)
Matt Mackall <mpm@selenic.com>
parents: 15066
diff changeset
  2474
    <url path: '\\\\blah\\blah\\blah', fragment: 'baz'>
20106
c33d9217e99d util: url keeps backslash in paths
Simon Heimberg <simohe@besonet.ch>
parents: 20000
diff changeset
  2475
    >>> url(r'file:///C:\users\me')
c33d9217e99d util: url keeps backslash in paths
Simon Heimberg <simohe@besonet.ch>
parents: 20000
diff changeset
  2476
    <url scheme: 'file', path: 'C:\\users\\me'>
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2477
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2478
    Authentication credentials:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2479
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2480
    >>> url('ssh://joe:xyz@x/repo')
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2481
    <url scheme: 'ssh', user: 'joe', passwd: 'xyz', host: 'x', path: 'repo'>
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2482
    >>> url('ssh://joe@x/repo')
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2483
    <url scheme: 'ssh', user: 'joe', host: 'x', path: 'repo'>
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2484
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2485
    Query strings and fragments:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2486
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2487
    >>> url('http://host/a?b#c')
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2488
    <url scheme: 'http', host: 'host', path: 'a', query: 'b', fragment: 'c'>
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2489
    >>> url('http://host/a?b#c', parsequery=False, parsefragment=False)
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2490
    <url scheme: 'http', host: 'host', path: 'a?b#c'>
30036
3f4e1c033f40 url: fix crash by empty path with #fragments
Yuya Nishihara <yuya@tcha.org>
parents: 30030
diff changeset
  2491
3f4e1c033f40 url: fix crash by empty path with #fragments
Yuya Nishihara <yuya@tcha.org>
parents: 30030
diff changeset
  2492
    Empty path:
3f4e1c033f40 url: fix crash by empty path with #fragments
Yuya Nishihara <yuya@tcha.org>
parents: 30030
diff changeset
  2493
3f4e1c033f40 url: fix crash by empty path with #fragments
Yuya Nishihara <yuya@tcha.org>
parents: 30030
diff changeset
  2494
    >>> url('')
3f4e1c033f40 url: fix crash by empty path with #fragments
Yuya Nishihara <yuya@tcha.org>
parents: 30030
diff changeset
  2495
    <url path: ''>
3f4e1c033f40 url: fix crash by empty path with #fragments
Yuya Nishihara <yuya@tcha.org>
parents: 30030
diff changeset
  2496
    >>> url('#a')
3f4e1c033f40 url: fix crash by empty path with #fragments
Yuya Nishihara <yuya@tcha.org>
parents: 30030
diff changeset
  2497
    <url path: '', fragment: 'a'>
3f4e1c033f40 url: fix crash by empty path with #fragments
Yuya Nishihara <yuya@tcha.org>
parents: 30030
diff changeset
  2498
    >>> url('http://host/')
3f4e1c033f40 url: fix crash by empty path with #fragments
Yuya Nishihara <yuya@tcha.org>
parents: 30030
diff changeset
  2499
    <url scheme: 'http', host: 'host', path: ''>
3f4e1c033f40 url: fix crash by empty path with #fragments
Yuya Nishihara <yuya@tcha.org>
parents: 30030
diff changeset
  2500
    >>> url('http://host/#a')
3f4e1c033f40 url: fix crash by empty path with #fragments
Yuya Nishihara <yuya@tcha.org>
parents: 30030
diff changeset
  2501
    <url scheme: 'http', host: 'host', path: '', fragment: 'a'>
3f4e1c033f40 url: fix crash by empty path with #fragments
Yuya Nishihara <yuya@tcha.org>
parents: 30030
diff changeset
  2502
3f4e1c033f40 url: fix crash by empty path with #fragments
Yuya Nishihara <yuya@tcha.org>
parents: 30030
diff changeset
  2503
    Only scheme:
3f4e1c033f40 url: fix crash by empty path with #fragments
Yuya Nishihara <yuya@tcha.org>
parents: 30030
diff changeset
  2504
3f4e1c033f40 url: fix crash by empty path with #fragments
Yuya Nishihara <yuya@tcha.org>
parents: 30030
diff changeset
  2505
    >>> url('http:')
3f4e1c033f40 url: fix crash by empty path with #fragments
Yuya Nishihara <yuya@tcha.org>
parents: 30030
diff changeset
  2506
    <url scheme: 'http'>
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2507
    """
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2508
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2509
    _safechars = "!~*'()+"
20106
c33d9217e99d util: url keeps backslash in paths
Simon Heimberg <simohe@besonet.ch>
parents: 20000
diff changeset
  2510
    _safepchars = "/!~*'()+:\\"
30329
dadb00a0ec0f util: use '\\' rather than using r'\'
Augie Fackler <augie@google.com>
parents: 30328
diff changeset
  2511
    _matchscheme = remod.compile('^[a-zA-Z0-9+.\\-]+:').match
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2512
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2513
    def __init__(self, path, parsequery=True, parsefragment=True):
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2514
        # We slowly chomp away at path until we have only the path left
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2515
        self.scheme = self.user = self.passwd = self.host = None
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2516
        self.port = self.path = self.query = self.fragment = None
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2517
        self._localpath = True
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2518
        self._hostport = ''
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2519
        self._origpath = path
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2520
15074
64fbd0de9773 url: parse fragments first (issue2997)
Matt Mackall <mpm@selenic.com>
parents: 15066
diff changeset
  2521
        if parsefragment and '#' in path:
64fbd0de9773 url: parse fragments first (issue2997)
Matt Mackall <mpm@selenic.com>
parents: 15066
diff changeset
  2522
            path, self.fragment = path.split('#', 1)
64fbd0de9773 url: parse fragments first (issue2997)
Matt Mackall <mpm@selenic.com>
parents: 15066
diff changeset
  2523
14699
388af80c058b url: catch UNC paths as yet another Windows special case (issue2808)
Matt Mackall <mpm@selenic.com>
parents: 14640
diff changeset
  2524
        # special case for Windows drive letters and UNC paths
30329
dadb00a0ec0f util: use '\\' rather than using r'\'
Augie Fackler <augie@google.com>
parents: 30328
diff changeset
  2525
        if hasdriveletter(path) or path.startswith('\\\\'):
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2526
            self.path = path
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2527
            return
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2528
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2529
        # For compatibility reasons, we can't handle bundle paths as
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2530
        # normal URLS
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2531
        if path.startswith('bundle:'):
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2532
            self.scheme = 'bundle'
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2533
            path = path[7:]
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2534
            if path.startswith('//'):
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2535
                path = path[2:]
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2536
            self.path = path
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2537
            return
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2538
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2539
        if self._matchscheme(path):
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2540
            parts = path.split(':', 1)
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2541
            if parts[0]:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2542
                self.scheme, path = parts
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2543
                self._localpath = False
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2544
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2545
        if not path:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2546
            path = None
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2547
            if self._localpath:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2548
                self.path = ''
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2549
                return
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2550
        else:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2551
            if self._localpath:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2552
                self.path = path
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2553
                return
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2554
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2555
            if parsequery and '?' in path:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2556
                path, self.query = path.split('?', 1)
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2557
                if not path:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2558
                    path = None
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2559
                if not self.query:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2560
                    self.query = None
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2561
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2562
            # // is required to specify a host/authority
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2563
            if path and path.startswith('//'):
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2564
                parts = path[2:].split('/', 1)
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2565
                if len(parts) > 1:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2566
                    self.host, path = parts
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2567
                else:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2568
                    self.host = parts[0]
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2569
                    path = None
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2570
                if not self.host:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2571
                    self.host = None
15018
e89f62dcd723 url: really handle urls of the form file:///c:/foo/bar/ correctly
Mads Kiilerich <mads@kiilerich.com>
parents: 14988
diff changeset
  2572
                    # path of file:///d is /d
e89f62dcd723 url: really handle urls of the form file:///c:/foo/bar/ correctly
Mads Kiilerich <mads@kiilerich.com>
parents: 14988
diff changeset
  2573
                    # path of file:///d:/ is d:/, not /d:/
14915
28edd65000d9 url: handle urls of the form file:///c:/foo/bar/ correctly
Matt Mackall <mpm@selenic.com>
parents: 14825
diff changeset
  2574
                    if path and not hasdriveletter(path):
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2575
                        path = '/' + path
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2576
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2577
            if self.host and '@' in self.host:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2578
                self.user, self.host = self.host.rsplit('@', 1)
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2579
                if ':' in self.user:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2580
                    self.user, self.passwd = self.user.split(':', 1)
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2581
                if not self.host:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2582
                    self.host = None
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2583
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2584
            # Don't split on colons in IPv6 addresses without ports
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2585
            if (self.host and ':' in self.host and
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2586
                not (self.host.startswith('[') and self.host.endswith(']'))):
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2587
                self._hostport = self.host
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2588
                self.host, self.port = self.host.rsplit(':', 1)
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2589
                if not self.host:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2590
                    self.host = None
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2591
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2592
            if (self.host and self.scheme == 'file' and
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2593
                self.host not in ('localhost', '127.0.0.1', '[::1]')):
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2594
                raise Abort(_('file:// URLs can only refer to localhost'))
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2595
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2596
        self.path = path
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2597
14988
e6730f9e13bc url: store and assume the query part of an url is in escaped form (issue2921)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 14915
diff changeset
  2598
        # leave the query string escaped
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2599
        for a in ('user', 'passwd', 'host', 'port',
14988
e6730f9e13bc url: store and assume the query part of an url is in escaped form (issue2921)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 14915
diff changeset
  2600
                  'path', 'fragment'):
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2601
            v = getattr(self, a)
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2602
            if v is not None:
30328
2d996af02fd8 util: use pycompat urlunquote function
Augie Fackler <augie@google.com>
parents: 30309
diff changeset
  2603
                setattr(self, a, pycompat.urlunquote(v))
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2604
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2605
    def __repr__(self):
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2606
        attrs = []
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2607
        for a in ('scheme', 'user', 'passwd', 'host', 'port', 'path',
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2608
                  'query', 'fragment'):
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2609
            v = getattr(self, a)
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2610
            if v is not None:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2611
                attrs.append('%s: %r' % (a, v))
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2612
        return '<url %s>' % ', '.join(attrs)
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2613
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2614
    def __str__(self):
14147
617483af1cc0 test: test that backslash is preserved by the url class
Mads Kiilerich <mads@kiilerich.com>
parents: 14146
diff changeset
  2615
        r"""Join the URL's components back into a URL string.
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2616
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2617
        Examples:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2618
15452
de7e2fba4326 util: don't encode ':' in url paths
Mads Kiilerich <mads@kiilerich.com>
parents: 15392
diff changeset
  2619
        >>> str(url('http://user:pw@host:80/c:/bob?fo:oo#ba:ar'))
de7e2fba4326 util: don't encode ':' in url paths
Mads Kiilerich <mads@kiilerich.com>
parents: 15392
diff changeset
  2620
        'http://user:pw@host:80/c:/bob?fo:oo#ba:ar'
14988
e6730f9e13bc url: store and assume the query part of an url is in escaped form (issue2921)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 14915
diff changeset
  2621
        >>> str(url('http://user:pw@host:80/?foo=bar&baz=42'))
e6730f9e13bc url: store and assume the query part of an url is in escaped form (issue2921)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 14915
diff changeset
  2622
        'http://user:pw@host:80/?foo=bar&baz=42'
e6730f9e13bc url: store and assume the query part of an url is in escaped form (issue2921)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 14915
diff changeset
  2623
        >>> str(url('http://user:pw@host:80/?foo=bar%3dbaz'))
e6730f9e13bc url: store and assume the query part of an url is in escaped form (issue2921)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 14915
diff changeset
  2624
        'http://user:pw@host:80/?foo=bar%3dbaz'
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2625
        >>> str(url('ssh://user:pw@[::1]:2200//home/joe#'))
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2626
        'ssh://user:pw@[::1]:2200//home/joe#'
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2627
        >>> str(url('http://localhost:80//'))
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2628
        'http://localhost:80//'
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2629
        >>> str(url('http://localhost:80/'))
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2630
        'http://localhost:80/'
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2631
        >>> str(url('http://localhost:80'))
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2632
        'http://localhost:80/'
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2633
        >>> str(url('bundle:foo'))
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2634
        'bundle:foo'
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2635
        >>> str(url('bundle://../foo'))
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2636
        'bundle:../foo'
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2637
        >>> str(url('path'))
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2638
        'path'
14313
a389dd285282 util: make str(url) return file:/// for abs paths again
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 14271
diff changeset
  2639
        >>> str(url('file:///tmp/foo/bar'))
a389dd285282 util: make str(url) return file:/// for abs paths again
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 14271
diff changeset
  2640
        'file:///tmp/foo/bar'
15609
8f4bad72d8b1 util: fix url.__str__() for windows file URLs
Patrick Mezard <pmezard@gmail.com>
parents: 15505
diff changeset
  2641
        >>> str(url('file:///c:/tmp/foo/bar'))
15611
ec8a49c46d7e merge with stable
Matt Mackall <mpm@selenic.com>
parents: 15513 15609
diff changeset
  2642
        'file:///c:/tmp/foo/bar'
14147
617483af1cc0 test: test that backslash is preserved by the url class
Mads Kiilerich <mads@kiilerich.com>
parents: 14146
diff changeset
  2643
        >>> print url(r'bundle:foo\bar')
617483af1cc0 test: test that backslash is preserved by the url class
Mads Kiilerich <mads@kiilerich.com>
parents: 14146
diff changeset
  2644
        bundle:foo\bar
20106
c33d9217e99d util: url keeps backslash in paths
Simon Heimberg <simohe@besonet.ch>
parents: 20000
diff changeset
  2645
        >>> print url(r'file:///D:\data\hg')
c33d9217e99d util: url keeps backslash in paths
Simon Heimberg <simohe@besonet.ch>
parents: 20000
diff changeset
  2646
        file:///D:\data\hg
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2647
        """
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2648
        if self._localpath:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2649
            s = self.path
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2650
            if self.scheme == 'bundle':
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2651
                s = 'bundle:' + s
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2652
            if self.fragment:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2653
                s += '#' + self.fragment
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2654
            return s
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2655
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2656
        s = self.scheme + ':'
14313
a389dd285282 util: make str(url) return file:/// for abs paths again
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 14271
diff changeset
  2657
        if self.user or self.passwd or self.host:
a389dd285282 util: make str(url) return file:/// for abs paths again
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 14271
diff changeset
  2658
            s += '//'
15609
8f4bad72d8b1 util: fix url.__str__() for windows file URLs
Patrick Mezard <pmezard@gmail.com>
parents: 15505
diff changeset
  2659
        elif self.scheme and (not self.path or self.path.startswith('/')
8f4bad72d8b1 util: fix url.__str__() for windows file URLs
Patrick Mezard <pmezard@gmail.com>
parents: 15505
diff changeset
  2660
                              or hasdriveletter(self.path)):
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2661
            s += '//'
15609
8f4bad72d8b1 util: fix url.__str__() for windows file URLs
Patrick Mezard <pmezard@gmail.com>
parents: 15505
diff changeset
  2662
            if hasdriveletter(self.path):
8f4bad72d8b1 util: fix url.__str__() for windows file URLs
Patrick Mezard <pmezard@gmail.com>
parents: 15505
diff changeset
  2663
                s += '/'
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2664
        if self.user:
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28882
diff changeset
  2665
            s += urlreq.quote(self.user, safe=self._safechars)
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2666
        if self.passwd:
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28882
diff changeset
  2667
            s += ':' + urlreq.quote(self.passwd, safe=self._safechars)
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2668
        if self.user or self.passwd:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2669
            s += '@'
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2670
        if self.host:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2671
            if not (self.host.startswith('[') and self.host.endswith(']')):
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28882
diff changeset
  2672
                s += urlreq.quote(self.host)
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2673
            else:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2674
                s += self.host
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2675
        if self.port:
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28882
diff changeset
  2676
            s += ':' + urlreq.quote(self.port)
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2677
        if self.host:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2678
            s += '/'
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2679
        if self.path:
14988
e6730f9e13bc url: store and assume the query part of an url is in escaped form (issue2921)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 14915
diff changeset
  2680
            # TODO: similar to the query string, we should not unescape the
e6730f9e13bc url: store and assume the query part of an url is in escaped form (issue2921)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 14915
diff changeset
  2681
            # path when we store it, the path might contain '%2f' = '/',
e6730f9e13bc url: store and assume the query part of an url is in escaped form (issue2921)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 14915
diff changeset
  2682
            # which we should *not* escape.
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28882
diff changeset
  2683
            s += urlreq.quote(self.path, safe=self._safepchars)
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2684
        if self.query:
14988
e6730f9e13bc url: store and assume the query part of an url is in escaped form (issue2921)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 14915
diff changeset
  2685
            # we store the query in escaped form.
e6730f9e13bc url: store and assume the query part of an url is in escaped form (issue2921)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 14915
diff changeset
  2686
            s += '?' + self.query
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2687
        if self.fragment is not None:
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28882
diff changeset
  2688
            s += '#' + urlreq.quote(self.fragment, safe=self._safepchars)
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2689
        return s
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2690
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2691
    def authinfo(self):
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2692
        user, passwd = self.user, self.passwd
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2693
        try:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2694
            self.user, self.passwd = None, None
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2695
            s = str(self)
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2696
        finally:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2697
            self.user, self.passwd = user, passwd
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2698
        if not self.user:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2699
            return (s, None)
15028
eb97a3e38656 http: explain why the host is passed to urllib2 password manager
Patrick Mezard <pmezard@gmail.com>
parents: 15027
diff changeset
  2700
        # authinfo[1] is passed to urllib2 password manager, and its
eb97a3e38656 http: explain why the host is passed to urllib2 password manager
Patrick Mezard <pmezard@gmail.com>
parents: 15027
diff changeset
  2701
        # URIs must not contain credentials. The host is passed in the
eb97a3e38656 http: explain why the host is passed to urllib2 password manager
Patrick Mezard <pmezard@gmail.com>
parents: 15027
diff changeset
  2702
        # URIs list because Python < 2.4.3 uses only that to search for
eb97a3e38656 http: explain why the host is passed to urllib2 password manager
Patrick Mezard <pmezard@gmail.com>
parents: 15027
diff changeset
  2703
        # a password.
15024
0f1311e829c9 http: strip credentials from urllib2 manager URIs (issue2885)
Patrick Mezard <pmezard@gmail.com>
parents: 15018
diff changeset
  2704
        return (s, (None, (s, self.host),
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2705
                    self.user, self.passwd or ''))
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2706
14766
4f56b7530eab subrepos: be smarter about what's an absolute path (issue2808)
Matt Mackall <mpm@selenic.com>
parents: 14699
diff changeset
  2707
    def isabs(self):
4f56b7530eab subrepos: be smarter about what's an absolute path (issue2808)
Matt Mackall <mpm@selenic.com>
parents: 14699
diff changeset
  2708
        if self.scheme and self.scheme != 'file':
4f56b7530eab subrepos: be smarter about what's an absolute path (issue2808)
Matt Mackall <mpm@selenic.com>
parents: 14699
diff changeset
  2709
            return True # remote URL
4f56b7530eab subrepos: be smarter about what's an absolute path (issue2808)
Matt Mackall <mpm@selenic.com>
parents: 14699
diff changeset
  2710
        if hasdriveletter(self.path):
4f56b7530eab subrepos: be smarter about what's an absolute path (issue2808)
Matt Mackall <mpm@selenic.com>
parents: 14699
diff changeset
  2711
            return True # absolute for our purposes - can't be joined()
4f56b7530eab subrepos: be smarter about what's an absolute path (issue2808)
Matt Mackall <mpm@selenic.com>
parents: 14699
diff changeset
  2712
        if self.path.startswith(r'\\'):
4f56b7530eab subrepos: be smarter about what's an absolute path (issue2808)
Matt Mackall <mpm@selenic.com>
parents: 14699
diff changeset
  2713
            return True # Windows UNC path
4f56b7530eab subrepos: be smarter about what's an absolute path (issue2808)
Matt Mackall <mpm@selenic.com>
parents: 14699
diff changeset
  2714
        if self.path.startswith('/'):
4f56b7530eab subrepos: be smarter about what's an absolute path (issue2808)
Matt Mackall <mpm@selenic.com>
parents: 14699
diff changeset
  2715
            return True # POSIX-style
4f56b7530eab subrepos: be smarter about what's an absolute path (issue2808)
Matt Mackall <mpm@selenic.com>
parents: 14699
diff changeset
  2716
        return False
4f56b7530eab subrepos: be smarter about what's an absolute path (issue2808)
Matt Mackall <mpm@selenic.com>
parents: 14699
diff changeset
  2717
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2718
    def localpath(self):
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2719
        if self.scheme == 'file' or self.scheme == 'bundle':
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2720
            path = self.path or '/'
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2721
            # For Windows, we need to promote hosts containing drive
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2722
            # letters to paths with drive letters.
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2723
            if hasdriveletter(self._hostport):
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2724
                path = self._hostport + '/' + self.path
15496
396e83d635a6 url: handle file://localhost/c:/foo "correctly"
Mads Kiilerich <mads@kiilerich.com>
parents: 15488
diff changeset
  2725
            elif (self.host is not None and self.path
396e83d635a6 url: handle file://localhost/c:/foo "correctly"
Mads Kiilerich <mads@kiilerich.com>
parents: 15488
diff changeset
  2726
                  and not hasdriveletter(path)):
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2727
                path = '/' + path
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2728
            return path
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2729
        return self._origpath
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2730
20353
0889585b44f1 util.url: add an 'islocal' method
Siddharth Agarwal <sid0@fb.com>
parents: 20244
diff changeset
  2731
    def islocal(self):
0889585b44f1 util.url: add an 'islocal' method
Siddharth Agarwal <sid0@fb.com>
parents: 20244
diff changeset
  2732
        '''whether localpath will return something that posixfile can open'''
0889585b44f1 util.url: add an 'islocal' method
Siddharth Agarwal <sid0@fb.com>
parents: 20244
diff changeset
  2733
        return (not self.scheme or self.scheme == 'file'
0889585b44f1 util.url: add an 'islocal' method
Siddharth Agarwal <sid0@fb.com>
parents: 20244
diff changeset
  2734
                or self.scheme == 'bundle')
0889585b44f1 util.url: add an 'islocal' method
Siddharth Agarwal <sid0@fb.com>
parents: 20244
diff changeset
  2735
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2736
def hasscheme(path):
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2737
    return bool(url(path).scheme)
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2738
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2739
def hasdriveletter(path):
15609
8f4bad72d8b1 util: fix url.__str__() for windows file URLs
Patrick Mezard <pmezard@gmail.com>
parents: 15505
diff changeset
  2740
    return path and path[1:2] == ':' and path[0:1].isalpha()
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2741
14825
de9eb6b1da4f util: rename the util.localpath that uses url to urllocalpath (issue2875)
Mads Kiilerich <mads@kiilerich.com>
parents: 14766
diff changeset
  2742
def urllocalpath(path):
14076
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2743
    return url(path, parsequery=False, parsefragment=False).localpath()
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2744
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2745
def hidepassword(u):
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2746
    '''hide user credential in a url string'''
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2747
    u = url(u)
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2748
    if u.passwd:
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2749
        u.passwd = '***'
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2750
    return str(u)
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2751
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2752
def removeauth(u):
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2753
    '''remove all authentication information from a url string'''
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2754
    u = url(u)
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2755
    u.user = u.passwd = None
924c82157d46 url: move URL parsing functions into util to improve startup time
Brodie Rao <brodie@bitheap.org>
parents: 14064
diff changeset
  2756
    return str(u)
14515
76f295eaed86 util: add helper function isatty(fd) to check for tty-ness
Idan Kamara <idankk86@gmail.com>
parents: 14313
diff changeset
  2757
18736
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2758
timecount = unitcountfn(
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2759
    (1, 1e3, _('%.0f s')),
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2760
    (100, 1, _('%.1f s')),
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2761
    (10, 1, _('%.2f s')),
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2762
    (1, 1, _('%.3f s')),
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2763
    (100, 0.001, _('%.1f ms')),
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2764
    (10, 0.001, _('%.2f ms')),
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2765
    (1, 0.001, _('%.3f ms')),
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2766
    (100, 0.000001, _('%.1f us')),
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2767
    (10, 0.000001, _('%.2f us')),
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2768
    (1, 0.000001, _('%.3f us')),
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2769
    (100, 0.000000001, _('%.1f ns')),
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2770
    (10, 0.000000001, _('%.2f ns')),
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2771
    (1, 0.000000001, _('%.3f ns')),
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2772
    )
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2773
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2774
_timenesting = [0]
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2775
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2776
def timed(func):
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2777
    '''Report the execution time of a function call to stderr.
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2778
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2779
    During development, use as a decorator when you need to measure
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2780
    the cost of a function, e.g. as follows:
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2781
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2782
    @util.timed
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2783
    def foo(a, b, c):
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2784
        pass
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2785
    '''
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2786
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2787
    def wrapper(*args, **kwargs):
30975
22fbca1d11ed mercurial: switch to util.timer for all interval timings
Simon Farnsworth <simonfar@fb.com>
parents: 30974
diff changeset
  2788
        start = timer()
18736
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2789
        indent = 2
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2790
        _timenesting[0] += indent
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2791
        try:
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2792
            return func(*args, **kwargs)
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2793
        finally:
30975
22fbca1d11ed mercurial: switch to util.timer for all interval timings
Simon Farnsworth <simonfar@fb.com>
parents: 30974
diff changeset
  2794
            elapsed = timer() - start
18736
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2795
            _timenesting[0] -= indent
30473
39d13b8c101d py3: bulk replace sys.stdin/out/err by util's
Yuya Nishihara <yuya@tcha.org>
parents: 30472
diff changeset
  2796
            stderr.write('%s%s: %s\n' %
39d13b8c101d py3: bulk replace sys.stdin/out/err by util's
Yuya Nishihara <yuya@tcha.org>
parents: 30472
diff changeset
  2797
                         (' ' * _timenesting[0], func.__name__,
39d13b8c101d py3: bulk replace sys.stdin/out/err by util's
Yuya Nishihara <yuya@tcha.org>
parents: 30472
diff changeset
  2798
                          timecount(elapsed)))
18736
af9ddea2cb99 util: add a timed function for use during development
Bryan O'Sullivan <bryano@fb.com>
parents: 18735
diff changeset
  2799
    return wrapper
19194
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2800
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2801
_sizeunits = (('m', 2**20), ('k', 2**10), ('g', 2**30),
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2802
              ('kb', 2**10), ('mb', 2**20), ('gb', 2**30), ('b', 1))
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2803
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2804
def sizetoint(s):
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2805
    '''Convert a space specifier to a byte count.
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2806
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2807
    >>> sizetoint('30')
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2808
    30
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2809
    >>> sizetoint('2.2kb')
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2810
    2252
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2811
    >>> sizetoint('6M')
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2812
    6291456
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2813
    '''
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2814
    t = s.strip().lower()
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2815
    try:
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2816
        for k, u in _sizeunits:
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2817
            if t.endswith(k):
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2818
                return int(float(t[:-len(k)]) * u)
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2819
        return int(t)
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2820
    except ValueError:
1d08df65cd3c util: migrate fileset._sizetoint to util.sizetoint
Bryan O'Sullivan <bryano@fb.com>
parents: 18938
diff changeset
  2821
        raise error.ParseError(_("couldn't parse size: %s") % s)
19211
3bfd7f1e7485 summary: augment output with info from extensions
Bryan O'Sullivan <bryano@fb.com>
parents: 19194
diff changeset
  2822
3bfd7f1e7485 summary: augment output with info from extensions
Bryan O'Sullivan <bryano@fb.com>
parents: 19194
diff changeset
  2823
class hooks(object):
3bfd7f1e7485 summary: augment output with info from extensions
Bryan O'Sullivan <bryano@fb.com>
parents: 19194
diff changeset
  2824
    '''A collection of hook functions that can be used to extend a
26098
ce26928cbe41 spelling: behaviour -> behavior
timeless@mozdev.org
parents: 25672
diff changeset
  2825
    function's behavior. Hooks are called in lexicographic order,
19211
3bfd7f1e7485 summary: augment output with info from extensions
Bryan O'Sullivan <bryano@fb.com>
parents: 19194
diff changeset
  2826
    based on the names of their sources.'''
3bfd7f1e7485 summary: augment output with info from extensions
Bryan O'Sullivan <bryano@fb.com>
parents: 19194
diff changeset
  2827
3bfd7f1e7485 summary: augment output with info from extensions
Bryan O'Sullivan <bryano@fb.com>
parents: 19194
diff changeset
  2828
    def __init__(self):
3bfd7f1e7485 summary: augment output with info from extensions
Bryan O'Sullivan <bryano@fb.com>
parents: 19194
diff changeset
  2829
        self._hooks = []
3bfd7f1e7485 summary: augment output with info from extensions
Bryan O'Sullivan <bryano@fb.com>
parents: 19194
diff changeset
  2830
3bfd7f1e7485 summary: augment output with info from extensions
Bryan O'Sullivan <bryano@fb.com>
parents: 19194
diff changeset
  2831
    def add(self, source, hook):
3bfd7f1e7485 summary: augment output with info from extensions
Bryan O'Sullivan <bryano@fb.com>
parents: 19194
diff changeset
  2832
        self._hooks.append((source, hook))
3bfd7f1e7485 summary: augment output with info from extensions
Bryan O'Sullivan <bryano@fb.com>
parents: 19194
diff changeset
  2833
3bfd7f1e7485 summary: augment output with info from extensions
Bryan O'Sullivan <bryano@fb.com>
parents: 19194
diff changeset
  2834
    def __call__(self, *args):
3bfd7f1e7485 summary: augment output with info from extensions
Bryan O'Sullivan <bryano@fb.com>
parents: 19194
diff changeset
  2835
        self._hooks.sort(key=lambda x: x[0])
21046
cc13addbd62b util: enable "hooks" to return list of the values returned from each hooks
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 21018
diff changeset
  2836
        results = []
19211
3bfd7f1e7485 summary: augment output with info from extensions
Bryan O'Sullivan <bryano@fb.com>
parents: 19194
diff changeset
  2837
        for source, hook in self._hooks:
21046
cc13addbd62b util: enable "hooks" to return list of the values returned from each hooks
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 21018
diff changeset
  2838
            results.append(hook(*args))
cc13addbd62b util: enable "hooks" to return list of the values returned from each hooks
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 21018
diff changeset
  2839
        return results
20244
47d0843647d1 util: introduce util.debugstacktrace for showing a stack trace without crashing
Mads Kiilerich <madski@unity3d.com>
parents: 20202
diff changeset
  2840
28497
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2841
def getstackframes(skip=0, line=' %-*s in %s\n', fileline='%s:%s'):
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2842
    '''Yields lines for a nicely formatted stacktrace.
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2843
    Skips the 'skip' last entries.
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2844
    Each file+linenumber is formatted according to fileline.
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2845
    Each line is formatted according to line.
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2846
    If line is None, it yields:
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2847
      length of longest filepath+line number,
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2848
      filepath+linenumber,
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2849
      function
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2850
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2851
    Not be used in production code but very convenient while developing.
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2852
    '''
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2853
    entries = [(fileline % (fn, ln), func)
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2854
        for fn, ln, func, _text in traceback.extract_stack()[:-skip - 1]]
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2855
    if entries:
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2856
        fnmax = max(len(entry[0]) for entry in entries)
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2857
        for fnln, func in entries:
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2858
            if line is None:
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2859
                yield (fnmax, fnln, func)
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2860
            else:
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2861
                yield line % (fnmax, fnln, func)
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2862
30473
39d13b8c101d py3: bulk replace sys.stdin/out/err by util's
Yuya Nishihara <yuya@tcha.org>
parents: 30472
diff changeset
  2863
def debugstacktrace(msg='stacktrace', skip=0, f=stderr, otherf=stdout):
20244
47d0843647d1 util: introduce util.debugstacktrace for showing a stack trace without crashing
Mads Kiilerich <madski@unity3d.com>
parents: 20202
diff changeset
  2864
    '''Writes a message to f (stderr) with a nicely formatted stacktrace.
20542
be27652675ce util: debugstacktrace, flush before and after writing
Mads Kiilerich <madski@unity3d.com>
parents: 20353
diff changeset
  2865
    Skips the 'skip' last entries. By default it will flush stdout first.
28496
b592564a803c util: reword debugstacktrace comment
timeless <timeless@mozdev.org>
parents: 28027
diff changeset
  2866
    It can be used everywhere and intentionally does not require an ui object.
20244
47d0843647d1 util: introduce util.debugstacktrace for showing a stack trace without crashing
Mads Kiilerich <madski@unity3d.com>
parents: 20202
diff changeset
  2867
    Not be used in production code but very convenient while developing.
47d0843647d1 util: introduce util.debugstacktrace for showing a stack trace without crashing
Mads Kiilerich <madski@unity3d.com>
parents: 20202
diff changeset
  2868
    '''
20542
be27652675ce util: debugstacktrace, flush before and after writing
Mads Kiilerich <madski@unity3d.com>
parents: 20353
diff changeset
  2869
    if otherf:
be27652675ce util: debugstacktrace, flush before and after writing
Mads Kiilerich <madski@unity3d.com>
parents: 20353
diff changeset
  2870
        otherf.flush()
20244
47d0843647d1 util: introduce util.debugstacktrace for showing a stack trace without crashing
Mads Kiilerich <madski@unity3d.com>
parents: 20202
diff changeset
  2871
    f.write('%s at:\n' % msg)
28497
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2872
    for line in getstackframes(skip + 1):
906fece80cfa util: refactor getstackframes
timeless <timeless@mozdev.org>
parents: 28496
diff changeset
  2873
        f.write(line)
20542
be27652675ce util: debugstacktrace, flush before and after writing
Mads Kiilerich <madski@unity3d.com>
parents: 20353
diff changeset
  2874
    f.flush()
20244
47d0843647d1 util: introduce util.debugstacktrace for showing a stack trace without crashing
Mads Kiilerich <madski@unity3d.com>
parents: 20202
diff changeset
  2875
24635
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2876
class dirs(object):
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2877
    '''a multiset of directory names from a dirstate or manifest'''
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2878
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2879
    def __init__(self, map, skip=None):
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2880
        self._dirs = {}
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2881
        addpath = self.addpath
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2882
        if safehasattr(map, 'iteritems') and skip is not None:
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2883
            for f, s in map.iteritems():
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2884
                if s[0] != skip:
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2885
                    addpath(f)
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2886
        else:
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2887
            for f in map:
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2888
                addpath(f)
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2889
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2890
    def addpath(self, path):
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2891
        dirs = self._dirs
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2892
        for base in finddirs(path):
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2893
            if base in dirs:
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2894
                dirs[base] += 1
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2895
                return
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2896
            dirs[base] = 1
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2897
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2898
    def delpath(self, path):
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2899
        dirs = self._dirs
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2900
        for base in finddirs(path):
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2901
            if dirs[base] > 1:
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2902
                dirs[base] -= 1
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2903
                return
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2904
            del dirs[base]
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2905
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2906
    def __iter__(self):
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2907
        return self._dirs.iterkeys()
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2908
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2909
    def __contains__(self, d):
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2910
        return d in self._dirs
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2911
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2912
if safehasattr(parsers, 'dirs'):
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2913
    dirs = parsers.dirs
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2914
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2915
def finddirs(path):
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2916
    pos = path.rfind('/')
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2917
    while pos != -1:
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2918
        yield path[:pos]
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2919
        pos = path.rfind('/', 0, pos)
21e1ece30f8c util: move dirs() and finddirs() from scmutil to util
Drew Gottlieb <drgott@google.com>
parents: 24605
diff changeset
  2920
27703
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2921
class ctxmanager(object):
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2922
    '''A context manager for use in 'with' blocks to allow multiple
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2923
    contexts to be entered at once.  This is both safer and more
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2924
    flexible than contextlib.nested.
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2925
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2926
    Once Mercurial supports Python 2.7+, this will become mostly
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2927
    unnecessary.
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2928
    '''
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2929
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2930
    def __init__(self, *args):
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2931
        '''Accepts a list of no-argument functions that return context
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2932
        managers.  These will be invoked at __call__ time.'''
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2933
        self._pending = args
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2934
        self._atexit = []
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2935
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2936
    def __enter__(self):
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2937
        return self
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2938
27785
ba427b51f1d8 util: rename ctxmanager's __call__ method to enter
Bryan O'Sullivan <bryano@fb.com>
parents: 27778
diff changeset
  2939
    def enter(self):
27703
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2940
        '''Create and enter context managers in the order in which they were
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2941
        passed to the constructor.'''
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2942
        values = []
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2943
        for func in self._pending:
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2944
            obj = func()
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2945
            values.append(obj.__enter__())
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2946
            self._atexit.append(obj.__exit__)
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2947
        del self._pending
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2948
        return values
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2949
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2950
    def atexit(self, func, *args, **kwargs):
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2951
        '''Add a function to call when this context manager exits.  The
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2952
        ordering of multiple atexit calls is unspecified, save that
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2953
        they will happen before any __exit__ functions.'''
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2954
        def wrapper(exc_type, exc_val, exc_tb):
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2955
            func(*args, **kwargs)
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2956
        self._atexit.append(wrapper)
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2957
        return func
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2958
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2959
    def __exit__(self, exc_type, exc_val, exc_tb):
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2960
        '''Context managers are exited in the reverse order from which
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2961
        they were created.'''
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2962
        received = exc_type is not None
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2963
        suppressed = False
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2964
        pending = None
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2965
        self._atexit.reverse()
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2966
        for exitfunc in self._atexit:
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2967
            try:
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2968
                if exitfunc(exc_type, exc_val, exc_tb):
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2969
                    suppressed = True
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2970
                    exc_type = None
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2971
                    exc_val = None
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2972
                    exc_tb = None
27755
50c5192e4a5e util: don't capture exception with a name since we don't use it
Augie Fackler <augie@google.com>
parents: 27703
diff changeset
  2973
            except BaseException:
27703
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2974
                pending = sys.exc_info()
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2975
                exc_type, exc_val, exc_tb = pending = sys.exc_info()
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2976
        del self._atexit
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2977
        if pending:
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2978
            raise exc_val
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2979
        return received and suppressed
4e27c0a70574 util: introduce ctxmanager, to avoid nested try/finally blocks
Bryan O'Sullivan <bos@serpentine.com>
parents: 27667
diff changeset
  2980
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  2981
# compression code
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  2982
30761
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  2983
SERVERROLE = 'server'
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  2984
CLIENTROLE = 'client'
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  2985
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  2986
compewireprotosupport = collections.namedtuple(u'compenginewireprotosupport',
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  2987
                                               (u'name', u'serverpriority',
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  2988
                                                u'clientpriority'))
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  2989
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  2990
class compressormanager(object):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  2991
    """Holds registrations of various compression engines.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  2992
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  2993
    This class essentially abstracts the differences between compression
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  2994
    engines to allow new compression formats to be added easily, possibly from
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  2995
    extensions.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  2996
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  2997
    Compressors are registered against the global instance by calling its
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  2998
    ``register()`` method.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  2999
    """
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3000
    def __init__(self):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3001
        self._engines = {}
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3002
        # Bundle spec human name to engine name.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3003
        self._bundlenames = {}
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3004
        # Internal bundle identifier to engine name.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3005
        self._bundletypes = {}
30798
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3006
        # Revlog header to engine name.
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3007
        self._revlogheaders = {}
30761
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3008
        # Wire proto identifier to engine name.
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3009
        self._wiretypes = {}
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3010
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3011
    def __getitem__(self, key):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3012
        return self._engines[key]
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3013
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3014
    def __contains__(self, key):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3015
        return key in self._engines
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3016
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3017
    def __iter__(self):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3018
        return iter(self._engines.keys())
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3019
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3020
    def register(self, engine):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3021
        """Register a compression engine with the manager.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3022
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3023
        The argument must be a ``compressionengine`` instance.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3024
        """
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3025
        if not isinstance(engine, compressionengine):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3026
            raise ValueError(_('argument must be a compressionengine'))
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3027
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3028
        name = engine.name()
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3029
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3030
        if name in self._engines:
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3031
            raise error.Abort(_('compression engine %s already registered') %
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3032
                              name)
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3033
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3034
        bundleinfo = engine.bundletype()
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3035
        if bundleinfo:
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3036
            bundlename, bundletype = bundleinfo
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3037
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3038
            if bundlename in self._bundlenames:
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3039
                raise error.Abort(_('bundle name %s already registered') %
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3040
                                  bundlename)
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3041
            if bundletype in self._bundletypes:
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3042
                raise error.Abort(_('bundle type %s already registered by %s') %
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3043
                                  (bundletype, self._bundletypes[bundletype]))
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3044
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3045
            # No external facing name declared.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3046
            if bundlename:
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3047
                self._bundlenames[bundlename] = name
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3048
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3049
            self._bundletypes[bundletype] = name
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3050
30761
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3051
        wiresupport = engine.wireprotosupport()
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3052
        if wiresupport:
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3053
            wiretype = wiresupport.name
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3054
            if wiretype in self._wiretypes:
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3055
                raise error.Abort(_('wire protocol compression %s already '
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3056
                                    'registered by %s') %
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3057
                                  (wiretype, self._wiretypes[wiretype]))
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3058
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3059
            self._wiretypes[wiretype] = name
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3060
30798
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3061
        revlogheader = engine.revlogheader()
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3062
        if revlogheader and revlogheader in self._revlogheaders:
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3063
            raise error.Abort(_('revlog header %s already registered by %s') %
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3064
                              (revlogheader, self._revlogheaders[revlogheader]))
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3065
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3066
        if revlogheader:
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3067
            self._revlogheaders[revlogheader] = name
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3068
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3069
        self._engines[name] = engine
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3070
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3071
    @property
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3072
    def supportedbundlenames(self):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3073
        return set(self._bundlenames.keys())
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3074
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3075
    @property
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3076
    def supportedbundletypes(self):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3077
        return set(self._bundletypes.keys())
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3078
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3079
    def forbundlename(self, bundlename):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3080
        """Obtain a compression engine registered to a bundle name.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3081
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3082
        Will raise KeyError if the bundle type isn't registered.
30438
90933e4e44fd util: check for compression engine availability before returning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30437
diff changeset
  3083
90933e4e44fd util: check for compression engine availability before returning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30437
diff changeset
  3084
        Will abort if the engine is known but not available.
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3085
        """
30438
90933e4e44fd util: check for compression engine availability before returning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30437
diff changeset
  3086
        engine = self._engines[self._bundlenames[bundlename]]
90933e4e44fd util: check for compression engine availability before returning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30437
diff changeset
  3087
        if not engine.available():
90933e4e44fd util: check for compression engine availability before returning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30437
diff changeset
  3088
            raise error.Abort(_('compression engine %s could not be loaded') %
90933e4e44fd util: check for compression engine availability before returning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30437
diff changeset
  3089
                              engine.name())
90933e4e44fd util: check for compression engine availability before returning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30437
diff changeset
  3090
        return engine
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3091
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3092
    def forbundletype(self, bundletype):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3093
        """Obtain a compression engine registered to a bundle type.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3094
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3095
        Will raise KeyError if the bundle type isn't registered.
30438
90933e4e44fd util: check for compression engine availability before returning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30437
diff changeset
  3096
90933e4e44fd util: check for compression engine availability before returning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30437
diff changeset
  3097
        Will abort if the engine is known but not available.
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3098
        """
30438
90933e4e44fd util: check for compression engine availability before returning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30437
diff changeset
  3099
        engine = self._engines[self._bundletypes[bundletype]]
90933e4e44fd util: check for compression engine availability before returning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30437
diff changeset
  3100
        if not engine.available():
90933e4e44fd util: check for compression engine availability before returning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30437
diff changeset
  3101
            raise error.Abort(_('compression engine %s could not be loaded') %
90933e4e44fd util: check for compression engine availability before returning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30437
diff changeset
  3102
                              engine.name())
90933e4e44fd util: check for compression engine availability before returning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30437
diff changeset
  3103
        return engine
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3104
30761
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3105
    def supportedwireengines(self, role, onlyavailable=True):
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3106
        """Obtain compression engines that support the wire protocol.
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3107
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3108
        Returns a list of engines in prioritized order, most desired first.
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3109
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3110
        If ``onlyavailable`` is set, filter out engines that can't be
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3111
        loaded.
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3112
        """
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3113
        assert role in (SERVERROLE, CLIENTROLE)
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3114
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3115
        attr = 'serverpriority' if role == SERVERROLE else 'clientpriority'
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3116
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3117
        engines = [self._engines[e] for e in self._wiretypes.values()]
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3118
        if onlyavailable:
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3119
            engines = [e for e in engines if e.available()]
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3120
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3121
        def getkey(e):
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3122
            # Sort first by priority, highest first. In case of tie, sort
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3123
            # alphabetically. This is arbitrary, but ensures output is
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3124
            # stable.
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3125
            w = e.wireprotosupport()
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3126
            return -1 * getattr(w, attr), w.name
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3127
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3128
        return list(sorted(engines, key=getkey))
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3129
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3130
    def forwiretype(self, wiretype):
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3131
        engine = self._engines[self._wiretypes[wiretype]]
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3132
        if not engine.available():
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3133
            raise error.Abort(_('compression engine %s could not be loaded') %
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3134
                              engine.name())
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3135
        return engine
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3136
30798
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3137
    def forrevlogheader(self, header):
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3138
        """Obtain a compression engine registered to a revlog header.
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3139
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3140
        Will raise KeyError if the revlog header value isn't registered.
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3141
        """
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3142
        return self._engines[self._revlogheaders[header]]
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3143
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3144
compengines = compressormanager()
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3145
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3146
class compressionengine(object):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3147
    """Base class for compression engines.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3148
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3149
    Compression engines must implement the interface defined by this class.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3150
    """
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3151
    def name(self):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3152
        """Returns the name of the compression engine.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3153
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3154
        This is the key the engine is registered under.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3155
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3156
        This method must be implemented.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3157
        """
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3158
        raise NotImplementedError()
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3159
30437
64d7275445d0 util: expose an "available" API on compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30418
diff changeset
  3160
    def available(self):
64d7275445d0 util: expose an "available" API on compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30418
diff changeset
  3161
        """Whether the compression engine is available.
64d7275445d0 util: expose an "available" API on compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30418
diff changeset
  3162
64d7275445d0 util: expose an "available" API on compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30418
diff changeset
  3163
        The intent of this method is to allow optional compression engines
64d7275445d0 util: expose an "available" API on compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30418
diff changeset
  3164
        that may not be available in all installations (such as engines relying
64d7275445d0 util: expose an "available" API on compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30418
diff changeset
  3165
        on C extensions that may not be present).
64d7275445d0 util: expose an "available" API on compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30418
diff changeset
  3166
        """
64d7275445d0 util: expose an "available" API on compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30418
diff changeset
  3167
        return True
64d7275445d0 util: expose an "available" API on compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30418
diff changeset
  3168
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3169
    def bundletype(self):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3170
        """Describes bundle identifiers for this engine.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3171
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3172
        If this compression engine isn't supported for bundles, returns None.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3173
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3174
        If this engine can be used for bundles, returns a 2-tuple of strings of
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3175
        the user-facing "bundle spec" compression name and an internal
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3176
        identifier used to denote the compression format within bundles. To
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3177
        exclude the name from external usage, set the first element to ``None``.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3178
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3179
        If bundle compression is supported, the class must also implement
30359
673f0fdc1046 util: remove compressorobj API from compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30356
diff changeset
  3180
        ``compressstream`` and `decompressorreader``.
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3181
        """
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3182
        return None
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3183
30761
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3184
    def wireprotosupport(self):
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3185
        """Declare support for this compression format on the wire protocol.
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3186
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3187
        If this compression engine isn't supported for compressing wire
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3188
        protocol payloads, returns None.
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3189
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3190
        Otherwise, returns ``compenginewireprotosupport`` with the following
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3191
        fields:
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3192
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3193
        * String format identifier
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3194
        * Integer priority for the server
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3195
        * Integer priority for the client
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3196
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3197
        The integer priorities are used to order the advertisement of format
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3198
        support by server and client. The highest integer is advertised
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3199
        first. Integers with non-positive values aren't advertised.
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3200
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3201
        The priority values are somewhat arbitrary and only used for default
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3202
        ordering. The relative order can be changed via config options.
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3203
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3204
        If wire protocol compression is supported, the class must also implement
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3205
        ``compressstream`` and ``decompressorreader``.
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3206
        """
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3207
        return None
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3208
30798
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3209
    def revlogheader(self):
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3210
        """Header added to revlog chunks that identifies this engine.
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3211
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3212
        If this engine can be used to compress revlogs, this method should
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3213
        return the bytes used to identify chunks compressed with this engine.
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3214
        Else, the method should return ``None`` to indicate it does not
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3215
        participate in revlog compression.
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3216
        """
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3217
        return None
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3218
30356
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3219
    def compressstream(self, it, opts=None):
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3220
        """Compress an iterator of chunks.
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3221
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3222
        The method receives an iterator (ideally a generator) of chunks of
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3223
        bytes to be compressed. It returns an iterator (ideally a generator)
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3224
        of bytes of chunks representing the compressed output.
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3225
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3226
        Optionally accepts an argument defining how to perform compression.
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3227
        Each engine treats this argument differently.
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3228
        """
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3229
        raise NotImplementedError()
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3230
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3231
    def decompressorreader(self, fh):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3232
        """Perform decompression on a file object.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3233
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3234
        Argument is an object with a ``read(size)`` method that returns
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3235
        compressed data. Return value is an object with a ``read(size)`` that
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3236
        returns uncompressed data.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3237
        """
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3238
        raise NotImplementedError()
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3239
30794
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3240
    def revlogcompressor(self, opts=None):
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3241
        """Obtain an object that can be used to compress revlog entries.
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3242
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3243
        The object has a ``compress(data)`` method that compresses binary
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3244
        data. This method returns compressed binary data or ``None`` if
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3245
        the data could not be compressed (too small, not compressible, etc).
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3246
        The returned data should have a header uniquely identifying this
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3247
        compression format so decompression can be routed to this engine.
30798
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3248
        This header should be identified by the ``revlogheader()`` return
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3249
        value.
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3250
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3251
        The object has a ``decompress(data)`` method that decompresses
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3252
        data. The method will only be called if ``data`` begins with
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3253
        ``revlogheader()``. The method should return the raw, uncompressed
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3254
        data or raise a ``RevlogError``.
30794
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3255
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3256
        The object is reusable but is not thread safe.
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3257
        """
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3258
        raise NotImplementedError()
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3259
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3260
class _zlibengine(compressionengine):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3261
    def name(self):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3262
        return 'zlib'
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3263
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3264
    def bundletype(self):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3265
        return 'gzip', 'GZ'
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3266
30761
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3267
    def wireprotosupport(self):
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3268
        return compewireprotosupport('zlib', 20, 20)
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3269
30798
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3270
    def revlogheader(self):
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3271
        return 'x'
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3272
30356
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3273
    def compressstream(self, it, opts=None):
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3274
        opts = opts or {}
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3275
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3276
        z = zlib.compressobj(opts.get('level', -1))
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3277
        for chunk in it:
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3278
            data = z.compress(chunk)
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3279
            # Not all calls to compress emit data. It is cheaper to inspect
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3280
            # here than to feed empty chunks through generator.
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3281
            if data:
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3282
                yield data
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3283
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3284
        yield z.flush()
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3285
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3286
    def decompressorreader(self, fh):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3287
        def gen():
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3288
            d = zlib.decompressobj()
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3289
            for chunk in filechunkiter(fh):
30536
98d7636c4729 util: limit output chunk size in zlib decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30473
diff changeset
  3290
                while chunk:
98d7636c4729 util: limit output chunk size in zlib decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30473
diff changeset
  3291
                    # Limit output size to limit memory.
98d7636c4729 util: limit output chunk size in zlib decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30473
diff changeset
  3292
                    yield d.decompress(chunk, 2 ** 18)
98d7636c4729 util: limit output chunk size in zlib decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30473
diff changeset
  3293
                    chunk = d.unconsumed_tail
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3294
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3295
        return chunkbuffer(gen())
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3296
30794
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3297
    class zlibrevlogcompressor(object):
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3298
        def compress(self, data):
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3299
            insize = len(data)
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3300
            # Caller handles empty input case.
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3301
            assert insize > 0
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3302
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3303
            if insize < 44:
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3304
                return None
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3305
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3306
            elif insize <= 1000000:
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3307
                compressed = zlib.compress(data)
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3308
                if len(compressed) < insize:
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3309
                    return compressed
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3310
                return None
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3311
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3312
            # zlib makes an internal copy of the input buffer, doubling
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3313
            # memory usage for large inputs. So do streaming compression
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3314
            # on large inputs.
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3315
            else:
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3316
                z = zlib.compressobj()
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3317
                parts = []
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3318
                pos = 0
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3319
                while pos < insize:
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3320
                    pos2 = pos + 2**20
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3321
                    parts.append(z.compress(data[pos:pos2]))
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3322
                    pos = pos2
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3323
                parts.append(z.flush())
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3324
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3325
                if sum(map(len, parts)) < insize:
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3326
                    return ''.join(parts)
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3327
                return None
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3328
30798
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3329
        def decompress(self, data):
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3330
            try:
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3331
                return zlib.decompress(data)
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3332
            except zlib.error as e:
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3333
                raise error.RevlogError(_('revlog decompress error: %s') %
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3334
                                        str(e))
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3335
30794
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3336
    def revlogcompressor(self, opts=None):
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3337
        return self.zlibrevlogcompressor()
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3338
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3339
compengines.register(_zlibengine())
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3340
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3341
class _bz2engine(compressionengine):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3342
    def name(self):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3343
        return 'bz2'
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3344
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3345
    def bundletype(self):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3346
        return 'bzip2', 'BZ'
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3347
30761
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3348
    # We declare a protocol name but don't advertise by default because
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3349
    # it is slow.
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3350
    def wireprotosupport(self):
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3351
        return compewireprotosupport('bzip2', 0, 0)
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3352
30356
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3353
    def compressstream(self, it, opts=None):
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3354
        opts = opts or {}
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3355
        z = bz2.BZ2Compressor(opts.get('level', 9))
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3356
        for chunk in it:
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3357
            data = z.compress(chunk)
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3358
            if data:
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3359
                yield data
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3360
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3361
        yield z.flush()
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3362
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3363
    def decompressorreader(self, fh):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3364
        def gen():
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3365
            d = bz2.BZ2Decompressor()
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3366
            for chunk in filechunkiter(fh):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3367
                yield d.decompress(chunk)
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3368
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3369
        return chunkbuffer(gen())
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3370
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3371
compengines.register(_bz2engine())
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3372
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3373
class _truncatedbz2engine(compressionengine):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3374
    def name(self):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3375
        return 'bz2truncated'
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3376
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3377
    def bundletype(self):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3378
        return None, '_truncatedBZ'
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3379
30359
673f0fdc1046 util: remove compressorobj API from compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30356
diff changeset
  3380
    # We don't implement compressstream because it is hackily handled elsewhere.
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3381
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3382
    def decompressorreader(self, fh):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3383
        def gen():
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3384
            # The input stream doesn't have the 'BZ' header. So add it back.
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3385
            d = bz2.BZ2Decompressor()
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3386
            d.decompress('BZ')
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3387
            for chunk in filechunkiter(fh):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3388
                yield d.decompress(chunk)
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3389
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3390
        return chunkbuffer(gen())
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3391
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3392
compengines.register(_truncatedbz2engine())
30265
6a8aff737a17 util: put compression code next to each other
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30181
diff changeset
  3393
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3394
class _noopengine(compressionengine):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3395
    def name(self):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3396
        return 'none'
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3397
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3398
    def bundletype(self):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3399
        return 'none', 'UN'
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3400
30761
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3401
    # Clients always support uncompressed payloads. Servers don't because
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3402
    # unless you are on a fast network, uncompressed payloads can easily
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3403
    # saturate your network pipe.
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3404
    def wireprotosupport(self):
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3405
        return compewireprotosupport('none', 0, 10)
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3406
30798
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3407
    # We don't implement revlogheader because it is handled specially
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3408
    # in the revlog class.
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3409
30356
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3410
    def compressstream(self, it, opts=None):
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3411
        return it
c86109eface7 util: add a stream compression API to compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30355
diff changeset
  3412
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3413
    def decompressorreader(self, fh):
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3414
        return fh
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3415
30794
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3416
    class nooprevlogcompressor(object):
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3417
        def compress(self, data):
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3418
            return None
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3419
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3420
    def revlogcompressor(self, opts=None):
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3421
        return self.nooprevlogcompressor()
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3422
30350
358cda0af6ee util: create new abstraction for compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30332
diff changeset
  3423
compengines.register(_noopengine())
26266
1e042e31bd0c changegroup: move all compressions utilities in util
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26201
diff changeset
  3424
30442
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3425
class _zstdengine(compressionengine):
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3426
    def name(self):
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3427
        return 'zstd'
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3428
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3429
    @propertycache
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3430
    def _module(self):
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3431
        # Not all installs have the zstd module available. So defer importing
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3432
        # until first access.
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3433
        try:
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3434
            from . import zstd
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3435
            # Force delayed import.
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3436
            zstd.__version__
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3437
            return zstd
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3438
        except ImportError:
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3439
            return None
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3440
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3441
    def available(self):
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3442
        return bool(self._module)
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3443
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3444
    def bundletype(self):
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3445
        return 'zstd', 'ZS'
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3446
30761
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3447
    def wireprotosupport(self):
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3448
        return compewireprotosupport('zstd', 50, 50)
7283719e2bfd util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30745
diff changeset
  3449
30798
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3450
    def revlogheader(self):
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3451
        return '\x28'
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3452
30442
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3453
    def compressstream(self, it, opts=None):
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3454
        opts = opts or {}
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3455
        # zstd level 3 is almost always significantly faster than zlib
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3456
        # while providing no worse compression. It strikes a good balance
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3457
        # between speed and compression.
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3458
        level = opts.get('level', 3)
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3459
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3460
        zstd = self._module
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3461
        z = zstd.ZstdCompressor(level=level).compressobj()
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3462
        for chunk in it:
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3463
            data = z.compress(chunk)
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3464
            if data:
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3465
                yield data
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3466
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3467
        yield z.flush()
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3468
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3469
    def decompressorreader(self, fh):
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3470
        zstd = self._module
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3471
        dctx = zstd.ZstdDecompressor()
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3472
        return chunkbuffer(dctx.read_from(fh))
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3473
30794
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3474
    class zstdrevlogcompressor(object):
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3475
        def __init__(self, zstd, level=3):
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3476
            # Writing the content size adds a few bytes to the output. However,
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3477
            # it allows decompression to be more optimal since we can
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3478
            # pre-allocate a buffer to hold the result.
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3479
            self._cctx = zstd.ZstdCompressor(level=level,
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3480
                                             write_content_size=True)
30798
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3481
            self._dctx = zstd.ZstdDecompressor()
30794
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3482
            self._compinsize = zstd.COMPRESSION_RECOMMENDED_INPUT_SIZE
30798
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3483
            self._decompinsize = zstd.DECOMPRESSION_RECOMMENDED_INPUT_SIZE
30794
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3484
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3485
        def compress(self, data):
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3486
            insize = len(data)
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3487
            # Caller handles empty input case.
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3488
            assert insize > 0
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3489
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3490
            if insize < 50:
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3491
                return None
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3492
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3493
            elif insize <= 1000000:
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3494
                compressed = self._cctx.compress(data)
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3495
                if len(compressed) < insize:
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3496
                    return compressed
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3497
                return None
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3498
            else:
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3499
                z = self._cctx.compressobj()
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3500
                chunks = []
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3501
                pos = 0
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3502
                while pos < insize:
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3503
                    pos2 = pos + self._compinsize
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3504
                    chunk = z.compress(data[pos:pos2])
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3505
                    if chunk:
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3506
                        chunks.append(chunk)
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3507
                    pos = pos2
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3508
                chunks.append(z.flush())
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3509
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3510
                if sum(map(len, chunks)) < insize:
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3511
                    return ''.join(chunks)
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3512
                return None
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3513
30798
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3514
        def decompress(self, data):
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3515
            insize = len(data)
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3516
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3517
            try:
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3518
                # This was measured to be faster than other streaming
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3519
                # decompressors.
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3520
                dobj = self._dctx.decompressobj()
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3521
                chunks = []
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3522
                pos = 0
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3523
                while pos < insize:
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3524
                    pos2 = pos + self._decompinsize
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3525
                    chunk = dobj.decompress(data[pos:pos2])
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3526
                    if chunk:
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3527
                        chunks.append(chunk)
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3528
                    pos = pos2
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3529
                # Frame should be exhausted, so no finish() API.
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3530
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3531
                return ''.join(chunks)
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3532
            except Exception as e:
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3533
                raise error.RevlogError(_('revlog decompress error: %s') %
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3534
                                        str(e))
f50c0db50025 util: compression APIs to support revlog decompression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30794
diff changeset
  3535
30794
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3536
    def revlogcompressor(self, opts=None):
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3537
        opts = opts or {}
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3538
        return self.zstdrevlogcompressor(self._module,
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3539
                                         level=opts.get('level', 3))
31e1f0d4ab44 util: compression APIs to support revlog compression
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30773
diff changeset
  3540
30442
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3541
compengines.register(_zstdengine())
41a8106789ca util: implement zstd compression engine
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30438
diff changeset
  3542
20244
47d0843647d1 util: introduce util.debugstacktrace for showing a stack trace without crashing
Mads Kiilerich <madski@unity3d.com>
parents: 20202
diff changeset
  3543
# convenient shortcut
47d0843647d1 util: introduce util.debugstacktrace for showing a stack trace without crashing
Mads Kiilerich <madski@unity3d.com>
parents: 20202
diff changeset
  3544
dst = debugstacktrace