bzr branch
http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
| 1
by mbp at sourcefrog import from baz patch-364 | 1 | # Bazaar-NG -- distributed version control
 | 
| 1185.1.41
by Robert Collins massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid | 2 | #
 | 
| 1
by mbp at sourcefrog import from baz patch-364 | 3 | # Copyright (C) 2005 by Canonical Ltd
 | 
| 1185.1.41
by Robert Collins massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid | 4 | #
 | 
| 1
by mbp at sourcefrog import from baz patch-364 | 5 | # This program is free software; you can redistribute it and/or modify
 | 
| 6 | # it under the terms of the GNU General Public License as published by
 | |
| 7 | # the Free Software Foundation; either version 2 of the License, or
 | |
| 8 | # (at your option) any later version.
 | |
| 1185.1.41
by Robert Collins massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid | 9 | #
 | 
| 1
by mbp at sourcefrog import from baz patch-364 | 10 | # This program is distributed in the hope that it will be useful,
 | 
| 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| 13 | # GNU General Public License for more details.
 | |
| 1185.1.41
by Robert Collins massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid | 14 | #
 | 
| 1
by mbp at sourcefrog import from baz patch-364 | 15 | # You should have received a copy of the GNU General Public License
 | 
| 16 | # along with this program; if not, write to the Free Software
 | |
| 17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | |
| 18 | ||
| 1185.1.46
by Robert Collins Aarons branch --basis patch | 19 | from shutil import copyfile | 
| 1185.3.28
by John Arbash Meinel Adding knowledge about fifo/block/etc, they will be unknown/ignored. | 20 | from stat import (S_ISREG, S_ISDIR, S_ISLNK, ST_MODE, ST_SIZE, | 
| 1185.1.41
by Robert Collins massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid | 21 | S_ISCHR, S_ISBLK, S_ISFIFO, S_ISSOCK) | 
| 1390
by Robert Collins pair programming worx... merge integration and weave | 22 | from cStringIO import StringIO | 
| 1185.1.41
by Robert Collins massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid | 23 | import errno | 
| 24 | import os | |
| 25 | import re | |
| 1236
by Martin Pool - fix up imports | 26 | import sha | 
| 1185.1.41
by Robert Collins massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid | 27 | import sys | 
| 28 | import time | |
| 29 | import types | |
| 1
by mbp at sourcefrog import from baz patch-364 | 30 | |
| 1185.1.41
by Robert Collins massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid | 31 | import bzrlib | 
| 694
by Martin Pool - weed out all remaining calls to bailout() and remove the function | 32 | from bzrlib.errors import BzrError | 
| 33 | from bzrlib.trace import mutter | |
| 1185.1.41
by Robert Collins massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid | 34 | |
| 1
by mbp at sourcefrog import from baz patch-364 | 35 | |
| 36 | def make_readonly(filename): | |
| 37 | """Make a filename read-only.""" | |
| 38 | mod = os.stat(filename).st_mode | |
| 39 | mod = mod & 0777555 | |
| 40 | os.chmod(filename, mod) | |
| 41 | ||
| 42 | ||
| 43 | def make_writable(filename): | |
| 44 | mod = os.stat(filename).st_mode | |
| 45 | mod = mod | 0200 | |
| 46 | os.chmod(filename, mod) | |
| 47 | ||
| 48 | ||
| 1077
by Martin Pool - avoid compiling REs at module load time | 49 | _QUOTE_RE = None | 
| 969
by Martin Pool - Add less-sucky is_within_any | 50 | |
| 51 | ||
| 1
by mbp at sourcefrog import from baz patch-364 | 52 | def quotefn(f): | 
| 779
by Martin Pool - better quotefn for windows: use doublequotes for strings with | 53 | """Return a quoted filename filename | 
| 54 | ||
| 55 |     This previously used backslash quoting, but that works poorly on
 | |
| 56 |     Windows."""
 | |
| 57 |     # TODO: I'm not really sure this is the best format either.x
 | |
