annotate upmana/mercurial/util.py @ 229:1645a78a33a4 alpha

Traipse Alpha 'OpenRPG' {100612-02} Traipse is a distribution of OpenRPG that is designed to be easy to setup and go. Traipse also makes it easy for developers to work on code without fear of sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to the code. 'Ornery-Orc's main goal is to offer more advanced features and enhance the productivity of the user. Update Summary (Preparing to close updates) New Features: New to Map, can re-order Grid, Miniatures, and Whiteboard layer draw order Fixes: Fix to InterParse that was causing an Infernal Loop with Namespace Internal Fix to XML data, removed old Minidom and switched to Element Tree Fix to Server that was causing eternal attempt to find a Server ID, in Register Rooms thread Fix to metaservers.xml file not being created
author sirebral
date Sat, 12 Jun 2010 04:46:16 -0500
parents 496dbf12a6cb
children
rev   line source
121
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1 # util.py - Mercurial utility functions and platform specfic implementations
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
2 #
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
3 # Copyright 2005 K. Thananchayan <thananck@yahoo.com>
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
6 #
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
7 # This software may be used and distributed according to the terms of the
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
8 # GNU General Public License version 2, incorporated herein by reference.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
9
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
10 """Mercurial utility functions and platform specfic implementations.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
11
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
12 This contains helper routines that are independent of the SCM core and
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
13 hide platform-specific details from the core.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
14 """
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
15
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
16 from i18n import _
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
17 import error, osutil
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
18 import cStringIO, errno, re, shutil, sys, tempfile, traceback
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
19 import os, stat, time, calendar, random, textwrap
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
20 import imp
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
21
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
22 # Python compatibility
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
23
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
24 def sha1(s):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
25 return _fastsha1(s)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
26
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
27 def _fastsha1(s):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
28 # This function will import sha1 from hashlib or sha (whichever is
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
29 # available) and overwrite itself with it on the first call.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
30 # Subsequent calls will go directly to the imported function.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
31 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
32 from hashlib import sha1 as _sha1
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
33 except ImportError:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
34 from sha import sha as _sha1
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
35 global _fastsha1, sha1
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
36 _fastsha1 = sha1 = _sha1
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
37 return _sha1(s)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
38
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
39 import subprocess
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
40 closefds = os.name == 'posix'
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
41 def popen2(cmd):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
42 # Setting bufsize to -1 lets the system decide the buffer size.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
43 # The default for bufsize is 0, meaning unbuffered. This leads to
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
44 # poor performance on Mac OS X: http://bugs.python.org/issue4194
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
45 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
46 close_fds=closefds,
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
47 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
48 return p.stdin, p.stdout
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
49 def popen3(cmd):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
50 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
51 close_fds=closefds,
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
52 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
53 stderr=subprocess.PIPE)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
54 return p.stdin, p.stdout, p.stderr
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
55
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
56 def version():
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
57 """Return version information if available."""
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
58 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
59 import __version__
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
60 return __version__.version
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
61 except ImportError:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
62 return 'unknown'
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
63
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
64 # used by parsedate
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
65 defaultdateformats = (
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
66 '%Y-%m-%d %H:%M:%S',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
67 '%Y-%m-%d %I:%M:%S%p',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
68 '%Y-%m-%d %H:%M',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
69 '%Y-%m-%d %I:%M%p',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
70 '%Y-%m-%d',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
71 '%m-%d',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
72 '%m/%d',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
73 '%m/%d/%y',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
74 '%m/%d/%Y',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
75 '%a %b %d %H:%M:%S %Y',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
76 '%a %b %d %I:%M:%S%p %Y',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
77 '%a, %d %b %Y %H:%M:%S', # GNU coreutils "/bin/date --rfc-2822"
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
78 '%b %d %H:%M:%S %Y',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
79 '%b %d %I:%M:%S%p %Y',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
80 '%b %d %H:%M:%S',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
81 '%b %d %I:%M:%S%p',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
82 '%b %d %H:%M',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
83 '%b %d %I:%M%p',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
84 '%b %d %Y',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
85 '%b %d',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
86 '%H:%M:%S',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
87 '%I:%M:%SP',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
88 '%H:%M',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
89 '%I:%M%p',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
90 )
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
91
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
92 extendeddateformats = defaultdateformats + (
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
93 "%Y",
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
94 "%Y-%m",
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
95 "%b",
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
96 "%b %Y",
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
97 )
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
98
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
99 def cachefunc(func):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
100 '''cache the result of function calls'''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
101 # XXX doesn't handle keywords args
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
102 cache = {}
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
103 if func.func_code.co_argcount == 1:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
104 # we gain a small amount of time because
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
105 # we don't need to pack/unpack the list
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
106 def f(arg):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
107 if arg not in cache:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
108 cache[arg] = func(arg)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
109 return cache[arg]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
110 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
111 def f(*args):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
112 if args not in cache:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
113 cache[args] = func(*args)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
114 return cache[args]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
115
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
116 return f
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
117
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
118 def lrucachefunc(func):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
119 '''cache most recent results of function calls'''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
120 cache = {}
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
121 order = []
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
122 if func.func_code.co_argcount == 1:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
123 def f(arg):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
124 if arg not in cache:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
125 if len(cache) > 20:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
126 del cache[order.pop(0)]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
127 cache[arg] = func(arg)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
128 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
129 order.remove(arg)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
130 order.append(arg)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
131 return cache[arg]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
132 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
133 def f(*args):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
134 if args not in cache:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
135 if len(cache) > 20:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
136 del cache[order.pop(0)]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
137 cache[args] = func(*args)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
138 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
139 order.remove(args)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
140 order.append(args)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
141 return cache[args]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
142
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
143 return f
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
144
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
145 class propertycache(object):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
146 def __init__(self, func):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
147 self.func = func
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
148 self.name = func.__name__
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
149 def __get__(self, obj, type=None):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
150 result = self.func(obj)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
151 setattr(obj, self.name, result)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
152 return result
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
153
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
154 def pipefilter(s, cmd):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
155 '''filter string S through command CMD, returning its output'''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
156 p = subprocess.Popen(cmd, shell=True, close_fds=closefds,
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
157 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
158 pout, perr = p.communicate(s)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
159 return pout
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
160
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
161 def tempfilter(s, cmd):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
162 '''filter string S through a pair of temporary files with CMD.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
163 CMD is used as a template to create the real command to be run,
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
164 with the strings INFILE and OUTFILE replaced by the real names of
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
165 the temporary files generated.'''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
166 inname, outname = None, None
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
167 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
168 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
169 fp = os.fdopen(infd, 'wb')
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
170 fp.write(s)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
171 fp.close()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
172 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
173 os.close(outfd)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
174 cmd = cmd.replace('INFILE', inname)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
175 cmd = cmd.replace('OUTFILE', outname)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
176 code = os.system(cmd)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
177 if sys.platform == 'OpenVMS' and code & 1:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
178 code = 0
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
179 if code: raise Abort(_("command '%s' failed: %s") %
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
180 (cmd, explain_exit(code)))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
181 return open(outname, 'rb').read()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
182 finally:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
183 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
184 if inname: os.unlink(inname)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
185 except: pass
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
186 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
187 if outname: os.unlink(outname)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
188 except: pass
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
189
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
190 filtertable = {
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
191 'tempfile:': tempfilter,
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
192 'pipe:': pipefilter,
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
193 }
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
194
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
195 def filter(s, cmd):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
196 "filter a string through a command that transforms its input to its output"
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
197 for name, fn in filtertable.iteritems():
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
198 if cmd.startswith(name):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
199 return fn(s, cmd[len(name):].lstrip())
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
200 return pipefilter(s, cmd)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
201
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
202 def binary(s):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
203 """return true if a string is binary data"""
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
204 return bool(s and '\0' in s)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
205
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
206 def increasingchunks(source, min=1024, max=65536):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
207 '''return no less than min bytes per chunk while data remains,
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
208 doubling min after each chunk until it reaches max'''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
209 def log2(x):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
210 if not x:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
211 return 0
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
212 i = 0
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
213 while x:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
214 x >>= 1
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
215 i += 1
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
216 return i - 1
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
217
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
218 buf = []
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
219 blen = 0
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
220 for chunk in source:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
221 buf.append(chunk)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
222 blen += len(chunk)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
223 if blen >= min:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
224 if min < max:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
225 min = min << 1
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
226 nmin = 1 << log2(blen)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
227 if nmin > min:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
228 min = nmin
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
229 if min > max:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
230 min = max
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
231 yield ''.join(buf)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
232 blen = 0
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
233 buf = []
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
234 if buf:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
235 yield ''.join(buf)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
236
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
237 Abort = error.Abort
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
238
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
239 def always(fn): return True
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
240 def never(fn): return False
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
241
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
242 def pathto(root, n1, n2):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
243 '''return the relative path from one place to another.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
244 root should use os.sep to separate directories
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
245 n1 should use os.sep to separate directories
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
246 n2 should use "/" to separate directories
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
247 returns an os.sep-separated path.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
248
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
249 If n1 is a relative path, it's assumed it's
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
250 relative to root.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
251 n2 should always be relative to root.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
252 '''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
253 if not n1: return localpath(n2)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
254 if os.path.isabs(n1):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
255 if os.path.splitdrive(root)[0] != os.path.splitdrive(n1)[0]:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
256 return os.path.join(root, localpath(n2))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
257 n2 = '/'.join((pconvert(root), n2))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
258 a, b = splitpath(n1), n2.split('/')
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
259 a.reverse()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
260 b.reverse()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
261 while a and b and a[-1] == b[-1]:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
262 a.pop()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
263 b.pop()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
264 b.reverse()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
265 return os.sep.join((['..'] * len(a)) + b) or '.'
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
266
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
267 def canonpath(root, cwd, myname):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
268 """return the canonical path of myname, given cwd and root"""
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
269 if root == os.sep:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
270 rootsep = os.sep
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
271 elif endswithsep(root):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
272 rootsep = root
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
273 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
274 rootsep = root + os.sep
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
275 name = myname
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
276 if not os.path.isabs(name):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
277 name = os.path.join(root, cwd, name)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
278 name = os.path.normpath(name)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
279 audit_path = path_auditor(root)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
280 if name != rootsep and name.startswith(rootsep):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
281 name = name[len(rootsep):]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
282 audit_path(name)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
283 return pconvert(name)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
284 elif name == root:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
285 return ''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
286 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
287 # Determine whether `name' is in the hierarchy at or beneath `root',
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
288 # by iterating name=dirname(name) until that causes no change (can't
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
289 # check name == '/', because that doesn't work on windows). For each
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
290 # `name', compare dev/inode numbers. If they match, the list `rel'
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
291 # holds the reversed list of components making up the relative file
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
292 # name we want.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
293 root_st = os.stat(root)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
294 rel = []
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
295 while True:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
296 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
297 name_st = os.stat(name)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
298 except OSError:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
299 break
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
300 if samestat(name_st, root_st):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
301 if not rel:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
302 # name was actually the same as root (maybe a symlink)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
303 return ''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
304 rel.reverse()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
305 name = os.path.join(*rel)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
306 audit_path(name)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
307 return pconvert(name)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
308 dirname, basename = os.path.split(name)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
309 rel.append(basename)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
310 if dirname == name:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
311 break
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
312 name = dirname
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
313
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
314 raise Abort('%s not under root' % myname)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
315
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
316 _hgexecutable = None
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
317
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
318 def main_is_frozen():
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
319 """return True if we are a frozen executable.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
320
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
321 The code supports py2exe (most common, Windows only) and tools/freeze
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
322 (portable, not much used).
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
323 """
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
324 return (hasattr(sys, "frozen") or # new py2exe
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
325 hasattr(sys, "importers") or # old py2exe
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
326 imp.is_frozen("__main__")) # tools/freeze
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
327
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
328 def hgexecutable():
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
329 """return location of the 'hg' executable.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
330
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
331 Defaults to $HG or 'hg' in the search path.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
332 """
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
333 if _hgexecutable is None:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
334 hg = os.environ.get('HG')
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
335 if hg:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
336 set_hgexecutable(hg)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
337 elif main_is_frozen():
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
338 set_hgexecutable(sys.executable)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
339 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
340 set_hgexecutable(find_exe('hg') or 'hg')
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
341 return _hgexecutable
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
342
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
343 def set_hgexecutable(path):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
344 """set location of the 'hg' executable"""
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
345 global _hgexecutable
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
346 _hgexecutable = path
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
347
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
348 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
349 '''enhanced shell command execution.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
350 run with environment maybe modified, maybe in different dir.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
351
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
352 if command fails and onerr is None, return status. if ui object,
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
353 print error message and return status, else raise onerr object as
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
354 exception.'''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
355 def py2shell(val):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
356 'convert python object into string that is useful to shell'
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
357 if val is None or val is False:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
358 return '0'
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
359 if val is True:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
360 return '1'
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
361 return str(val)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
362 oldenv = {}
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
363 for k in environ:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
364 oldenv[k] = os.environ.get(k)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
365 if cwd is not None:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
366 oldcwd = os.getcwd()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
367 origcmd = cmd
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
368 if os.name == 'nt':
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
369 cmd = '"%s"' % cmd
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
370 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
371 for k, v in environ.iteritems():
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
372 os.environ[k] = py2shell(v)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
373 os.environ['HG'] = hgexecutable()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
374 if cwd is not None and oldcwd != cwd:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
375 os.chdir(cwd)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
376 rc = os.system(cmd)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
377 if sys.platform == 'OpenVMS' and rc & 1:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
378 rc = 0
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
379 if rc and onerr:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
380 errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
381 explain_exit(rc)[0])
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
382 if errprefix:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
383 errmsg = '%s: %s' % (errprefix, errmsg)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
384 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
385 onerr.warn(errmsg + '\n')
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
386 except AttributeError:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
387 raise onerr(errmsg)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
388 return rc
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
389 finally:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
390 for k, v in oldenv.iteritems():
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
391 if v is None:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
392 del os.environ[k]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
393 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
394 os.environ[k] = v
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
395 if cwd is not None and oldcwd != cwd:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
396 os.chdir(oldcwd)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
397
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
398 def checksignature(func):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
399 '''wrap a function with code to check for calling errors'''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
400 def check(*args, **kwargs):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
401 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
402 return func(*args, **kwargs)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
403 except TypeError:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
404 if len(traceback.extract_tb(sys.exc_info()[2])) == 1:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
405 raise error.SignatureError
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
406 raise
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
407
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
408 return check
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
409
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
410 # os.path.lexists is not available on python2.3
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
411 def lexists(filename):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
412 "test whether a file with this name exists. does not follow symlinks"
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
413 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
414 os.lstat(filename)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
415 except:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
416 return False
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
417 return True
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
418
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
419 def rename(src, dst):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
420 """forcibly rename a file"""
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
421 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
422 os.rename(src, dst)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
423 except OSError, err: # FIXME: check err (EEXIST ?)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
424
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
425 # On windows, rename to existing file is not allowed, so we
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
426 # must delete destination first. But if a file is open, unlink
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
427 # schedules it for delete but does not delete it. Rename
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
428 # happens immediately even for open files, so we rename
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
429 # destination to a temporary name, then delete that. Then
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
430 # rename is safe to do.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
431 # The temporary name is chosen at random to avoid the situation
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
432 # where a file is left lying around from a previous aborted run.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
433 # The usual race condition this introduces can't be avoided as
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
434 # we need the name to rename into, and not the file itself. Due
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
435 # to the nature of the operation however, any races will at worst
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
436 # lead to the rename failing and the current operation aborting.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
437
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
438 def tempname(prefix):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
439 for tries in xrange(10):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
440 temp = '%s-%08x' % (prefix, random.randint(0, 0xffffffff))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
441 if not os.path.exists(temp):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
442 return temp
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
443 raise IOError, (errno.EEXIST, "No usable temporary filename found")
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
444
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
445 temp = tempname(dst)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
446 os.rename(dst, temp)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
447 os.unlink(temp)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
448 os.rename(src, dst)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
449
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
450 def unlink(f):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
451 """unlink and remove the directory if it is empty"""
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
452 os.unlink(f)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
453 # try removing directories that might now be empty
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
454 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
455 os.removedirs(os.path.dirname(f))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
456 except OSError:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
457 pass
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
458
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
459 def copyfile(src, dest):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
460 "copy a file, preserving mode and atime/mtime"
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
461 if os.path.islink(src):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
462 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
463 os.unlink(dest)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
464 except:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
465 pass
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
466 os.symlink(os.readlink(src), dest)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
467 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
468 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
469 shutil.copyfile(src, dest)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
470 shutil.copystat(src, dest)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
471 except shutil.Error, inst:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
472 raise Abort(str(inst))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
473
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
474 def copyfiles(src, dst, hardlink=None):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
475 """Copy a directory tree using hardlinks if possible"""
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
476
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
477 if hardlink is None:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
478 hardlink = (os.stat(src).st_dev ==
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
479 os.stat(os.path.dirname(dst)).st_dev)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
480
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
481 if os.path.isdir(src):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
482 os.mkdir(dst)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
483 for name, kind in osutil.listdir(src):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
484 srcname = os.path.join(src, name)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
485 dstname = os.path.join(dst, name)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
486 copyfiles(srcname, dstname, hardlink)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
487 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
488 if hardlink:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
489 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
490 os_link(src, dst)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
491 except (IOError, OSError):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
492 hardlink = False
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
493 shutil.copy(src, dst)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
494 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
495 shutil.copy(src, dst)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
496
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
497 class path_auditor(object):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
498 '''ensure that a filesystem path contains no banned components.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
499 the following properties of a path are checked:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
500
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
501 - under top-level .hg
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
502 - starts at the root of a windows drive
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
503 - contains ".."
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
504 - traverses a symlink (e.g. a/symlink_here/b)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
505 - inside a nested repository'''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
506
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
507 def __init__(self, root):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
508 self.audited = set()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
509 self.auditeddir = set()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
510 self.root = root
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
511
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
512 def __call__(self, path):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
513 if path in self.audited:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
514 return
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
515 normpath = os.path.normcase(path)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
516 parts = splitpath(normpath)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
517 if (os.path.splitdrive(path)[0]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
518 or parts[0].lower() in ('.hg', '.hg.', '')
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
519 or os.pardir in parts):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
520 raise Abort(_("path contains illegal component: %s") % path)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
521 if '.hg' in path.lower():
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
522 lparts = [p.lower() for p in parts]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
523 for p in '.hg', '.hg.':
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
524 if p in lparts[1:]:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
525 pos = lparts.index(p)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
526 base = os.path.join(*parts[:pos])
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
527 raise Abort(_('path %r is inside repo %r') % (path, base))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
528 def check(prefix):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
529 curpath = os.path.join(self.root, prefix)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
530 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
531 st = os.lstat(curpath)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
532 except OSError, err:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
533 # EINVAL can be raised as invalid path syntax under win32.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
534 # They must be ignored for patterns can be checked too.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
535 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
536 raise
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
537 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
538 if stat.S_ISLNK(st.st_mode):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
539 raise Abort(_('path %r traverses symbolic link %r') %
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
540 (path, prefix))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
541 elif (stat.S_ISDIR(st.st_mode) and
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
542 os.path.isdir(os.path.join(curpath, '.hg'))):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
543 raise Abort(_('path %r is inside repo %r') %
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
544 (path, prefix))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
545 parts.pop()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
546 prefixes = []
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
547 while parts:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
548 prefix = os.sep.join(parts)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
549 if prefix in self.auditeddir:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
550 break
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
551 check(prefix)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
552 prefixes.append(prefix)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
553 parts.pop()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
554
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
555 self.audited.add(path)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
556 # only add prefixes to the cache after checking everything: we don't
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
557 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
558 self.auditeddir.update(prefixes)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
559
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
560 def nlinks(pathname):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
561 """Return number of hardlinks for the given file."""
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
562 return os.lstat(pathname).st_nlink
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
563
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
564 if hasattr(os, 'link'):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
565 os_link = os.link
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
566 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
567 def os_link(src, dst):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
568 raise OSError(0, _("Hardlinks not supported"))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
569
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
570 def lookup_reg(key, name=None, scope=None):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
571 return None
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
572
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
573 if os.name == 'nt':
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
574 from windows import *
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
575 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
576 from posix import *
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
577
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
578 def makelock(info, pathname):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
579 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
580 return os.symlink(info, pathname)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
581 except OSError, why:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
582 if why.errno == errno.EEXIST:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
583 raise
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
584 except AttributeError: # no symlink in os
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
585 pass
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
586
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
587 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
588 os.write(ld, info)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
589 os.close(ld)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
590
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
591 def readlock(pathname):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
592 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
593 return os.readlink(pathname)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
594 except OSError, why:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
595 if why.errno not in (errno.EINVAL, errno.ENOSYS):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
596 raise
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
597 except AttributeError: # no symlink in os
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
598 pass
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
599 return posixfile(pathname).read()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
600
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
601 def fstat(fp):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
602 '''stat file object that may not have fileno method.'''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
603 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
604 return os.fstat(fp.fileno())
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
605 except AttributeError:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
606 return os.stat(fp.name)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
607
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
608 # File system features
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
609
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
610 def checkcase(path):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
611 """
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
612 Check whether the given path is on a case-sensitive filesystem
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
613
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
614 Requires a path (like /foo/.hg) ending with a foldable final
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
615 directory component.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
616 """
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
617 s1 = os.stat(path)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
618 d, b = os.path.split(path)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
619 p2 = os.path.join(d, b.upper())
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
620 if path == p2:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
621 p2 = os.path.join(d, b.lower())
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
622 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
623 s2 = os.stat(p2)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
624 if s2 == s1:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
625 return False
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
626 return True
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
627 except:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
628 return True
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
629
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
630 _fspathcache = {}
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
631 def fspath(name, root):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
632 '''Get name in the case stored in the filesystem
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
633
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
634 The name is either relative to root, or it is an absolute path starting
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
635 with root. Note that this function is unnecessary, and should not be
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
636 called, for case-sensitive filesystems (simply because it's expensive).
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
637 '''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
638 # If name is absolute, make it relative
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
639 if name.lower().startswith(root.lower()):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
640 l = len(root)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
641 if name[l] == os.sep or name[l] == os.altsep:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
642 l = l + 1
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
643 name = name[l:]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
644
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
645 if not os.path.exists(os.path.join(root, name)):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
646 return None
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
647
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
648 seps = os.sep
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
649 if os.altsep:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
650 seps = seps + os.altsep
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
651 # Protect backslashes. This gets silly very quickly.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
652 seps.replace('\\','\\\\')
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
653 pattern = re.compile(r'([^%s]+)|([%s]+)' % (seps, seps))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
654 dir = os.path.normcase(os.path.normpath(root))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
655 result = []
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
656 for part, sep in pattern.findall(name):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
657 if sep:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
658 result.append(sep)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
659 continue
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
660
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
661 if dir not in _fspathcache:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
662 _fspathcache[dir] = os.listdir(dir)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
663 contents = _fspathcache[dir]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
664
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
665 lpart = part.lower()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
666 for n in contents:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
667 if n.lower() == lpart:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
668 result.append(n)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
669 break
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
670 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
671 # Cannot happen, as the file exists!
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
672 result.append(part)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
673 dir = os.path.join(dir, lpart)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
674
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
675 return ''.join(result)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
676
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
677 def checkexec(path):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
678 """
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
679 Check whether the given path is on a filesystem with UNIX-like exec flags
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
680
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
681 Requires a directory (like /foo/.hg)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
682 """
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
683
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
684 # VFAT on some Linux versions can flip mode but it doesn't persist
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
685 # a FS remount. Frequently we can detect it if files are created
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
686 # with exec bit on.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
687
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
688 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
689 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
690 fh, fn = tempfile.mkstemp("", "", path)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
691 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
692 os.close(fh)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
693 m = os.stat(fn).st_mode & 0777
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
694 new_file_has_exec = m & EXECFLAGS
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
695 os.chmod(fn, m ^ EXECFLAGS)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
696 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0777) == m)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
697 finally:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
698 os.unlink(fn)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
699 except (IOError, OSError):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
700 # we don't care, the user probably won't be able to commit anyway
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
701 return False
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
702 return not (new_file_has_exec or exec_flags_cannot_flip)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
703
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
704 def checklink(path):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
705 """check whether the given path is on a symlink-capable filesystem"""
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
706 # mktemp is not racy because symlink creation will fail if the
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
707 # file already exists
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
708 name = tempfile.mktemp(dir=path)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
709 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
710 os.symlink(".", name)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
711 os.unlink(name)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
712 return True
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
713 except (OSError, AttributeError):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
714 return False
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
715
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
716 def needbinarypatch():
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
717 """return True if patches should be applied in binary mode by default."""
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
718 return os.name == 'nt'
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
719
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
720 def endswithsep(path):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
721 '''Check path ends with os.sep or os.altsep.'''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
722 return path.endswith(os.sep) or os.altsep and path.endswith(os.altsep)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
723
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
724 def splitpath(path):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
725 '''Split path by os.sep.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
726 Note that this function does not use os.altsep because this is
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
727 an alternative of simple "xxx.split(os.sep)".
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
728 It is recommended to use os.path.normpath() before using this
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
729 function if need.'''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
730 return path.split(os.sep)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
731
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
732 def gui():
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
733 '''Are we running in a GUI?'''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
734 return os.name == "nt" or os.name == "mac" or os.environ.get("DISPLAY")
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
735
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
736 def mktempcopy(name, emptyok=False, createmode=None):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
737 """Create a temporary file with the same contents from name
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
738
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
739 The permission bits are copied from the original file.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
740
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
741 If the temporary file is going to be truncated immediately, you
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
742 can use emptyok=True as an optimization.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
743
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
744 Returns the name of the temporary file.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
745 """
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
746 d, fn = os.path.split(name)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
747 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
748 os.close(fd)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
749 # Temporary files are created with mode 0600, which is usually not
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
750 # what we want. If the original file already exists, just copy
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
751 # its mode. Otherwise, manually obey umask.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
752 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
753 st_mode = os.lstat(name).st_mode & 0777
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
754 except OSError, inst:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
755 if inst.errno != errno.ENOENT:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
756 raise
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
757 st_mode = createmode
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
758 if st_mode is None:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
759 st_mode = ~umask
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
760 st_mode &= 0666
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
761 os.chmod(temp, st_mode)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
762 if emptyok:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
763 return temp
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
764 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
765 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
766 ifp = posixfile(name, "rb")
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
767 except IOError, inst:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
768 if inst.errno == errno.ENOENT:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
769 return temp
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
770 if not getattr(inst, 'filename', None):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
771 inst.filename = name
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
772 raise
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
773 ofp = posixfile(temp, "wb")
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
774 for chunk in filechunkiter(ifp):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
775 ofp.write(chunk)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
776 ifp.close()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
777 ofp.close()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
778 except:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
779 try: os.unlink(temp)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
780 except: pass
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
781 raise
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
782 return temp
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
783
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
784 class atomictempfile(object):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
785 """file-like object that atomically updates a file
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
786
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
787 All writes will be redirected to a temporary copy of the original
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
788 file. When rename is called, the copy is renamed to the original
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
789 name, making the changes visible.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
790 """
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
791 def __init__(self, name, mode, createmode):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
792 self.__name = name
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
793 self._fp = None
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
794 self.temp = mktempcopy(name, emptyok=('w' in mode),
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
795 createmode=createmode)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
796 self._fp = posixfile(self.temp, mode)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
797
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
798 def __getattr__(self, name):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
799 return getattr(self._fp, name)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
800
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
801 def rename(self):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
802 if not self._fp.closed:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
803 self._fp.close()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
804 rename(self.temp, localpath(self.__name))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
805
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
806 def __del__(self):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
807 if not self._fp:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
808 return
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
809 if not self._fp.closed:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
810 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
811 os.unlink(self.temp)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
812 except: pass
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
813 self._fp.close()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
814
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
815 def makedirs(name, mode=None):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
816 """recursive directory creation with parent mode inheritance"""
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
817 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
818 os.mkdir(name)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
819 if mode is not None:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
820 os.chmod(name, mode)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
821 return
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
822 except OSError, err:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
823 if err.errno == errno.EEXIST:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
824 return
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
825 if err.errno != errno.ENOENT:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
826 raise
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
827 parent = os.path.abspath(os.path.dirname(name))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
828 makedirs(parent, mode)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
829 makedirs(name, mode)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
830
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
831 class opener(object):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
832 """Open files relative to a base directory
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
833
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
834 This class is used to hide the details of COW semantics and
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
835 remote file access from higher level code.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
836 """
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
837 def __init__(self, base, audit=True):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
838 self.base = base
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
839 if audit:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
840 self.audit_path = path_auditor(base)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
841 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
842 self.audit_path = always
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
843 self.createmode = None
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
844
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
845 def __getattr__(self, name):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
846 if name == '_can_symlink':
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
847 self._can_symlink = checklink(self.base)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
848 return self._can_symlink
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
849 raise AttributeError(name)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
850
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
851 def _fixfilemode(self, name):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
852 if self.createmode is None:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
853 return
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
854 os.chmod(name, self.createmode & 0666)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
855
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
856 def __call__(self, path, mode="r", text=False, atomictemp=False):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
857 self.audit_path(path)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
858 f = os.path.join(self.base, path)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
859
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
860 if not text and "b" not in mode:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
861 mode += "b" # for that other OS
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
862
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
863 nlink = -1
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
864 if mode not in ("r", "rb"):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
865 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
866 nlink = nlinks(f)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
867 except OSError:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
868 nlink = 0
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
869 d = os.path.dirname(f)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
870 if not os.path.isdir(d):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
871 makedirs(d, self.createmode)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
872 if atomictemp:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
873 return atomictempfile(f, mode, self.createmode)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
874 if nlink > 1:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
875 rename(mktempcopy(f), f)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
876 fp = posixfile(f, mode)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
877 if nlink == 0:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
878 self._fixfilemode(f)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
879 return fp
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
880
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
881 def symlink(self, src, dst):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
882 self.audit_path(dst)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
883 linkname = os.path.join(self.base, dst)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
884 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
885 os.unlink(linkname)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
886 except OSError:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
887 pass
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
888
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
889 dirname = os.path.dirname(linkname)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
890 if not os.path.exists(dirname):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
891 makedirs(dirname, self.createmode)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
892
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
893 if self._can_symlink:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
894 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
895 os.symlink(src, linkname)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
896 except OSError, err:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
897 raise OSError(err.errno, _('could not symlink to %r: %s') %
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
898 (src, err.strerror), linkname)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
899 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
900 f = self(dst, "w")
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
901 f.write(src)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
902 f.close()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
903 self._fixfilemode(dst)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
904
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
905 class chunkbuffer(object):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
906 """Allow arbitrary sized chunks of data to be efficiently read from an
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
907 iterator over chunks of arbitrary size."""
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
908
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
909 def __init__(self, in_iter):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
910 """in_iter is the iterator that's iterating over the input chunks.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
911 targetsize is how big a buffer to try to maintain."""
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
912 self.iter = iter(in_iter)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
913 self.buf = ''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
914 self.targetsize = 2**16
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
915
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
916 def read(self, l):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
917 """Read L bytes of data from the iterator of chunks of data.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
918 Returns less than L bytes if the iterator runs dry."""
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
919 if l > len(self.buf) and self.iter:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
920 # Clamp to a multiple of self.targetsize
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
921 targetsize = max(l, self.targetsize)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
922 collector = cStringIO.StringIO()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
923 collector.write(self.buf)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
924 collected = len(self.buf)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
925 for chunk in self.iter:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
926 collector.write(chunk)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
927 collected += len(chunk)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
928 if collected >= targetsize:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
929 break
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
930 if collected < targetsize:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
931 self.iter = False
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
932 self.buf = collector.getvalue()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
933 if len(self.buf) == l:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
934 s, self.buf = str(self.buf), ''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
935 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
936 s, self.buf = self.buf[:l], buffer(self.buf, l)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
937 return s
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
938
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
939 def filechunkiter(f, size=65536, limit=None):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
940 """Create a generator that produces the data in the file size
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
941 (default 65536) bytes at a time, up to optional limit (default is
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
942 to read all data). Chunks may be less than size bytes if the
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
943 chunk is the last chunk in the file, or the file is a socket or
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
944 some other type of file that sometimes reads less data than is
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
945 requested."""
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
946 assert size >= 0
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
947 assert limit is None or limit >= 0
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
948 while True:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
949 if limit is None: nbytes = size
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
950 else: nbytes = min(limit, size)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
951 s = nbytes and f.read(nbytes)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
952 if not s: break
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
953 if limit: limit -= len(s)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
954 yield s
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
955
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
956 def makedate():
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
957 lt = time.localtime()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
958 if lt[8] == 1 and time.daylight:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
959 tz = time.altzone
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
960 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
961 tz = time.timezone
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
962 return time.mktime(lt), tz
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
963
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
964 def datestr(date=None, format='%a %b %d %H:%M:%S %Y %1%2'):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
965 """represent a (unixtime, offset) tuple as a localized time.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
966 unixtime is seconds since the epoch, and offset is the time zone's
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
967 number of seconds away from UTC. if timezone is false, do not
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
968 append time zone to string."""
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
969 t, tz = date or makedate()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
970 if "%1" in format or "%2" in format:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
971 sign = (tz > 0) and "-" or "+"
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
972 minutes = abs(tz) / 60
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
973 format = format.replace("%1", "%c%02d" % (sign, minutes / 60))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
974 format = format.replace("%2", "%02d" % (minutes % 60))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
975 s = time.strftime(format, time.gmtime(float(t) - tz))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
976 return s
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
977
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
978 def shortdate(date=None):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
979 """turn (timestamp, tzoff) tuple into iso 8631 date."""
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
980 return datestr(date, format='%Y-%m-%d')
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
981
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
982 def strdate(string, format, defaults=[]):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
983 """parse a localized time string and return a (unixtime, offset) tuple.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
984 if the string cannot be parsed, ValueError is raised."""
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
985 def timezone(string):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
986 tz = string.split()[-1]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
987 if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
988 sign = (tz[0] == "+") and 1 or -1
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
989 hours = int(tz[1:3])
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
990 minutes = int(tz[3:5])
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
991 return -sign * (hours * 60 + minutes) * 60
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
992 if tz == "GMT" or tz == "UTC":
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
993 return 0
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
994 return None
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
995
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
996 # NOTE: unixtime = localunixtime + offset
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
997 offset, date = timezone(string), string
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
998 if offset != None:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
999 date = " ".join(string.split()[:-1])
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1000
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1001 # add missing elements from defaults
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1002 for part in defaults:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1003 found = [True for p in part if ("%"+p) in format]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1004 if not found:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1005 date += "@" + defaults[part]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1006 format += "@%" + part[0]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1007
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1008 timetuple = time.strptime(date, format)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1009 localunixtime = int(calendar.timegm(timetuple))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1010 if offset is None:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1011 # local timezone
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1012 unixtime = int(time.mktime(timetuple))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1013 offset = unixtime - localunixtime
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1014 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1015 unixtime = localunixtime + offset
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1016 return unixtime, offset
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1017
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1018 def parsedate(date, formats=None, defaults=None):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1019 """parse a localized date/time string and return a (unixtime, offset) tuple.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1020
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1021 The date may be a "unixtime offset" string or in one of the specified
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1022 formats. If the date already is a (unixtime, offset) tuple, it is returned.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1023 """
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1024 if not date:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1025 return 0, 0
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1026 if isinstance(date, tuple) and len(date) == 2:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1027 return date
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1028 if not formats:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1029 formats = defaultdateformats
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1030 date = date.strip()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1031 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1032 when, offset = map(int, date.split(' '))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1033 except ValueError:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1034 # fill out defaults
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1035 if not defaults:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1036 defaults = {}
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1037 now = makedate()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1038 for part in "d mb yY HI M S".split():
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1039 if part not in defaults:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1040 if part[0] in "HMS":
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1041 defaults[part] = "00"
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1042 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1043 defaults[part] = datestr(now, "%" + part[0])
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1044
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1045 for format in formats:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1046 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1047 when, offset = strdate(date, format, defaults)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1048 except (ValueError, OverflowError):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1049 pass
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1050 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1051 break
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1052 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1053 raise Abort(_('invalid date: %r ') % date)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1054 # validate explicit (probably user-specified) date and
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1055 # time zone offset. values must fit in signed 32 bits for
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1056 # current 32-bit linux runtimes. timezones go from UTC-12
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1057 # to UTC+14
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1058 if abs(when) > 0x7fffffff:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1059 raise Abort(_('date exceeds 32 bits: %d') % when)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1060 if offset < -50400 or offset > 43200:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1061 raise Abort(_('impossible time zone offset: %d') % offset)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1062 return when, offset
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1063
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1064 def matchdate(date):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1065 """Return a function that matches a given date match specifier
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1066
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1067 Formats include:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1068
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1069 '{date}' match a given date to the accuracy provided
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1070
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1071 '<{date}' on or before a given date
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1072
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1073 '>{date}' on or after a given date
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1074
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1075 """
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1076
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1077 def lower(date):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1078 d = dict(mb="1", d="1")
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1079 return parsedate(date, extendeddateformats, d)[0]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1080
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1081 def upper(date):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1082 d = dict(mb="12", HI="23", M="59", S="59")
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1083 for days in "31 30 29".split():
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1084 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1085 d["d"] = days
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1086 return parsedate(date, extendeddateformats, d)[0]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1087 except:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1088 pass
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1089 d["d"] = "28"
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1090 return parsedate(date, extendeddateformats, d)[0]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1091
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1092 date = date.strip()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1093 if date[0] == "<":
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1094 when = upper(date[1:])
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1095 return lambda x: x <= when
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1096 elif date[0] == ">":
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1097 when = lower(date[1:])
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1098 return lambda x: x >= when
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1099 elif date[0] == "-":
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1100 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1101 days = int(date[1:])
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1102 except ValueError:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1103 raise Abort(_("invalid day spec: %s") % date[1:])
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1104 when = makedate()[0] - days * 3600 * 24
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1105 return lambda x: x >= when
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1106 elif " to " in date:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1107 a, b = date.split(" to ")
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1108 start, stop = lower(a), upper(b)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1109 return lambda x: x >= start and x <= stop
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1110 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1111 start, stop = lower(date), upper(date)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1112 return lambda x: x >= start and x <= stop
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1113
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1114 def shortuser(user):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1115 """Return a short representation of a user name or email address."""
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1116 f = user.find('@')
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1117 if f >= 0:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1118 user = user[:f]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1119 f = user.find('<')
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1120 if f >= 0:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1121 user = user[f+1:]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1122 f = user.find(' ')
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1123 if f >= 0:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1124 user = user[:f]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1125 f = user.find('.')
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1126 if f >= 0:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1127 user = user[:f]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1128 return user
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1129
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1130 def email(author):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1131 '''get email of author.'''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1132 r = author.find('>')
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1133 if r == -1: r = None
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1134 return author[author.find('<')+1:r]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1135
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1136 def ellipsis(text, maxlength=400):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1137 """Trim string to at most maxlength (default: 400) characters."""
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1138 if len(text) <= maxlength:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1139 return text
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1140 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1141 return "%s..." % (text[:maxlength-3])
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1142
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1143 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1144 '''yield every hg repository under path, recursively.'''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1145 def errhandler(err):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1146 if err.filename == path:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1147 raise err
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1148 if followsym and hasattr(os.path, 'samestat'):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1149 def _add_dir_if_not_there(dirlst, dirname):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1150 match = False
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1151 samestat = os.path.samestat
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1152 dirstat = os.stat(dirname)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1153 for lstdirstat in dirlst:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1154 if samestat(dirstat, lstdirstat):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1155 match = True
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1156 break
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1157 if not match:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1158 dirlst.append(dirstat)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1159 return not match
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1160 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1161 followsym = False
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1162
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1163 if (seen_dirs is None) and followsym:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1164 seen_dirs = []
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1165 _add_dir_if_not_there(seen_dirs, path)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1166 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1167 if '.hg' in dirs:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1168 yield root # found a repository
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1169 qroot = os.path.join(root, '.hg', 'patches')
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1170 if os.path.isdir(os.path.join(qroot, '.hg')):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1171 yield qroot # we have a patch queue repo here
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1172 if recurse:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1173 # avoid recursing inside the .hg directory
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1174 dirs.remove('.hg')
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1175 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1176 dirs[:] = [] # don't descend further
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1177 elif followsym:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1178 newdirs = []
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1179 for d in dirs:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1180 fname = os.path.join(root, d)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1181 if _add_dir_if_not_there(seen_dirs, fname):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1182 if os.path.islink(fname):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1183 for hgname in walkrepos(fname, True, seen_dirs):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1184 yield hgname
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1185 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1186 newdirs.append(d)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1187 dirs[:] = newdirs
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1188
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1189 _rcpath = None
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1190
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1191 def os_rcpath():
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1192 '''return default os-specific hgrc search path'''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1193 path = system_rcpath()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1194 path.extend(user_rcpath())
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1195 path = [os.path.normpath(f) for f in path]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1196 return path
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1197
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1198 def rcpath():
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1199 '''return hgrc search path. if env var HGRCPATH is set, use it.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1200 for each item in path, if directory, use files ending in .rc,
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1201 else use item.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1202 make HGRCPATH empty to only look in .hg/hgrc of current repo.
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1203 if no HGRCPATH, use default os-specific path.'''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1204 global _rcpath
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1205 if _rcpath is None:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1206 if 'HGRCPATH' in os.environ:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1207 _rcpath = []
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1208 for p in os.environ['HGRCPATH'].split(os.pathsep):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1209 if not p: continue
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1210 if os.path.isdir(p):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1211 for f, kind in osutil.listdir(p):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1212 if f.endswith('.rc'):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1213 _rcpath.append(os.path.join(p, f))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1214 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1215 _rcpath.append(p)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1216 else:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1217 _rcpath = os_rcpath()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1218 return _rcpath
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1219
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1220 def bytecount(nbytes):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1221 '''return byte count formatted as readable string, with units'''
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1222
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1223 units = (
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1224 (100, 1<<30, _('%.0f GB')),
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1225 (10, 1<<30, _('%.1f GB')),
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1226 (1, 1<<30, _('%.2f GB')),
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1227 (100, 1<<20, _('%.0f MB')),
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1228 (10, 1<<20, _('%.1f MB')),
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1229 (1, 1<<20, _('%.2f MB')),
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1230 (100, 1<<10, _('%.0f KB')),
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1231 (10, 1<<10, _('%.1f KB')),
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1232 (1, 1<<10, _('%.2f KB')),
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1233 (1, 1, _('%.0f bytes')),
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1234 )
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1235
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1236 for multiplier, divisor, format in units:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1237 if nbytes >= divisor * multiplier:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1238 return format % (nbytes / float(divisor))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1239 return units[-1][2] % nbytes
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1240
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1241 def drop_scheme(scheme, path):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1242 sc = scheme + ':'
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1243 if path.startswith(sc):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1244 path = path[len(sc):]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1245 if path.startswith('//'):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1246 path = path[2:]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1247 return path
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1248
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1249 def uirepr(s):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1250 # Avoid double backslash in Windows path repr()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1251 return repr(s).replace('\\\\', '\\')
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1252
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1253 def termwidth():
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1254 if 'COLUMNS' in os.environ:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1255 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1256 return int(os.environ['COLUMNS'])
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1257 except ValueError:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1258 pass
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1259 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1260 import termios, array, fcntl
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1261 for dev in (sys.stdout, sys.stdin):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1262 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1263 try:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1264 fd = dev.fileno()
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1265 except AttributeError:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1266 continue
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1267 if not os.isatty(fd):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1268 continue
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1269 arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8)
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1270 return array.array('h', arri)[1]
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1271 except ValueError:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1272 pass
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1273 except ImportError:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1274 pass
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1275 return 80
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1276
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1277 def wrap(line, hangindent, width=78):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1278 padding = '\n' + ' ' * hangindent
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1279 return padding.join(textwrap.wrap(line, width=width - hangindent))
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1280
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1281 def iterlines(iterator):
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1282 for chunk in iterator:
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1283 for line in chunk.splitlines():
496dbf12a6cb Traipse Alpha 'OpenRPG' {091030-00}
sirebral
parents:
diff changeset
1284 yield line