annotate mercurial/pure/osutil.py @ 26623:5a95fe44121d

clonebundles: support for seeding clones from pre-generated bundles Cloning can be an expensive operation for servers because the server generates a bundle from existing repository data at request time. For a large repository like mozilla-central, this consumes 4+ minutes of CPU time on the server. It also results in significant network utilization. Multiplied by hundreds or even thousands of clients and the ensuing load can result in difficulties scaling the Mercurial server. Despite generation of bundles being deterministic until the next changeset is added, the generation of bundles to service a clone request is not cached. Each clone thus performs redundant work. This is wasteful. This patch introduces the "clonebundles" extension and related client-side functionality to help alleviate this deficiency. The client-side feature is behind an experimental flag and is not enabled by default. It works as follows: 1) Server operator generates a bundle and makes it available on a server (likely HTTP). 2) Server operator defines the URL of a bundle file in a .hg/clonebundles.manifest file. 3) Client `hg clone`ing sees the server is advertising bundle URLs. 4) Client fetches and applies the advertised bundle. 5) Client performs equivalent of `hg pull` to fetch changes made since the bundle was created. Essentially, the server performs the expensive work of generating a bundle once and all subsequent clones fetch a static file from somewhere. Scaling static file serving is a much more manageable problem than scaling a Python application like Mercurial. Assuming your repository grows less than 1% per day, the end result is 99+% of CPU and network load from clones is eliminated, allowing Mercurial servers to scale more easily. Serving static files also means data can be transferred to clients as fast as they can consume it, rather than as fast as servers can generate it. This makes clones faster. Mozilla has implemented similar functionality of this patch on hg.mozilla.org using a custom extension. We are hosting bundle files in Amazon S3 and CloudFront (a CDN) and have successfully offloaded >1 TB/day in data transfer from hg.mozilla.org, freeing up significant bandwidth and CPU resources. The positive impact has been stellar and I believe it has proved its value to be included in Mercurial core. I feel it is important for the client-side support to be enabled in core by default because it means that clients will get faster, more reliable clones and will enable server operators to reduce load without requiring any client-side configuration changes (assuming clients are up to date, of course). The scope of this feature is narrowly and specifically tailored to cloning, despite "serve pulls from pre-generated bundles" being a valid and useful feature. I would eventually like for Mercurial servers to support transferring *all* repository data via statically hosted files. You could imagine a server that siphons all pushed data to bundle files and instructs clients to apply a stream of bundles to reconstruct all repository data. This feature, while useful and powerful, is significantly more work to implement because it requires the server component have awareness of discovery and a mapping of which changesets are in which files. Full, clone bundles, by contrast, are much simpler. The wire protocol command is named "clonebundles" instead of something more generic like "staticbundles" to leave the door open for a new, more powerful and more generic server-side component with minimal backwards compatibility implications. The name "bundleclone" is used by Mozilla's extension and would cause problems since there are subtle differences in Mozilla's extension. Mozilla's experience with this idea has taught us that some form of "content negotiation" is required. Not all clients will support all bundle formats or even URLs (advanced TLS requirements, etc). To ensure the highest uptake possible, a server needs to advertise multiple versions of bundles and clients need to be able to choose the most appropriate from that list one. The "attributes" in each server-advertised entry facilitate this filtering and sorting. Their use will become apparent in subsequent patches. Initial inspiration and credit for the idea of cloning from static files belongs to Augie Fackler and his "lookaside clone" extension proof of concept.
author Gregory Szorc <gregory.szorc@gmail.com>
date Fri, 09 Oct 2015 11:22:01 -0700
parents 977102cb12fc
children 810337ae1b76
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
8232
823f25b25dea pure/osutil: add copyright and license header
Martin Geisler <mg@lazybytes.net>
parents: 7704
diff changeset
1 # osutil.py - pure Python version of osutil.c
823f25b25dea pure/osutil: add copyright and license header
Martin Geisler <mg@lazybytes.net>
parents: 7704
diff changeset
2 #
823f25b25dea pure/osutil: add copyright and license header
Martin Geisler <mg@lazybytes.net>
parents: 7704
diff changeset
3 # Copyright 2009 Matt Mackall <mpm@selenic.com> and others
823f25b25dea pure/osutil: add copyright and license header
Martin Geisler <mg@lazybytes.net>
parents: 7704
diff changeset
4 #
823f25b25dea pure/osutil: add copyright and license header
Martin Geisler <mg@lazybytes.net>
parents: 7704
diff changeset
5 # This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 9031
diff changeset
6 # GNU General Public License version 2 or any later version.
8232
823f25b25dea pure/osutil: add copyright and license header
Martin Geisler <mg@lazybytes.net>
parents: 7704
diff changeset
7
7704
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
8 import os
10651
5f091fc1bab7 style: use consistent variable names (*mod) with imports which would shadow
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
9 import stat as statmod
7704
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
10
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
11 def _mode_to_kind(mode):
10651
5f091fc1bab7 style: use consistent variable names (*mod) with imports which would shadow
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
12 if statmod.S_ISREG(mode):
5f091fc1bab7 style: use consistent variable names (*mod) with imports which would shadow
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
13 return statmod.S_IFREG
5f091fc1bab7 style: use consistent variable names (*mod) with imports which would shadow
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
14 if statmod.S_ISDIR(mode):
5f091fc1bab7 style: use consistent variable names (*mod) with imports which would shadow
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
15 return statmod.S_IFDIR
5f091fc1bab7 style: use consistent variable names (*mod) with imports which would shadow
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
16 if statmod.S_ISLNK(mode):
5f091fc1bab7 style: use consistent variable names (*mod) with imports which would shadow
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
17 return statmod.S_IFLNK
5f091fc1bab7 style: use consistent variable names (*mod) with imports which would shadow
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
18 if statmod.S_ISBLK(mode):
5f091fc1bab7 style: use consistent variable names (*mod) with imports which would shadow
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
19 return statmod.S_IFBLK
5f091fc1bab7 style: use consistent variable names (*mod) with imports which would shadow
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
20 if statmod.S_ISCHR(mode):
5f091fc1bab7 style: use consistent variable names (*mod) with imports which would shadow
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
21 return statmod.S_IFCHR
5f091fc1bab7 style: use consistent variable names (*mod) with imports which would shadow
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
22 if statmod.S_ISFIFO(mode):
5f091fc1bab7 style: use consistent variable names (*mod) with imports which would shadow
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
23 return statmod.S_IFIFO
5f091fc1bab7 style: use consistent variable names (*mod) with imports which would shadow
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
24 if statmod.S_ISSOCK(mode):
5f091fc1bab7 style: use consistent variable names (*mod) with imports which would shadow
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
25 return statmod.S_IFSOCK
7704
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
26 return mode
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
27
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
28 def listdir(path, stat=False, skip=None):
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
29 '''listdir(path, stat=False) -> list_of_tuples
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
30
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
31 Return a sorted list containing information about the entries
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
32 in the directory.
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
33
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
34 If stat is True, each element is a 3-tuple:
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
35
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
36 (name, type, stat object)
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
37
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
38 Otherwise, each element is a 2-tuple:
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
39
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
40 (name, type)
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
41 '''
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
42 result = []
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
43 prefix = path
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
44 if not prefix.endswith(os.sep):
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
45 prefix += os.sep
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
46 names = os.listdir(path)
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
47 names.sort()
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
48 for fn in names:
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
49 st = os.lstat(prefix + fn)
10651
5f091fc1bab7 style: use consistent variable names (*mod) with imports which would shadow
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
50 if fn == skip and statmod.S_ISDIR(st.st_mode):
7704
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
51 return []
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
52 if stat:
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
53 result.append((fn, _mode_to_kind(st.st_mode), st))
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
54 else:
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
55 result.append((fn, _mode_to_kind(st.st_mode)))
30d1d313370b move mercurial.osutil to mercurial.pure.osutil
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
56 return result
8421
b6d0fa8c7685 posixfile: remove posixfile_nt and fix import bug in windows.py
Sune Foldager <cryo@cyanite.org>
parents: 8232
diff changeset
57
14413
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
58 if os.name != 'nt':
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
59 posixfile = open
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
60 else:
16474
ee553e6cd8c4 pure/osutil: use Python's msvcrt module (issue3380)
Adrian Buehlmann <adrian@cadifra.com>
parents: 15040
diff changeset
61 import ctypes, msvcrt
14413
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
62
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
63 _kernel32 = ctypes.windll.kernel32
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
64
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
65 _DWORD = ctypes.c_ulong
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
66 _LPCSTR = _LPSTR = ctypes.c_char_p
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
67 _HANDLE = ctypes.c_void_p
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
68
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
69 _INVALID_HANDLE_VALUE = _HANDLE(-1).value
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
70
18959
2f6418d8a4c9 check-code: catch trailing space in comments
Mads Kiilerich <madski@unity3d.com>
parents: 17429
diff changeset
71 # CreateFile
14413
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
72 _FILE_SHARE_READ = 0x00000001
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
73 _FILE_SHARE_WRITE = 0x00000002
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
74 _FILE_SHARE_DELETE = 0x00000004
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
75
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
76 _CREATE_ALWAYS = 2
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
77 _OPEN_EXISTING = 3
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
78 _OPEN_ALWAYS = 4
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
79
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
80 _GENERIC_READ = 0x80000000
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
81 _GENERIC_WRITE = 0x40000000
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
82
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
83 _FILE_ATTRIBUTE_NORMAL = 0x80
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
84
17429
72fa4ef2245f declare local constants instead of using magic values and comments
Mads Kiilerich <mads@kiilerich.com>
parents: 16686
diff changeset
85 # open_osfhandle flags
14413
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
86 _O_RDONLY = 0x0000
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
87 _O_RDWR = 0x0002
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
88 _O_APPEND = 0x0008
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
89
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
90 _O_TEXT = 0x4000
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
91 _O_BINARY = 0x8000
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
92
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
93 # types of parameters of C functions used (required by pypy)
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
94
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
95 _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p,
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
96 _DWORD, _DWORD, _HANDLE]
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
97 _kernel32.CreateFileA.restype = _HANDLE
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
98
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
99 def _raiseioerror(name):
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
100 err = ctypes.WinError()
25645
977102cb12fc osutil: remove Python 2.4 errno conversion workaround
Gregory Szorc <gregory.szorc@gmail.com>
parents: 19465
diff changeset
101 raise IOError(err.errno, '%s: %s' % (name, err.strerror))
14413
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
102
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
103 class posixfile(object):
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
104 '''a file object aiming for POSIX-like semantics
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
105
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
106 CPython's open() returns a file that was opened *without* setting the
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
107 _FILE_SHARE_DELETE flag, which causes rename and unlink to abort.
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
108 This even happens if any hardlinked copy of the file is in open state.
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
109 We set _FILE_SHARE_DELETE here, so files opened with posixfile can be
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
110 renamed and deleted while they are held open.
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
111 Note that if a file opened with posixfile is unlinked, the file
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
112 remains but cannot be opened again or be recreated under the same name,
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
113 until all reading processes have closed the file.'''
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
114
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
115 def __init__(self, name, mode='r', bufsize=-1):
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
116 if 'b' in mode:
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
117 flags = _O_BINARY
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
118 else:
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
119 flags = _O_TEXT
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
120
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
121 m0 = mode[0]
16686
67964cda8701 cleanup: "not x in y" -> "x not in y"
Brodie Rao <brodie@sf.io>
parents: 16474
diff changeset
122 if m0 == 'r' and '+' not in mode:
14413
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
123 flags |= _O_RDONLY
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
124 access = _GENERIC_READ
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
125 else:
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
126 # work around http://support.microsoft.com/kb/899149 and
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
127 # set _O_RDWR for 'w' and 'a', even if mode has no '+'
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
128 flags |= _O_RDWR
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
129 access = _GENERIC_READ | _GENERIC_WRITE
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
130
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
131 if m0 == 'r':
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
132 creation = _OPEN_EXISTING
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
133 elif m0 == 'w':
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
134 creation = _CREATE_ALWAYS
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
135 elif m0 == 'a':
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
136 creation = _OPEN_ALWAYS
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
137 flags |= _O_APPEND
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
138 else:
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
139 raise ValueError("invalid mode: %s" % mode)
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
140
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
141 fh = _kernel32.CreateFileA(name, access,
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
142 _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
143 None, creation, _FILE_ATTRIBUTE_NORMAL, None)
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
144 if fh == _INVALID_HANDLE_VALUE:
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
145 _raiseioerror(name)
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
146
16474
ee553e6cd8c4 pure/osutil: use Python's msvcrt module (issue3380)
Adrian Buehlmann <adrian@cadifra.com>
parents: 15040
diff changeset
147 fd = msvcrt.open_osfhandle(fh, flags)
14413
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
148 if fd == -1:
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
149 _kernel32.CloseHandle(fh)
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
150 _raiseioerror(name)
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
151
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
152 f = os.fdopen(fd, mode, bufsize)
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
153 # unfortunately, f.name is '<fdopen>' at this point -- so we store
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
154 # the name on this wrapper. We cannot just assign to f.name,
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
155 # because that attribute is read-only.
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
156 object.__setattr__(self, 'name', name)
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
157 object.__setattr__(self, '_file', f)
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
158
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
159 def __iter__(self):
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
160 return self._file
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
161
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
162 def __getattr__(self, name):
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
163 return getattr(self._file, name)
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
164
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
165 def __setattr__(self, name, value):
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
166 '''mimics the read-only attributes of Python file objects
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
167 by raising 'TypeError: readonly attribute' if someone tries:
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
168 f = posixfile('foo.txt')
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
169 f.name = 'bla' '''
5ef18e28df19 pure: provide more correct implementation of posixfile for Windows
Adrian Buehlmann <adrian@cadifra.com>
parents: 10651
diff changeset
170 return self._file.__setattr__(name, value)