| 1077
by Martin Pool - avoid compiling REs at module load time | 58 | global _QUOTE_RE | 
| 59 | if _QUOTE_RE == None: | |
| 1185.1.41
by Robert Collins massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid | 60 | _QUOTE_RE = re.compile(r'([^a-zA-Z0-9.,:/\\_~-])') | 
| 1077
by Martin Pool - avoid compiling REs at module load time | 61 | |
| 779
by Martin Pool - better quotefn for windows: use doublequotes for strings with | 62 | if _QUOTE_RE.search(f): | 
| 63 | return '"' + f + '"' | |
| 64 | else: | |
| 65 | return f | |
| 1
by mbp at sourcefrog import from baz patch-364 | 66 | |
| 67 | ||
| 68 | def file_kind(f): | |
| 69 | mode = os.lstat(f)[ST_MODE] | |
| 70 | if S_ISREG(mode): | |
| 71 | return 'file' | |
| 72 | elif S_ISDIR(mode): | |
| 73 | return 'directory' | |
| 20
by mbp at sourcefrog don't abort on trees that happen to contain symlinks | 74 | elif S_ISLNK(mode): | 
| 75 | return 'symlink' | |
| 1185.3.28
by John Arbash Meinel Adding knowledge about fifo/block/etc, they will be unknown/ignored. | 76 | elif S_ISCHR(mode): | 
| 77 | return 'chardev' | |
| 78 | elif S_ISBLK(mode): | |
| 79 | return 'block' | |
| 80 | elif S_ISFIFO(mode): | |
| 81 | return 'fifo' | |
| 82 | elif S_ISSOCK(mode): | |
| 83 | return 'socket' | |
| 1
by mbp at sourcefrog import from baz patch-364 | 84 | else: | 
| 1185.3.28
by John Arbash Meinel Adding knowledge about fifo/block/etc, they will be unknown/ignored. | 85 | return 'unknown' | 
| 488
by Martin Pool - new helper function kind_marker() | 86 | |
| 87 | ||
| 88 | def kind_marker(kind): | |
| 89 | if kind == 'file': | |
| 90 | return '' | |
| 91 | elif kind == 'directory': | |
| 92 | return '/' | |
| 93 | elif kind == 'symlink': | |
| 94 | return '@' | |
| 95 | else: | |
| 96 | raise BzrError('invalid file kind %r' % kind) | |
| 1
by mbp at sourcefrog import from baz patch-364 | 97 | |
| 1092.2.6
by Robert Collins symlink support updated to work | 98 | def lexists(f): | 
| 99 | try: | |
| 100 | if hasattr(os, 'lstat'): | |
| 101 | os.lstat(f) | |
| 102 | else: | |
| 103 | os.stat(f) | |
| 104 | return True | |
| 105 | except OSError,e: | |
| 106 | if e.errno == errno.ENOENT: | |
| 107 | return False; | |
| 108 | else: | |
| 109 | raise BzrError("lstat/stat of (%r): %r" % (f, e)) | |
| 1
by mbp at sourcefrog import from baz patch-364 | 110 | |
| 1092.2.6
by Robert Collins symlink support updated to work | 111 | def normalizepath(f): | 
| 112 | if hasattr(os.path, 'realpath'): | |
| 113 | F = os.path.realpath | |
| 114 | else: | |
| 115 | F = os.path.abspath | |
| 116 | [p,e] = os.path.split(f) | |
| 117 | if e == "" or e == "." or e == "..": | |
| 118 | return F(f) | |
| 119 | else: | |
| 120 | return os.path.join(F(p), e) | |
| 121 | ||
| 1
by mbp at sourcefrog import from baz patch-364 | 122 | |
| 779
by Martin Pool - better quotefn for windows: use doublequotes for strings with | 123 | def backup_file(fn): | 
| 124 | """Copy a file to a backup. | |
| 125 | ||
| 126 |     Backups are named in GNU-style, with a ~ suffix.
 | |
| 127 | ||
| 128 |     If the file is already a backup, it's not copied.
 | |
| 129 |     """
 | |
| 130 | if fn[-1] == '~': | |
| 131 |         return
 | |
