annotate upmana/mercurial/util.py @ 39:ed322725b928 ornery-orc tip

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