| 132 | bfn = fn + '~' | |
| 133 | ||
| 134 | inf = file(fn, 'rb') | |
| 135 | try: | |
| 136 | content = inf.read() | |
| 137 | finally: | |
| 138 | inf.close() | |
| 139 | ||
| 140 | outf = file(bfn, 'wb') | |
| 141 | try: | |
| 142 | outf.write(content) | |
| 143 | finally: | |
| 144 | outf.close() | |
| 145 | ||
| 1185.1.40
by Robert Collins Merge what applied of Alexander Belchenko's win32 patch. | 146 | if os.name == 'nt': | 
| 147 | import shutil | |
| 148 | rename = shutil.move | |
| 149 | else: | |
| 150 | rename = os.rename | |
| 779
by Martin Pool - better quotefn for windows: use doublequotes for strings with | 151 | |
| 152 | ||
| 1
by mbp at sourcefrog import from baz patch-364 | 153 | def isdir(f): | 
| 154 | """True if f is an accessible directory.""" | |
| 155 | try: | |
| 156 | return S_ISDIR(os.lstat(f)[ST_MODE]) | |
| 157 | except OSError: | |
| 158 | return False | |
| 159 | ||
| 160 | ||
| 161 | def isfile(f): | |
| 162 | """True if f is a regular file.""" | |
| 163 | try: | |
| 164 | return S_ISREG(os.lstat(f)[ST_MODE]) | |
| 165 | except OSError: | |
| 166 | return False | |
| 167 | ||
| 1092.2.6
by Robert Collins symlink support updated to work | 168 | def islink(f): | 
| 169 | """True if f is a symlink.""" | |
| 170 | try: | |
| 171 | return S_ISLNK(os.lstat(f)[ST_MODE]) | |
| 172 | except OSError: | |
| 173 | return False | |
| 1
by mbp at sourcefrog import from baz patch-364 | 174 | |
| 485
by Martin Pool - move commit code into its own module | 175 | def is_inside(dir, fname): | 
| 176 | """True if fname is inside dir. | |
| 969
by Martin Pool - Add less-sucky is_within_any | 177 |     
 | 
| 178 |     The parameters should typically be passed to os.path.normpath first, so
 | |
| 179 |     that . and .. and repeated slashes are eliminated, and the separators
 | |
| 180 |     are canonical for the platform.
 | |
| 181 |     
 | |
| 974.1.26
by aaron.bentley at utoronto merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472 | 182 |     The empty string as a dir name is taken as top-of-tree and matches 
 | 
| 183 |     everything.
 | |
| 184 |     
 | |
| 1185.1.40
by Robert Collins Merge what applied of Alexander Belchenko's win32 patch. | 185 |     >>> is_inside('src', os.path.join('src', 'foo.c'))
 | 
| 969
by Martin Pool - Add less-sucky is_within_any | 186 |     True
 | 
| 187 |     >>> is_inside('src', 'srccontrol')
 | |
| 188 |     False
 | |
| 1185.1.40
by Robert Collins Merge what applied of Alexander Belchenko's win32 patch. | 189 |     >>> is_inside('src', os.path.join('src', 'a', 'a', 'a', 'foo.c'))
 | 
| 969
by Martin Pool - Add less-sucky is_within_any | 190 |     True
 | 
| 191 |     >>> is_inside('foo.c', 'foo.c')
 | |
| 192 |     True
 | |
| 974.1.26
by aaron.bentley at utoronto merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472 | 193 |     >>> is_inside('foo.c', '')
 | 
| 194 |     False
 | |
| 195 |     >>> is_inside('', 'foo.c')
 | |
| 196 |     True
 | |
| 485
by Martin Pool - move commit code into its own module | 197 |     """
 | 
| 969
by Martin Pool - Add less-sucky is_within_any | 198 |     # XXX: Most callers of this can actually do something smarter by 
 | 
| 199 |     # looking at the inventory
 | |
| 972
by Martin Pool - less dodgy is_inside function | 200 | if dir == fname: | 
| 201 | return True | |
| 202 | ||
| 974.1.26
by aaron.bentley at utoronto merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472 | 203 | if dir == '': | 
| 204 | return True | |
| 1185.1.41
by Robert Collins massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid | 205 | |
| 972
by Martin Pool - less dodgy is_inside function | 206 | if dir[-1] != os.sep: | 
| 207 | dir += os.sep | |
| 1185.1.41
by Robert Collins massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid | 208 | |
| 972
by Martin Pool - less dodgy is_inside function | 209 | return fname.startswith(dir) | 
| 210 | ||
| 485
by Martin Pool - move commit code into its own module | 211 | |
| 212 | def is_inside_any(dir_list, fname): | |
| 213 | """True if fname is inside any of given dirs.""" | |
| 214 | for dirname in dir_list: | |
| 215 | if is_inside(dirname, fname): | |
| 216 | return True | |
| 217 | else: | |
| 218 | return False | |
| 219 | ||
| 220 | ||
| 1
by mbp at sourcefrog import from baz patch-364 | 221 | def pumpfile(fromfile, tofile): | 
| 222 | """Copy contents of one file to another.""" | |
| 223 | tofile.write(fromfile.read()) | |
| 224 | ||
| 225 | ||
| 226 | def sha_file(f): | |
| 227 | if hasattr(f, 'tell'): | |
| 228 | assert f.tell() == 0 | |
| 229 | s = sha.new() | |
| 320
by Martin Pool - Compute SHA-1 of files in chunks | 230 | BUFSIZE = 128<<10 | 
| 231 | while True: | |
| 232 | b = f.read(BUFSIZE) | |
| 233 | if not b: | |
| 234 |             break
 | |
| 235 | s.update(b) | |
| 1
by mbp at sourcefrog import from baz patch-364 | 236 | return s.hexdigest() | 
| 237 | ||
| 238 | ||
| 1235
by Martin Pool - split sha_strings into osutils | 239 | |
| 240 | def sha_strings(strings): | |
| 241 | """Return the sha-1 of concatenation of strings""" | |
| 242 | s = sha.new() | |
| 243 | map(s.update, strings) | |
| 244 | return s.hexdigest() | |
| 245 | ||
| 246 | ||
| 1
by mbp at sourcefrog import from baz patch-364 | 247 | def sha_string(f): | 
| 248 | s = sha.new() | |
| 249 | s.update(f) | |
| 250 | return s.hexdigest() | |
| 251 | ||
| 252 | ||
| 124
by mbp at sourcefrog - check file text for past revisions is correct | 253 | def fingerprint_file(f): | 
| 254 | s = sha.new() | |
| 126
by mbp at sourcefrog Use just one big read to fingerprint files | 255 | b = f.read() | 
| 256 | s.update(b) | |
| 257 | size = len(b) | |
| 124
by mbp at sourcefrog - check file text for past revisions is correct | 258 | return {'size': size, | 
| 259 | 'sha1': s.hexdigest()} | |
| 260 | ||
| 261 | ||
| 258
by Martin Pool - Take email from ~/.bzr.conf/email | 262 | def config_dir(): | 
| 263 | """Return per-user configuration directory. | |
| 264 | ||
| 265 |     By default this is ~/.bzr.conf/
 | |
| 266 |     
 | |
| 267 |     TODO: Global option --config-dir to override this.
 | |
| 268 |     """
 | |
| 1185.1.41
by Robert Collins massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid | 269 | return os.path.join(os.path.expanduser("~"), ".bzr.conf") | 
| 258
by Martin Pool - Take email from ~/.bzr.conf/email | 270 | |
| 271 | ||
| 252
by Martin Pool - Don't use host fqdn for default user name, because DNS tends | 272 | def _auto_user_id(): | 
| 246
by mbp at sourcefrog - unicode decoding in getting email and userid strings | 273 | """Calculate automatic user identification. | 
| 274 | ||
| 275 |     Returns (realname, email).
 | |
| 276 | ||
| 252
by Martin Pool - Don't use host fqdn for default user name, because DNS tends | 277 |     Only used when none is set in the environment or the id file.
 | 
| 246
by mbp at sourcefrog - unicode decoding in getting email and userid strings | 278 | |
| 252
by Martin Pool - Don't use host fqdn for default user name, because DNS tends | 279 |     This previously used the FQDN as the default domain, but that can
 | 
| 280 |     be very slow on machines where DNS is broken.  So now we simply
 | |
| 281 |     use the hostname.
 | |
| 1
by mbp at sourcefrog import from baz patch-364 | 282 |     """
 | 
| 251
by mbp at sourcefrog - factor out locale.getpreferredencoding() | 283 | import socket | 
| 246
by mbp at sourcefrog - unicode decoding in getting email and userid strings | 284 | |
| 285 |     # XXX: Any good way to get real user name on win32?
 | |
| 286 | ||
| 1
by mbp at sourcefrog import from baz patch-364 | 287 | try: | 
| 288 | import pwd | |
| 289 | uid = os.getuid() | |
| 290 | w = pwd.getpwuid(uid) | |
| 251
by mbp at sourcefrog - factor out locale.getpreferredencoding() | 291 | gecos = w.pw_gecos.decode(bzrlib.user_encoding) | 
| 292 | username = w.pw_name.decode(bzrlib.user_encoding) | |
| 25
by Martin Pool cope when gecos field doesn't have a comma | 293 | comma = gecos.find(',') | 
| 294 | if comma == -1: | |
| 295 | realname = gecos | |
| 296 | else: | |
| 297 | realname = gecos[:comma] | |
| 256
by Martin Pool - More handling of auto-username case | 298 | if not realname: | 
| 299 | realname = username | |
| 246
by mbp at sourcefrog - unicode decoding in getting email and userid strings | 300 | |
| 1
by mbp at sourcefrog import from baz patch-364 | 301 | except ImportError: | 
| 246
by mbp at sourcefrog - unicode decoding in getting email and userid strings | 302 | import getpass | 
| 256
by Martin Pool - More handling of auto-username case | 303 | realname = username = getpass.getuser().decode(bzrlib.user_encoding) | 
| 252
by Martin Pool - Don't use host fqdn for default user name, because DNS tends | 304 | |
| 256
by Martin Pool - More handling of auto-username case | 305 | return realname, (username + '@' + socket.gethostname()) | 
| 252
by Martin Pool - Don't use host fqdn for default user name, because DNS tends | 306 | |
| 307 | ||
| 1074
by Martin Pool - check for email address in BRANCH_ROOT/.bzr/email, so you can | 308 | def _get_user_id(branch): | 
| 258
by Martin Pool - Take email from ~/.bzr.conf/email | 309 | """Return the full user id from a file or environment variable. | 
| 310 | ||
| 1074
by Martin Pool - check for email address in BRANCH_ROOT/.bzr/email, so you can | 311 |     e.g. "John Hacker <jhacker@foo.org>"
 | 
| 312 | ||
| 313 |     branch
 | |
| 314 |         A branch to use for a per-branch configuration, or None.
 | |
| 315 | ||
| 316 |     The following are searched in order:
 | |
| 317 | ||
| 318 |     1. $BZREMAIL
 | |
| 319 |     2. .bzr/email for this branch.
 | |
| 320 |     3. ~/.bzr.conf/email
 | |
| 321 |     4. $EMAIL
 | |
| 322 |     """
 | |
| 252
by Martin Pool - Don't use host fqdn for default user name, because DNS tends | 323 | v = os.environ.get('BZREMAIL') | 
| 324 | if v: | |
| 325 | return v.decode(bzrlib.user_encoding) | |
| 1074
by Martin Pool - check for email address in BRANCH_ROOT/.bzr/email, so you can | 326 | |
| 327 | if branch: | |
| 328 | try: | |
| 329 | return (branch.controlfile("email", "r") | |
| 330 | .read() | |
| 331 | .decode(bzrlib.user_encoding) | |
| 332 | .rstrip("\r\n")) | |
| 333 | except IOError, e: | |
| 334 | if e.errno != errno.ENOENT: | |
| 335 |                 raise
 | |
| 336 | except BzrError, e: | |
| 337 |             pass
 | |
| 252
by Martin Pool - Don't use host fqdn for default user name, because DNS tends | 338 | |
| 339 | try: | |
| 258
by Martin Pool - Take email from ~/.bzr.conf/email | 340 | return (open(os.path.join(config_dir(), "email")) | 
| 252
by Martin Pool - Don't use host fqdn for default user name, because DNS tends | 341 | .read() | 
| 342 | .decode(bzrlib.user_encoding) | |
| 343 | .rstrip("\r\n")) | |
| 256
by Martin Pool - More handling of auto-username case | 344 | except IOError, e: | 
| 345 | if e.errno != errno.ENOENT: | |
| 252
by Martin Pool - Don't use host fqdn for default user name, because DNS tends | 346 | raise e | 
| 347 | ||
| 348 | v = os.environ.get('EMAIL') | |
| 349 | if v: | |
| 350 | return v.decode(bzrlib.user_encoding) | |
| 351 | else: | |
| 352 | return None | |
| 246
by mbp at sourcefrog - unicode decoding in getting email and userid strings | 353 | |
| 354 | ||
| 1074
by Martin Pool - check for email address in BRANCH_ROOT/.bzr/email, so you can | 355 | def username(branch): | 
| 246
by mbp at sourcefrog - unicode decoding in getting email and userid strings | 356 | """Return email-style username. | 
| 357 | ||
| 358 |     Something similar to 'Martin Pool <mbp@sourcefrog.net>'
 | |
| 359 | ||
| 254
by Martin Pool - Doc cleanups from Magnus Therning | 360 |     TODO: Check it's reasonably well-formed.
 | 
| 246
by mbp at sourcefrog - unicode decoding in getting email and userid strings | 361 |     """
 | 
| 1074
by Martin Pool - check for email address in BRANCH_ROOT/.bzr/email, so you can | 362 | v = _get_user_id(branch) | 
| 252
by Martin Pool - Don't use host fqdn for default user name, because DNS tends | 363 | if v: | 
| 364 | return v | |
| 365 | ||
| 366 | name, email = _auto_user_id() | |
| 246
by mbp at sourcefrog - unicode decoding in getting email and userid strings | 367 | if name: | 
| 368 | return '%s <%s>' % (name, email) | |
| 369 | else: | |
| 370 | return email | |
| 1
by mbp at sourcefrog import from baz patch-364 | 371 | |
| 372 | ||
| 1074
by Martin Pool - check for email address in BRANCH_ROOT/.bzr/email, so you can | 373 | def user_email(branch): | 
| 1
by mbp at sourcefrog import from baz patch-364 | 374 | """Return just the email component of a username.""" | 
| 1074
by Martin Pool - check for email address in BRANCH_ROOT/.bzr/email, so you can | 375 | e = _get_user_id(branch) | 
| 1
by mbp at sourcefrog import from baz patch-364 | 376 | if e: | 
| 1077
by Martin Pool - avoid compiling REs at module load time | 377 | m = re.search(r'[\w+.-]+@[\w+.-]+', e) | 
| 1
by mbp at sourcefrog import from baz patch-364 | 378 | if not m: | 
| 1185.1.41
by Robert Collins massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid | 379 | raise BzrError("%r doesn't seem to contain " | 
| 380 | "a reasonable email address" % e) | |
| 1
by mbp at sourcefrog import from baz patch-364 | 381 | return m.group(0) | 
| 382 | ||
| 252
by Martin Pool - Don't use host fqdn for default user name, because DNS tends | 383 | return _auto_user_id()[1] | 
| 1
by mbp at sourcefrog import from baz patch-364 | 384 | |
| 385 | ||
| 386 | def compare_files(a, b): | |
| 387 | """Returns true if equal in contents""" | |
| 74
by mbp at sourcefrog compare_files: read in one page at a time rather than | 388 | BUFSIZE = 4096 | 
| 389 | while True: | |
| 390 | ai = a.read(BUFSIZE) | |
| 391 | bi = b.read(BUFSIZE) | |
| 392 | if ai != bi: | |
| 393 | return False | |
| 394 | if ai == '': | |
| 395 | return True | |
| 1
by mbp at sourcefrog import from baz patch-364 | 396 | |
| 397 | ||
| 49
by mbp at sourcefrog fix local-time-offset calculation | 398 | def local_time_offset(t=None): | 
| 399 | """Return offset of local zone from GMT, either at present or at time t.""" | |
| 73
by mbp at sourcefrog fix time.localtime call for python 2.3 | 400 |     # python2.3 localtime() can't take None
 | 
| 183
by mbp at sourcefrog pychecker fixups | 401 | if t == None: | 
| 73
by mbp at sourcefrog fix time.localtime call for python 2.3 | 402 | t = time.time() | 
| 403 | ||
| 49
by mbp at sourcefrog fix local-time-offset calculation | 404 | if time.localtime(t).tm_isdst and time.daylight: | 
| 8
by mbp at sourcefrog store committer's timezone in revision and show | 405 | return -time.altzone | 
| 406 | else: | |
| 407 | return -time.timezone | |
| 408 | ||
| 409 | ||
| 410 | def format_date(t, offset=0, timezone='original'): | |
| 1
by mbp at sourcefrog import from baz patch-364 | 411 |     ## TODO: Perhaps a global option to use either universal or local time?
 | 
| 412 |     ## Or perhaps just let people set $TZ?
 | |
| 413 | assert isinstance(t, float) | |
| 414 | ||
| 8
by mbp at sourcefrog store committer's timezone in revision and show | 415 | if timezone == 'utc': | 
| 1
by mbp at sourcefrog import from baz patch-364 | 416 | tt = time.gmtime(t) | 
| 417 | offset = 0 | |
| 8
by mbp at sourcefrog store committer's timezone in revision and show | 418 | elif timezone == 'original': | 
| 23
by mbp at sourcefrog format_date: handle revisions with no timezone offset | 419 | if offset == None: | 
| 420 | offset = 0 | |
| 16
by mbp at sourcefrog fix inverted calculation for original timezone -> utc | 421 | tt = time.gmtime(t + offset) | 
| 12
by mbp at sourcefrog new --timezone option for bzr log | 422 | elif timezone == 'local': | 
| 1
by mbp at sourcefrog import from baz patch-364 | 423 | tt = time.localtime(t) | 
| 49
by mbp at sourcefrog fix local-time-offset calculation | 424 | offset = local_time_offset(t) | 
| 12
by mbp at sourcefrog new --timezone option for bzr log | 425 | else: | 
| 974.1.26
by aaron.bentley at utoronto merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472 | 426 | raise BzrError("unsupported timezone format %r" % timezone, | 
| 427 | ['options are "utc", "original", "local"']) | |
| 8
by mbp at sourcefrog store committer's timezone in revision and show | 428 | |
| 1
by mbp at sourcefrog import from baz patch-364 | 429 | return (time.strftime("%a %Y-%m-%d %H:%M:%S", tt) | 
| 8
by mbp at sourcefrog store committer's timezone in revision and show | 430 | + ' %+03d%02d' % (offset / 3600, (offset / 60) % 60)) | 
| 1
by mbp at sourcefrog import from baz patch-364 | 431 | |
| 432 | ||
| 433 | def compact_date(when): | |
| 434 | return time.strftime('%Y%m%d%H%M%S', time.gmtime(when)) | |
| 435 | ||
| 436 | ||
| 437 | ||
| 438 | def filesize(f): | |
| 439 | """Return size of given open file.""" | |
| 440 | return os.fstat(f.fileno())[ST_SIZE] | |
| 441 | ||
| 1185.1.7
by Robert Collins Nathaniel McCallums patch for urandom friendliness on aix. | 442 | # Define rand_bytes based on platform.
 | 
| 443 | try: | |
| 444 |     # Python 2.4 and later have os.urandom,
 | |
| 445 |     # but it doesn't work on some arches
 | |
| 446 | os.urandom(1) | |
| 1
by mbp at sourcefrog import from baz patch-364 | 447 | rand_bytes = os.urandom | 
| 1185.1.7
by Robert Collins Nathaniel McCallums patch for urandom friendliness on aix. | 448 | except (NotImplementedError, AttributeError): | 
| 449 |     # If python doesn't have os.urandom, or it doesn't work,
 | |
| 450 |     # then try to first pull random data from /dev/urandom
 | |
| 451 | if os.path.exists("/dev/urandom"): | |
| 452 | rand_bytes = file('/dev/urandom', 'rb').read | |
| 453 |     # Otherwise, use this hack as a last resort
 | |
| 454 | else: | |
| 455 |         # not well seeded, but better than nothing
 | |
| 456 | def rand_bytes(n): | |
| 457 | import random | |
| 458 | s = '' | |
| 459 | while n: | |
| 460 | s += chr(random.randint(0, 255)) | |
| 461 | n -= 1 | |
| 462 | return s | |
| 1
by mbp at sourcefrog import from baz patch-364 | 463 | |
| 464 | ## TODO: We could later have path objects that remember their list
 | |
| 465 | ## decomposition (might be too tricksy though.)
 | |
| 466 | ||
| 467 | def splitpath(p): | |
| 468 | """Turn string into list of parts. | |
| 469 | ||
| 470 |     >>> splitpath('a')
 | |
| 471 |     ['a']
 | |
| 472 |     >>> splitpath('a/b')
 | |
| 473 |     ['a', 'b']
 | |
| 474 |     >>> splitpath('a/./b')
 | |
| 475 |     ['a', 'b']
 | |
| 476 |     >>> splitpath('a/.b')
 | |
| 477 |     ['a', '.b']
 | |
| 478 |     >>> splitpath('a/../b')
 | |
| 184
by mbp at sourcefrog pychecker fixups | 479 |     Traceback (most recent call last):
 | 
| 1
by mbp at sourcefrog import from baz patch-364 | 480 |     ...
 | 
| 694
by Martin Pool - weed out all remaining calls to bailout() and remove the function | 481 |     BzrError: sorry, '..' not allowed in path
 | 
| 1
by mbp at sourcefrog import from baz patch-364 | 482 |     """
 | 
| 483 | assert isinstance(p, types.StringTypes) | |
| 271
by Martin Pool - Windows path fixes | 484 | |
| 485 |     # split on either delimiter because people might use either on
 | |
| 486 |     # Windows
 | |
| 487 | ps = re.split(r'[\\/]', p) | |
| 488 | ||
| 489 | rps = [] | |
| 1
by mbp at sourcefrog import from baz patch-364 | 490 | for f in ps: | 
| 491 | if f == '..': | |
| 694
by Martin Pool - weed out all remaining calls to bailout() and remove the function | 492 | raise BzrError("sorry, %r not allowed in path" % f) | 
| 271
by Martin Pool - Windows path fixes | 493 | elif (f == '.') or (f == ''): | 
| 494 |             pass
 | |
| 495 | else: | |
| 496 | rps.append(f) | |
| 497 | return rps | |
| 1
by mbp at sourcefrog import from baz patch-364 | 498 | |
| 499 | def joinpath(p): | |
| 500 | assert isinstance(p, list) | |
| 501 | for f in p: | |
| 183
by mbp at sourcefrog pychecker fixups | 502 | if (f == '..') or (f == None) or (f == ''): | 
| 694
by Martin Pool - weed out all remaining calls to bailout() and remove the function | 503 | raise BzrError("sorry, %r not allowed in path" % f) | 
| 271
by Martin Pool - Windows path fixes | 504 | return os.path.join(*p) | 
| 1
by mbp at sourcefrog import from baz patch-364 | 505 | |
| 506 | ||
| 507 | def appendpath(p1, p2): | |
| 508 | if p1 == '': | |
| 509 | return p2 | |
| 510 | else: | |
| 271
by Martin Pool - Windows path fixes | 511 | return os.path.join(p1, p2) | 
| 1
by mbp at sourcefrog import from baz patch-364 | 512 | |
| 513 | ||
| 763
by Martin Pool - Patch from Torsten Marek to take commit messages through an | 514 | def _read_config_value(name): | 
| 515 | """Read a config value from the file ~/.bzr.conf/<name> | |
| 516 |     Return None if the file does not exist"""
 | |
| 517 | try: | |
| 518 | f = file(os.path.join(config_dir(), name), "r") | |
| 519 | return f.read().decode(bzrlib.user_encoding).rstrip("\r\n") | |
| 520 | except IOError, e: | |
| 521 | if e.errno == errno.ENOENT: | |
| 522 | return None | |
| 523 |         raise
 | |
| 524 | ||
| 1185.1.46
by Robert Collins Aarons branch --basis patch | 525 | |
| 1231
by Martin Pool - more progress on fetch on top of weaves | 526 | def split_lines(s): | 
| 527 | """Split s into lines, but without removing the newline characters.""" | |
| 528 | return StringIO(s).readlines() | |
| 1391
by Robert Collins merge from integration | 529 | |
| 530 | ||
| 1185.10.4
by Aaron Bentley Disabled hardlinks on cygwin, mac OS | 531 | def hardlinks_good(): | 
| 1185.10.5
by Aaron Bentley Fixed hardlinks_good test | 532 | return sys.platform not in ('win32', 'cygwin', 'darwin') | 
| 1185.10.4
by Aaron Bentley Disabled hardlinks on cygwin, mac OS | 533 | |
| 1185.1.46
by Robert Collins Aarons branch --basis patch | 534 | |
| 1185.10.3
by Aaron Bentley Made copy_multi_immutable create hardlinks opportunistically | 535 | def link_or_copy(src, dest): | 
| 536 | """Hardlink a file, or copy it if it can't be hardlinked.""" | |
| 1185.10.4
by Aaron Bentley Disabled hardlinks on cygwin, mac OS | 537 | if not hardlinks_good(): | 
| 1185.10.3
by Aaron Bentley Made copy_multi_immutable create hardlinks opportunistically | 538 | copyfile(src, dest) | 
| 539 |         return
 | |
| 540 | try: | |
| 541 | os.link(src, dest) | |
| 542 | except (OSError, IOError), e: | |
| 543 | if e.errno != errno.EXDEV: | |
| 544 |             raise
 | |
| 545 | copyfile(src, dest) |