mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-22 21:32:31 +00:00
python-3.6.zip added from Github
README.cosmo contains the necessary links.
This commit is contained in:
parent
75fc601ff5
commit
0c4c56ff39
4219 changed files with 1968626 additions and 0 deletions
48
third_party/python/Tools/README
vendored
Normal file
48
third_party/python/Tools/README
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
This directory contains a number of Python programs that are useful
|
||||
while building or extending Python.
|
||||
|
||||
buildbot Batchfiles for running on Windows buildslaves.
|
||||
|
||||
ccbench A Python threads-based concurrency benchmark. (*)
|
||||
|
||||
demo Several Python programming demos.
|
||||
|
||||
freeze Create a stand-alone executable from a Python program.
|
||||
|
||||
gdb Python code to be run inside gdb, to make it easier to
|
||||
debug Python itself (by David Malcolm).
|
||||
|
||||
i18n Tools for internationalization. pygettext.py
|
||||
parses Python source code and generates .pot files,
|
||||
and msgfmt.py generates a binary message catalog
|
||||
from a catalog in text format.
|
||||
|
||||
iobench Benchmark for the new Python I/O system. (*)
|
||||
|
||||
msi Support for packaging Python as an MSI package on Windows.
|
||||
|
||||
parser Un-parsing tool to generate code from an AST.
|
||||
|
||||
pybench Low-level benchmarking for the Python evaluation loop. (*)
|
||||
|
||||
pynche A Tkinter-based color editor.
|
||||
|
||||
scripts A number of useful single-file programs, e.g. tabnanny.py
|
||||
by Tim Peters, which checks for inconsistent mixing of
|
||||
tabs and spaces, and 2to3, which converts Python 2 code
|
||||
to Python 3 code.
|
||||
|
||||
stringbench A suite of micro-benchmarks for various operations on
|
||||
strings (both 8-bit and unicode). (*)
|
||||
|
||||
test2to3 A demonstration of how to use 2to3 transparently in setup.py.
|
||||
|
||||
unicode Tools for generating unicodedata and codecs from unicode.org
|
||||
and other mapping files (by Fredrik Lundh, Marc-Andre Lemburg
|
||||
and Martin von Loewis).
|
||||
|
||||
unittestgui A Tkinter based GUI test runner for unittest, with test
|
||||
discovery.
|
||||
|
||||
|
||||
(*) A generic benchmark suite is maintained separately at https://github.com/python/performance
|
17
third_party/python/Tools/buildbot/build.bat
vendored
Normal file
17
third_party/python/Tools/buildbot/build.bat
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
@rem Used by the buildbot "compile" step.
|
||||
|
||||
@rem Clean up
|
||||
call "%~dp0clean.bat" %*
|
||||
|
||||
@rem If you need the buildbots to start fresh (such as when upgrading to
|
||||
@rem a new version of an external library, especially Tcl/Tk):
|
||||
@rem 1) uncomment the following line:
|
||||
|
||||
@rem call "%~dp0..\..\PCbuild\get_externals.bat" --clean-only
|
||||
|
||||
@rem 2) commit and push
|
||||
@rem 3) wait for all Windows bots to start a build with that changeset
|
||||
@rem 4) re-comment, commit and push again
|
||||
|
||||
@rem Do the build
|
||||
call "%~dp0..\..\PCbuild\build.bat" -e -d -k -v %*
|
9
third_party/python/Tools/buildbot/buildmsi.bat
vendored
Normal file
9
third_party/python/Tools/buildbot/buildmsi.bat
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
@rem Used by the buildbot "buildmsi" step.
|
||||
setlocal
|
||||
|
||||
pushd
|
||||
|
||||
@rem build both snapshot MSIs
|
||||
call "%~dp0..\msi\build.bat" -x86 -x64
|
||||
|
||||
popd
|
17
third_party/python/Tools/buildbot/clean.bat
vendored
Normal file
17
third_party/python/Tools/buildbot/clean.bat
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
@echo off
|
||||
rem Used by the buildbot "clean" step.
|
||||
|
||||
setlocal
|
||||
set root=%~dp0..\..
|
||||
set pcbuild=%root%\PCbuild
|
||||
|
||||
echo Deleting build
|
||||
call "%pcbuild%\build.bat" -t Clean -k %*
|
||||
call "%pcbuild%\build.bat" -t Clean -k -d %*
|
||||
|
||||
echo Deleting .pyc/.pyo files ...
|
||||
del /s "%root%\Lib\*.pyc" "%root%\Lib\*.pyo"
|
||||
|
||||
echo Deleting test leftovers ...
|
||||
rmdir /s /q "%root%\build"
|
||||
del /s "%pcbuild%\python*.zip"
|
19
third_party/python/Tools/buildbot/test.bat
vendored
Normal file
19
third_party/python/Tools/buildbot/test.bat
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
@echo off
|
||||
rem Used by the buildbot "test" step.
|
||||
setlocal
|
||||
|
||||
set here=%~dp0
|
||||
set rt_opts=-q -d
|
||||
set regrtest_args=-j1
|
||||
|
||||
:CheckOpts
|
||||
if "%1"=="-x64" (set rt_opts=%rt_opts% %1) & shift & goto CheckOpts
|
||||
if "%1"=="-d" (set rt_opts=%rt_opts% %1) & shift & goto CheckOpts
|
||||
if "%1"=="-O" (set rt_opts=%rt_opts% %1) & shift & goto CheckOpts
|
||||
if "%1"=="-q" (set rt_opts=%rt_opts% %1) & shift & goto CheckOpts
|
||||
if "%1"=="+d" (set rt_opts=%rt_opts:-d=%) & shift & goto CheckOpts
|
||||
if "%1"=="+q" (set rt_opts=%rt_opts:-q=%) & shift & goto CheckOpts
|
||||
if NOT "%1"=="" (set regrtest_args=%regrtest_args% %1) & shift & goto CheckOpts
|
||||
|
||||
echo on
|
||||
call "%here%..\..\PCbuild\rt.bat" %rt_opts% -uall -rwW --slowest --timeout=1200 %regrtest_args%
|
611
third_party/python/Tools/ccbench/ccbench.py
vendored
Normal file
611
third_party/python/Tools/ccbench/ccbench.py
vendored
Normal file
|
@ -0,0 +1,611 @@
|
|||
# This file should be kept compatible with both Python 2.6 and Python >= 3.0.
|
||||
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
"""
|
||||
ccbench, a Python concurrency benchmark.
|
||||
"""
|
||||
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import itertools
|
||||
import threading
|
||||
import subprocess
|
||||
import socket
|
||||
from optparse import OptionParser, SUPPRESS_HELP
|
||||
import platform
|
||||
|
||||
# Compatibility
|
||||
try:
|
||||
xrange
|
||||
except NameError:
|
||||
xrange = range
|
||||
|
||||
try:
|
||||
map = itertools.imap
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
||||
THROUGHPUT_DURATION = 2.0
|
||||
|
||||
LATENCY_PING_INTERVAL = 0.1
|
||||
LATENCY_DURATION = 2.0
|
||||
|
||||
BANDWIDTH_PACKET_SIZE = 1024
|
||||
BANDWIDTH_DURATION = 2.0
|
||||
|
||||
|
||||
def task_pidigits():
|
||||
"""Pi calculation (Python)"""
|
||||
_map = map
|
||||
_count = itertools.count
|
||||
_islice = itertools.islice
|
||||
|
||||
def calc_ndigits(n):
|
||||
# From http://shootout.alioth.debian.org/
|
||||
def gen_x():
|
||||
return _map(lambda k: (k, 4*k + 2, 0, 2*k + 1), _count(1))
|
||||
|
||||
def compose(a, b):
|
||||
aq, ar, as_, at = a
|
||||
bq, br, bs, bt = b
|
||||
return (aq * bq,
|
||||
aq * br + ar * bt,
|
||||
as_ * bq + at * bs,
|
||||
as_ * br + at * bt)
|
||||
|
||||
def extract(z, j):
|
||||
q, r, s, t = z
|
||||
return (q*j + r) // (s*j + t)
|
||||
|
||||
def pi_digits():
|
||||
z = (1, 0, 0, 1)
|
||||
x = gen_x()
|
||||
while 1:
|
||||
y = extract(z, 3)
|
||||
while y != extract(z, 4):
|
||||
z = compose(z, next(x))
|
||||
y = extract(z, 3)
|
||||
z = compose((10, -10*y, 0, 1), z)
|
||||
yield y
|
||||
|
||||
return list(_islice(pi_digits(), n))
|
||||
|
||||
return calc_ndigits, (50, )
|
||||
|
||||
def task_regex():
|
||||
"""regular expression (C)"""
|
||||
# XXX this task gives horrendous latency results.
|
||||
import re
|
||||
# Taken from the `inspect` module
|
||||
pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)', re.MULTILINE)
|
||||
with open(__file__, "r") as f:
|
||||
arg = f.read(2000)
|
||||
|
||||
def findall(s):
|
||||
t = time.time()
|
||||
try:
|
||||
return pat.findall(s)
|
||||
finally:
|
||||
print(time.time() - t)
|
||||
return pat.findall, (arg, )
|
||||
|
||||
def task_sort():
|
||||
"""list sorting (C)"""
|
||||
def list_sort(l):
|
||||
l = l[::-1]
|
||||
l.sort()
|
||||
|
||||
return list_sort, (list(range(1000)), )
|
||||
|
||||
def task_compress_zlib():
|
||||
"""zlib compression (C)"""
|
||||
import zlib
|
||||
with open(__file__, "rb") as f:
|
||||
arg = f.read(5000) * 3
|
||||
|
||||
def compress(s):
|
||||
zlib.decompress(zlib.compress(s, 5))
|
||||
return compress, (arg, )
|
||||
|
||||
def task_compress_bz2():
|
||||
"""bz2 compression (C)"""
|
||||
import bz2
|
||||
with open(__file__, "rb") as f:
|
||||
arg = f.read(3000) * 2
|
||||
|
||||
def compress(s):
|
||||
bz2.compress(s)
|
||||
return compress, (arg, )
|
||||
|
||||
def task_hashing():
|
||||
"""SHA1 hashing (C)"""
|
||||
import hashlib
|
||||
with open(__file__, "rb") as f:
|
||||
arg = f.read(5000) * 30
|
||||
|
||||
def compute(s):
|
||||
hashlib.sha1(s).digest()
|
||||
return compute, (arg, )
|
||||
|
||||
|
||||
throughput_tasks = [task_pidigits, task_regex]
|
||||
for mod in 'bz2', 'hashlib':
|
||||
try:
|
||||
globals()[mod] = __import__(mod)
|
||||
except ImportError:
|
||||
globals()[mod] = None
|
||||
|
||||
# For whatever reasons, zlib gives irregular results, so we prefer bz2 or
|
||||
# hashlib if available.
|
||||
# (NOTE: hashlib releases the GIL from 2.7 and 3.1 onwards)
|
||||
if bz2 is not None:
|
||||
throughput_tasks.append(task_compress_bz2)
|
||||
elif hashlib is not None:
|
||||
throughput_tasks.append(task_hashing)
|
||||
else:
|
||||
throughput_tasks.append(task_compress_zlib)
|
||||
|
||||
latency_tasks = throughput_tasks
|
||||
bandwidth_tasks = [task_pidigits]
|
||||
|
||||
|
||||
class TimedLoop:
|
||||
def __init__(self, func, args):
|
||||
self.func = func
|
||||
self.args = args
|
||||
|
||||
def __call__(self, start_time, min_duration, end_event, do_yield=False):
|
||||
step = 20
|
||||
niters = 0
|
||||
duration = 0.0
|
||||
_time = time.time
|
||||
_sleep = time.sleep
|
||||
_func = self.func
|
||||
_args = self.args
|
||||
t1 = start_time
|
||||
while True:
|
||||
for i in range(step):
|
||||
_func(*_args)
|
||||
t2 = _time()
|
||||
# If another thread terminated, the current measurement is invalid
|
||||
# => return the previous one.
|
||||
if end_event:
|
||||
return niters, duration
|
||||
niters += step
|
||||
duration = t2 - start_time
|
||||
if duration >= min_duration:
|
||||
end_event.append(None)
|
||||
return niters, duration
|
||||
if t2 - t1 < 0.01:
|
||||
# Minimize interference of measurement on overall runtime
|
||||
step = step * 3 // 2
|
||||
elif do_yield:
|
||||
# OS scheduling of Python threads is sometimes so bad that we
|
||||
# have to force thread switching ourselves, otherwise we get
|
||||
# completely useless results.
|
||||
_sleep(0.0001)
|
||||
t1 = t2
|
||||
|
||||
|
||||
def run_throughput_test(func, args, nthreads):
|
||||
assert nthreads >= 1
|
||||
|
||||
# Warm up
|
||||
func(*args)
|
||||
|
||||
results = []
|
||||
loop = TimedLoop(func, args)
|
||||
end_event = []
|
||||
|
||||
if nthreads == 1:
|
||||
# Pure single-threaded performance, without any switching or
|
||||
# synchronization overhead.
|
||||
start_time = time.time()
|
||||
results.append(loop(start_time, THROUGHPUT_DURATION,
|
||||
end_event, do_yield=False))
|
||||
return results
|
||||
|
||||
started = False
|
||||
ready_cond = threading.Condition()
|
||||
start_cond = threading.Condition()
|
||||
ready = []
|
||||
|
||||
def run():
|
||||
with ready_cond:
|
||||
ready.append(None)
|
||||
ready_cond.notify()
|
||||
with start_cond:
|
||||
while not started:
|
||||
start_cond.wait()
|
||||
results.append(loop(start_time, THROUGHPUT_DURATION,
|
||||
end_event, do_yield=True))
|
||||
|
||||
threads = []
|
||||
for i in range(nthreads):
|
||||
threads.append(threading.Thread(target=run))
|
||||
for t in threads:
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
# We don't want measurements to include thread startup overhead,
|
||||
# so we arrange for timing to start after all threads are ready.
|
||||
with ready_cond:
|
||||
while len(ready) < nthreads:
|
||||
ready_cond.wait()
|
||||
with start_cond:
|
||||
start_time = time.time()
|
||||
started = True
|
||||
start_cond.notify(nthreads)
|
||||
for t in threads:
|
||||
t.join()
|
||||
|
||||
return results
|
||||
|
||||
def run_throughput_tests(max_threads):
|
||||
for task in throughput_tasks:
|
||||
print(task.__doc__)
|
||||
print()
|
||||
func, args = task()
|
||||
nthreads = 1
|
||||
baseline_speed = None
|
||||
while nthreads <= max_threads:
|
||||
results = run_throughput_test(func, args, nthreads)
|
||||
# Taking the max duration rather than average gives pessimistic
|
||||
# results rather than optimistic.
|
||||
speed = sum(r[0] for r in results) / max(r[1] for r in results)
|
||||
print("threads=%d: %d" % (nthreads, speed), end="")
|
||||
if baseline_speed is None:
|
||||
print(" iterations/s.")
|
||||
baseline_speed = speed
|
||||
else:
|
||||
print(" ( %d %%)" % (speed / baseline_speed * 100))
|
||||
nthreads += 1
|
||||
print()
|
||||
|
||||
|
||||
LAT_END = "END"
|
||||
|
||||
def _sendto(sock, s, addr):
|
||||
sock.sendto(s.encode('ascii'), addr)
|
||||
|
||||
def _recv(sock, n):
|
||||
return sock.recv(n).decode('ascii')
|
||||
|
||||
def latency_client(addr, nb_pings, interval):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
try:
|
||||
_time = time.time
|
||||
_sleep = time.sleep
|
||||
def _ping():
|
||||
_sendto(sock, "%r\n" % _time(), addr)
|
||||
# The first ping signals the parent process that we are ready.
|
||||
_ping()
|
||||
# We give the parent a bit of time to notice.
|
||||
_sleep(1.0)
|
||||
for i in range(nb_pings):
|
||||
_sleep(interval)
|
||||
_ping()
|
||||
_sendto(sock, LAT_END + "\n", addr)
|
||||
finally:
|
||||
sock.close()
|
||||
|
||||
def run_latency_client(**kwargs):
|
||||
cmd_line = [sys.executable, '-E', os.path.abspath(__file__)]
|
||||
cmd_line.extend(['--latclient', repr(kwargs)])
|
||||
return subprocess.Popen(cmd_line) #, stdin=subprocess.PIPE,
|
||||
#stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
|
||||
def run_latency_test(func, args, nthreads):
|
||||
# Create a listening socket to receive the pings. We use UDP which should
|
||||
# be painlessly cross-platform.
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.bind(("127.0.0.1", 0))
|
||||
addr = sock.getsockname()
|
||||
|
||||
interval = LATENCY_PING_INTERVAL
|
||||
duration = LATENCY_DURATION
|
||||
nb_pings = int(duration / interval)
|
||||
|
||||
results = []
|
||||
threads = []
|
||||
end_event = []
|
||||
start_cond = threading.Condition()
|
||||
started = False
|
||||
if nthreads > 0:
|
||||
# Warm up
|
||||
func(*args)
|
||||
|
||||
results = []
|
||||
loop = TimedLoop(func, args)
|
||||
ready = []
|
||||
ready_cond = threading.Condition()
|
||||
|
||||
def run():
|
||||
with ready_cond:
|
||||
ready.append(None)
|
||||
ready_cond.notify()
|
||||
with start_cond:
|
||||
while not started:
|
||||
start_cond.wait()
|
||||
loop(start_time, duration * 1.5, end_event, do_yield=False)
|
||||
|
||||
for i in range(nthreads):
|
||||
threads.append(threading.Thread(target=run))
|
||||
for t in threads:
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
# Wait for threads to be ready
|
||||
with ready_cond:
|
||||
while len(ready) < nthreads:
|
||||
ready_cond.wait()
|
||||
|
||||
# Run the client and wait for the first ping(s) to arrive before
|
||||
# unblocking the background threads.
|
||||
chunks = []
|
||||
process = run_latency_client(addr=sock.getsockname(),
|
||||
nb_pings=nb_pings, interval=interval)
|
||||
s = _recv(sock, 4096)
|
||||
_time = time.time
|
||||
|
||||
with start_cond:
|
||||
start_time = _time()
|
||||
started = True
|
||||
start_cond.notify(nthreads)
|
||||
|
||||
while LAT_END not in s:
|
||||
s = _recv(sock, 4096)
|
||||
t = _time()
|
||||
chunks.append((t, s))
|
||||
|
||||
# Tell the background threads to stop.
|
||||
end_event.append(None)
|
||||
for t in threads:
|
||||
t.join()
|
||||
process.wait()
|
||||
sock.close()
|
||||
|
||||
for recv_time, chunk in chunks:
|
||||
# NOTE: it is assumed that a line sent by a client wasn't received
|
||||
# in two chunks because the lines are very small.
|
||||
for line in chunk.splitlines():
|
||||
line = line.strip()
|
||||
if line and line != LAT_END:
|
||||
send_time = eval(line)
|
||||
assert isinstance(send_time, float)
|
||||
results.append((send_time, recv_time))
|
||||
|
||||
return results
|
||||
|
||||
def run_latency_tests(max_threads):
|
||||
for task in latency_tasks:
|
||||
print("Background CPU task:", task.__doc__)
|
||||
print()
|
||||
func, args = task()
|
||||
nthreads = 0
|
||||
while nthreads <= max_threads:
|
||||
results = run_latency_test(func, args, nthreads)
|
||||
n = len(results)
|
||||
# We print out milliseconds
|
||||
lats = [1000 * (t2 - t1) for (t1, t2) in results]
|
||||
#print(list(map(int, lats)))
|
||||
avg = sum(lats) / n
|
||||
dev = (sum((x - avg) ** 2 for x in lats) / n) ** 0.5
|
||||
print("CPU threads=%d: %d ms. (std dev: %d ms.)" % (nthreads, avg, dev), end="")
|
||||
print()
|
||||
#print(" [... from %d samples]" % n)
|
||||
nthreads += 1
|
||||
print()
|
||||
|
||||
|
||||
BW_END = "END"
|
||||
|
||||
def bandwidth_client(addr, packet_size, duration):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.bind(("127.0.0.1", 0))
|
||||
local_addr = sock.getsockname()
|
||||
_time = time.time
|
||||
_sleep = time.sleep
|
||||
def _send_chunk(msg):
|
||||
_sendto(sock, ("%r#%s\n" % (local_addr, msg)).rjust(packet_size), addr)
|
||||
# We give the parent some time to be ready.
|
||||
_sleep(1.0)
|
||||
try:
|
||||
start_time = _time()
|
||||
end_time = start_time + duration * 2.0
|
||||
i = 0
|
||||
while _time() < end_time:
|
||||
_send_chunk(str(i))
|
||||
s = _recv(sock, packet_size)
|
||||
assert len(s) == packet_size
|
||||
i += 1
|
||||
_send_chunk(BW_END)
|
||||
finally:
|
||||
sock.close()
|
||||
|
||||
def run_bandwidth_client(**kwargs):
|
||||
cmd_line = [sys.executable, '-E', os.path.abspath(__file__)]
|
||||
cmd_line.extend(['--bwclient', repr(kwargs)])
|
||||
return subprocess.Popen(cmd_line) #, stdin=subprocess.PIPE,
|
||||
#stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
|
||||
def run_bandwidth_test(func, args, nthreads):
|
||||
# Create a listening socket to receive the packets. We use UDP which should
|
||||
# be painlessly cross-platform.
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
|
||||
sock.bind(("127.0.0.1", 0))
|
||||
addr = sock.getsockname()
|
||||
|
||||
duration = BANDWIDTH_DURATION
|
||||
packet_size = BANDWIDTH_PACKET_SIZE
|
||||
|
||||
results = []
|
||||
threads = []
|
||||
end_event = []
|
||||
start_cond = threading.Condition()
|
||||
started = False
|
||||
if nthreads > 0:
|
||||
# Warm up
|
||||
func(*args)
|
||||
|
||||
results = []
|
||||
loop = TimedLoop(func, args)
|
||||
ready = []
|
||||
ready_cond = threading.Condition()
|
||||
|
||||
def run():
|
||||
with ready_cond:
|
||||
ready.append(None)
|
||||
ready_cond.notify()
|
||||
with start_cond:
|
||||
while not started:
|
||||
start_cond.wait()
|
||||
loop(start_time, duration * 1.5, end_event, do_yield=False)
|
||||
|
||||
for i in range(nthreads):
|
||||
threads.append(threading.Thread(target=run))
|
||||
for t in threads:
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
# Wait for threads to be ready
|
||||
with ready_cond:
|
||||
while len(ready) < nthreads:
|
||||
ready_cond.wait()
|
||||
|
||||
# Run the client and wait for the first packet to arrive before
|
||||
# unblocking the background threads.
|
||||
process = run_bandwidth_client(addr=addr,
|
||||
packet_size=packet_size,
|
||||
duration=duration)
|
||||
_time = time.time
|
||||
# This will also wait for the parent to be ready
|
||||
s = _recv(sock, packet_size)
|
||||
remote_addr = eval(s.partition('#')[0])
|
||||
|
||||
with start_cond:
|
||||
start_time = _time()
|
||||
started = True
|
||||
start_cond.notify(nthreads)
|
||||
|
||||
n = 0
|
||||
first_time = None
|
||||
while not end_event and BW_END not in s:
|
||||
_sendto(sock, s, remote_addr)
|
||||
s = _recv(sock, packet_size)
|
||||
if first_time is None:
|
||||
first_time = _time()
|
||||
n += 1
|
||||
end_time = _time()
|
||||
|
||||
end_event.append(None)
|
||||
for t in threads:
|
||||
t.join()
|
||||
process.kill()
|
||||
|
||||
return (n - 1) / (end_time - first_time)
|
||||
|
||||
def run_bandwidth_tests(max_threads):
|
||||
for task in bandwidth_tasks:
|
||||
print("Background CPU task:", task.__doc__)
|
||||
print()
|
||||
func, args = task()
|
||||
nthreads = 0
|
||||
baseline_speed = None
|
||||
while nthreads <= max_threads:
|
||||
results = run_bandwidth_test(func, args, nthreads)
|
||||
speed = results
|
||||
#speed = len(results) * 1.0 / results[-1][0]
|
||||
print("CPU threads=%d: %.1f" % (nthreads, speed), end="")
|
||||
if baseline_speed is None:
|
||||
print(" packets/s.")
|
||||
baseline_speed = speed
|
||||
else:
|
||||
print(" ( %d %%)" % (speed / baseline_speed * 100))
|
||||
nthreads += 1
|
||||
print()
|
||||
|
||||
|
||||
def main():
|
||||
usage = "usage: %prog [-h|--help] [options]"
|
||||
parser = OptionParser(usage=usage)
|
||||
parser.add_option("-t", "--throughput",
|
||||
action="store_true", dest="throughput", default=False,
|
||||
help="run throughput tests")
|
||||
parser.add_option("-l", "--latency",
|
||||
action="store_true", dest="latency", default=False,
|
||||
help="run latency tests")
|
||||
parser.add_option("-b", "--bandwidth",
|
||||
action="store_true", dest="bandwidth", default=False,
|
||||
help="run I/O bandwidth tests")
|
||||
parser.add_option("-i", "--interval",
|
||||
action="store", type="int", dest="check_interval", default=None,
|
||||
help="sys.setcheckinterval() value")
|
||||
parser.add_option("-I", "--switch-interval",
|
||||
action="store", type="float", dest="switch_interval", default=None,
|
||||
help="sys.setswitchinterval() value")
|
||||
parser.add_option("-n", "--num-threads",
|
||||
action="store", type="int", dest="nthreads", default=4,
|
||||
help="max number of threads in tests")
|
||||
|
||||
# Hidden option to run the pinging and bandwidth clients
|
||||
parser.add_option("", "--latclient",
|
||||
action="store", dest="latclient", default=None,
|
||||
help=SUPPRESS_HELP)
|
||||
parser.add_option("", "--bwclient",
|
||||
action="store", dest="bwclient", default=None,
|
||||
help=SUPPRESS_HELP)
|
||||
|
||||
options, args = parser.parse_args()
|
||||
if args:
|
||||
parser.error("unexpected arguments")
|
||||
|
||||
if options.latclient:
|
||||
kwargs = eval(options.latclient)
|
||||
latency_client(**kwargs)
|
||||
return
|
||||
|
||||
if options.bwclient:
|
||||
kwargs = eval(options.bwclient)
|
||||
bandwidth_client(**kwargs)
|
||||
return
|
||||
|
||||
if not options.throughput and not options.latency and not options.bandwidth:
|
||||
options.throughput = options.latency = options.bandwidth = True
|
||||
if options.check_interval:
|
||||
sys.setcheckinterval(options.check_interval)
|
||||
if options.switch_interval:
|
||||
sys.setswitchinterval(options.switch_interval)
|
||||
|
||||
print("== %s %s (%s) ==" % (
|
||||
platform.python_implementation(),
|
||||
platform.python_version(),
|
||||
platform.python_build()[0],
|
||||
))
|
||||
# Processor identification often has repeated spaces
|
||||
cpu = ' '.join(platform.processor().split())
|
||||
print("== %s %s on '%s' ==" % (
|
||||
platform.machine(),
|
||||
platform.system(),
|
||||
cpu,
|
||||
))
|
||||
print()
|
||||
|
||||
if options.throughput:
|
||||
print("--- Throughput ---")
|
||||
print()
|
||||
run_throughput_tests(options.nthreads)
|
||||
|
||||
if options.latency:
|
||||
print("--- Latency ---")
|
||||
print()
|
||||
run_latency_tests(options.nthreads)
|
||||
|
||||
if options.bandwidth:
|
||||
print("--- I/O bandwidth ---")
|
||||
print()
|
||||
run_bandwidth_tests(options.nthreads)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
4384
third_party/python/Tools/clinic/clinic.py
vendored
Executable file
4384
third_party/python/Tools/clinic/clinic.py
vendored
Executable file
File diff suppressed because it is too large
Load diff
791
third_party/python/Tools/clinic/clinic_test.py
vendored
Normal file
791
third_party/python/Tools/clinic/clinic_test.py
vendored
Normal file
|
@ -0,0 +1,791 @@
|
|||
# Argument Clinic
|
||||
# Copyright 2012-2013 by Larry Hastings.
|
||||
# Licensed to the PSF under a contributor agreement.
|
||||
#
|
||||
|
||||
import clinic
|
||||
from clinic import DSLParser
|
||||
import collections
|
||||
import inspect
|
||||
from test import support
|
||||
import sys
|
||||
import unittest
|
||||
from unittest import TestCase
|
||||
|
||||
|
||||
class FakeConverter:
|
||||
def __init__(self, name, args):
|
||||
self.name = name
|
||||
self.args = args
|
||||
|
||||
|
||||
class FakeConverterFactory:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def __call__(self, name, default, **kwargs):
|
||||
return FakeConverter(self.name, kwargs)
|
||||
|
||||
|
||||
class FakeConvertersDict:
|
||||
def __init__(self):
|
||||
self.used_converters = {}
|
||||
|
||||
def get(self, name, default):
|
||||
return self.used_converters.setdefault(name, FakeConverterFactory(name))
|
||||
|
||||
clinic.Clinic.presets_text = ''
|
||||
c = clinic.Clinic(language='C')
|
||||
|
||||
class FakeClinic:
|
||||
def __init__(self):
|
||||
self.converters = FakeConvertersDict()
|
||||
self.legacy_converters = FakeConvertersDict()
|
||||
self.language = clinic.CLanguage(None)
|
||||
self.filename = None
|
||||
self.block_parser = clinic.BlockParser('', self.language)
|
||||
self.modules = collections.OrderedDict()
|
||||
self.classes = collections.OrderedDict()
|
||||
clinic.clinic = self
|
||||
self.name = "FakeClinic"
|
||||
self.line_prefix = self.line_suffix = ''
|
||||
self.destinations = {}
|
||||
self.add_destination("block", "buffer")
|
||||
self.add_destination("file", "buffer")
|
||||
self.add_destination("suppress", "suppress")
|
||||
d = self.destinations.get
|
||||
self.field_destinations = collections.OrderedDict((
|
||||
('docstring_prototype', d('suppress')),
|
||||
('docstring_definition', d('block')),
|
||||
('methoddef_define', d('block')),
|
||||
('impl_prototype', d('block')),
|
||||
('parser_prototype', d('suppress')),
|
||||
('parser_definition', d('block')),
|
||||
('impl_definition', d('block')),
|
||||
))
|
||||
|
||||
def get_destination(self, name):
|
||||
d = self.destinations.get(name)
|
||||
if not d:
|
||||
sys.exit("Destination does not exist: " + repr(name))
|
||||
return d
|
||||
|
||||
def add_destination(self, name, type, *args):
|
||||
if name in self.destinations:
|
||||
sys.exit("Destination already exists: " + repr(name))
|
||||
self.destinations[name] = clinic.Destination(name, type, self, *args)
|
||||
|
||||
def is_directive(self, name):
|
||||
return name == "module"
|
||||
|
||||
def directive(self, name, args):
|
||||
self.called_directives[name] = args
|
||||
|
||||
_module_and_class = clinic.Clinic._module_and_class
|
||||
|
||||
class ClinicWholeFileTest(TestCase):
|
||||
def test_eol(self):
|
||||
# regression test:
|
||||
# clinic's block parser didn't recognize
|
||||
# the "end line" for the block if it
|
||||
# didn't end in "\n" (as in, the last)
|
||||
# byte of the file was '/'.
|
||||
# so it would spit out an end line for you.
|
||||
# and since you really already had one,
|
||||
# the last line of the block got corrupted.
|
||||
c = clinic.Clinic(clinic.CLanguage(None))
|
||||
raw = "/*[clinic]\nfoo\n[clinic]*/"
|
||||
cooked = c.parse(raw).splitlines()
|
||||
end_line = cooked[2].rstrip()
|
||||
# this test is redundant, it's just here explicitly to catch
|
||||
# the regression test so we don't forget what it looked like
|
||||
self.assertNotEqual(end_line, "[clinic]*/[clinic]*/")
|
||||
self.assertEqual(end_line, "[clinic]*/")
|
||||
|
||||
|
||||
|
||||
class ClinicGroupPermuterTest(TestCase):
|
||||
def _test(self, l, m, r, output):
|
||||
computed = clinic.permute_optional_groups(l, m, r)
|
||||
self.assertEqual(output, computed)
|
||||
|
||||
def test_range(self):
|
||||
self._test([['start']], ['stop'], [['step']],
|
||||
(
|
||||
('stop',),
|
||||
('start', 'stop',),
|
||||
('start', 'stop', 'step',),
|
||||
))
|
||||
|
||||
def test_add_window(self):
|
||||
self._test([['x', 'y']], ['ch'], [['attr']],
|
||||
(
|
||||
('ch',),
|
||||
('ch', 'attr'),
|
||||
('x', 'y', 'ch',),
|
||||
('x', 'y', 'ch', 'attr'),
|
||||
))
|
||||
|
||||
def test_ludicrous(self):
|
||||
self._test([['a1', 'a2', 'a3'], ['b1', 'b2']], ['c1'], [['d1', 'd2'], ['e1', 'e2', 'e3']],
|
||||
(
|
||||
('c1',),
|
||||
('b1', 'b2', 'c1'),
|
||||
('b1', 'b2', 'c1', 'd1', 'd2'),
|
||||
('a1', 'a2', 'a3', 'b1', 'b2', 'c1'),
|
||||
('a1', 'a2', 'a3', 'b1', 'b2', 'c1', 'd1', 'd2'),
|
||||
('a1', 'a2', 'a3', 'b1', 'b2', 'c1', 'd1', 'd2', 'e1', 'e2', 'e3'),
|
||||
))
|
||||
|
||||
def test_right_only(self):
|
||||
self._test([], [], [['a'],['b'],['c']],
|
||||
(
|
||||
(),
|
||||
('a',),
|
||||
('a', 'b'),
|
||||
('a', 'b', 'c')
|
||||
))
|
||||
|
||||
def test_have_left_options_but_required_is_empty(self):
|
||||
def fn():
|
||||
clinic.permute_optional_groups(['a'], [], [])
|
||||
self.assertRaises(AssertionError, fn)
|
||||
|
||||
|
||||
class ClinicLinearFormatTest(TestCase):
|
||||
def _test(self, input, output, **kwargs):
|
||||
computed = clinic.linear_format(input, **kwargs)
|
||||
self.assertEqual(output, computed)
|
||||
|
||||
def test_empty_strings(self):
|
||||
self._test('', '')
|
||||
|
||||
def test_solo_newline(self):
|
||||
self._test('\n', '\n')
|
||||
|
||||
def test_no_substitution(self):
|
||||
self._test("""
|
||||
abc
|
||||
""", """
|
||||
abc
|
||||
""")
|
||||
|
||||
def test_empty_substitution(self):
|
||||
self._test("""
|
||||
abc
|
||||
{name}
|
||||
def
|
||||
""", """
|
||||
abc
|
||||
def
|
||||
""", name='')
|
||||
|
||||
def test_single_line_substitution(self):
|
||||
self._test("""
|
||||
abc
|
||||
{name}
|
||||
def
|
||||
""", """
|
||||
abc
|
||||
GARGLE
|
||||
def
|
||||
""", name='GARGLE')
|
||||
|
||||
def test_multiline_substitution(self):
|
||||
self._test("""
|
||||
abc
|
||||
{name}
|
||||
def
|
||||
""", """
|
||||
abc
|
||||
bingle
|
||||
bungle
|
||||
|
||||
def
|
||||
""", name='bingle\nbungle\n')
|
||||
|
||||
class InertParser:
|
||||
def __init__(self, clinic):
|
||||
pass
|
||||
|
||||
def parse(self, block):
|
||||
pass
|
||||
|
||||
class CopyParser:
|
||||
def __init__(self, clinic):
|
||||
pass
|
||||
|
||||
def parse(self, block):
|
||||
block.output = block.input
|
||||
|
||||
|
||||
class ClinicBlockParserTest(TestCase):
|
||||
def _test(self, input, output):
|
||||
language = clinic.CLanguage(None)
|
||||
|
||||
blocks = list(clinic.BlockParser(input, language))
|
||||
writer = clinic.BlockPrinter(language)
|
||||
for block in blocks:
|
||||
writer.print_block(block)
|
||||
output = writer.f.getvalue()
|
||||
assert output == input, "output != input!\n\noutput " + repr(output) + "\n\n input " + repr(input)
|
||||
|
||||
def round_trip(self, input):
|
||||
return self._test(input, input)
|
||||
|
||||
def test_round_trip_1(self):
|
||||
self.round_trip("""
|
||||
verbatim text here
|
||||
lah dee dah
|
||||
""")
|
||||
def test_round_trip_2(self):
|
||||
self.round_trip("""
|
||||
verbatim text here
|
||||
lah dee dah
|
||||
/*[inert]
|
||||
abc
|
||||
[inert]*/
|
||||
def
|
||||
/*[inert checksum: 7b18d017f89f61cf17d47f92749ea6930a3f1deb]*/
|
||||
xyz
|
||||
""")
|
||||
|
||||
def _test_clinic(self, input, output):
|
||||
language = clinic.CLanguage(None)
|
||||
c = clinic.Clinic(language)
|
||||
c.parsers['inert'] = InertParser(c)
|
||||
c.parsers['copy'] = CopyParser(c)
|
||||
computed = c.parse(input)
|
||||
self.assertEqual(output, computed)
|
||||
|
||||
def test_clinic_1(self):
|
||||
self._test_clinic("""
|
||||
verbatim text here
|
||||
lah dee dah
|
||||
/*[copy input]
|
||||
def
|
||||
[copy start generated code]*/
|
||||
abc
|
||||
/*[copy end generated code: output=03cfd743661f0797 input=7b18d017f89f61cf]*/
|
||||
xyz
|
||||
""", """
|
||||
verbatim text here
|
||||
lah dee dah
|
||||
/*[copy input]
|
||||
def
|
||||
[copy start generated code]*/
|
||||
def
|
||||
/*[copy end generated code: output=7b18d017f89f61cf input=7b18d017f89f61cf]*/
|
||||
xyz
|
||||
""")
|
||||
|
||||
|
||||
class ClinicParserTest(TestCase):
|
||||
def test_trivial(self):
|
||||
parser = DSLParser(FakeClinic())
|
||||
block = clinic.Block("module os\nos.access")
|
||||
parser.parse(block)
|
||||
module, function = block.signatures
|
||||
self.assertEqual("access", function.name)
|
||||
self.assertEqual("os", module.name)
|
||||
|
||||
def test_ignore_line(self):
|
||||
block = self.parse("#\nmodule os\nos.access")
|
||||
module, function = block.signatures
|
||||
self.assertEqual("access", function.name)
|
||||
self.assertEqual("os", module.name)
|
||||
|
||||
def test_param(self):
|
||||
function = self.parse_function("module os\nos.access\n path: int")
|
||||
self.assertEqual("access", function.name)
|
||||
self.assertEqual(2, len(function.parameters))
|
||||
p = function.parameters['path']
|
||||
self.assertEqual('path', p.name)
|
||||
self.assertIsInstance(p.converter, clinic.int_converter)
|
||||
|
||||
def test_param_default(self):
|
||||
function = self.parse_function("module os\nos.access\n follow_symlinks: bool = True")
|
||||
p = function.parameters['follow_symlinks']
|
||||
self.assertEqual(True, p.default)
|
||||
|
||||
def test_param_with_continuations(self):
|
||||
function = self.parse_function("module os\nos.access\n follow_symlinks: \\\n bool \\\n =\\\n True")
|
||||
p = function.parameters['follow_symlinks']
|
||||
self.assertEqual(True, p.default)
|
||||
|
||||
def test_param_default_expression(self):
|
||||
function = self.parse_function("module os\nos.access\n follow_symlinks: int(c_default='MAXSIZE') = sys.maxsize")
|
||||
p = function.parameters['follow_symlinks']
|
||||
self.assertEqual(sys.maxsize, p.default)
|
||||
self.assertEqual("MAXSIZE", p.converter.c_default)
|
||||
|
||||
s = self.parse_function_should_fail("module os\nos.access\n follow_symlinks: int = sys.maxsize")
|
||||
self.assertEqual(s, "Error on line 0:\nWhen you specify a named constant ('sys.maxsize') as your default value,\nyou MUST specify a valid c_default.\n")
|
||||
|
||||
def test_param_no_docstring(self):
|
||||
function = self.parse_function("""
|
||||
module os
|
||||
os.access
|
||||
follow_symlinks: bool = True
|
||||
something_else: str = ''""")
|
||||
p = function.parameters['follow_symlinks']
|
||||
self.assertEqual(3, len(function.parameters))
|
||||
self.assertIsInstance(function.parameters['something_else'].converter, clinic.str_converter)
|
||||
|
||||
def test_param_default_parameters_out_of_order(self):
|
||||
s = self.parse_function_should_fail("""
|
||||
module os
|
||||
os.access
|
||||
follow_symlinks: bool = True
|
||||
something_else: str""")
|
||||
self.assertEqual(s, """Error on line 0:
|
||||
Can't have a parameter without a default ('something_else')
|
||||
after a parameter with a default!
|
||||
""")
|
||||
|
||||
def disabled_test_converter_arguments(self):
|
||||
function = self.parse_function("module os\nos.access\n path: path_t(allow_fd=1)")
|
||||
p = function.parameters['path']
|
||||
self.assertEqual(1, p.converter.args['allow_fd'])
|
||||
|
||||
def test_function_docstring(self):
|
||||
function = self.parse_function("""
|
||||
module os
|
||||
os.stat as os_stat_fn
|
||||
|
||||
path: str
|
||||
Path to be examined
|
||||
|
||||
Perform a stat system call on the given path.""")
|
||||
self.assertEqual("""
|
||||
stat($module, /, path)
|
||||
--
|
||||
|
||||
Perform a stat system call on the given path.
|
||||
|
||||
path
|
||||
Path to be examined
|
||||
""".strip(), function.docstring)
|
||||
|
||||
def test_explicit_parameters_in_docstring(self):
|
||||
function = self.parse_function("""
|
||||
module foo
|
||||
foo.bar
|
||||
x: int
|
||||
Documentation for x.
|
||||
y: int
|
||||
|
||||
This is the documentation for foo.
|
||||
|
||||
Okay, we're done here.
|
||||
""")
|
||||
self.assertEqual("""
|
||||
bar($module, /, x, y)
|
||||
--
|
||||
|
||||
This is the documentation for foo.
|
||||
|
||||
x
|
||||
Documentation for x.
|
||||
|
||||
Okay, we're done here.
|
||||
""".strip(), function.docstring)
|
||||
|
||||
def test_parser_regression_special_character_in_parameter_column_of_docstring_first_line(self):
|
||||
function = self.parse_function("""
|
||||
module os
|
||||
os.stat
|
||||
path: str
|
||||
This/used to break Clinic!
|
||||
""")
|
||||
self.assertEqual("stat($module, /, path)\n--\n\nThis/used to break Clinic!", function.docstring)
|
||||
|
||||
def test_c_name(self):
|
||||
function = self.parse_function("module os\nos.stat as os_stat_fn")
|
||||
self.assertEqual("os_stat_fn", function.c_basename)
|
||||
|
||||
def test_return_converter(self):
|
||||
function = self.parse_function("module os\nos.stat -> int")
|
||||
self.assertIsInstance(function.return_converter, clinic.int_return_converter)
|
||||
|
||||
def test_star(self):
|
||||
function = self.parse_function("module os\nos.access\n *\n follow_symlinks: bool = True")
|
||||
p = function.parameters['follow_symlinks']
|
||||
self.assertEqual(inspect.Parameter.KEYWORD_ONLY, p.kind)
|
||||
self.assertEqual(0, p.group)
|
||||
|
||||
def test_group(self):
|
||||
function = self.parse_function("module window\nwindow.border\n [\n ls : int\n ]\n /\n")
|
||||
p = function.parameters['ls']
|
||||
self.assertEqual(1, p.group)
|
||||
|
||||
def test_left_group(self):
|
||||
function = self.parse_function("""
|
||||
module curses
|
||||
curses.addch
|
||||
[
|
||||
y: int
|
||||
Y-coordinate.
|
||||
x: int
|
||||
X-coordinate.
|
||||
]
|
||||
ch: char
|
||||
Character to add.
|
||||
[
|
||||
attr: long
|
||||
Attributes for the character.
|
||||
]
|
||||
/
|
||||
""")
|
||||
for name, group in (
|
||||
('y', -1), ('x', -1),
|
||||
('ch', 0),
|
||||
('attr', 1),
|
||||
):
|
||||
p = function.parameters[name]
|
||||
self.assertEqual(p.group, group)
|
||||
self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
|
||||
self.assertEqual(function.docstring.strip(), """
|
||||
addch([y, x,] ch, [attr])
|
||||
|
||||
|
||||
y
|
||||
Y-coordinate.
|
||||
x
|
||||
X-coordinate.
|
||||
ch
|
||||
Character to add.
|
||||
attr
|
||||
Attributes for the character.
|
||||
""".strip())
|
||||
|
||||
def test_nested_groups(self):
|
||||
function = self.parse_function("""
|
||||
module curses
|
||||
curses.imaginary
|
||||
[
|
||||
[
|
||||
y1: int
|
||||
Y-coordinate.
|
||||
y2: int
|
||||
Y-coordinate.
|
||||
]
|
||||
x1: int
|
||||
X-coordinate.
|
||||
x2: int
|
||||
X-coordinate.
|
||||
]
|
||||
ch: char
|
||||
Character to add.
|
||||
[
|
||||
attr1: long
|
||||
Attributes for the character.
|
||||
attr2: long
|
||||
Attributes for the character.
|
||||
attr3: long
|
||||
Attributes for the character.
|
||||
[
|
||||
attr4: long
|
||||
Attributes for the character.
|
||||
attr5: long
|
||||
Attributes for the character.
|
||||
attr6: long
|
||||
Attributes for the character.
|
||||
]
|
||||
]
|
||||
/
|
||||
""")
|
||||
for name, group in (
|
||||
('y1', -2), ('y2', -2),
|
||||
('x1', -1), ('x2', -1),
|
||||
('ch', 0),
|
||||
('attr1', 1), ('attr2', 1), ('attr3', 1),
|
||||
('attr4', 2), ('attr5', 2), ('attr6', 2),
|
||||
):
|
||||
p = function.parameters[name]
|
||||
self.assertEqual(p.group, group)
|
||||
self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
|
||||
|
||||
self.assertEqual(function.docstring.strip(), """
|
||||
imaginary([[y1, y2,] x1, x2,] ch, [attr1, attr2, attr3, [attr4, attr5,
|
||||
attr6]])
|
||||
|
||||
|
||||
y1
|
||||
Y-coordinate.
|
||||
y2
|
||||
Y-coordinate.
|
||||
x1
|
||||
X-coordinate.
|
||||
x2
|
||||
X-coordinate.
|
||||
ch
|
||||
Character to add.
|
||||
attr1
|
||||
Attributes for the character.
|
||||
attr2
|
||||
Attributes for the character.
|
||||
attr3
|
||||
Attributes for the character.
|
||||
attr4
|
||||
Attributes for the character.
|
||||
attr5
|
||||
Attributes for the character.
|
||||
attr6
|
||||
Attributes for the character.
|
||||
""".strip())
|
||||
|
||||
def parse_function_should_fail(self, s):
|
||||
with support.captured_stdout() as stdout:
|
||||
with self.assertRaises(SystemExit):
|
||||
self.parse_function(s)
|
||||
return stdout.getvalue()
|
||||
|
||||
def test_disallowed_grouping__two_top_groups_on_left(self):
|
||||
s = self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.two_top_groups_on_left
|
||||
[
|
||||
group1 : int
|
||||
]
|
||||
[
|
||||
group2 : int
|
||||
]
|
||||
param: int
|
||||
""")
|
||||
self.assertEqual(s,
|
||||
('Error on line 0:\n'
|
||||
'Function two_top_groups_on_left has an unsupported group configuration. (Unexpected state 2.b)\n'))
|
||||
|
||||
def test_disallowed_grouping__two_top_groups_on_right(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.two_top_groups_on_right
|
||||
param: int
|
||||
[
|
||||
group1 : int
|
||||
]
|
||||
[
|
||||
group2 : int
|
||||
]
|
||||
""")
|
||||
|
||||
def test_disallowed_grouping__parameter_after_group_on_right(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.parameter_after_group_on_right
|
||||
param: int
|
||||
[
|
||||
[
|
||||
group1 : int
|
||||
]
|
||||
group2 : int
|
||||
]
|
||||
""")
|
||||
|
||||
def test_disallowed_grouping__group_after_parameter_on_left(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.group_after_parameter_on_left
|
||||
[
|
||||
group2 : int
|
||||
[
|
||||
group1 : int
|
||||
]
|
||||
]
|
||||
param: int
|
||||
""")
|
||||
|
||||
def test_disallowed_grouping__empty_group_on_left(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.empty_group
|
||||
[
|
||||
[
|
||||
]
|
||||
group2 : int
|
||||
]
|
||||
param: int
|
||||
""")
|
||||
|
||||
def test_disallowed_grouping__empty_group_on_right(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.empty_group
|
||||
param: int
|
||||
[
|
||||
[
|
||||
]
|
||||
group2 : int
|
||||
]
|
||||
""")
|
||||
|
||||
def test_no_parameters(self):
|
||||
function = self.parse_function("""
|
||||
module foo
|
||||
foo.bar
|
||||
|
||||
Docstring
|
||||
|
||||
""")
|
||||
self.assertEqual("bar($module, /)\n--\n\nDocstring", function.docstring)
|
||||
self.assertEqual(1, len(function.parameters)) # self!
|
||||
|
||||
def test_init_with_no_parameters(self):
|
||||
function = self.parse_function("""
|
||||
module foo
|
||||
class foo.Bar "unused" "notneeded"
|
||||
foo.Bar.__init__
|
||||
|
||||
Docstring
|
||||
|
||||
""", signatures_in_block=3, function_index=2)
|
||||
# self is not in the signature
|
||||
self.assertEqual("Bar()\n--\n\nDocstring", function.docstring)
|
||||
# but it *is* a parameter
|
||||
self.assertEqual(1, len(function.parameters))
|
||||
|
||||
def test_illegal_module_line(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.bar => int
|
||||
/
|
||||
""")
|
||||
|
||||
def test_illegal_c_basename(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.bar as 935
|
||||
/
|
||||
""")
|
||||
|
||||
def test_single_star(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.bar
|
||||
*
|
||||
*
|
||||
""")
|
||||
|
||||
def test_parameters_required_after_star_without_initial_parameters_or_docstring(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.bar
|
||||
*
|
||||
""")
|
||||
|
||||
def test_parameters_required_after_star_without_initial_parameters_with_docstring(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.bar
|
||||
*
|
||||
Docstring here.
|
||||
""")
|
||||
|
||||
def test_parameters_required_after_star_with_initial_parameters_without_docstring(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.bar
|
||||
this: int
|
||||
*
|
||||
""")
|
||||
|
||||
def test_parameters_required_after_star_with_initial_parameters_and_docstring(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.bar
|
||||
this: int
|
||||
*
|
||||
Docstring.
|
||||
""")
|
||||
|
||||
def test_single_slash(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.bar
|
||||
/
|
||||
/
|
||||
""")
|
||||
|
||||
def test_mix_star_and_slash(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.bar
|
||||
x: int
|
||||
y: int
|
||||
*
|
||||
z: int
|
||||
/
|
||||
""")
|
||||
|
||||
def test_parameters_not_permitted_after_slash_for_now(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.bar
|
||||
/
|
||||
x: int
|
||||
""")
|
||||
|
||||
def test_function_not_at_column_0(self):
|
||||
function = self.parse_function("""
|
||||
module foo
|
||||
foo.bar
|
||||
x: int
|
||||
Nested docstring here, goeth.
|
||||
*
|
||||
y: str
|
||||
Not at column 0!
|
||||
""")
|
||||
self.assertEqual("""
|
||||
bar($module, /, x, *, y)
|
||||
--
|
||||
|
||||
Not at column 0!
|
||||
|
||||
x
|
||||
Nested docstring here, goeth.
|
||||
""".strip(), function.docstring)
|
||||
|
||||
def test_directive(self):
|
||||
c = FakeClinic()
|
||||
parser = DSLParser(c)
|
||||
parser.flag = False
|
||||
parser.directives['setflag'] = lambda : setattr(parser, 'flag', True)
|
||||
block = clinic.Block("setflag")
|
||||
parser.parse(block)
|
||||
self.assertTrue(parser.flag)
|
||||
|
||||
def test_legacy_converters(self):
|
||||
block = self.parse('module os\nos.access\n path: "s"')
|
||||
module, function = block.signatures
|
||||
self.assertIsInstance((function.parameters['path']).converter, clinic.str_converter)
|
||||
|
||||
def parse(self, text):
|
||||
c = FakeClinic()
|
||||
parser = DSLParser(c)
|
||||
block = clinic.Block(text)
|
||||
parser.parse(block)
|
||||
return block
|
||||
|
||||
def parse_function(self, text, signatures_in_block=2, function_index=1):
|
||||
block = self.parse(text)
|
||||
s = block.signatures
|
||||
self.assertEqual(len(s), signatures_in_block)
|
||||
assert isinstance(s[0], clinic.Module)
|
||||
assert isinstance(s[function_index], clinic.Function)
|
||||
return s[function_index]
|
||||
|
||||
def test_scaffolding(self):
|
||||
# test repr on special values
|
||||
self.assertEqual(repr(clinic.unspecified), '<Unspecified>')
|
||||
self.assertEqual(repr(clinic.NULL), '<Null>')
|
||||
|
||||
# test that fail fails
|
||||
with support.captured_stdout() as stdout:
|
||||
with self.assertRaises(SystemExit):
|
||||
clinic.fail('The igloos are melting!', filename='clown.txt', line_number=69)
|
||||
self.assertEqual(stdout.getvalue(), 'Error in file "clown.txt" on line 69:\nThe igloos are melting!\n')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
191
third_party/python/Tools/clinic/cpp.py
vendored
Normal file
191
third_party/python/Tools/clinic/cpp.py
vendored
Normal file
|
@ -0,0 +1,191 @@
|
|||
import re
|
||||
import sys
|
||||
|
||||
def negate(condition):
|
||||
"""
|
||||
Returns a CPP conditional that is the opposite of the conditional passed in.
|
||||
"""
|
||||
if condition.startswith('!'):
|
||||
return condition[1:]
|
||||
return "!" + condition
|
||||
|
||||
class Monitor:
|
||||
"""
|
||||
A simple C preprocessor that scans C source and computes, line by line,
|
||||
what the current C preprocessor #if state is.
|
||||
|
||||
Doesn't handle everything--for example, if you have /* inside a C string,
|
||||
without a matching */ (also inside a C string), or with a */ inside a C
|
||||
string but on another line and with preprocessor macros in between...
|
||||
the parser will get lost.
|
||||
|
||||
Anyway this implementation seems to work well enough for the CPython sources.
|
||||
"""
|
||||
|
||||
is_a_simple_defined = re.compile(r'^defined\s*\(\s*[A-Za-z0-9_]+\s*\)$').match
|
||||
|
||||
def __init__(self, filename=None, *, verbose=False):
|
||||
self.stack = []
|
||||
self.in_comment = False
|
||||
self.continuation = None
|
||||
self.line_number = 0
|
||||
self.filename = filename
|
||||
self.verbose = verbose
|
||||
|
||||
def __repr__(self):
|
||||
return ''.join((
|
||||
'<Monitor ',
|
||||
str(id(self)),
|
||||
" line=", str(self.line_number),
|
||||
" condition=", repr(self.condition()),
|
||||
">"))
|
||||
|
||||
def status(self):
|
||||
return str(self.line_number).rjust(4) + ": " + self.condition()
|
||||
|
||||
def condition(self):
|
||||
"""
|
||||
Returns the current preprocessor state, as a single #if condition.
|
||||
"""
|
||||
return " && ".join(condition for token, condition in self.stack)
|
||||
|
||||
def fail(self, *a):
|
||||
if self.filename:
|
||||
filename = " " + self.filename
|
||||
else:
|
||||
filename = ''
|
||||
print("Error at" + filename, "line", self.line_number, ":")
|
||||
print(" ", ' '.join(str(x) for x in a))
|
||||
sys.exit(-1)
|
||||
|
||||
def close(self):
|
||||
if self.stack:
|
||||
self.fail("Ended file while still in a preprocessor conditional block!")
|
||||
|
||||
def write(self, s):
|
||||
for line in s.split("\n"):
|
||||
self.writeline(line)
|
||||
|
||||
def writeline(self, line):
|
||||
self.line_number += 1
|
||||
line = line.strip()
|
||||
|
||||
def pop_stack():
|
||||
if not self.stack:
|
||||
self.fail("#" + token + " without matching #if / #ifdef / #ifndef!")
|
||||
return self.stack.pop()
|
||||
|
||||
if self.continuation:
|
||||
line = self.continuation + line
|
||||
self.continuation = None
|
||||
|
||||
if not line:
|
||||
return
|
||||
|
||||
if line.endswith('\\'):
|
||||
self.continuation = line[:-1].rstrip() + " "
|
||||
return
|
||||
|
||||
# we have to ignore preprocessor commands inside comments
|
||||
#
|
||||
# we also have to handle this:
|
||||
# /* start
|
||||
# ...
|
||||
# */ /* <-- tricky!
|
||||
# ...
|
||||
# */
|
||||
# and this:
|
||||
# /* start
|
||||
# ...
|
||||
# */ /* also tricky! */
|
||||
if self.in_comment:
|
||||
if '*/' in line:
|
||||
# snip out the comment and continue
|
||||
#
|
||||
# GCC allows
|
||||
# /* comment
|
||||
# */ #include <stdio.h>
|
||||
# maybe other compilers too?
|
||||
_, _, line = line.partition('*/')
|
||||
self.in_comment = False
|
||||
|
||||
while True:
|
||||
if '/*' in line:
|
||||
if self.in_comment:
|
||||
self.fail("Nested block comment!")
|
||||
|
||||
before, _, remainder = line.partition('/*')
|
||||
comment, comment_ends, after = remainder.partition('*/')
|
||||
if comment_ends:
|
||||
# snip out the comment
|
||||
line = before.rstrip() + ' ' + after.lstrip()
|
||||
continue
|
||||
# comment continues to eol
|
||||
self.in_comment = True
|
||||
line = before.rstrip()
|
||||
break
|
||||
|
||||
# we actually have some // comments
|
||||
# (but block comments take precedence)
|
||||
before, line_comment, comment = line.partition('//')
|
||||
if line_comment:
|
||||
line = before.rstrip()
|
||||
|
||||
if not line.startswith('#'):
|
||||
return
|
||||
|
||||
line = line[1:].lstrip()
|
||||
assert line
|
||||
|
||||
fields = line.split()
|
||||
token = fields[0].lower()
|
||||
condition = ' '.join(fields[1:]).strip()
|
||||
|
||||
if_tokens = {'if', 'ifdef', 'ifndef'}
|
||||
all_tokens = if_tokens | {'elif', 'else', 'endif'}
|
||||
|
||||
if token not in all_tokens:
|
||||
return
|
||||
|
||||
# cheat a little here, to reuse the implementation of if
|
||||
if token == 'elif':
|
||||
pop_stack()
|
||||
token = 'if'
|
||||
|
||||
if token in if_tokens:
|
||||
if not condition:
|
||||
self.fail("Invalid format for #" + token + " line: no argument!")
|
||||
if token == 'if':
|
||||
if not self.is_a_simple_defined(condition):
|
||||
condition = "(" + condition + ")"
|
||||
else:
|
||||
fields = condition.split()
|
||||
if len(fields) != 1:
|
||||
self.fail("Invalid format for #" + token + " line: should be exactly one argument!")
|
||||
symbol = fields[0]
|
||||
condition = 'defined(' + symbol + ')'
|
||||
if token == 'ifndef':
|
||||
condition = '!' + condition
|
||||
|
||||
self.stack.append(("if", condition))
|
||||
if self.verbose:
|
||||
print(self.status())
|
||||
return
|
||||
|
||||
previous_token, previous_condition = pop_stack()
|
||||
|
||||
if token == 'else':
|
||||
self.stack.append(('else', negate(previous_condition)))
|
||||
elif token == 'endif':
|
||||
pass
|
||||
if self.verbose:
|
||||
print(self.status())
|
||||
|
||||
if __name__ == '__main__':
|
||||
for filename in sys.argv[1:]:
|
||||
with open(filename, "rt") as f:
|
||||
cpp = Monitor(filename, verbose=True)
|
||||
print()
|
||||
print(filename)
|
||||
for line_number, line in enumerate(f.read().split('\n'), 1):
|
||||
cpp.writeline(line)
|
16
third_party/python/Tools/demo/README
vendored
Normal file
16
third_party/python/Tools/demo/README
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
This directory contains a collection of demonstration scripts for
|
||||
various aspects of Python programming.
|
||||
|
||||
beer.py Well-known programming example: Bottles of beer.
|
||||
eiffel.py Python advanced magic: A metaclass for Eiffel post/preconditions.
|
||||
hanoi.py Well-known programming example: Towers of Hanoi.
|
||||
life.py Curses programming: Simple game-of-life.
|
||||
markov.py Algorithms: Markov chain simulation.
|
||||
mcast.py Network programming: Send and receive UDP multicast packets.
|
||||
queens.py Well-known programming example: N-Queens problem.
|
||||
redemo.py Regular Expressions: GUI script to test regexes.
|
||||
rpython.py Network programming: Small client for remote code execution.
|
||||
rpythond.py Network programming: Small server for remote code execution.
|
||||
sortvisu.py GUI programming: Visualization of different sort algorithms.
|
||||
ss1.py GUI/Application programming: A simple spreadsheet application.
|
||||
vector.py Python basics: A vector class with demonstrating special methods.
|
25
third_party/python/Tools/demo/beer.py
vendored
Executable file
25
third_party/python/Tools/demo/beer.py
vendored
Executable file
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
A Python version of the classic "bottles of beer on the wall" programming
|
||||
example.
|
||||
|
||||
By Guido van Rossum, demystified after a version by Fredrik Lundh.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
n = 100
|
||||
if sys.argv[1:]:
|
||||
n = int(sys.argv[1])
|
||||
|
||||
def bottle(n):
|
||||
if n == 0: return "no more bottles of beer"
|
||||
if n == 1: return "one bottle of beer"
|
||||
return str(n) + " bottles of beer"
|
||||
|
||||
for i in range(n, 0, -1):
|
||||
print(bottle(i), "on the wall,")
|
||||
print(bottle(i) + ".")
|
||||
print("Take one down, pass it around,")
|
||||
print(bottle(i-1), "on the wall.")
|
146
third_party/python/Tools/demo/eiffel.py
vendored
Executable file
146
third_party/python/Tools/demo/eiffel.py
vendored
Executable file
|
@ -0,0 +1,146 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Support Eiffel-style preconditions and postconditions for functions.
|
||||
|
||||
An example for Python metaclasses.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from types import FunctionType as function
|
||||
|
||||
class EiffelBaseMetaClass(type):
|
||||
|
||||
def __new__(meta, name, bases, dict):
|
||||
meta.convert_methods(dict)
|
||||
return super(EiffelBaseMetaClass, meta).__new__(
|
||||
meta, name, bases, dict)
|
||||
|
||||
@classmethod
|
||||
def convert_methods(cls, dict):
|
||||
"""Replace functions in dict with EiffelMethod wrappers.
|
||||
|
||||
The dict is modified in place.
|
||||
|
||||
If a method ends in _pre or _post, it is removed from the dict
|
||||
regardless of whether there is a corresponding method.
|
||||
"""
|
||||
# find methods with pre or post conditions
|
||||
methods = []
|
||||
for k, v in dict.items():
|
||||
if k.endswith('_pre') or k.endswith('_post'):
|
||||
assert isinstance(v, function)
|
||||
elif isinstance(v, function):
|
||||
methods.append(k)
|
||||
for m in methods:
|
||||
pre = dict.get("%s_pre" % m)
|
||||
post = dict.get("%s_post" % m)
|
||||
if pre or post:
|
||||
dict[m] = cls.make_eiffel_method(dict[m], pre, post)
|
||||
|
||||
|
||||
class EiffelMetaClass1(EiffelBaseMetaClass):
|
||||
# an implementation of the "eiffel" meta class that uses nested functions
|
||||
|
||||
@staticmethod
|
||||
def make_eiffel_method(func, pre, post):
|
||||
def method(self, *args, **kwargs):
|
||||
if pre:
|
||||
pre(self, *args, **kwargs)
|
||||
rv = func(self, *args, **kwargs)
|
||||
if post:
|
||||
post(self, rv, *args, **kwargs)
|
||||
return rv
|
||||
|
||||
if func.__doc__:
|
||||
method.__doc__ = func.__doc__
|
||||
|
||||
return method
|
||||
|
||||
|
||||
class EiffelMethodWrapper:
|
||||
|
||||
def __init__(self, inst, descr):
|
||||
self._inst = inst
|
||||
self._descr = descr
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self._descr.callmethod(self._inst, args, kwargs)
|
||||
|
||||
|
||||
class EiffelDescriptor:
|
||||
|
||||
def __init__(self, func, pre, post):
|
||||
self._func = func
|
||||
self._pre = pre
|
||||
self._post = post
|
||||
|
||||
self.__name__ = func.__name__
|
||||
self.__doc__ = func.__doc__
|
||||
|
||||
def __get__(self, obj, cls):
|
||||
return EiffelMethodWrapper(obj, self)
|
||||
|
||||
def callmethod(self, inst, args, kwargs):
|
||||
if self._pre:
|
||||
self._pre(inst, *args, **kwargs)
|
||||
x = self._func(inst, *args, **kwargs)
|
||||
if self._post:
|
||||
self._post(inst, x, *args, **kwargs)
|
||||
return x
|
||||
|
||||
|
||||
class EiffelMetaClass2(EiffelBaseMetaClass):
|
||||
# an implementation of the "eiffel" meta class that uses descriptors
|
||||
|
||||
make_eiffel_method = EiffelDescriptor
|
||||
|
||||
|
||||
class Tests(unittest.TestCase):
|
||||
|
||||
def testEiffelMetaClass1(self):
|
||||
self._test(EiffelMetaClass1)
|
||||
|
||||
def testEiffelMetaClass2(self):
|
||||
self._test(EiffelMetaClass2)
|
||||
|
||||
def _test(self, metaclass):
|
||||
class Eiffel(metaclass=metaclass):
|
||||
pass
|
||||
|
||||
class Test(Eiffel):
|
||||
def m(self, arg):
|
||||
"""Make it a little larger"""
|
||||
return arg + 1
|
||||
|
||||
def m2(self, arg):
|
||||
"""Make it a little larger"""
|
||||
return arg + 1
|
||||
|
||||
def m2_pre(self, arg):
|
||||
assert arg > 0
|
||||
|
||||
def m2_post(self, result, arg):
|
||||
assert result > arg
|
||||
|
||||
class Sub(Test):
|
||||
def m2(self, arg):
|
||||
return arg**2
|
||||
|
||||
def m2_post(self, Result, arg):
|
||||
super(Sub, self).m2_post(Result, arg)
|
||||
assert Result < 100
|
||||
|
||||
t = Test()
|
||||
self.assertEqual(t.m(1), 2)
|
||||
self.assertEqual(t.m2(1), 2)
|
||||
self.assertRaises(AssertionError, t.m2, 0)
|
||||
|
||||
s = Sub()
|
||||
self.assertRaises(AssertionError, s.m2, 1)
|
||||
self.assertRaises(AssertionError, s.m2, 10)
|
||||
self.assertEqual(s.m2(5), 25)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
154
third_party/python/Tools/demo/hanoi.py
vendored
Executable file
154
third_party/python/Tools/demo/hanoi.py
vendored
Executable file
|
@ -0,0 +1,154 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Animated Towers of Hanoi using Tk with optional bitmap file in background.
|
||||
|
||||
Usage: hanoi.py [n [bitmapfile]]
|
||||
|
||||
n is the number of pieces to animate; default is 4, maximum 15.
|
||||
|
||||
The bitmap file can be any X11 bitmap file (look in /usr/include/X11/bitmaps for
|
||||
samples); it is displayed as the background of the animation. Default is no
|
||||
bitmap.
|
||||
"""
|
||||
|
||||
from tkinter import Tk, Canvas
|
||||
|
||||
# Basic Towers-of-Hanoi algorithm: move n pieces from a to b, using c
|
||||
# as temporary. For each move, call report()
|
||||
def hanoi(n, a, b, c, report):
|
||||
if n <= 0: return
|
||||
hanoi(n-1, a, c, b, report)
|
||||
report(n, a, b)
|
||||
hanoi(n-1, c, b, a, report)
|
||||
|
||||
|
||||
# The graphical interface
|
||||
class Tkhanoi:
|
||||
|
||||
# Create our objects
|
||||
def __init__(self, n, bitmap = None):
|
||||
self.n = n
|
||||
self.tk = tk = Tk()
|
||||
self.canvas = c = Canvas(tk)
|
||||
c.pack()
|
||||
width, height = tk.getint(c['width']), tk.getint(c['height'])
|
||||
|
||||
# Add background bitmap
|
||||
if bitmap:
|
||||
self.bitmap = c.create_bitmap(width//2, height//2,
|
||||
bitmap=bitmap,
|
||||
foreground='blue')
|
||||
|
||||
# Generate pegs
|
||||
pegwidth = 10
|
||||
pegheight = height//2
|
||||
pegdist = width//3
|
||||
x1, y1 = (pegdist-pegwidth)//2, height*1//3
|
||||
x2, y2 = x1+pegwidth, y1+pegheight
|
||||
self.pegs = []
|
||||
p = c.create_rectangle(x1, y1, x2, y2, fill='black')
|
||||
self.pegs.append(p)
|
||||
x1, x2 = x1+pegdist, x2+pegdist
|
||||
p = c.create_rectangle(x1, y1, x2, y2, fill='black')
|
||||
self.pegs.append(p)
|
||||
x1, x2 = x1+pegdist, x2+pegdist
|
||||
p = c.create_rectangle(x1, y1, x2, y2, fill='black')
|
||||
self.pegs.append(p)
|
||||
self.tk.update()
|
||||
|
||||
# Generate pieces
|
||||
pieceheight = pegheight//16
|
||||
maxpiecewidth = pegdist*2//3
|
||||
minpiecewidth = 2*pegwidth
|
||||
self.pegstate = [[], [], []]
|
||||
self.pieces = {}
|
||||
x1, y1 = (pegdist-maxpiecewidth)//2, y2-pieceheight-2
|
||||
x2, y2 = x1+maxpiecewidth, y1+pieceheight
|
||||
dx = (maxpiecewidth-minpiecewidth) // (2*max(1, n-1))
|
||||
for i in range(n, 0, -1):
|
||||
p = c.create_rectangle(x1, y1, x2, y2, fill='red')
|
||||
self.pieces[i] = p
|
||||
self.pegstate[0].append(i)
|
||||
x1, x2 = x1 + dx, x2-dx
|
||||
y1, y2 = y1 - pieceheight-2, y2-pieceheight-2
|
||||
self.tk.update()
|
||||
self.tk.after(25)
|
||||
|
||||
# Run -- never returns
|
||||
def run(self):
|
||||
while 1:
|
||||
hanoi(self.n, 0, 1, 2, self.report)
|
||||
hanoi(self.n, 1, 2, 0, self.report)
|
||||
hanoi(self.n, 2, 0, 1, self.report)
|
||||
hanoi(self.n, 0, 2, 1, self.report)
|
||||
hanoi(self.n, 2, 1, 0, self.report)
|
||||
hanoi(self.n, 1, 0, 2, self.report)
|
||||
|
||||
# Reporting callback for the actual hanoi function
|
||||
def report(self, i, a, b):
|
||||
if self.pegstate[a][-1] != i: raise RuntimeError # Assertion
|
||||
del self.pegstate[a][-1]
|
||||
p = self.pieces[i]
|
||||
c = self.canvas
|
||||
|
||||
# Lift the piece above peg a
|
||||
ax1, ay1, ax2, ay2 = c.bbox(self.pegs[a])
|
||||
while 1:
|
||||
x1, y1, x2, y2 = c.bbox(p)
|
||||
if y2 < ay1: break
|
||||
c.move(p, 0, -1)
|
||||
self.tk.update()
|
||||
|
||||
# Move it towards peg b
|
||||
bx1, by1, bx2, by2 = c.bbox(self.pegs[b])
|
||||
newcenter = (bx1+bx2)//2
|
||||
while 1:
|
||||
x1, y1, x2, y2 = c.bbox(p)
|
||||
center = (x1+x2)//2
|
||||
if center == newcenter: break
|
||||
if center > newcenter: c.move(p, -1, 0)
|
||||
else: c.move(p, 1, 0)
|
||||
self.tk.update()
|
||||
|
||||
# Move it down on top of the previous piece
|
||||
pieceheight = y2-y1
|
||||
newbottom = by2 - pieceheight*len(self.pegstate[b]) - 2
|
||||
while 1:
|
||||
x1, y1, x2, y2 = c.bbox(p)
|
||||
if y2 >= newbottom: break
|
||||
c.move(p, 0, 1)
|
||||
self.tk.update()
|
||||
|
||||
# Update peg state
|
||||
self.pegstate[b].append(i)
|
||||
|
||||
|
||||
def main():
|
||||
import sys
|
||||
|
||||
# First argument is number of pegs, default 4
|
||||
if sys.argv[1:]:
|
||||
n = int(sys.argv[1])
|
||||
else:
|
||||
n = 4
|
||||
|
||||
# Second argument is bitmap file, default none
|
||||
if sys.argv[2:]:
|
||||
bitmap = sys.argv[2]
|
||||
# Reverse meaning of leading '@' compared to Tk
|
||||
if bitmap[0] == '@': bitmap = bitmap[1:]
|
||||
else: bitmap = '@' + bitmap
|
||||
else:
|
||||
bitmap = None
|
||||
|
||||
# Create the graphical objects...
|
||||
h = Tkhanoi(n, bitmap)
|
||||
|
||||
# ...and run!
|
||||
h.run()
|
||||
|
||||
|
||||
# Call main when run as script
|
||||
if __name__ == '__main__':
|
||||
main()
|
262
third_party/python/Tools/demo/life.py
vendored
Executable file
262
third_party/python/Tools/demo/life.py
vendored
Executable file
|
@ -0,0 +1,262 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
A curses-based version of Conway's Game of Life.
|
||||
|
||||
An empty board will be displayed, and the following commands are available:
|
||||
E : Erase the board
|
||||
R : Fill the board randomly
|
||||
S : Step for a single generation
|
||||
C : Update continuously until a key is struck
|
||||
Q : Quit
|
||||
Cursor keys : Move the cursor around the board
|
||||
Space or Enter : Toggle the contents of the cursor's position
|
||||
|
||||
Contributed by Andrew Kuchling, Mouse support and color by Dafydd Crosby.
|
||||
"""
|
||||
|
||||
import curses
|
||||
import random
|
||||
|
||||
|
||||
class LifeBoard:
|
||||
"""Encapsulates a Life board
|
||||
|
||||
Attributes:
|
||||
X,Y : horizontal and vertical size of the board
|
||||
state : dictionary mapping (x,y) to 0 or 1
|
||||
|
||||
Methods:
|
||||
display(update_board) -- If update_board is true, compute the
|
||||
next generation. Then display the state
|
||||
of the board and refresh the screen.
|
||||
erase() -- clear the entire board
|
||||
make_random() -- fill the board randomly
|
||||
set(y,x) -- set the given cell to Live; doesn't refresh the screen
|
||||
toggle(y,x) -- change the given cell from live to dead, or vice
|
||||
versa, and refresh the screen display
|
||||
|
||||
"""
|
||||
def __init__(self, scr, char=ord('*')):
|
||||
"""Create a new LifeBoard instance.
|
||||
|
||||
scr -- curses screen object to use for display
|
||||
char -- character used to render live cells (default: '*')
|
||||
"""
|
||||
self.state = {}
|
||||
self.scr = scr
|
||||
Y, X = self.scr.getmaxyx()
|
||||
self.X, self.Y = X - 2, Y - 2 - 1
|
||||
self.char = char
|
||||
self.scr.clear()
|
||||
|
||||
# Draw a border around the board
|
||||
border_line = '+' + (self.X * '-') + '+'
|
||||
self.scr.addstr(0, 0, border_line)
|
||||
self.scr.addstr(self.Y + 1, 0, border_line)
|
||||
for y in range(0, self.Y):
|
||||
self.scr.addstr(1 + y, 0, '|')
|
||||
self.scr.addstr(1 + y, self.X + 1, '|')
|
||||
self.scr.refresh()
|
||||
|
||||
def set(self, y, x):
|
||||
"""Set a cell to the live state"""
|
||||
if x < 0 or self.X <= x or y < 0 or self.Y <= y:
|
||||
raise ValueError("Coordinates out of range %i,%i" % (y, x))
|
||||
self.state[x, y] = 1
|
||||
|
||||
def toggle(self, y, x):
|
||||
"""Toggle a cell's state between live and dead"""
|
||||
if x < 0 or self.X <= x or y < 0 or self.Y <= y:
|
||||
raise ValueError("Coordinates out of range %i,%i" % (y, x))
|
||||
if (x, y) in self.state:
|
||||
del self.state[x, y]
|
||||
self.scr.addch(y + 1, x + 1, ' ')
|
||||
else:
|
||||
self.state[x, y] = 1
|
||||
if curses.has_colors():
|
||||
# Let's pick a random color!
|
||||
self.scr.attrset(curses.color_pair(random.randrange(1, 7)))
|
||||
self.scr.addch(y + 1, x + 1, self.char)
|
||||
self.scr.attrset(0)
|
||||
self.scr.refresh()
|
||||
|
||||
def erase(self):
|
||||
"""Clear the entire board and update the board display"""
|
||||
self.state = {}
|
||||
self.display(update_board=False)
|
||||
|
||||
def display(self, update_board=True):
|
||||
"""Display the whole board, optionally computing one generation"""
|
||||
M, N = self.X, self.Y
|
||||
if not update_board:
|
||||
for i in range(0, M):
|
||||
for j in range(0, N):
|
||||
if (i, j) in self.state:
|
||||
self.scr.addch(j + 1, i + 1, self.char)
|
||||
else:
|
||||
self.scr.addch(j + 1, i + 1, ' ')
|
||||
self.scr.refresh()
|
||||
return
|
||||
|
||||
d = {}
|
||||
self.boring = 1
|
||||
for i in range(0, M):
|
||||
L = range(max(0, i - 1), min(M, i + 2))
|
||||
for j in range(0, N):
|
||||
s = 0
|
||||
live = (i, j) in self.state
|
||||
for k in range(max(0, j - 1), min(N, j + 2)):
|
||||
for l in L:
|
||||
if (l, k) in self.state:
|
||||
s += 1
|
||||
s -= live
|
||||
if s == 3:
|
||||
# Birth
|
||||
d[i, j] = 1
|
||||
if curses.has_colors():
|
||||
# Let's pick a random color!
|
||||
self.scr.attrset(curses.color_pair(
|
||||
random.randrange(1, 7)))
|
||||
self.scr.addch(j + 1, i + 1, self.char)
|
||||
self.scr.attrset(0)
|
||||
if not live:
|
||||
self.boring = 0
|
||||
elif s == 2 and live:
|
||||
# Survival
|
||||
d[i, j] = 1
|
||||
elif live:
|
||||
# Death
|
||||
self.scr.addch(j + 1, i + 1, ' ')
|
||||
self.boring = 0
|
||||
self.state = d
|
||||
self.scr.refresh()
|
||||
|
||||
def make_random(self):
|
||||
"Fill the board with a random pattern"
|
||||
self.state = {}
|
||||
for i in range(0, self.X):
|
||||
for j in range(0, self.Y):
|
||||
if random.random() > 0.5:
|
||||
self.set(j, i)
|
||||
|
||||
|
||||
def erase_menu(stdscr, menu_y):
|
||||
"Clear the space where the menu resides"
|
||||
stdscr.move(menu_y, 0)
|
||||
stdscr.clrtoeol()
|
||||
stdscr.move(menu_y + 1, 0)
|
||||
stdscr.clrtoeol()
|
||||
|
||||
|
||||
def display_menu(stdscr, menu_y):
|
||||
"Display the menu of possible keystroke commands"
|
||||
erase_menu(stdscr, menu_y)
|
||||
|
||||
# If color, then light the menu up :-)
|
||||
if curses.has_colors():
|
||||
stdscr.attrset(curses.color_pair(1))
|
||||
stdscr.addstr(menu_y, 4,
|
||||
'Use the cursor keys to move, and space or Enter to toggle a cell.')
|
||||
stdscr.addstr(menu_y + 1, 4,
|
||||
'E)rase the board, R)andom fill, S)tep once or C)ontinuously, Q)uit')
|
||||
stdscr.attrset(0)
|
||||
|
||||
|
||||
def keyloop(stdscr):
|
||||
# Clear the screen and display the menu of keys
|
||||
stdscr.clear()
|
||||
stdscr_y, stdscr_x = stdscr.getmaxyx()
|
||||
menu_y = (stdscr_y - 3) - 1
|
||||
display_menu(stdscr, menu_y)
|
||||
|
||||
# If color, then initialize the color pairs
|
||||
if curses.has_colors():
|
||||
curses.init_pair(1, curses.COLOR_BLUE, 0)
|
||||
curses.init_pair(2, curses.COLOR_CYAN, 0)
|
||||
curses.init_pair(3, curses.COLOR_GREEN, 0)
|
||||
curses.init_pair(4, curses.COLOR_MAGENTA, 0)
|
||||
curses.init_pair(5, curses.COLOR_RED, 0)
|
||||
curses.init_pair(6, curses.COLOR_YELLOW, 0)
|
||||
curses.init_pair(7, curses.COLOR_WHITE, 0)
|
||||
|
||||
# Set up the mask to listen for mouse events
|
||||
curses.mousemask(curses.BUTTON1_CLICKED)
|
||||
|
||||
# Allocate a subwindow for the Life board and create the board object
|
||||
subwin = stdscr.subwin(stdscr_y - 3, stdscr_x, 0, 0)
|
||||
board = LifeBoard(subwin, char=ord('*'))
|
||||
board.display(update_board=False)
|
||||
|
||||
# xpos, ypos are the cursor's position
|
||||
xpos, ypos = board.X // 2, board.Y // 2
|
||||
|
||||
# Main loop:
|
||||
while True:
|
||||
stdscr.move(1 + ypos, 1 + xpos) # Move the cursor
|
||||
c = stdscr.getch() # Get a keystroke
|
||||
if 0 < c < 256:
|
||||
c = chr(c)
|
||||
if c in ' \n':
|
||||
board.toggle(ypos, xpos)
|
||||
elif c in 'Cc':
|
||||
erase_menu(stdscr, menu_y)
|
||||
stdscr.addstr(menu_y, 6, ' Hit any key to stop continuously '
|
||||
'updating the screen.')
|
||||
stdscr.refresh()
|
||||
# Activate nodelay mode; getch() will return -1
|
||||
# if no keystroke is available, instead of waiting.
|
||||
stdscr.nodelay(1)
|
||||
while True:
|
||||
c = stdscr.getch()
|
||||
if c != -1:
|
||||
break
|
||||
stdscr.addstr(0, 0, '/')
|
||||
stdscr.refresh()
|
||||
board.display()
|
||||
stdscr.addstr(0, 0, '+')
|
||||
stdscr.refresh()
|
||||
|
||||
stdscr.nodelay(0) # Disable nodelay mode
|
||||
display_menu(stdscr, menu_y)
|
||||
|
||||
elif c in 'Ee':
|
||||
board.erase()
|
||||
elif c in 'Qq':
|
||||
break
|
||||
elif c in 'Rr':
|
||||
board.make_random()
|
||||
board.display(update_board=False)
|
||||
elif c in 'Ss':
|
||||
board.display()
|
||||
else:
|
||||
# Ignore incorrect keys
|
||||
pass
|
||||
elif c == curses.KEY_UP and ypos > 0:
|
||||
ypos -= 1
|
||||
elif c == curses.KEY_DOWN and ypos + 1 < board.Y:
|
||||
ypos += 1
|
||||
elif c == curses.KEY_LEFT and xpos > 0:
|
||||
xpos -= 1
|
||||
elif c == curses.KEY_RIGHT and xpos + 1 < board.X:
|
||||
xpos += 1
|
||||
elif c == curses.KEY_MOUSE:
|
||||
mouse_id, mouse_x, mouse_y, mouse_z, button_state = curses.getmouse()
|
||||
if (mouse_x > 0 and mouse_x < board.X + 1 and
|
||||
mouse_y > 0 and mouse_y < board.Y + 1):
|
||||
xpos = mouse_x - 1
|
||||
ypos = mouse_y - 1
|
||||
board.toggle(ypos, xpos)
|
||||
else:
|
||||
# They've clicked outside the board
|
||||
curses.flash()
|
||||
else:
|
||||
# Ignore incorrect keys
|
||||
pass
|
||||
|
||||
|
||||
def main(stdscr):
|
||||
keyloop(stdscr) # Enter the main loop
|
||||
|
||||
if __name__ == '__main__':
|
||||
curses.wrapper(main)
|
125
third_party/python/Tools/demo/markov.py
vendored
Executable file
125
third_party/python/Tools/demo/markov.py
vendored
Executable file
|
@ -0,0 +1,125 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Markov chain simulation of words or characters.
|
||||
"""
|
||||
|
||||
class Markov:
|
||||
def __init__(self, histsize, choice):
|
||||
self.histsize = histsize
|
||||
self.choice = choice
|
||||
self.trans = {}
|
||||
|
||||
def add(self, state, next):
|
||||
self.trans.setdefault(state, []).append(next)
|
||||
|
||||
def put(self, seq):
|
||||
n = self.histsize
|
||||
add = self.add
|
||||
add(None, seq[:0])
|
||||
for i in range(len(seq)):
|
||||
add(seq[max(0, i-n):i], seq[i:i+1])
|
||||
add(seq[len(seq)-n:], None)
|
||||
|
||||
def get(self):
|
||||
choice = self.choice
|
||||
trans = self.trans
|
||||
n = self.histsize
|
||||
seq = choice(trans[None])
|
||||
while True:
|
||||
subseq = seq[max(0, len(seq)-n):]
|
||||
options = trans[subseq]
|
||||
next = choice(options)
|
||||
if not next:
|
||||
break
|
||||
seq += next
|
||||
return seq
|
||||
|
||||
|
||||
def test():
|
||||
import sys, random, getopt
|
||||
args = sys.argv[1:]
|
||||
try:
|
||||
opts, args = getopt.getopt(args, '0123456789cdwq')
|
||||
except getopt.error:
|
||||
print('Usage: %s [-#] [-cddqw] [file] ...' % sys.argv[0])
|
||||
print('Options:')
|
||||
print('-#: 1-digit history size (default 2)')
|
||||
print('-c: characters (default)')
|
||||
print('-w: words')
|
||||
print('-d: more debugging output')
|
||||
print('-q: no debugging output')
|
||||
print('Input files (default stdin) are split in paragraphs')
|
||||
print('separated blank lines and each paragraph is split')
|
||||
print('in words by whitespace, then reconcatenated with')
|
||||
print('exactly one space separating words.')
|
||||
print('Output consists of paragraphs separated by blank')
|
||||
print('lines, where lines are no longer than 72 characters.')
|
||||
sys.exit(2)
|
||||
histsize = 2
|
||||
do_words = False
|
||||
debug = 1
|
||||
for o, a in opts:
|
||||
if '-0' <= o <= '-9': histsize = int(o[1:])
|
||||
if o == '-c': do_words = False
|
||||
if o == '-d': debug += 1
|
||||
if o == '-q': debug = 0
|
||||
if o == '-w': do_words = True
|
||||
if not args:
|
||||
args = ['-']
|
||||
|
||||
m = Markov(histsize, random.choice)
|
||||
try:
|
||||
for filename in args:
|
||||
if filename == '-':
|
||||
f = sys.stdin
|
||||
if f.isatty():
|
||||
print('Sorry, need stdin from file')
|
||||
continue
|
||||
else:
|
||||
f = open(filename, 'r')
|
||||
if debug: print('processing', filename, '...')
|
||||
text = f.read()
|
||||
f.close()
|
||||
paralist = text.split('\n\n')
|
||||
for para in paralist:
|
||||
if debug > 1: print('feeding ...')
|
||||
words = para.split()
|
||||
if words:
|
||||
if do_words:
|
||||
data = tuple(words)
|
||||
else:
|
||||
data = ' '.join(words)
|
||||
m.put(data)
|
||||
except KeyboardInterrupt:
|
||||
print('Interrupted -- continue with data read so far')
|
||||
if not m.trans:
|
||||
print('No valid input files')
|
||||
return
|
||||
if debug: print('done.')
|
||||
|
||||
if debug > 1:
|
||||
for key in m.trans.keys():
|
||||
if key is None or len(key) < histsize:
|
||||
print(repr(key), m.trans[key])
|
||||
if histsize == 0: print(repr(''), m.trans[''])
|
||||
print()
|
||||
while True:
|
||||
data = m.get()
|
||||
if do_words:
|
||||
words = data
|
||||
else:
|
||||
words = data.split()
|
||||
n = 0
|
||||
limit = 72
|
||||
for w in words:
|
||||
if n + len(w) > limit:
|
||||
print()
|
||||
n = 0
|
||||
print(w, end=' ')
|
||||
n += len(w) + 1
|
||||
print()
|
||||
print()
|
||||
|
||||
if __name__ == "__main__":
|
||||
test()
|
82
third_party/python/Tools/demo/mcast.py
vendored
Executable file
82
third_party/python/Tools/demo/mcast.py
vendored
Executable file
|
@ -0,0 +1,82 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Send/receive UDP multicast packets.
|
||||
Requires that your OS kernel supports IP multicast.
|
||||
|
||||
Usage:
|
||||
mcast -s (sender, IPv4)
|
||||
mcast -s -6 (sender, IPv6)
|
||||
mcast (receivers, IPv4)
|
||||
mcast -6 (receivers, IPv6)
|
||||
"""
|
||||
|
||||
MYPORT = 8123
|
||||
MYGROUP_4 = '225.0.0.250'
|
||||
MYGROUP_6 = 'ff15:7079:7468:6f6e:6465:6d6f:6d63:6173'
|
||||
MYTTL = 1 # Increase to reach other networks
|
||||
|
||||
import time
|
||||
import struct
|
||||
import socket
|
||||
import sys
|
||||
|
||||
def main():
|
||||
group = MYGROUP_6 if "-6" in sys.argv[1:] else MYGROUP_4
|
||||
|
||||
if "-s" in sys.argv[1:]:
|
||||
sender(group)
|
||||
else:
|
||||
receiver(group)
|
||||
|
||||
|
||||
def sender(group):
|
||||
addrinfo = socket.getaddrinfo(group, None)[0]
|
||||
|
||||
s = socket.socket(addrinfo[0], socket.SOCK_DGRAM)
|
||||
|
||||
# Set Time-to-live (optional)
|
||||
ttl_bin = struct.pack('@i', MYTTL)
|
||||
if addrinfo[0] == socket.AF_INET: # IPv4
|
||||
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl_bin)
|
||||
else:
|
||||
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, ttl_bin)
|
||||
|
||||
while True:
|
||||
data = repr(time.time()).encode('utf-8') + b'\0'
|
||||
s.sendto(data, (addrinfo[4][0], MYPORT))
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
def receiver(group):
|
||||
# Look up multicast group address in name server and find out IP version
|
||||
addrinfo = socket.getaddrinfo(group, None)[0]
|
||||
|
||||
# Create a socket
|
||||
s = socket.socket(addrinfo[0], socket.SOCK_DGRAM)
|
||||
|
||||
# Allow multiple copies of this program on one machine
|
||||
# (not strictly needed)
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
|
||||
# Bind it to the port
|
||||
s.bind(('', MYPORT))
|
||||
|
||||
group_bin = socket.inet_pton(addrinfo[0], addrinfo[4][0])
|
||||
# Join group
|
||||
if addrinfo[0] == socket.AF_INET: # IPv4
|
||||
mreq = group_bin + struct.pack('=I', socket.INADDR_ANY)
|
||||
s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
|
||||
else:
|
||||
mreq = group_bin + struct.pack('@I', 0)
|
||||
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
|
||||
|
||||
# Loop, printing any data we receive
|
||||
while True:
|
||||
data, sender = s.recvfrom(1500)
|
||||
while data[-1:] == '\0': data = data[:-1] # Strip trailing \0's
|
||||
print(str(sender) + ' ' + repr(data))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
85
third_party/python/Tools/demo/queens.py
vendored
Executable file
85
third_party/python/Tools/demo/queens.py
vendored
Executable file
|
@ -0,0 +1,85 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
N queens problem.
|
||||
|
||||
The (well-known) problem is due to Niklaus Wirth.
|
||||
|
||||
This solution is inspired by Dijkstra (Structured Programming). It is
|
||||
a classic recursive backtracking approach.
|
||||
"""
|
||||
|
||||
N = 8 # Default; command line overrides
|
||||
|
||||
class Queens:
|
||||
|
||||
def __init__(self, n=N):
|
||||
self.n = n
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
n = self.n
|
||||
self.y = [None] * n # Where is the queen in column x
|
||||
self.row = [0] * n # Is row[y] safe?
|
||||
self.up = [0] * (2*n-1) # Is upward diagonal[x-y] safe?
|
||||
self.down = [0] * (2*n-1) # Is downward diagonal[x+y] safe?
|
||||
self.nfound = 0 # Instrumentation
|
||||
|
||||
def solve(self, x=0): # Recursive solver
|
||||
for y in range(self.n):
|
||||
if self.safe(x, y):
|
||||
self.place(x, y)
|
||||
if x+1 == self.n:
|
||||
self.display()
|
||||
else:
|
||||
self.solve(x+1)
|
||||
self.remove(x, y)
|
||||
|
||||
def safe(self, x, y):
|
||||
return not self.row[y] and not self.up[x-y] and not self.down[x+y]
|
||||
|
||||
def place(self, x, y):
|
||||
self.y[x] = y
|
||||
self.row[y] = 1
|
||||
self.up[x-y] = 1
|
||||
self.down[x+y] = 1
|
||||
|
||||
def remove(self, x, y):
|
||||
self.y[x] = None
|
||||
self.row[y] = 0
|
||||
self.up[x-y] = 0
|
||||
self.down[x+y] = 0
|
||||
|
||||
silent = 0 # If true, count solutions only
|
||||
|
||||
def display(self):
|
||||
self.nfound = self.nfound + 1
|
||||
if self.silent:
|
||||
return
|
||||
print('+-' + '--'*self.n + '+')
|
||||
for y in range(self.n-1, -1, -1):
|
||||
print('|', end=' ')
|
||||
for x in range(self.n):
|
||||
if self.y[x] == y:
|
||||
print("Q", end=' ')
|
||||
else:
|
||||
print(".", end=' ')
|
||||
print('|')
|
||||
print('+-' + '--'*self.n + '+')
|
||||
|
||||
def main():
|
||||
import sys
|
||||
silent = 0
|
||||
n = N
|
||||
if sys.argv[1:2] == ['-n']:
|
||||
silent = 1
|
||||
del sys.argv[1]
|
||||
if sys.argv[1:]:
|
||||
n = int(sys.argv[1])
|
||||
q = Queens(n)
|
||||
q.silent = silent
|
||||
q.solve()
|
||||
print("Found", q.nfound, "solutions.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
172
third_party/python/Tools/demo/redemo.py
vendored
Executable file
172
third_party/python/Tools/demo/redemo.py
vendored
Executable file
|
@ -0,0 +1,172 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""Basic regular expression demonstration facility (Perl style syntax)."""
|
||||
|
||||
from tkinter import *
|
||||
import re
|
||||
|
||||
class ReDemo:
|
||||
|
||||
def __init__(self, master):
|
||||
self.master = master
|
||||
|
||||
self.promptdisplay = Label(self.master, anchor=W,
|
||||
text="Enter a Perl-style regular expression:")
|
||||
self.promptdisplay.pack(side=TOP, fill=X)
|
||||
|
||||
self.regexdisplay = Entry(self.master)
|
||||
self.regexdisplay.pack(fill=X)
|
||||
self.regexdisplay.focus_set()
|
||||
|
||||
self.addoptions()
|
||||
|
||||
self.statusdisplay = Label(self.master, text="", anchor=W)
|
||||
self.statusdisplay.pack(side=TOP, fill=X)
|
||||
|
||||
self.labeldisplay = Label(self.master, anchor=W,
|
||||
text="Enter a string to search:")
|
||||
self.labeldisplay.pack(fill=X)
|
||||
self.labeldisplay.pack(fill=X)
|
||||
|
||||
self.showframe = Frame(master)
|
||||
self.showframe.pack(fill=X, anchor=W)
|
||||
|
||||
self.showvar = StringVar(master)
|
||||
self.showvar.set("first")
|
||||
|
||||
self.showfirstradio = Radiobutton(self.showframe,
|
||||
text="Highlight first match",
|
||||
variable=self.showvar,
|
||||
value="first",
|
||||
command=self.recompile)
|
||||
self.showfirstradio.pack(side=LEFT)
|
||||
|
||||
self.showallradio = Radiobutton(self.showframe,
|
||||
text="Highlight all matches",
|
||||
variable=self.showvar,
|
||||
value="all",
|
||||
command=self.recompile)
|
||||
self.showallradio.pack(side=LEFT)
|
||||
|
||||
self.stringdisplay = Text(self.master, width=60, height=4)
|
||||
self.stringdisplay.pack(fill=BOTH, expand=1)
|
||||
self.stringdisplay.tag_configure("hit", background="yellow")
|
||||
|
||||
self.grouplabel = Label(self.master, text="Groups:", anchor=W)
|
||||
self.grouplabel.pack(fill=X)
|
||||
|
||||
self.grouplist = Listbox(self.master)
|
||||
self.grouplist.pack(expand=1, fill=BOTH)
|
||||
|
||||
self.regexdisplay.bind('<Key>', self.recompile)
|
||||
self.stringdisplay.bind('<Key>', self.reevaluate)
|
||||
|
||||
self.compiled = None
|
||||
self.recompile()
|
||||
|
||||
btags = self.regexdisplay.bindtags()
|
||||
self.regexdisplay.bindtags(btags[1:] + btags[:1])
|
||||
|
||||
btags = self.stringdisplay.bindtags()
|
||||
self.stringdisplay.bindtags(btags[1:] + btags[:1])
|
||||
|
||||
def addoptions(self):
|
||||
self.frames = []
|
||||
self.boxes = []
|
||||
self.vars = []
|
||||
for name in ('IGNORECASE',
|
||||
'MULTILINE',
|
||||
'DOTALL',
|
||||
'VERBOSE'):
|
||||
if len(self.boxes) % 3 == 0:
|
||||
frame = Frame(self.master)
|
||||
frame.pack(fill=X)
|
||||
self.frames.append(frame)
|
||||
val = getattr(re, name).value
|
||||
var = IntVar()
|
||||
box = Checkbutton(frame,
|
||||
variable=var, text=name,
|
||||
offvalue=0, onvalue=val,
|
||||
command=self.recompile)
|
||||
box.pack(side=LEFT)
|
||||
self.boxes.append(box)
|
||||
self.vars.append(var)
|
||||
|
||||
def getflags(self):
|
||||
flags = 0
|
||||
for var in self.vars:
|
||||
flags = flags | var.get()
|
||||
flags = flags
|
||||
return flags
|
||||
|
||||
def recompile(self, event=None):
|
||||
try:
|
||||
self.compiled = re.compile(self.regexdisplay.get(),
|
||||
self.getflags())
|
||||
bg = self.promptdisplay['background']
|
||||
self.statusdisplay.config(text="", background=bg)
|
||||
except re.error as msg:
|
||||
self.compiled = None
|
||||
self.statusdisplay.config(
|
||||
text="re.error: %s" % str(msg),
|
||||
background="red")
|
||||
self.reevaluate()
|
||||
|
||||
def reevaluate(self, event=None):
|
||||
try:
|
||||
self.stringdisplay.tag_remove("hit", "1.0", END)
|
||||
except TclError:
|
||||
pass
|
||||
try:
|
||||
self.stringdisplay.tag_remove("hit0", "1.0", END)
|
||||
except TclError:
|
||||
pass
|
||||
self.grouplist.delete(0, END)
|
||||
if not self.compiled:
|
||||
return
|
||||
self.stringdisplay.tag_configure("hit", background="yellow")
|
||||
self.stringdisplay.tag_configure("hit0", background="orange")
|
||||
text = self.stringdisplay.get("1.0", END)
|
||||
last = 0
|
||||
nmatches = 0
|
||||
while last <= len(text):
|
||||
m = self.compiled.search(text, last)
|
||||
if m is None:
|
||||
break
|
||||
first, last = m.span()
|
||||
if last == first:
|
||||
last = first+1
|
||||
tag = "hit0"
|
||||
else:
|
||||
tag = "hit"
|
||||
pfirst = "1.0 + %d chars" % first
|
||||
plast = "1.0 + %d chars" % last
|
||||
self.stringdisplay.tag_add(tag, pfirst, plast)
|
||||
if nmatches == 0:
|
||||
self.stringdisplay.yview_pickplace(pfirst)
|
||||
groups = list(m.groups())
|
||||
groups.insert(0, m.group())
|
||||
for i in range(len(groups)):
|
||||
g = "%2d: %r" % (i, groups[i])
|
||||
self.grouplist.insert(END, g)
|
||||
nmatches = nmatches + 1
|
||||
if self.showvar.get() == "first":
|
||||
break
|
||||
|
||||
if nmatches == 0:
|
||||
self.statusdisplay.config(text="(no match)",
|
||||
background="yellow")
|
||||
else:
|
||||
self.statusdisplay.config(text="")
|
||||
|
||||
|
||||
# Main function, run when invoked as a stand-alone Python program.
|
||||
|
||||
def main():
|
||||
root = Tk()
|
||||
demo = ReDemo(root)
|
||||
root.protocol('WM_DELETE_WINDOW', root.quit)
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
38
third_party/python/Tools/demo/rpython.py
vendored
Executable file
38
third_party/python/Tools/demo/rpython.py
vendored
Executable file
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Remote python client.
|
||||
Execute Python commands remotely and send output back.
|
||||
"""
|
||||
|
||||
import sys
|
||||
from socket import socket, AF_INET, SOCK_STREAM, SHUT_WR
|
||||
|
||||
PORT = 4127
|
||||
BUFSIZE = 1024
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 3:
|
||||
print("usage: rpython host command")
|
||||
sys.exit(2)
|
||||
host = sys.argv[1]
|
||||
port = PORT
|
||||
i = host.find(':')
|
||||
if i >= 0:
|
||||
port = int(port[i+1:])
|
||||
host = host[:i]
|
||||
command = ' '.join(sys.argv[2:])
|
||||
s = socket(AF_INET, SOCK_STREAM)
|
||||
s.connect((host, port))
|
||||
s.send(command.encode())
|
||||
s.shutdown(SHUT_WR)
|
||||
reply = b''
|
||||
while True:
|
||||
data = s.recv(BUFSIZE)
|
||||
if not data:
|
||||
break
|
||||
reply += data
|
||||
print(reply.decode(), end=' ')
|
||||
s.close()
|
||||
|
||||
main()
|
58
third_party/python/Tools/demo/rpythond.py
vendored
Executable file
58
third_party/python/Tools/demo/rpythond.py
vendored
Executable file
|
@ -0,0 +1,58 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Remote python server.
|
||||
Execute Python commands remotely and send output back.
|
||||
|
||||
WARNING: This version has a gaping security hole -- it accepts requests
|
||||
from any host on the Internet!
|
||||
"""
|
||||
|
||||
import sys
|
||||
from socket import socket, AF_INET, SOCK_STREAM
|
||||
import io
|
||||
import traceback
|
||||
|
||||
PORT = 4127
|
||||
BUFSIZE = 1024
|
||||
|
||||
def main():
|
||||
if len(sys.argv) > 1:
|
||||
port = int(sys.argv[1])
|
||||
else:
|
||||
port = PORT
|
||||
s = socket(AF_INET, SOCK_STREAM)
|
||||
s.bind(('', port))
|
||||
s.listen(1)
|
||||
while True:
|
||||
conn, (remotehost, remoteport) = s.accept()
|
||||
print('connection from', remotehost, remoteport)
|
||||
request = b''
|
||||
while 1:
|
||||
data = conn.recv(BUFSIZE)
|
||||
if not data:
|
||||
break
|
||||
request += data
|
||||
reply = execute(request.decode())
|
||||
conn.send(reply.encode())
|
||||
conn.close()
|
||||
|
||||
def execute(request):
|
||||
stdout = sys.stdout
|
||||
stderr = sys.stderr
|
||||
sys.stdout = sys.stderr = fakefile = io.StringIO()
|
||||
try:
|
||||
try:
|
||||
exec(request, {}, {})
|
||||
except:
|
||||
print()
|
||||
traceback.print_exc(100)
|
||||
finally:
|
||||
sys.stderr = stderr
|
||||
sys.stdout = stdout
|
||||
return fakefile.getvalue()
|
||||
|
||||
try:
|
||||
main()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
635
third_party/python/Tools/demo/sortvisu.py
vendored
Executable file
635
third_party/python/Tools/demo/sortvisu.py
vendored
Executable file
|
@ -0,0 +1,635 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Sorting algorithms visualizer using Tkinter.
|
||||
|
||||
This module is comprised of three ``components'':
|
||||
|
||||
- an array visualizer with methods that implement basic sorting
|
||||
operations (compare, swap) as well as methods for ``annotating'' the
|
||||
sorting algorithm (e.g. to show the pivot element);
|
||||
|
||||
- a number of sorting algorithms (currently quicksort, insertion sort,
|
||||
selection sort and bubble sort, as well as a randomization function),
|
||||
all using the array visualizer for its basic operations and with calls
|
||||
to its annotation methods;
|
||||
|
||||
- and a ``driver'' class which can be used as a Grail applet or as a
|
||||
stand-alone application.
|
||||
"""
|
||||
|
||||
from tkinter import *
|
||||
import random
|
||||
|
||||
XGRID = 10
|
||||
YGRID = 10
|
||||
WIDTH = 6
|
||||
|
||||
|
||||
class Array:
|
||||
|
||||
class Cancelled(BaseException):
|
||||
pass
|
||||
|
||||
def __init__(self, master, data=None):
|
||||
self.master = master
|
||||
self.frame = Frame(self.master)
|
||||
self.frame.pack(fill=X)
|
||||
self.label = Label(self.frame)
|
||||
self.label.pack()
|
||||
self.canvas = Canvas(self.frame)
|
||||
self.canvas.pack()
|
||||
self.report = Label(self.frame)
|
||||
self.report.pack()
|
||||
self.left = self.canvas.create_line(0, 0, 0, 0)
|
||||
self.right = self.canvas.create_line(0, 0, 0, 0)
|
||||
self.pivot = self.canvas.create_line(0, 0, 0, 0)
|
||||
self.items = []
|
||||
self.size = self.maxvalue = 0
|
||||
if data:
|
||||
self.setdata(data)
|
||||
|
||||
def setdata(self, data):
|
||||
olditems = self.items
|
||||
self.items = []
|
||||
for item in olditems:
|
||||
item.delete()
|
||||
self.size = len(data)
|
||||
self.maxvalue = max(data)
|
||||
self.canvas.config(width=(self.size+1)*XGRID,
|
||||
height=(self.maxvalue+1)*YGRID)
|
||||
for i in range(self.size):
|
||||
self.items.append(ArrayItem(self, i, data[i]))
|
||||
self.reset("Sort demo, size %d" % self.size)
|
||||
|
||||
speed = "normal"
|
||||
|
||||
def setspeed(self, speed):
|
||||
self.speed = speed
|
||||
|
||||
def destroy(self):
|
||||
self.frame.destroy()
|
||||
|
||||
in_mainloop = 0
|
||||
stop_mainloop = 0
|
||||
|
||||
def cancel(self):
|
||||
self.stop_mainloop = 1
|
||||
if self.in_mainloop:
|
||||
self.master.quit()
|
||||
|
||||
def step(self):
|
||||
if self.in_mainloop:
|
||||
self.master.quit()
|
||||
|
||||
def wait(self, msecs):
|
||||
if self.speed == "fastest":
|
||||
msecs = 0
|
||||
elif self.speed == "fast":
|
||||
msecs = msecs//10
|
||||
elif self.speed == "single-step":
|
||||
msecs = 1000000000
|
||||
if not self.stop_mainloop:
|
||||
self.master.update()
|
||||
id = self.master.after(msecs, self.master.quit)
|
||||
self.in_mainloop = 1
|
||||
self.master.mainloop()
|
||||
self.master.after_cancel(id)
|
||||
self.in_mainloop = 0
|
||||
if self.stop_mainloop:
|
||||
self.stop_mainloop = 0
|
||||
self.message("Cancelled")
|
||||
raise Array.Cancelled
|
||||
|
||||
def getsize(self):
|
||||
return self.size
|
||||
|
||||
def show_partition(self, first, last):
|
||||
for i in range(self.size):
|
||||
item = self.items[i]
|
||||
if first <= i < last:
|
||||
self.canvas.itemconfig(item, fill='red')
|
||||
else:
|
||||
self.canvas.itemconfig(item, fill='orange')
|
||||
self.hide_left_right_pivot()
|
||||
|
||||
def hide_partition(self):
|
||||
for i in range(self.size):
|
||||
item = self.items[i]
|
||||
self.canvas.itemconfig(item, fill='red')
|
||||
self.hide_left_right_pivot()
|
||||
|
||||
def show_left(self, left):
|
||||
if not 0 <= left < self.size:
|
||||
self.hide_left()
|
||||
return
|
||||
x1, y1, x2, y2 = self.items[left].position()
|
||||
## top, bot = HIRO
|
||||
self.canvas.coords(self.left, (x1 - 2, 0, x1 - 2, 9999))
|
||||
self.master.update()
|
||||
|
||||
def show_right(self, right):
|
||||
if not 0 <= right < self.size:
|
||||
self.hide_right()
|
||||
return
|
||||
x1, y1, x2, y2 = self.items[right].position()
|
||||
self.canvas.coords(self.right, (x2 + 2, 0, x2 + 2, 9999))
|
||||
self.master.update()
|
||||
|
||||
def hide_left_right_pivot(self):
|
||||
self.hide_left()
|
||||
self.hide_right()
|
||||
self.hide_pivot()
|
||||
|
||||
def hide_left(self):
|
||||
self.canvas.coords(self.left, (0, 0, 0, 0))
|
||||
|
||||
def hide_right(self):
|
||||
self.canvas.coords(self.right, (0, 0, 0, 0))
|
||||
|
||||
def show_pivot(self, pivot):
|
||||
x1, y1, x2, y2 = self.items[pivot].position()
|
||||
self.canvas.coords(self.pivot, (0, y1 - 2, 9999, y1 - 2))
|
||||
|
||||
def hide_pivot(self):
|
||||
self.canvas.coords(self.pivot, (0, 0, 0, 0))
|
||||
|
||||
def swap(self, i, j):
|
||||
if i == j: return
|
||||
self.countswap()
|
||||
item = self.items[i]
|
||||
other = self.items[j]
|
||||
self.items[i], self.items[j] = other, item
|
||||
item.swapwith(other)
|
||||
|
||||
def compare(self, i, j):
|
||||
self.countcompare()
|
||||
item = self.items[i]
|
||||
other = self.items[j]
|
||||
return item.compareto(other)
|
||||
|
||||
def reset(self, msg):
|
||||
self.ncompares = 0
|
||||
self.nswaps = 0
|
||||
self.message(msg)
|
||||
self.updatereport()
|
||||
self.hide_partition()
|
||||
|
||||
def message(self, msg):
|
||||
self.label.config(text=msg)
|
||||
|
||||
def countswap(self):
|
||||
self.nswaps = self.nswaps + 1
|
||||
self.updatereport()
|
||||
|
||||
def countcompare(self):
|
||||
self.ncompares = self.ncompares + 1
|
||||
self.updatereport()
|
||||
|
||||
def updatereport(self):
|
||||
text = "%d cmps, %d swaps" % (self.ncompares, self.nswaps)
|
||||
self.report.config(text=text)
|
||||
|
||||
|
||||
class ArrayItem:
|
||||
|
||||
def __init__(self, array, index, value):
|
||||
self.array = array
|
||||
self.index = index
|
||||
self.value = value
|
||||
self.canvas = array.canvas
|
||||
x1, y1, x2, y2 = self.position()
|
||||
self.item_id = array.canvas.create_rectangle(x1, y1, x2, y2,
|
||||
fill='red', outline='black', width=1)
|
||||
self.canvas.tag_bind(self.item_id, '<Button-1>', self.mouse_down)
|
||||
self.canvas.tag_bind(self.item_id, '<Button1-Motion>', self.mouse_move)
|
||||
self.canvas.tag_bind(self.item_id, '<ButtonRelease-1>', self.mouse_up)
|
||||
|
||||
def delete(self):
|
||||
item_id = self.item_id
|
||||
self.array = None
|
||||
self.item_id = None
|
||||
self.canvas.delete(item_id)
|
||||
|
||||
def mouse_down(self, event):
|
||||
self.lastx = event.x
|
||||
self.lasty = event.y
|
||||
self.origx = event.x
|
||||
self.origy = event.y
|
||||
self.canvas.tag_raise(self.item_id)
|
||||
|
||||
def mouse_move(self, event):
|
||||
self.canvas.move(self.item_id,
|
||||
event.x - self.lastx, event.y - self.lasty)
|
||||
self.lastx = event.x
|
||||
self.lasty = event.y
|
||||
|
||||
def mouse_up(self, event):
|
||||
i = self.nearestindex(event.x)
|
||||
if i >= self.array.getsize():
|
||||
i = self.array.getsize() - 1
|
||||
if i < 0:
|
||||
i = 0
|
||||
other = self.array.items[i]
|
||||
here = self.index
|
||||
self.array.items[here], self.array.items[i] = other, self
|
||||
self.index = i
|
||||
x1, y1, x2, y2 = self.position()
|
||||
self.canvas.coords(self.item_id, (x1, y1, x2, y2))
|
||||
other.setindex(here)
|
||||
|
||||
def setindex(self, index):
|
||||
nsteps = steps(self.index, index)
|
||||
if not nsteps: return
|
||||
if self.array.speed == "fastest":
|
||||
nsteps = 0
|
||||
oldpts = self.position()
|
||||
self.index = index
|
||||
newpts = self.position()
|
||||
trajectory = interpolate(oldpts, newpts, nsteps)
|
||||
self.canvas.tag_raise(self.item_id)
|
||||
for pts in trajectory:
|
||||
self.canvas.coords(self.item_id, pts)
|
||||
self.array.wait(50)
|
||||
|
||||
def swapwith(self, other):
|
||||
nsteps = steps(self.index, other.index)
|
||||
if not nsteps: return
|
||||
if self.array.speed == "fastest":
|
||||
nsteps = 0
|
||||
myoldpts = self.position()
|
||||
otheroldpts = other.position()
|
||||
self.index, other.index = other.index, self.index
|
||||
mynewpts = self.position()
|
||||
othernewpts = other.position()
|
||||
myfill = self.canvas.itemcget(self.item_id, 'fill')
|
||||
otherfill = self.canvas.itemcget(other.item_id, 'fill')
|
||||
self.canvas.itemconfig(self.item_id, fill='green')
|
||||
self.canvas.itemconfig(other.item_id, fill='yellow')
|
||||
self.array.master.update()
|
||||
if self.array.speed == "single-step":
|
||||
self.canvas.coords(self.item_id, mynewpts)
|
||||
self.canvas.coords(other.item_id, othernewpts)
|
||||
self.array.master.update()
|
||||
self.canvas.itemconfig(self.item_id, fill=myfill)
|
||||
self.canvas.itemconfig(other.item_id, fill=otherfill)
|
||||
self.array.wait(0)
|
||||
return
|
||||
mytrajectory = interpolate(myoldpts, mynewpts, nsteps)
|
||||
othertrajectory = interpolate(otheroldpts, othernewpts, nsteps)
|
||||
if self.value > other.value:
|
||||
self.canvas.tag_raise(self.item_id)
|
||||
self.canvas.tag_raise(other.item_id)
|
||||
else:
|
||||
self.canvas.tag_raise(other.item_id)
|
||||
self.canvas.tag_raise(self.item_id)
|
||||
try:
|
||||
for i in range(len(mytrajectory)):
|
||||
mypts = mytrajectory[i]
|
||||
otherpts = othertrajectory[i]
|
||||
self.canvas.coords(self.item_id, mypts)
|
||||
self.canvas.coords(other.item_id, otherpts)
|
||||
self.array.wait(50)
|
||||
finally:
|
||||
mypts = mytrajectory[-1]
|
||||
otherpts = othertrajectory[-1]
|
||||
self.canvas.coords(self.item_id, mypts)
|
||||
self.canvas.coords(other.item_id, otherpts)
|
||||
self.canvas.itemconfig(self.item_id, fill=myfill)
|
||||
self.canvas.itemconfig(other.item_id, fill=otherfill)
|
||||
|
||||
def compareto(self, other):
|
||||
myfill = self.canvas.itemcget(self.item_id, 'fill')
|
||||
otherfill = self.canvas.itemcget(other.item_id, 'fill')
|
||||
if self.value < other.value:
|
||||
myflash = 'white'
|
||||
otherflash = 'black'
|
||||
outcome = -1
|
||||
elif self.value > other.value:
|
||||
myflash = 'black'
|
||||
otherflash = 'white'
|
||||
outcome = 1
|
||||
else:
|
||||
myflash = otherflash = 'grey'
|
||||
outcome = 0
|
||||
try:
|
||||
self.canvas.itemconfig(self.item_id, fill=myflash)
|
||||
self.canvas.itemconfig(other.item_id, fill=otherflash)
|
||||
self.array.wait(500)
|
||||
finally:
|
||||
self.canvas.itemconfig(self.item_id, fill=myfill)
|
||||
self.canvas.itemconfig(other.item_id, fill=otherfill)
|
||||
return outcome
|
||||
|
||||
def position(self):
|
||||
x1 = (self.index+1)*XGRID - WIDTH//2
|
||||
x2 = x1+WIDTH
|
||||
y2 = (self.array.maxvalue+1)*YGRID
|
||||
y1 = y2 - (self.value)*YGRID
|
||||
return x1, y1, x2, y2
|
||||
|
||||
def nearestindex(self, x):
|
||||
return int(round(float(x)/XGRID)) - 1
|
||||
|
||||
|
||||
# Subroutines that don't need an object
|
||||
|
||||
def steps(here, there):
|
||||
nsteps = abs(here - there)
|
||||
if nsteps <= 3:
|
||||
nsteps = nsteps * 3
|
||||
elif nsteps <= 5:
|
||||
nsteps = nsteps * 2
|
||||
elif nsteps > 10:
|
||||
nsteps = 10
|
||||
return nsteps
|
||||
|
||||
def interpolate(oldpts, newpts, n):
|
||||
if len(oldpts) != len(newpts):
|
||||
raise ValueError("can't interpolate arrays of different length")
|
||||
pts = [0]*len(oldpts)
|
||||
res = [tuple(oldpts)]
|
||||
for i in range(1, n):
|
||||
for k in range(len(pts)):
|
||||
pts[k] = oldpts[k] + (newpts[k] - oldpts[k])*i//n
|
||||
res.append(tuple(pts))
|
||||
res.append(tuple(newpts))
|
||||
return res
|
||||
|
||||
|
||||
# Various (un)sorting algorithms
|
||||
|
||||
def uniform(array):
|
||||
size = array.getsize()
|
||||
array.setdata([(size+1)//2] * size)
|
||||
array.reset("Uniform data, size %d" % size)
|
||||
|
||||
def distinct(array):
|
||||
size = array.getsize()
|
||||
array.setdata(range(1, size+1))
|
||||
array.reset("Distinct data, size %d" % size)
|
||||
|
||||
def randomize(array):
|
||||
array.reset("Randomizing")
|
||||
n = array.getsize()
|
||||
for i in range(n):
|
||||
j = random.randint(0, n-1)
|
||||
array.swap(i, j)
|
||||
array.message("Randomized")
|
||||
|
||||
def insertionsort(array):
|
||||
size = array.getsize()
|
||||
array.reset("Insertion sort")
|
||||
for i in range(1, size):
|
||||
j = i-1
|
||||
while j >= 0:
|
||||
if array.compare(j, j+1) <= 0:
|
||||
break
|
||||
array.swap(j, j+1)
|
||||
j = j-1
|
||||
array.message("Sorted")
|
||||
|
||||
def selectionsort(array):
|
||||
size = array.getsize()
|
||||
array.reset("Selection sort")
|
||||
try:
|
||||
for i in range(size):
|
||||
array.show_partition(i, size)
|
||||
for j in range(i+1, size):
|
||||
if array.compare(i, j) > 0:
|
||||
array.swap(i, j)
|
||||
array.message("Sorted")
|
||||
finally:
|
||||
array.hide_partition()
|
||||
|
||||
def bubblesort(array):
|
||||
size = array.getsize()
|
||||
array.reset("Bubble sort")
|
||||
for i in range(size):
|
||||
for j in range(1, size):
|
||||
if array.compare(j-1, j) > 0:
|
||||
array.swap(j-1, j)
|
||||
array.message("Sorted")
|
||||
|
||||
def quicksort(array):
|
||||
size = array.getsize()
|
||||
array.reset("Quicksort")
|
||||
try:
|
||||
stack = [(0, size)]
|
||||
while stack:
|
||||
first, last = stack[-1]
|
||||
del stack[-1]
|
||||
array.show_partition(first, last)
|
||||
if last-first < 5:
|
||||
array.message("Insertion sort")
|
||||
for i in range(first+1, last):
|
||||
j = i-1
|
||||
while j >= first:
|
||||
if array.compare(j, j+1) <= 0:
|
||||
break
|
||||
array.swap(j, j+1)
|
||||
j = j-1
|
||||
continue
|
||||
array.message("Choosing pivot")
|
||||
j, i, k = first, (first+last) // 2, last-1
|
||||
if array.compare(k, i) < 0:
|
||||
array.swap(k, i)
|
||||
if array.compare(k, j) < 0:
|
||||
array.swap(k, j)
|
||||
if array.compare(j, i) < 0:
|
||||
array.swap(j, i)
|
||||
pivot = j
|
||||
array.show_pivot(pivot)
|
||||
array.message("Pivot at left of partition")
|
||||
array.wait(1000)
|
||||
left = first
|
||||
right = last
|
||||
while 1:
|
||||
array.message("Sweep right pointer")
|
||||
right = right-1
|
||||
array.show_right(right)
|
||||
while right > first and array.compare(right, pivot) >= 0:
|
||||
right = right-1
|
||||
array.show_right(right)
|
||||
array.message("Sweep left pointer")
|
||||
left = left+1
|
||||
array.show_left(left)
|
||||
while left < last and array.compare(left, pivot) <= 0:
|
||||
left = left+1
|
||||
array.show_left(left)
|
||||
if left > right:
|
||||
array.message("End of partition")
|
||||
break
|
||||
array.message("Swap items")
|
||||
array.swap(left, right)
|
||||
array.message("Swap pivot back")
|
||||
array.swap(pivot, right)
|
||||
n1 = right-first
|
||||
n2 = last-left
|
||||
if n1 > 1: stack.append((first, right))
|
||||
if n2 > 1: stack.append((left, last))
|
||||
array.message("Sorted")
|
||||
finally:
|
||||
array.hide_partition()
|
||||
|
||||
def demosort(array):
|
||||
while 1:
|
||||
for alg in [quicksort, insertionsort, selectionsort, bubblesort]:
|
||||
randomize(array)
|
||||
alg(array)
|
||||
|
||||
|
||||
# Sort demo class -- usable as a Grail applet
|
||||
|
||||
class SortDemo:
|
||||
|
||||
def __init__(self, master, size=15):
|
||||
self.master = master
|
||||
self.size = size
|
||||
self.busy = 0
|
||||
self.array = Array(self.master)
|
||||
|
||||
self.botframe = Frame(master)
|
||||
self.botframe.pack(side=BOTTOM)
|
||||
self.botleftframe = Frame(self.botframe)
|
||||
self.botleftframe.pack(side=LEFT, fill=Y)
|
||||
self.botrightframe = Frame(self.botframe)
|
||||
self.botrightframe.pack(side=RIGHT, fill=Y)
|
||||
|
||||
self.b_qsort = Button(self.botleftframe,
|
||||
text="Quicksort", command=self.c_qsort)
|
||||
self.b_qsort.pack(fill=X)
|
||||
self.b_isort = Button(self.botleftframe,
|
||||
text="Insertion sort", command=self.c_isort)
|
||||
self.b_isort.pack(fill=X)
|
||||
self.b_ssort = Button(self.botleftframe,
|
||||
text="Selection sort", command=self.c_ssort)
|
||||
self.b_ssort.pack(fill=X)
|
||||
self.b_bsort = Button(self.botleftframe,
|
||||
text="Bubble sort", command=self.c_bsort)
|
||||
self.b_bsort.pack(fill=X)
|
||||
|
||||
# Terrible hack to overcome limitation of OptionMenu...
|
||||
class MyIntVar(IntVar):
|
||||
def __init__(self, master, demo):
|
||||
self.demo = demo
|
||||
IntVar.__init__(self, master)
|
||||
def set(self, value):
|
||||
IntVar.set(self, value)
|
||||
if str(value) != '0':
|
||||
self.demo.resize(value)
|
||||
|
||||
self.v_size = MyIntVar(self.master, self)
|
||||
self.v_size.set(size)
|
||||
sizes = [1, 2, 3, 4] + list(range(5, 55, 5))
|
||||
if self.size not in sizes:
|
||||
sizes.append(self.size)
|
||||
sizes.sort()
|
||||
self.m_size = OptionMenu(self.botleftframe, self.v_size, *sizes)
|
||||
self.m_size.pack(fill=X)
|
||||
|
||||
self.v_speed = StringVar(self.master)
|
||||
self.v_speed.set("normal")
|
||||
self.m_speed = OptionMenu(self.botleftframe, self.v_speed,
|
||||
"single-step", "normal", "fast", "fastest")
|
||||
self.m_speed.pack(fill=X)
|
||||
|
||||
self.b_step = Button(self.botleftframe,
|
||||
text="Step", command=self.c_step)
|
||||
self.b_step.pack(fill=X)
|
||||
|
||||
self.b_randomize = Button(self.botrightframe,
|
||||
text="Randomize", command=self.c_randomize)
|
||||
self.b_randomize.pack(fill=X)
|
||||
self.b_uniform = Button(self.botrightframe,
|
||||
text="Uniform", command=self.c_uniform)
|
||||
self.b_uniform.pack(fill=X)
|
||||
self.b_distinct = Button(self.botrightframe,
|
||||
text="Distinct", command=self.c_distinct)
|
||||
self.b_distinct.pack(fill=X)
|
||||
self.b_demo = Button(self.botrightframe,
|
||||
text="Demo", command=self.c_demo)
|
||||
self.b_demo.pack(fill=X)
|
||||
self.b_cancel = Button(self.botrightframe,
|
||||
text="Cancel", command=self.c_cancel)
|
||||
self.b_cancel.pack(fill=X)
|
||||
self.b_cancel.config(state=DISABLED)
|
||||
self.b_quit = Button(self.botrightframe,
|
||||
text="Quit", command=self.c_quit)
|
||||
self.b_quit.pack(fill=X)
|
||||
|
||||
def resize(self, newsize):
|
||||
if self.busy:
|
||||
self.master.bell()
|
||||
return
|
||||
self.size = newsize
|
||||
self.array.setdata(range(1, self.size+1))
|
||||
|
||||
def c_qsort(self):
|
||||
self.run(quicksort)
|
||||
|
||||
def c_isort(self):
|
||||
self.run(insertionsort)
|
||||
|
||||
def c_ssort(self):
|
||||
self.run(selectionsort)
|
||||
|
||||
def c_bsort(self):
|
||||
self.run(bubblesort)
|
||||
|
||||
def c_demo(self):
|
||||
self.run(demosort)
|
||||
|
||||
def c_randomize(self):
|
||||
self.run(randomize)
|
||||
|
||||
def c_uniform(self):
|
||||
self.run(uniform)
|
||||
|
||||
def c_distinct(self):
|
||||
self.run(distinct)
|
||||
|
||||
def run(self, func):
|
||||
if self.busy:
|
||||
self.master.bell()
|
||||
return
|
||||
self.busy = 1
|
||||
self.array.setspeed(self.v_speed.get())
|
||||
self.b_cancel.config(state=NORMAL)
|
||||
try:
|
||||
func(self.array)
|
||||
except Array.Cancelled:
|
||||
pass
|
||||
self.b_cancel.config(state=DISABLED)
|
||||
self.busy = 0
|
||||
|
||||
def c_cancel(self):
|
||||
if not self.busy:
|
||||
self.master.bell()
|
||||
return
|
||||
self.array.cancel()
|
||||
|
||||
def c_step(self):
|
||||
if not self.busy:
|
||||
self.master.bell()
|
||||
return
|
||||
self.v_speed.set("single-step")
|
||||
self.array.setspeed("single-step")
|
||||
self.array.step()
|
||||
|
||||
def c_quit(self):
|
||||
if self.busy:
|
||||
self.array.cancel()
|
||||
self.master.after_idle(self.master.quit)
|
||||
|
||||
|
||||
# Main program -- for stand-alone operation outside Grail
|
||||
|
||||
def main():
|
||||
root = Tk()
|
||||
demo = SortDemo(root)
|
||||
root.protocol('WM_DELETE_WINDOW', demo.c_quit)
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
829
third_party/python/Tools/demo/ss1.py
vendored
Executable file
829
third_party/python/Tools/demo/ss1.py
vendored
Executable file
|
@ -0,0 +1,829 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
SS1 -- a spreadsheet-like application.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from xml.parsers import expat
|
||||
from xml.sax.saxutils import escape
|
||||
|
||||
LEFT, CENTER, RIGHT = "LEFT", "CENTER", "RIGHT"
|
||||
|
||||
def ljust(x, n):
|
||||
return x.ljust(n)
|
||||
def center(x, n):
|
||||
return x.center(n)
|
||||
def rjust(x, n):
|
||||
return x.rjust(n)
|
||||
align2action = {LEFT: ljust, CENTER: center, RIGHT: rjust}
|
||||
|
||||
align2xml = {LEFT: "left", CENTER: "center", RIGHT: "right"}
|
||||
xml2align = {"left": LEFT, "center": CENTER, "right": RIGHT}
|
||||
|
||||
align2anchor = {LEFT: "w", CENTER: "center", RIGHT: "e"}
|
||||
|
||||
def sum(seq):
|
||||
total = 0
|
||||
for x in seq:
|
||||
if x is not None:
|
||||
total += x
|
||||
return total
|
||||
|
||||
class Sheet:
|
||||
|
||||
def __init__(self):
|
||||
self.cells = {} # {(x, y): cell, ...}
|
||||
self.ns = dict(
|
||||
cell = self.cellvalue,
|
||||
cells = self.multicellvalue,
|
||||
sum = sum,
|
||||
)
|
||||
|
||||
def cellvalue(self, x, y):
|
||||
cell = self.getcell(x, y)
|
||||
if hasattr(cell, 'recalc'):
|
||||
return cell.recalc(self.ns)
|
||||
else:
|
||||
return cell
|
||||
|
||||
def multicellvalue(self, x1, y1, x2, y2):
|
||||
if x1 > x2:
|
||||
x1, x2 = x2, x1
|
||||
if y1 > y2:
|
||||
y1, y2 = y2, y1
|
||||
seq = []
|
||||
for y in range(y1, y2+1):
|
||||
for x in range(x1, x2+1):
|
||||
seq.append(self.cellvalue(x, y))
|
||||
return seq
|
||||
|
||||
def getcell(self, x, y):
|
||||
return self.cells.get((x, y))
|
||||
|
||||
def setcell(self, x, y, cell):
|
||||
assert x > 0 and y > 0
|
||||
assert isinstance(cell, BaseCell)
|
||||
self.cells[x, y] = cell
|
||||
|
||||
def clearcell(self, x, y):
|
||||
try:
|
||||
del self.cells[x, y]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def clearcells(self, x1, y1, x2, y2):
|
||||
for xy in self.selectcells(x1, y1, x2, y2):
|
||||
del self.cells[xy]
|
||||
|
||||
def clearrows(self, y1, y2):
|
||||
self.clearcells(0, y1, sys.maxsize, y2)
|
||||
|
||||
def clearcolumns(self, x1, x2):
|
||||
self.clearcells(x1, 0, x2, sys.maxsize)
|
||||
|
||||
def selectcells(self, x1, y1, x2, y2):
|
||||
if x1 > x2:
|
||||
x1, x2 = x2, x1
|
||||
if y1 > y2:
|
||||
y1, y2 = y2, y1
|
||||
return [(x, y) for x, y in self.cells
|
||||
if x1 <= x <= x2 and y1 <= y <= y2]
|
||||
|
||||
def movecells(self, x1, y1, x2, y2, dx, dy):
|
||||
if dx == 0 and dy == 0:
|
||||
return
|
||||
if x1 > x2:
|
||||
x1, x2 = x2, x1
|
||||
if y1 > y2:
|
||||
y1, y2 = y2, y1
|
||||
assert x1+dx > 0 and y1+dy > 0
|
||||
new = {}
|
||||
for x, y in self.cells:
|
||||
cell = self.cells[x, y]
|
||||
if hasattr(cell, 'renumber'):
|
||||
cell = cell.renumber(x1, y1, x2, y2, dx, dy)
|
||||
if x1 <= x <= x2 and y1 <= y <= y2:
|
||||
x += dx
|
||||
y += dy
|
||||
new[x, y] = cell
|
||||
self.cells = new
|
||||
|
||||
def insertrows(self, y, n):
|
||||
assert n > 0
|
||||
self.movecells(0, y, sys.maxsize, sys.maxsize, 0, n)
|
||||
|
||||
def deleterows(self, y1, y2):
|
||||
if y1 > y2:
|
||||
y1, y2 = y2, y1
|
||||
self.clearrows(y1, y2)
|
||||
self.movecells(0, y2+1, sys.maxsize, sys.maxsize, 0, y1-y2-1)
|
||||
|
||||
def insertcolumns(self, x, n):
|
||||
assert n > 0
|
||||
self.movecells(x, 0, sys.maxsize, sys.maxsize, n, 0)
|
||||
|
||||
def deletecolumns(self, x1, x2):
|
||||
if x1 > x2:
|
||||
x1, x2 = x2, x1
|
||||
self.clearcells(x1, x2)
|
||||
self.movecells(x2+1, 0, sys.maxsize, sys.maxsize, x1-x2-1, 0)
|
||||
|
||||
def getsize(self):
|
||||
maxx = maxy = 0
|
||||
for x, y in self.cells:
|
||||
maxx = max(maxx, x)
|
||||
maxy = max(maxy, y)
|
||||
return maxx, maxy
|
||||
|
||||
def reset(self):
|
||||
for cell in self.cells.values():
|
||||
if hasattr(cell, 'reset'):
|
||||
cell.reset()
|
||||
|
||||
def recalc(self):
|
||||
self.reset()
|
||||
for cell in self.cells.values():
|
||||
if hasattr(cell, 'recalc'):
|
||||
cell.recalc(self.ns)
|
||||
|
||||
def display(self):
|
||||
maxx, maxy = self.getsize()
|
||||
width, height = maxx+1, maxy+1
|
||||
colwidth = [1] * width
|
||||
full = {}
|
||||
# Add column heading labels in row 0
|
||||
for x in range(1, width):
|
||||
full[x, 0] = text, alignment = colnum2name(x), RIGHT
|
||||
colwidth[x] = max(colwidth[x], len(text))
|
||||
# Add row labels in column 0
|
||||
for y in range(1, height):
|
||||
full[0, y] = text, alignment = str(y), RIGHT
|
||||
colwidth[0] = max(colwidth[0], len(text))
|
||||
# Add sheet cells in columns with x>0 and y>0
|
||||
for (x, y), cell in self.cells.items():
|
||||
if x <= 0 or y <= 0:
|
||||
continue
|
||||
if hasattr(cell, 'recalc'):
|
||||
cell.recalc(self.ns)
|
||||
if hasattr(cell, 'format'):
|
||||
text, alignment = cell.format()
|
||||
assert isinstance(text, str)
|
||||
assert alignment in (LEFT, CENTER, RIGHT)
|
||||
else:
|
||||
text = str(cell)
|
||||
if isinstance(cell, str):
|
||||
alignment = LEFT
|
||||
else:
|
||||
alignment = RIGHT
|
||||
full[x, y] = (text, alignment)
|
||||
colwidth[x] = max(colwidth[x], len(text))
|
||||
# Calculate the horizontal separator line (dashes and dots)
|
||||
sep = ""
|
||||
for x in range(width):
|
||||
if sep:
|
||||
sep += "+"
|
||||
sep += "-"*colwidth[x]
|
||||
# Now print The full grid
|
||||
for y in range(height):
|
||||
line = ""
|
||||
for x in range(width):
|
||||
text, alignment = full.get((x, y)) or ("", LEFT)
|
||||
text = align2action[alignment](text, colwidth[x])
|
||||
if line:
|
||||
line += '|'
|
||||
line += text
|
||||
print(line)
|
||||
if y == 0:
|
||||
print(sep)
|
||||
|
||||
def xml(self):
|
||||
out = ['<spreadsheet>']
|
||||
for (x, y), cell in self.cells.items():
|
||||
if hasattr(cell, 'xml'):
|
||||
cellxml = cell.xml()
|
||||
else:
|
||||
cellxml = '<value>%s</value>' % escape(cell)
|
||||
out.append('<cell row="%s" col="%s">\n %s\n</cell>' %
|
||||
(y, x, cellxml))
|
||||
out.append('</spreadsheet>')
|
||||
return '\n'.join(out)
|
||||
|
||||
def save(self, filename):
|
||||
text = self.xml()
|
||||
with open(filename, "w", encoding='utf-8') as f:
|
||||
f.write(text)
|
||||
if text and not text.endswith('\n'):
|
||||
f.write('\n')
|
||||
|
||||
def load(self, filename):
|
||||
with open(filename, 'rb') as f:
|
||||
SheetParser(self).parsefile(f)
|
||||
|
||||
class SheetParser:
|
||||
|
||||
def __init__(self, sheet):
|
||||
self.sheet = sheet
|
||||
|
||||
def parsefile(self, f):
|
||||
parser = expat.ParserCreate()
|
||||
parser.StartElementHandler = self.startelement
|
||||
parser.EndElementHandler = self.endelement
|
||||
parser.CharacterDataHandler = self.data
|
||||
parser.ParseFile(f)
|
||||
|
||||
def startelement(self, tag, attrs):
|
||||
method = getattr(self, 'start_'+tag, None)
|
||||
if method:
|
||||
method(attrs)
|
||||
self.texts = []
|
||||
|
||||
def data(self, text):
|
||||
self.texts.append(text)
|
||||
|
||||
def endelement(self, tag):
|
||||
method = getattr(self, 'end_'+tag, None)
|
||||
if method:
|
||||
method("".join(self.texts))
|
||||
|
||||
def start_cell(self, attrs):
|
||||
self.y = int(attrs.get("row"))
|
||||
self.x = int(attrs.get("col"))
|
||||
|
||||
def start_value(self, attrs):
|
||||
self.fmt = attrs.get('format')
|
||||
self.alignment = xml2align.get(attrs.get('align'))
|
||||
|
||||
start_formula = start_value
|
||||
|
||||
def end_int(self, text):
|
||||
try:
|
||||
self.value = int(text)
|
||||
except (TypeError, ValueError):
|
||||
self.value = None
|
||||
|
||||
end_long = end_int
|
||||
|
||||
def end_double(self, text):
|
||||
try:
|
||||
self.value = float(text)
|
||||
except (TypeError, ValueError):
|
||||
self.value = None
|
||||
|
||||
def end_complex(self, text):
|
||||
try:
|
||||
self.value = complex(text)
|
||||
except (TypeError, ValueError):
|
||||
self.value = None
|
||||
|
||||
def end_string(self, text):
|
||||
self.value = text
|
||||
|
||||
def end_value(self, text):
|
||||
if isinstance(self.value, BaseCell):
|
||||
self.cell = self.value
|
||||
elif isinstance(self.value, str):
|
||||
self.cell = StringCell(self.value,
|
||||
self.fmt or "%s",
|
||||
self.alignment or LEFT)
|
||||
else:
|
||||
self.cell = NumericCell(self.value,
|
||||
self.fmt or "%s",
|
||||
self.alignment or RIGHT)
|
||||
|
||||
def end_formula(self, text):
|
||||
self.cell = FormulaCell(text,
|
||||
self.fmt or "%s",
|
||||
self.alignment or RIGHT)
|
||||
|
||||
def end_cell(self, text):
|
||||
self.sheet.setcell(self.x, self.y, self.cell)
|
||||
|
||||
class BaseCell:
|
||||
__init__ = None # Must provide
|
||||
"""Abstract base class for sheet cells.
|
||||
|
||||
Subclasses may but needn't provide the following APIs:
|
||||
|
||||
cell.reset() -- prepare for recalculation
|
||||
cell.recalc(ns) -> value -- recalculate formula
|
||||
cell.format() -> (value, alignment) -- return formatted value
|
||||
cell.xml() -> string -- return XML
|
||||
"""
|
||||
|
||||
class NumericCell(BaseCell):
|
||||
|
||||
def __init__(self, value, fmt="%s", alignment=RIGHT):
|
||||
assert isinstance(value, (int, float, complex))
|
||||
assert alignment in (LEFT, CENTER, RIGHT)
|
||||
self.value = value
|
||||
self.fmt = fmt
|
||||
self.alignment = alignment
|
||||
|
||||
def recalc(self, ns):
|
||||
return self.value
|
||||
|
||||
def format(self):
|
||||
try:
|
||||
text = self.fmt % self.value
|
||||
except:
|
||||
text = str(self.value)
|
||||
return text, self.alignment
|
||||
|
||||
def xml(self):
|
||||
method = getattr(self, '_xml_' + type(self.value).__name__)
|
||||
return '<value align="%s" format="%s">%s</value>' % (
|
||||
align2xml[self.alignment],
|
||||
self.fmt,
|
||||
method())
|
||||
|
||||
def _xml_int(self):
|
||||
if -2**31 <= self.value < 2**31:
|
||||
return '<int>%s</int>' % self.value
|
||||
else:
|
||||
return '<long>%s</long>' % self.value
|
||||
|
||||
def _xml_float(self):
|
||||
return '<double>%r</double>' % self.value
|
||||
|
||||
def _xml_complex(self):
|
||||
return '<complex>%r</complex>' % self.value
|
||||
|
||||
class StringCell(BaseCell):
|
||||
|
||||
def __init__(self, text, fmt="%s", alignment=LEFT):
|
||||
assert isinstance(text, str)
|
||||
assert alignment in (LEFT, CENTER, RIGHT)
|
||||
self.text = text
|
||||
self.fmt = fmt
|
||||
self.alignment = alignment
|
||||
|
||||
def recalc(self, ns):
|
||||
return self.text
|
||||
|
||||
def format(self):
|
||||
return self.text, self.alignment
|
||||
|
||||
def xml(self):
|
||||
s = '<value align="%s" format="%s"><string>%s</string></value>'
|
||||
return s % (
|
||||
align2xml[self.alignment],
|
||||
self.fmt,
|
||||
escape(self.text))
|
||||
|
||||
class FormulaCell(BaseCell):
|
||||
|
||||
def __init__(self, formula, fmt="%s", alignment=RIGHT):
|
||||
assert alignment in (LEFT, CENTER, RIGHT)
|
||||
self.formula = formula
|
||||
self.translated = translate(self.formula)
|
||||
self.fmt = fmt
|
||||
self.alignment = alignment
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
self.value = None
|
||||
|
||||
def recalc(self, ns):
|
||||
if self.value is None:
|
||||
try:
|
||||
self.value = eval(self.translated, ns)
|
||||
except:
|
||||
exc = sys.exc_info()[0]
|
||||
if hasattr(exc, "__name__"):
|
||||
self.value = exc.__name__
|
||||
else:
|
||||
self.value = str(exc)
|
||||
return self.value
|
||||
|
||||
def format(self):
|
||||
try:
|
||||
text = self.fmt % self.value
|
||||
except:
|
||||
text = str(self.value)
|
||||
return text, self.alignment
|
||||
|
||||
def xml(self):
|
||||
return '<formula align="%s" format="%s">%s</formula>' % (
|
||||
align2xml[self.alignment],
|
||||
self.fmt,
|
||||
escape(self.formula))
|
||||
|
||||
def renumber(self, x1, y1, x2, y2, dx, dy):
|
||||
out = []
|
||||
for part in re.split(r'(\w+)', self.formula):
|
||||
m = re.match('^([A-Z]+)([1-9][0-9]*)$', part)
|
||||
if m is not None:
|
||||
sx, sy = m.groups()
|
||||
x = colname2num(sx)
|
||||
y = int(sy)
|
||||
if x1 <= x <= x2 and y1 <= y <= y2:
|
||||
part = cellname(x+dx, y+dy)
|
||||
out.append(part)
|
||||
return FormulaCell("".join(out), self.fmt, self.alignment)
|
||||
|
||||
def translate(formula):
|
||||
"""Translate a formula containing fancy cell names to valid Python code.
|
||||
|
||||
Examples:
|
||||
B4 -> cell(2, 4)
|
||||
B4:Z100 -> cells(2, 4, 26, 100)
|
||||
"""
|
||||
out = []
|
||||
for part in re.split(r"(\w+(?::\w+)?)", formula):
|
||||
m = re.match(r"^([A-Z]+)([1-9][0-9]*)(?::([A-Z]+)([1-9][0-9]*))?$", part)
|
||||
if m is None:
|
||||
out.append(part)
|
||||
else:
|
||||
x1, y1, x2, y2 = m.groups()
|
||||
x1 = colname2num(x1)
|
||||
if x2 is None:
|
||||
s = "cell(%s, %s)" % (x1, y1)
|
||||
else:
|
||||
x2 = colname2num(x2)
|
||||
s = "cells(%s, %s, %s, %s)" % (x1, y1, x2, y2)
|
||||
out.append(s)
|
||||
return "".join(out)
|
||||
|
||||
def cellname(x, y):
|
||||
"Translate a cell coordinate to a fancy cell name (e.g. (1, 1)->'A1')."
|
||||
assert x > 0 # Column 0 has an empty name, so can't use that
|
||||
return colnum2name(x) + str(y)
|
||||
|
||||
def colname2num(s):
|
||||
"Translate a column name to number (e.g. 'A'->1, 'Z'->26, 'AA'->27)."
|
||||
s = s.upper()
|
||||
n = 0
|
||||
for c in s:
|
||||
assert 'A' <= c <= 'Z'
|
||||
n = n*26 + ord(c) - ord('A') + 1
|
||||
return n
|
||||
|
||||
def colnum2name(n):
|
||||
"Translate a column number to name (e.g. 1->'A', etc.)."
|
||||
assert n > 0
|
||||
s = ""
|
||||
while n:
|
||||
n, m = divmod(n-1, 26)
|
||||
s = chr(m+ord('A')) + s
|
||||
return s
|
||||
|
||||
import tkinter as Tk
|
||||
|
||||
class SheetGUI:
|
||||
|
||||
"""Beginnings of a GUI for a spreadsheet.
|
||||
|
||||
TO DO:
|
||||
- clear multiple cells
|
||||
- Insert, clear, remove rows or columns
|
||||
- Show new contents while typing
|
||||
- Scroll bars
|
||||
- Grow grid when window is grown
|
||||
- Proper menus
|
||||
- Undo, redo
|
||||
- Cut, copy and paste
|
||||
- Formatting and alignment
|
||||
"""
|
||||
|
||||
def __init__(self, filename="sheet1.xml", rows=10, columns=5):
|
||||
"""Constructor.
|
||||
|
||||
Load the sheet from the filename argument.
|
||||
Set up the Tk widget tree.
|
||||
"""
|
||||
# Create and load the sheet
|
||||
self.filename = filename
|
||||
self.sheet = Sheet()
|
||||
if os.path.isfile(filename):
|
||||
self.sheet.load(filename)
|
||||
# Calculate the needed grid size
|
||||
maxx, maxy = self.sheet.getsize()
|
||||
rows = max(rows, maxy)
|
||||
columns = max(columns, maxx)
|
||||
# Create the widgets
|
||||
self.root = Tk.Tk()
|
||||
self.root.wm_title("Spreadsheet: %s" % self.filename)
|
||||
self.beacon = Tk.Label(self.root, text="A1",
|
||||
font=('helvetica', 16, 'bold'))
|
||||
self.entry = Tk.Entry(self.root)
|
||||
self.savebutton = Tk.Button(self.root, text="Save",
|
||||
command=self.save)
|
||||
self.cellgrid = Tk.Frame(self.root)
|
||||
# Configure the widget lay-out
|
||||
self.cellgrid.pack(side="bottom", expand=1, fill="both")
|
||||
self.beacon.pack(side="left")
|
||||
self.savebutton.pack(side="right")
|
||||
self.entry.pack(side="left", expand=1, fill="x")
|
||||
# Bind some events
|
||||
self.entry.bind("<Return>", self.return_event)
|
||||
self.entry.bind("<Shift-Return>", self.shift_return_event)
|
||||
self.entry.bind("<Tab>", self.tab_event)
|
||||
self.entry.bind("<Shift-Tab>", self.shift_tab_event)
|
||||
self.entry.bind("<Delete>", self.delete_event)
|
||||
self.entry.bind("<Escape>", self.escape_event)
|
||||
# Now create the cell grid
|
||||
self.makegrid(rows, columns)
|
||||
# Select the top-left cell
|
||||
self.currentxy = None
|
||||
self.cornerxy = None
|
||||
self.setcurrent(1, 1)
|
||||
# Copy the sheet cells to the GUI cells
|
||||
self.sync()
|
||||
|
||||
def delete_event(self, event):
|
||||
if self.cornerxy != self.currentxy and self.cornerxy is not None:
|
||||
self.sheet.clearcells(*(self.currentxy + self.cornerxy))
|
||||
else:
|
||||
self.sheet.clearcell(*self.currentxy)
|
||||
self.sync()
|
||||
self.entry.delete(0, 'end')
|
||||
return "break"
|
||||
|
||||
def escape_event(self, event):
|
||||
x, y = self.currentxy
|
||||
self.load_entry(x, y)
|
||||
|
||||
def load_entry(self, x, y):
|
||||
cell = self.sheet.getcell(x, y)
|
||||
if cell is None:
|
||||
text = ""
|
||||
elif isinstance(cell, FormulaCell):
|
||||
text = '=' + cell.formula
|
||||
else:
|
||||
text, alignment = cell.format()
|
||||
self.entry.delete(0, 'end')
|
||||
self.entry.insert(0, text)
|
||||
self.entry.selection_range(0, 'end')
|
||||
|
||||
def makegrid(self, rows, columns):
|
||||
"""Helper to create the grid of GUI cells.
|
||||
|
||||
The edge (x==0 or y==0) is filled with labels; the rest is real cells.
|
||||
"""
|
||||
self.rows = rows
|
||||
self.columns = columns
|
||||
self.gridcells = {}
|
||||
# Create the top left corner cell (which selects all)
|
||||
cell = Tk.Label(self.cellgrid, relief='raised')
|
||||
cell.grid_configure(column=0, row=0, sticky='NSWE')
|
||||
cell.bind("<ButtonPress-1>", self.selectall)
|
||||
# Create the top row of labels, and configure the grid columns
|
||||
for x in range(1, columns+1):
|
||||
self.cellgrid.grid_columnconfigure(x, minsize=64)
|
||||
cell = Tk.Label(self.cellgrid, text=colnum2name(x), relief='raised')
|
||||
cell.grid_configure(column=x, row=0, sticky='WE')
|
||||
self.gridcells[x, 0] = cell
|
||||
cell.__x = x
|
||||
cell.__y = 0
|
||||
cell.bind("<ButtonPress-1>", self.selectcolumn)
|
||||
cell.bind("<B1-Motion>", self.extendcolumn)
|
||||
cell.bind("<ButtonRelease-1>", self.extendcolumn)
|
||||
cell.bind("<Shift-Button-1>", self.extendcolumn)
|
||||
# Create the leftmost column of labels
|
||||
for y in range(1, rows+1):
|
||||
cell = Tk.Label(self.cellgrid, text=str(y), relief='raised')
|
||||
cell.grid_configure(column=0, row=y, sticky='WE')
|
||||
self.gridcells[0, y] = cell
|
||||
cell.__x = 0
|
||||
cell.__y = y
|
||||
cell.bind("<ButtonPress-1>", self.selectrow)
|
||||
cell.bind("<B1-Motion>", self.extendrow)
|
||||
cell.bind("<ButtonRelease-1>", self.extendrow)
|
||||
cell.bind("<Shift-Button-1>", self.extendrow)
|
||||
# Create the real cells
|
||||
for x in range(1, columns+1):
|
||||
for y in range(1, rows+1):
|
||||
cell = Tk.Label(self.cellgrid, relief='sunken',
|
||||
bg='white', fg='black')
|
||||
cell.grid_configure(column=x, row=y, sticky='NSWE')
|
||||
self.gridcells[x, y] = cell
|
||||
cell.__x = x
|
||||
cell.__y = y
|
||||
# Bind mouse events
|
||||
cell.bind("<ButtonPress-1>", self.press)
|
||||
cell.bind("<B1-Motion>", self.motion)
|
||||
cell.bind("<ButtonRelease-1>", self.release)
|
||||
cell.bind("<Shift-Button-1>", self.release)
|
||||
|
||||
def selectall(self, event):
|
||||
self.setcurrent(1, 1)
|
||||
self.setcorner(sys.maxsize, sys.maxsize)
|
||||
|
||||
def selectcolumn(self, event):
|
||||
x, y = self.whichxy(event)
|
||||
self.setcurrent(x, 1)
|
||||
self.setcorner(x, sys.maxsize)
|
||||
|
||||
def extendcolumn(self, event):
|
||||
x, y = self.whichxy(event)
|
||||
if x > 0:
|
||||
self.setcurrent(self.currentxy[0], 1)
|
||||
self.setcorner(x, sys.maxsize)
|
||||
|
||||
def selectrow(self, event):
|
||||
x, y = self.whichxy(event)
|
||||
self.setcurrent(1, y)
|
||||
self.setcorner(sys.maxsize, y)
|
||||
|
||||
def extendrow(self, event):
|
||||
x, y = self.whichxy(event)
|
||||
if y > 0:
|
||||
self.setcurrent(1, self.currentxy[1])
|
||||
self.setcorner(sys.maxsize, y)
|
||||
|
||||
def press(self, event):
|
||||
x, y = self.whichxy(event)
|
||||
if x > 0 and y > 0:
|
||||
self.setcurrent(x, y)
|
||||
|
||||
def motion(self, event):
|
||||
x, y = self.whichxy(event)
|
||||
if x > 0 and y > 0:
|
||||
self.setcorner(x, y)
|
||||
|
||||
release = motion
|
||||
|
||||
def whichxy(self, event):
|
||||
w = self.cellgrid.winfo_containing(event.x_root, event.y_root)
|
||||
if w is not None and isinstance(w, Tk.Label):
|
||||
try:
|
||||
return w.__x, w.__y
|
||||
except AttributeError:
|
||||
pass
|
||||
return 0, 0
|
||||
|
||||
def save(self):
|
||||
self.sheet.save(self.filename)
|
||||
|
||||
def setcurrent(self, x, y):
|
||||
"Make (x, y) the current cell."
|
||||
if self.currentxy is not None:
|
||||
self.change_cell()
|
||||
self.clearfocus()
|
||||
self.beacon['text'] = cellname(x, y)
|
||||
self.load_entry(x, y)
|
||||
self.entry.focus_set()
|
||||
self.currentxy = x, y
|
||||
self.cornerxy = None
|
||||
gridcell = self.gridcells.get(self.currentxy)
|
||||
if gridcell is not None:
|
||||
gridcell['bg'] = 'yellow'
|
||||
|
||||
def setcorner(self, x, y):
|
||||
if self.currentxy is None or self.currentxy == (x, y):
|
||||
self.setcurrent(x, y)
|
||||
return
|
||||
self.clearfocus()
|
||||
self.cornerxy = x, y
|
||||
x1, y1 = self.currentxy
|
||||
x2, y2 = self.cornerxy or self.currentxy
|
||||
if x1 > x2:
|
||||
x1, x2 = x2, x1
|
||||
if y1 > y2:
|
||||
y1, y2 = y2, y1
|
||||
for (x, y), cell in self.gridcells.items():
|
||||
if x1 <= x <= x2 and y1 <= y <= y2:
|
||||
cell['bg'] = 'lightBlue'
|
||||
gridcell = self.gridcells.get(self.currentxy)
|
||||
if gridcell is not None:
|
||||
gridcell['bg'] = 'yellow'
|
||||
self.setbeacon(x1, y1, x2, y2)
|
||||
|
||||
def setbeacon(self, x1, y1, x2, y2):
|
||||
if x1 == y1 == 1 and x2 == y2 == sys.maxsize:
|
||||
name = ":"
|
||||
elif (x1, x2) == (1, sys.maxsize):
|
||||
if y1 == y2:
|
||||
name = "%d" % y1
|
||||
else:
|
||||
name = "%d:%d" % (y1, y2)
|
||||
elif (y1, y2) == (1, sys.maxsize):
|
||||
if x1 == x2:
|
||||
name = "%s" % colnum2name(x1)
|
||||
else:
|
||||
name = "%s:%s" % (colnum2name(x1), colnum2name(x2))
|
||||
else:
|
||||
name1 = cellname(*self.currentxy)
|
||||
name2 = cellname(*self.cornerxy)
|
||||
name = "%s:%s" % (name1, name2)
|
||||
self.beacon['text'] = name
|
||||
|
||||
|
||||
def clearfocus(self):
|
||||
if self.currentxy is not None:
|
||||
x1, y1 = self.currentxy
|
||||
x2, y2 = self.cornerxy or self.currentxy
|
||||
if x1 > x2:
|
||||
x1, x2 = x2, x1
|
||||
if y1 > y2:
|
||||
y1, y2 = y2, y1
|
||||
for (x, y), cell in self.gridcells.items():
|
||||
if x1 <= x <= x2 and y1 <= y <= y2:
|
||||
cell['bg'] = 'white'
|
||||
|
||||
def return_event(self, event):
|
||||
"Callback for the Return key."
|
||||
self.change_cell()
|
||||
x, y = self.currentxy
|
||||
self.setcurrent(x, y+1)
|
||||
return "break"
|
||||
|
||||
def shift_return_event(self, event):
|
||||
"Callback for the Return key with Shift modifier."
|
||||
self.change_cell()
|
||||
x, y = self.currentxy
|
||||
self.setcurrent(x, max(1, y-1))
|
||||
return "break"
|
||||
|
||||
def tab_event(self, event):
|
||||
"Callback for the Tab key."
|
||||
self.change_cell()
|
||||
x, y = self.currentxy
|
||||
self.setcurrent(x+1, y)
|
||||
return "break"
|
||||
|
||||
def shift_tab_event(self, event):
|
||||
"Callback for the Tab key with Shift modifier."
|
||||
self.change_cell()
|
||||
x, y = self.currentxy
|
||||
self.setcurrent(max(1, x-1), y)
|
||||
return "break"
|
||||
|
||||
def change_cell(self):
|
||||
"Set the current cell from the entry widget."
|
||||
x, y = self.currentxy
|
||||
text = self.entry.get()
|
||||
cell = None
|
||||
if text.startswith('='):
|
||||
cell = FormulaCell(text[1:])
|
||||
else:
|
||||
for cls in int, float, complex:
|
||||
try:
|
||||
value = cls(text)
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
else:
|
||||
cell = NumericCell(value)
|
||||
break
|
||||
if cell is None and text:
|
||||
cell = StringCell(text)
|
||||
if cell is None:
|
||||
self.sheet.clearcell(x, y)
|
||||
else:
|
||||
self.sheet.setcell(x, y, cell)
|
||||
self.sync()
|
||||
|
||||
def sync(self):
|
||||
"Fill the GUI cells from the sheet cells."
|
||||
self.sheet.recalc()
|
||||
for (x, y), gridcell in self.gridcells.items():
|
||||
if x == 0 or y == 0:
|
||||
continue
|
||||
cell = self.sheet.getcell(x, y)
|
||||
if cell is None:
|
||||
gridcell['text'] = ""
|
||||
else:
|
||||
if hasattr(cell, 'format'):
|
||||
text, alignment = cell.format()
|
||||
else:
|
||||
text, alignment = str(cell), LEFT
|
||||
gridcell['text'] = text
|
||||
gridcell['anchor'] = align2anchor[alignment]
|
||||
|
||||
|
||||
def test_basic():
|
||||
"Basic non-gui self-test."
|
||||
a = Sheet()
|
||||
for x in range(1, 11):
|
||||
for y in range(1, 11):
|
||||
if x == 1:
|
||||
cell = NumericCell(y)
|
||||
elif y == 1:
|
||||
cell = NumericCell(x)
|
||||
else:
|
||||
c1 = cellname(x, 1)
|
||||
c2 = cellname(1, y)
|
||||
formula = "%s*%s" % (c1, c2)
|
||||
cell = FormulaCell(formula)
|
||||
a.setcell(x, y, cell)
|
||||
## if os.path.isfile("sheet1.xml"):
|
||||
## print "Loading from sheet1.xml"
|
||||
## a.load("sheet1.xml")
|
||||
a.display()
|
||||
a.save("sheet1.xml")
|
||||
|
||||
def test_gui():
|
||||
"GUI test."
|
||||
if sys.argv[1:]:
|
||||
filename = sys.argv[1]
|
||||
else:
|
||||
filename = "sheet1.xml"
|
||||
g = SheetGUI(filename)
|
||||
g.root.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
#test_basic()
|
||||
test_gui()
|
74
third_party/python/Tools/demo/vector.py
vendored
Executable file
74
third_party/python/Tools/demo/vector.py
vendored
Executable file
|
@ -0,0 +1,74 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
A demonstration of classes and their special methods in Python.
|
||||
"""
|
||||
|
||||
class Vec:
|
||||
"""A simple vector class.
|
||||
|
||||
Instances of the Vec class can be constructed from numbers
|
||||
|
||||
>>> a = Vec(1, 2, 3)
|
||||
>>> b = Vec(3, 2, 1)
|
||||
|
||||
added
|
||||
>>> a + b
|
||||
Vec(4, 4, 4)
|
||||
|
||||
subtracted
|
||||
>>> a - b
|
||||
Vec(-2, 0, 2)
|
||||
|
||||
and multiplied by a scalar on the left
|
||||
>>> 3.0 * a
|
||||
Vec(3.0, 6.0, 9.0)
|
||||
|
||||
or on the right
|
||||
>>> a * 3.0
|
||||
Vec(3.0, 6.0, 9.0)
|
||||
"""
|
||||
def __init__(self, *v):
|
||||
self.v = list(v)
|
||||
|
||||
@classmethod
|
||||
def fromlist(cls, v):
|
||||
if not isinstance(v, list):
|
||||
raise TypeError
|
||||
inst = cls()
|
||||
inst.v = v
|
||||
return inst
|
||||
|
||||
def __repr__(self):
|
||||
args = ', '.join(repr(x) for x in self.v)
|
||||
return 'Vec({})'.format(args)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.v)
|
||||
|
||||
def __getitem__(self, i):
|
||||
return self.v[i]
|
||||
|
||||
def __add__(self, other):
|
||||
# Element-wise addition
|
||||
v = [x + y for x, y in zip(self.v, other.v)]
|
||||
return Vec.fromlist(v)
|
||||
|
||||
def __sub__(self, other):
|
||||
# Element-wise subtraction
|
||||
v = [x - y for x, y in zip(self.v, other.v)]
|
||||
return Vec.fromlist(v)
|
||||
|
||||
def __mul__(self, scalar):
|
||||
# Multiply by scalar
|
||||
v = [x * scalar for x in self.v]
|
||||
return Vec.fromlist(v)
|
||||
|
||||
__rmul__ = __mul__
|
||||
|
||||
|
||||
def test():
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
||||
test()
|
296
third_party/python/Tools/freeze/README
vendored
Normal file
296
third_party/python/Tools/freeze/README
vendored
Normal file
|
@ -0,0 +1,296 @@
|
|||
THE FREEZE SCRIPT
|
||||
=================
|
||||
|
||||
(Directions for Windows are at the end of this file.)
|
||||
|
||||
|
||||
What is Freeze?
|
||||
---------------
|
||||
|
||||
Freeze make it possible to ship arbitrary Python programs to people
|
||||
who don't have Python. The shipped file (called a "frozen" version of
|
||||
your Python program) is an executable, so this only works if your
|
||||
platform is compatible with that on the receiving end (this is usually
|
||||
a matter of having the same major operating system revision and CPU
|
||||
type).
|
||||
|
||||
The shipped file contains a Python interpreter and large portions of
|
||||
the Python run-time. Some measures have been taken to avoid linking
|
||||
unneeded modules, but the resulting binary is usually not small.
|
||||
|
||||
The Python source code of your program (and of the library modules
|
||||
written in Python that it uses) is not included in the binary --
|
||||
instead, the compiled byte-code (the instruction stream used
|
||||
internally by the interpreter) is incorporated. This gives some
|
||||
protection of your Python source code, though not much -- a
|
||||
disassembler for Python byte-code is available in the standard Python
|
||||
library. At least someone running "strings" on your binary won't see
|
||||
the source.
|
||||
|
||||
|
||||
How does Freeze know which modules to include?
|
||||
----------------------------------------------
|
||||
|
||||
Previous versions of Freeze used a pretty simple-minded algorithm to
|
||||
find the modules that your program uses, essentially searching for
|
||||
lines starting with the word "import". It was pretty easy to trick it
|
||||
into making mistakes, either missing valid import statements, or
|
||||
mistaking string literals (e.g. doc strings) for import statements.
|
||||
|
||||
This has been remedied: Freeze now uses the regular Python parser to
|
||||
parse the program (and all its modules) and scans the generated byte
|
||||
code for IMPORT instructions. It may still be confused -- it will not
|
||||
know about calls to the __import__ built-in function, or about import
|
||||
statements constructed on the fly and executed using the 'exec'
|
||||
statement, and it will consider import statements even when they are
|
||||
unreachable (e.g. "if 0: import foobar").
|
||||
|
||||
This new version of Freeze also knows about Python's new package
|
||||
import mechanism, and uses exactly the same rules to find imported
|
||||
modules and packages. One exception: if you write 'from package
|
||||
import *', Python will look into the __all__ variable of the package
|
||||
to determine which modules are to be imported, while Freeze will do a
|
||||
directory listing.
|
||||
|
||||
One tricky issue: Freeze assumes that the Python interpreter and
|
||||
environment you're using to run Freeze is the same one that would be
|
||||
used to run your program, which should also be the same whose sources
|
||||
and installed files you will learn about in the next section. In
|
||||
particular, your PYTHONPATH setting should be the same as for running
|
||||
your program locally. (Tip: if the program doesn't run when you type
|
||||
"python hello.py" there's little chance of getting the frozen version
|
||||
to run.)
|
||||
|
||||
|
||||
How do I use Freeze?
|
||||
--------------------
|
||||
|
||||
Normally, you should be able to use it as follows:
|
||||
|
||||
python freeze.py hello.py
|
||||
|
||||
where hello.py is your program and freeze.py is the main file of
|
||||
Freeze (in actuality, you'll probably specify an absolute pathname
|
||||
such as /usr/joe/python/Tools/freeze/freeze.py).
|
||||
|
||||
|
||||
What do I do next?
|
||||
------------------
|
||||
|
||||
Freeze creates a number of files: frozen.c, config.c and Makefile,
|
||||
plus one file for each Python module that gets included named
|
||||
M_<module>.c. To produce the frozen version of your program, you can
|
||||
simply type "make". This should produce a binary file. If the
|
||||
filename argument to Freeze was "hello.py", the binary will be called
|
||||
"hello".
|
||||
|
||||
Note: you can use the -o option to freeze to specify an alternative
|
||||
directory where these files are created. This makes it easier to
|
||||
clean up after you've shipped the frozen binary. You should invoke
|
||||
"make" in the given directory.
|
||||
|
||||
|
||||
Freezing Tkinter programs
|
||||
-------------------------
|
||||
|
||||
Unfortunately, it is currently not possible to freeze programs that
|
||||
use Tkinter without a Tcl/Tk installation. The best way to ship a
|
||||
frozen Tkinter program is to decide in advance where you are going
|
||||
to place the Tcl and Tk library files in the distributed setup, and
|
||||
then declare these directories in your frozen Python program using
|
||||
the TCL_LIBRARY, TK_LIBRARY and TIX_LIBRARY environment variables.
|
||||
|
||||
For example, assume you will ship your frozen program in the directory
|
||||
<root>/bin/windows-x86 and will place your Tcl library files
|
||||
in <root>/lib/tcl8.2 and your Tk library files in <root>/lib/tk8.2. Then
|
||||
placing the following lines in your frozen Python script before importing
|
||||
Tkinter or Tix would set the environment correctly for Tcl/Tk/Tix:
|
||||
|
||||
import os
|
||||
import os.path
|
||||
RootDir = os.path.dirname(os.path.dirname(os.getcwd()))
|
||||
|
||||
import sys
|
||||
if sys.platform == "win32":
|
||||
sys.path = ['', '..\\..\\lib\\python-2.0']
|
||||
os.environ['TCL_LIBRARY'] = RootDir + '\\lib\\tcl8.2'
|
||||
os.environ['TK_LIBRARY'] = RootDir + '\\lib\\tk8.2'
|
||||
os.environ['TIX_LIBRARY'] = RootDir + '\\lib\\tix8.1'
|
||||
elif sys.platform == "linux2":
|
||||
sys.path = ['', '../../lib/python-2.0']
|
||||
os.environ['TCL_LIBRARY'] = RootDir + '/lib/tcl8.2'
|
||||
os.environ['TK_LIBRARY'] = RootDir + '/lib/tk8.2'
|
||||
os.environ['TIX_LIBRARY'] = RootDir + '/lib/tix8.1'
|
||||
elif sys.platform == "solaris":
|
||||
sys.path = ['', '../../lib/python-2.0']
|
||||
os.environ['TCL_LIBRARY'] = RootDir + '/lib/tcl8.2'
|
||||
os.environ['TK_LIBRARY'] = RootDir + '/lib/tk8.2'
|
||||
os.environ['TIX_LIBRARY'] = RootDir + '/lib/tix8.1'
|
||||
|
||||
This also adds <root>/lib/python-2.0 to your Python path
|
||||
for any Python files such as _tkinter.pyd you may need.
|
||||
|
||||
Note that the dynamic libraries (such as tcl82.dll tk82.dll python20.dll
|
||||
under Windows, or libtcl8.2.so and libtcl8.2.so under Unix) are required
|
||||
at program load time, and are searched by the operating system loader
|
||||
before Python can be started. Under Windows, the environment
|
||||
variable PATH is consulted, and under Unix, it may be the
|
||||
environment variable LD_LIBRARY_PATH and/or the system
|
||||
shared library cache (ld.so). An additional preferred directory for
|
||||
finding the dynamic libraries is built into the .dll or .so files at
|
||||
compile time - see the LIB_RUNTIME_DIR variable in the Tcl makefile.
|
||||
The OS must find the dynamic libraries or your frozen program won't start.
|
||||
Usually I make sure that the .so or .dll files are in the same directory
|
||||
as the executable, but this may not be foolproof.
|
||||
|
||||
A workaround to installing your Tcl library files with your frozen
|
||||
executable would be possible, in which the Tcl/Tk library files are
|
||||
incorporated in a frozen Python module as string literals and written
|
||||
to a temporary location when the program runs; this is currently left
|
||||
as an exercise for the reader. An easier approach is to freeze the
|
||||
Tcl/Tk/Tix code into the dynamic libraries using the Tcl ET code,
|
||||
or the Tix Stand-Alone-Module code. Of course, you can also simply
|
||||
require that Tcl/Tk is required on the target installation, but be
|
||||
careful that the version corresponds.
|
||||
|
||||
There are some caveats using frozen Tkinter applications:
|
||||
Under Windows if you use the -s windows option, writing
|
||||
to stdout or stderr is an error.
|
||||
The Tcl [info nameofexecutable] will be set to where the
|
||||
program was frozen, not where it is run from.
|
||||
The global variables argc and argv do not exist.
|
||||
|
||||
|
||||
A warning about shared library modules
|
||||
--------------------------------------
|
||||
|
||||
When your Python installation uses shared library modules such as
|
||||
_tkinter.pyd, these will not be incorporated in the frozen program.
|
||||
Again, the frozen program will work when you test it, but it won't
|
||||
work when you ship it to a site without a Python installation.
|
||||
|
||||
Freeze prints a warning when this is the case at the end of the
|
||||
freezing process:
|
||||
|
||||
Warning: unknown modules remain: ...
|
||||
|
||||
When this occurs, the best thing to do is usually to rebuild Python
|
||||
using static linking only. Or use the approach described in the previous
|
||||
section to declare a library path using sys.path, and place the modules
|
||||
such as _tkinter.pyd there.
|
||||
|
||||
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
If you have trouble using Freeze for a large program, it's probably
|
||||
best to start playing with a really simple program first (like the file
|
||||
hello.py). If you can't get that to work there's something
|
||||
fundamentally wrong -- perhaps you haven't installed Python. To do a
|
||||
proper install, you should do "make install" in the Python root
|
||||
directory.
|
||||
|
||||
|
||||
Usage under Windows 95 or NT
|
||||
----------------------------
|
||||
|
||||
Under Windows 95 or NT, you *must* use the -p option and point it to
|
||||
the top of the Python source tree.
|
||||
|
||||
WARNING: the resulting executable is not self-contained; it requires
|
||||
the Python DLL, currently PYTHON20.DLL (it does not require the
|
||||
standard library of .py files though). It may also require one or
|
||||
more extension modules loaded from .DLL or .PYD files; the module
|
||||
names are printed in the warning message about remaining unknown
|
||||
modules.
|
||||
|
||||
The driver script generates a Makefile that works with the Microsoft
|
||||
command line C compiler (CL). To compile, run "nmake"; this will
|
||||
build a target "hello.exe" if the source was "hello.py". Only the
|
||||
files frozenmain.c and frozen.c are used; no config.c is generated or
|
||||
used, since the standard DLL is used.
|
||||
|
||||
In order for this to work, you must have built Python using the VC++
|
||||
(Developer Studio) 5.0 compiler. The provided project builds
|
||||
python20.lib in the subdirectory pcbuild\Release of thje Python source
|
||||
tree, and this is where the generated Makefile expects it to be. If
|
||||
this is not the case, you can edit the Makefile or (probably better)
|
||||
winmakemakefile.py (e.g., if you are using the 4.2 compiler, the
|
||||
python20.lib file is generated in the subdirectory vc40 of the Python
|
||||
source tree).
|
||||
|
||||
It is possible to create frozen programs that don't have a console
|
||||
window, by specifying the option '-s windows'. See the Usage below.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Here is a list of all of the options (taken from freeze.__doc__):
|
||||
|
||||
usage: freeze [options...] script [module]...
|
||||
|
||||
Options:
|
||||
-p prefix: This is the prefix used when you ran ``make install''
|
||||
in the Python build directory.
|
||||
(If you never ran this, freeze won't work.)
|
||||
The default is whatever sys.prefix evaluates to.
|
||||
It can also be the top directory of the Python source
|
||||
tree; then -P must point to the build tree.
|
||||
|
||||
-P exec_prefix: Like -p but this is the 'exec_prefix', used to
|
||||
install objects etc. The default is whatever sys.exec_prefix
|
||||
evaluates to, or the -p argument if given.
|
||||
If -p points to the Python source tree, -P must point
|
||||
to the build tree, if different.
|
||||
|
||||
-e extension: A directory containing additional .o files that
|
||||
may be used to resolve modules. This directory
|
||||
should also have a Setup file describing the .o files.
|
||||
On Windows, the name of a .INI file describing one
|
||||
or more extensions is passed.
|
||||
More than one -e option may be given.
|
||||
|
||||
-o dir: Directory where the output files are created; default '.'.
|
||||
|
||||
-m: Additional arguments are module names instead of filenames.
|
||||
|
||||
-a package=dir: Additional directories to be added to the package's
|
||||
__path__. Used to simulate directories added by the
|
||||
package at runtime (eg, by OpenGL and win32com).
|
||||
More than one -a option may be given for each package.
|
||||
|
||||
-l file: Pass the file to the linker (windows only)
|
||||
|
||||
-d: Debugging mode for the module finder.
|
||||
|
||||
-q: Make the module finder totally quiet.
|
||||
|
||||
-h: Print this help message.
|
||||
|
||||
-x module Exclude the specified module.
|
||||
|
||||
-i filename: Include a file with additional command line options. Used
|
||||
to prevent command lines growing beyond the capabilities of
|
||||
the shell/OS. All arguments specified in filename
|
||||
are read and the -i option replaced with the parsed
|
||||
params (note - quoting args in this file is NOT supported)
|
||||
|
||||
-s subsystem: Specify the subsystem (For Windows only.);
|
||||
'console' (default), 'windows', 'service' or 'com_dll'
|
||||
|
||||
-w: Toggle Windows (NT or 95) behavior.
|
||||
(For debugging only -- on a win32 platform, win32 behavior
|
||||
is automatic.)
|
||||
|
||||
Arguments:
|
||||
|
||||
script: The Python script to be executed by the resulting binary.
|
||||
|
||||
module ...: Additional Python modules (referenced by pathname)
|
||||
that will be included in the resulting binary. These
|
||||
may be .py or .pyc files. If -m is specified, these are
|
||||
module names that are search in the path instead.
|
||||
|
||||
|
||||
|
||||
--Guido van Rossum (home page: http://www.python.org/~guido/)
|
26
third_party/python/Tools/freeze/bkfile.py
vendored
Normal file
26
third_party/python/Tools/freeze/bkfile.py
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
from builtins import open as _orig_open
|
||||
|
||||
def open(file, mode='r', bufsize=-1):
|
||||
if 'w' not in mode:
|
||||
return _orig_open(file, mode, bufsize)
|
||||
import os
|
||||
backup = file + '~'
|
||||
try:
|
||||
os.unlink(backup)
|
||||
except OSError:
|
||||
pass
|
||||
try:
|
||||
os.rename(file, backup)
|
||||
except OSError:
|
||||
return _orig_open(file, mode, bufsize)
|
||||
f = _orig_open(file, mode, bufsize)
|
||||
_orig_close = f.close
|
||||
def close():
|
||||
_orig_close()
|
||||
import filecmp
|
||||
if filecmp.cmp(backup, file, shallow=False):
|
||||
import os
|
||||
os.unlink(file)
|
||||
os.rename(backup, file)
|
||||
f.close = close
|
||||
return f
|
90
third_party/python/Tools/freeze/checkextensions.py
vendored
Normal file
90
third_party/python/Tools/freeze/checkextensions.py
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
# Check for a module in a set of extension directories.
|
||||
# An extension directory should contain a Setup file
|
||||
# and one or more .o files or a lib.a file.
|
||||
|
||||
import os
|
||||
import parsesetup
|
||||
|
||||
def checkextensions(unknown, extensions):
|
||||
files = []
|
||||
modules = []
|
||||
edict = {}
|
||||
for e in extensions:
|
||||
setup = os.path.join(e, 'Setup')
|
||||
liba = os.path.join(e, 'lib.a')
|
||||
if not os.path.isfile(liba):
|
||||
liba = None
|
||||
edict[e] = parsesetup.getsetupinfo(setup), liba
|
||||
for mod in unknown:
|
||||
for e in extensions:
|
||||
(mods, vars), liba = edict[e]
|
||||
if mod not in mods:
|
||||
continue
|
||||
modules.append(mod)
|
||||
if liba:
|
||||
# If we find a lib.a, use it, ignore the
|
||||
# .o files, and use *all* libraries for
|
||||
# *all* modules in the Setup file
|
||||
if liba in files:
|
||||
break
|
||||
files.append(liba)
|
||||
for m in list(mods.keys()):
|
||||
files = files + select(e, mods, vars,
|
||||
m, 1)
|
||||
break
|
||||
files = files + select(e, mods, vars, mod, 0)
|
||||
break
|
||||
return files, modules
|
||||
|
||||
def select(e, mods, vars, mod, skipofiles):
|
||||
files = []
|
||||
for w in mods[mod]:
|
||||
w = treatword(w)
|
||||
if not w:
|
||||
continue
|
||||
w = expandvars(w, vars)
|
||||
for w in w.split():
|
||||
if skipofiles and w[-2:] == '.o':
|
||||
continue
|
||||
# Assume $var expands to absolute pathname
|
||||
if w[0] not in ('-', '$') and w[-2:] in ('.o', '.a'):
|
||||
w = os.path.join(e, w)
|
||||
if w[:2] in ('-L', '-R') and w[2:3] != '$':
|
||||
w = w[:2] + os.path.join(e, w[2:])
|
||||
files.append(w)
|
||||
return files
|
||||
|
||||
cc_flags = ['-I', '-D', '-U']
|
||||
cc_exts = ['.c', '.C', '.cc', '.c++']
|
||||
|
||||
def treatword(w):
|
||||
if w[:2] in cc_flags:
|
||||
return None
|
||||
if w[:1] == '-':
|
||||
return w # Assume loader flag
|
||||
head, tail = os.path.split(w)
|
||||
base, ext = os.path.splitext(tail)
|
||||
if ext in cc_exts:
|
||||
tail = base + '.o'
|
||||
w = os.path.join(head, tail)
|
||||
return w
|
||||
|
||||
def expandvars(str, vars):
|
||||
i = 0
|
||||
while i < len(str):
|
||||
i = k = str.find('$', i)
|
||||
if i < 0:
|
||||
break
|
||||
i = i+1
|
||||
var = str[i:i+1]
|
||||
i = i+1
|
||||
if var == '(':
|
||||
j = str.find(')', i)
|
||||
if j < 0:
|
||||
break
|
||||
var = str[i:j]
|
||||
i = j+1
|
||||
if var in vars:
|
||||
str = str[:k] + vars[var] + str[i:]
|
||||
i = k
|
||||
return str
|
188
third_party/python/Tools/freeze/checkextensions_win32.py
vendored
Normal file
188
third_party/python/Tools/freeze/checkextensions_win32.py
vendored
Normal file
|
@ -0,0 +1,188 @@
|
|||
"""Extension management for Windows.
|
||||
|
||||
Under Windows it is unlikely the .obj files are of use, as special compiler options
|
||||
are needed (primarily to toggle the behavior of "public" symbols.
|
||||
|
||||
I don't consider it worth parsing the MSVC makefiles for compiler options. Even if
|
||||
we get it just right, a specific freeze application may have specific compiler
|
||||
options anyway (eg, to enable or disable specific functionality)
|
||||
|
||||
So my basic strategy is:
|
||||
|
||||
* Have some Windows INI files which "describe" one or more extension modules.
|
||||
(Freeze comes with a default one for all known modules - but you can specify
|
||||
your own).
|
||||
* This description can include:
|
||||
- The MSVC .dsp file for the extension. The .c source file names
|
||||
are extracted from there.
|
||||
- Specific compiler/linker options
|
||||
- Flag to indicate if Unicode compilation is expected.
|
||||
|
||||
At the moment the name and location of this INI file is hardcoded,
|
||||
but an obvious enhancement would be to provide command line options.
|
||||
"""
|
||||
|
||||
import os, sys
|
||||
try:
|
||||
import win32api
|
||||
except ImportError:
|
||||
win32api = None # User has already been warned
|
||||
|
||||
class CExtension:
|
||||
"""An abstraction of an extension implemented in C/C++
|
||||
"""
|
||||
def __init__(self, name, sourceFiles):
|
||||
self.name = name
|
||||
# A list of strings defining additional compiler options.
|
||||
self.sourceFiles = sourceFiles
|
||||
# A list of special compiler options to be applied to
|
||||
# all source modules in this extension.
|
||||
self.compilerOptions = []
|
||||
# A list of .lib files the final .EXE will need.
|
||||
self.linkerLibs = []
|
||||
|
||||
def GetSourceFiles(self):
|
||||
return self.sourceFiles
|
||||
|
||||
def AddCompilerOption(self, option):
|
||||
self.compilerOptions.append(option)
|
||||
def GetCompilerOptions(self):
|
||||
return self.compilerOptions
|
||||
|
||||
def AddLinkerLib(self, lib):
|
||||
self.linkerLibs.append(lib)
|
||||
def GetLinkerLibs(self):
|
||||
return self.linkerLibs
|
||||
|
||||
def checkextensions(unknown, extra_inis, prefix):
|
||||
# Create a table of frozen extensions
|
||||
|
||||
defaultMapName = os.path.join( os.path.split(sys.argv[0])[0], "extensions_win32.ini")
|
||||
if not os.path.isfile(defaultMapName):
|
||||
sys.stderr.write("WARNING: %s can not be found - standard extensions may not be found\n" % defaultMapName)
|
||||
else:
|
||||
# must go on end, so other inis can override.
|
||||
extra_inis.append(defaultMapName)
|
||||
|
||||
ret = []
|
||||
for mod in unknown:
|
||||
for ini in extra_inis:
|
||||
# print "Looking for", mod, "in", win32api.GetFullPathName(ini),"...",
|
||||
defn = get_extension_defn( mod, ini, prefix )
|
||||
if defn is not None:
|
||||
# print "Yay - found it!"
|
||||
ret.append( defn )
|
||||
break
|
||||
# print "Nope!"
|
||||
else: # For not broken!
|
||||
sys.stderr.write("No definition of module %s in any specified map file.\n" % (mod))
|
||||
|
||||
return ret
|
||||
|
||||
def get_extension_defn(moduleName, mapFileName, prefix):
|
||||
if win32api is None: return None
|
||||
os.environ['PYTHONPREFIX'] = prefix
|
||||
dsp = win32api.GetProfileVal(moduleName, "dsp", "", mapFileName)
|
||||
if dsp=="":
|
||||
return None
|
||||
|
||||
# We allow environment variables in the file name
|
||||
dsp = win32api.ExpandEnvironmentStrings(dsp)
|
||||
# If the path to the .DSP file is not absolute, assume it is relative
|
||||
# to the description file.
|
||||
if not os.path.isabs(dsp):
|
||||
dsp = os.path.join( os.path.split(mapFileName)[0], dsp)
|
||||
# Parse it to extract the source files.
|
||||
sourceFiles = parse_dsp(dsp)
|
||||
if sourceFiles is None:
|
||||
return None
|
||||
|
||||
module = CExtension(moduleName, sourceFiles)
|
||||
# Put the path to the DSP into the environment so entries can reference it.
|
||||
os.environ['dsp_path'] = os.path.split(dsp)[0]
|
||||
os.environ['ini_path'] = os.path.split(mapFileName)[0]
|
||||
|
||||
cl_options = win32api.GetProfileVal(moduleName, "cl", "", mapFileName)
|
||||
if cl_options:
|
||||
module.AddCompilerOption(win32api.ExpandEnvironmentStrings(cl_options))
|
||||
|
||||
exclude = win32api.GetProfileVal(moduleName, "exclude", "", mapFileName)
|
||||
exclude = exclude.split()
|
||||
|
||||
if win32api.GetProfileVal(moduleName, "Unicode", 0, mapFileName):
|
||||
module.AddCompilerOption('/D UNICODE /D _UNICODE')
|
||||
|
||||
libs = win32api.GetProfileVal(moduleName, "libs", "", mapFileName).split()
|
||||
for lib in libs:
|
||||
module.AddLinkerLib(win32api.ExpandEnvironmentStrings(lib))
|
||||
|
||||
for exc in exclude:
|
||||
if exc in module.sourceFiles:
|
||||
module.sourceFiles.remove(exc)
|
||||
|
||||
return module
|
||||
|
||||
# Given an MSVC DSP file, locate C source files it uses
|
||||
# returns a list of source files.
|
||||
def parse_dsp(dsp):
|
||||
# print "Processing", dsp
|
||||
# For now, only support
|
||||
ret = []
|
||||
dsp_path, dsp_name = os.path.split(dsp)
|
||||
try:
|
||||
lines = open(dsp, "r").readlines()
|
||||
except IOError as msg:
|
||||
sys.stderr.write("%s: %s\n" % (dsp, msg))
|
||||
return None
|
||||
for line in lines:
|
||||
fields = line.strip().split("=", 2)
|
||||
if fields[0]=="SOURCE":
|
||||
if os.path.splitext(fields[1])[1].lower() in ['.cpp', '.c']:
|
||||
ret.append( win32api.GetFullPathName(os.path.join(dsp_path, fields[1] ) ) )
|
||||
return ret
|
||||
|
||||
def write_extension_table(fname, modules):
|
||||
fp = open(fname, "w")
|
||||
try:
|
||||
fp.write (ext_src_header)
|
||||
# Write fn protos
|
||||
for module in modules:
|
||||
# bit of a hack for .pyd's as part of packages.
|
||||
name = module.name.split('.')[-1]
|
||||
fp.write('extern void init%s(void);\n' % (name) )
|
||||
# Write the table
|
||||
fp.write (ext_tab_header)
|
||||
for module in modules:
|
||||
name = module.name.split('.')[-1]
|
||||
fp.write('\t{"%s", init%s},\n' % (name, name) )
|
||||
|
||||
fp.write (ext_tab_footer)
|
||||
fp.write(ext_src_footer)
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
|
||||
ext_src_header = """\
|
||||
#include "Python.h"
|
||||
"""
|
||||
|
||||
ext_tab_header = """\
|
||||
|
||||
static struct _inittab extensions[] = {
|
||||
"""
|
||||
|
||||
ext_tab_footer = """\
|
||||
/* Sentinel */
|
||||
{0, 0}
|
||||
};
|
||||
"""
|
||||
|
||||
ext_src_footer = """\
|
||||
extern DL_IMPORT(int) PyImport_ExtendInittab(struct _inittab *newtab);
|
||||
|
||||
int PyInitFrozenExtensions()
|
||||
{
|
||||
return PyImport_ExtendInittab(extensions);
|
||||
}
|
||||
|
||||
"""
|
171
third_party/python/Tools/freeze/extensions_win32.ini
vendored
Normal file
171
third_party/python/Tools/freeze/extensions_win32.ini
vendored
Normal file
|
@ -0,0 +1,171 @@
|
|||
; This is a list of modules generally build as .pyd files.
|
||||
;
|
||||
; Each section contains enough information about a module for
|
||||
; freeze to include the module as a static, built-in module
|
||||
; in a frozen .EXE/.DLL.
|
||||
|
||||
; This is all setup for all the win32 extension modules
|
||||
; released by Mark Hammond.
|
||||
; You must ensure that the environment variable PYTHONEX is set
|
||||
; to point to the root win32 extensions directory
|
||||
|
||||
; PYTHONPREFIX must point to the Python build root directory
|
||||
; (the *parent* of PCbuild); normally the freeze script takes
|
||||
; care of this.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
;--------------------------------------------------------------
|
||||
;
|
||||
; Standard Python extension modules
|
||||
;
|
||||
|
||||
; Here are some of the standard Python extensions modules.
|
||||
; If you need others, add them here
|
||||
|
||||
[_socket]
|
||||
dsp=%PYTHONPREFIX%\PCBuild\_socket.dsp
|
||||
|
||||
[_sre]
|
||||
dsp=%PYTHONPREFIX%\PCBuild\_sre.dsp
|
||||
|
||||
[unicodedata]
|
||||
dsp=%PYTHONPREFIX%\PCBuild\unicodedata.dsp
|
||||
|
||||
[mmap]
|
||||
dsp=%PYTHONPREFIX%\PCBuild\mmap.dsp
|
||||
|
||||
[winsound]
|
||||
dsp=%PYTHONPREFIX%\PCBuild\winsound.dsp
|
||||
libs=winmm.lib
|
||||
|
||||
[parser]
|
||||
dsp=%PYTHONPREFIX%\PCBuild\parser.dsp
|
||||
|
||||
[select]
|
||||
dsp=%PYTHONPREFIX%\PCBuild\select.dsp
|
||||
|
||||
[zlib]
|
||||
dsp=%PYTHONPREFIX%\PCBuild\zlib.dsp
|
||||
cl=/I %PYTHONPREFIX%\..\zlib-1.1.4 /D _WINDOWS /D WIN32
|
||||
libs=%PYTHONPREFIX%\..\zlib-1.1.4\zlib.lib /nodefaultlib:libc
|
||||
|
||||
[winreg]
|
||||
dsp=%PYTHONPREFIX%\PCBuild\winreg.dsp
|
||||
libs=advapi32.lib
|
||||
|
||||
|
||||
;--------------------------------------------------------------
|
||||
;
|
||||
; Win32 Projects.
|
||||
;
|
||||
[perfmon]
|
||||
dsp=%PYTHONEX%\win32\perfmon.dsp
|
||||
cl=/I %PYTHONEX%\win32\src
|
||||
Unicode=1
|
||||
|
||||
[pywintypes]
|
||||
dsp=%PYTHONEX%\win32\pywintypes.dsp
|
||||
cl=/I %PYTHONEX%\win32\src
|
||||
libs=ole32.lib oleaut32.lib
|
||||
|
||||
[win32api]
|
||||
dsp=%PYTHONEX%\win32\win32api.dsp
|
||||
cl=/I %PYTHONEX%\win32\src
|
||||
libs=kernel32.lib user32.lib shell32.lib advapi32.lib
|
||||
|
||||
[win32service]
|
||||
dsp=%PYTHONEX%\win32\win32service.dsp
|
||||
cl=/I %PYTHONEX%\win32\src
|
||||
Unicode=1
|
||||
libs=advapi32.lib
|
||||
|
||||
[win32evtlog]
|
||||
dsp=%PYTHONEX%\win32\win32evtlog.dsp
|
||||
cl=/I %PYTHONEX%\win32\src
|
||||
|
||||
[win32process]
|
||||
dsp=%PYTHONEX%\win32\win32process.dsp
|
||||
cl=/I %PYTHONEX%\win32\src
|
||||
|
||||
[win32event]
|
||||
dsp=%PYTHONEX%\win32\win32event.dsp
|
||||
cl=/I %PYTHONEX%\win32\src
|
||||
|
||||
[win32file]
|
||||
dsp=%PYTHONEX%\win32\win32file.dsp
|
||||
cl=/I %PYTHONEX%\win32\src
|
||||
|
||||
[win32net]
|
||||
dsp=%PYTHONEX%\win32\win32net.dsp
|
||||
cl=/I %PYTHONEX%\win32\src
|
||||
libs=netapi32.lib
|
||||
|
||||
[win32pdh]
|
||||
dsp=%PYTHONEX%\win32\win32pdh.dsp
|
||||
cl=/I %PYTHONEX%\win32\src
|
||||
|
||||
[win32pipe]
|
||||
dsp=%PYTHONEX%\win32\win32pipe.dsp
|
||||
cl=/I %PYTHONEX%\win32\src
|
||||
|
||||
[win32security]
|
||||
dsp=%PYTHONEX%\win32\win32security.dsp
|
||||
cl=/I %PYTHONEX%\win32\src
|
||||
|
||||
[win32service]
|
||||
dsp=%PYTHONEX%\win32\win32service.dsp
|
||||
cl=/I %PYTHONEX%\win32\src
|
||||
|
||||
[win32trace]
|
||||
dsp=%PYTHONEX%\win32\win32trace.dsp
|
||||
cl=/I %PYTHONEX%\win32\src
|
||||
|
||||
;--------------------------------------------------------------
|
||||
;
|
||||
; COM Projects.
|
||||
;
|
||||
|
||||
[pythoncom]
|
||||
dsp=%PYTHONEX%\com\win32com.dsp
|
||||
cl=/I %PYTHONEX%\com\win32com\src\include /I %PYTHONEX%\win32\src
|
||||
libs=uuid.lib
|
||||
|
||||
[win32com.axcontrol.axcontrol]
|
||||
dsp=%PYTHONEX%\com\axcontrol.dsp
|
||||
cl=/I %PYTHONEX%\win32\src /I %PYTHONEX%\com\win32com\src\include
|
||||
|
||||
[win32com.axscript.axscript]
|
||||
dsp=%PYTHONEX%\com\Active Scripting.dsp
|
||||
cl=/I %PYTHONEX%\win32\src /I %PYTHONEX%\com\win32com\src\include
|
||||
|
||||
[win32com.axdebug.axdebug]
|
||||
dsp=%PYTHONEX%\com\Active Debugging.dsp
|
||||
cl=/I %PYTHONEX%\win32\src /I %PYTHONEX%\com\win32com\src\include
|
||||
|
||||
[win32com.mapi.mapi]
|
||||
dsp=%PYTHONEX%\com\mapi.dsp
|
||||
cl=/I %PYTHONEX%\win32\src /I %PYTHONEX%\com\win32com\src\include
|
||||
libs=MBLOGON.lib ADDRLKUP.LIB mapi32.lib version.lib
|
||||
|
||||
[win32com.mapi.exchange]
|
||||
dsp=%PYTHONEX%\com\exchange.dsp
|
||||
cl=/I %PYTHONEX%\win32\src /I %PYTHONEX%\com\win32com\src\include
|
||||
libs=MBLOGON.lib ADDRLKUP.LIB exchinst.lib EDKCFG.LIB EDKUTILS.LIB EDKMAPI.LIB mapi32.lib version.lib
|
||||
|
||||
[win32com.mapi.exchdapi]
|
||||
dsp=%PYTHONEX%\com\exchdapi.dsp
|
||||
cl=/I %PYTHONEX%\win32\src /I %PYTHONEX%\com\win32com\src\include
|
||||
libs=DAPI.LIB
|
||||
|
||||
[servicemanager]
|
||||
dsp=%PYTHONEX%\win32\PythonService EXE.dsp
|
||||
Unicode = 1
|
||||
|
||||
; Pythonwin
|
||||
[win32ui]
|
||||
dsp=%PYTHONEX%\Pythonwin\win32ui.dsp
|
||||
cl=/D _AFXDLL /D FREEZE_WIN32UI /GX /I %PYTHONEX%\win32\src
|
||||
libs=mfc42.lib
|
2
third_party/python/Tools/freeze/flag.py
vendored
Normal file
2
third_party/python/Tools/freeze/flag.py
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
initialized = True
|
||||
print("Hello world!")
|
491
third_party/python/Tools/freeze/freeze.py
vendored
Executable file
491
third_party/python/Tools/freeze/freeze.py
vendored
Executable file
|
@ -0,0 +1,491 @@
|
|||
#! /usr/bin/env python3
|
||||
|
||||
"""Freeze a Python script into a binary.
|
||||
|
||||
usage: freeze [options...] script [module]...
|
||||
|
||||
Options:
|
||||
-p prefix: This is the prefix used when you ran ``make install''
|
||||
in the Python build directory.
|
||||
(If you never ran this, freeze won't work.)
|
||||
The default is whatever sys.prefix evaluates to.
|
||||
It can also be the top directory of the Python source
|
||||
tree; then -P must point to the build tree.
|
||||
|
||||
-P exec_prefix: Like -p but this is the 'exec_prefix', used to
|
||||
install objects etc. The default is whatever sys.exec_prefix
|
||||
evaluates to, or the -p argument if given.
|
||||
If -p points to the Python source tree, -P must point
|
||||
to the build tree, if different.
|
||||
|
||||
-e extension: A directory containing additional .o files that
|
||||
may be used to resolve modules. This directory
|
||||
should also have a Setup file describing the .o files.
|
||||
On Windows, the name of a .INI file describing one
|
||||
or more extensions is passed.
|
||||
More than one -e option may be given.
|
||||
|
||||
-o dir: Directory where the output files are created; default '.'.
|
||||
|
||||
-m: Additional arguments are module names instead of filenames.
|
||||
|
||||
-a package=dir: Additional directories to be added to the package's
|
||||
__path__. Used to simulate directories added by the
|
||||
package at runtime (eg, by OpenGL and win32com).
|
||||
More than one -a option may be given for each package.
|
||||
|
||||
-l file: Pass the file to the linker (windows only)
|
||||
|
||||
-d: Debugging mode for the module finder.
|
||||
|
||||
-q: Make the module finder totally quiet.
|
||||
|
||||
-h: Print this help message.
|
||||
|
||||
-x module Exclude the specified module. It will still be imported
|
||||
by the frozen binary if it exists on the host system.
|
||||
|
||||
-X module Like -x, except the module can never be imported by
|
||||
the frozen binary.
|
||||
|
||||
-E: Freeze will fail if any modules can't be found (that
|
||||
were not excluded using -x or -X).
|
||||
|
||||
-i filename: Include a file with additional command line options. Used
|
||||
to prevent command lines growing beyond the capabilities of
|
||||
the shell/OS. All arguments specified in filename
|
||||
are read and the -i option replaced with the parsed
|
||||
params (note - quoting args in this file is NOT supported)
|
||||
|
||||
-s subsystem: Specify the subsystem (For Windows only.);
|
||||
'console' (default), 'windows', 'service' or 'com_dll'
|
||||
|
||||
-w: Toggle Windows (NT or 95) behavior.
|
||||
(For debugging only -- on a win32 platform, win32 behavior
|
||||
is automatic.)
|
||||
|
||||
-r prefix=f: Replace path prefix.
|
||||
Replace prefix with f in the source path references
|
||||
contained in the resulting binary.
|
||||
|
||||
Arguments:
|
||||
|
||||
script: The Python script to be executed by the resulting binary.
|
||||
|
||||
module ...: Additional Python modules (referenced by pathname)
|
||||
that will be included in the resulting binary. These
|
||||
may be .py or .pyc files. If -m is specified, these are
|
||||
module names that are search in the path instead.
|
||||
|
||||
NOTES:
|
||||
|
||||
In order to use freeze successfully, you must have built Python and
|
||||
installed it ("make install").
|
||||
|
||||
The script should not use modules provided only as shared libraries;
|
||||
if it does, the resulting binary is not self-contained.
|
||||
"""
|
||||
|
||||
|
||||
# Import standard modules
|
||||
|
||||
import modulefinder
|
||||
import getopt
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
# Import the freeze-private modules
|
||||
|
||||
import checkextensions
|
||||
import makeconfig
|
||||
import makefreeze
|
||||
import makemakefile
|
||||
import parsesetup
|
||||
import bkfile
|
||||
|
||||
|
||||
# Main program
|
||||
|
||||
def main():
|
||||
# overridable context
|
||||
prefix = None # settable with -p option
|
||||
exec_prefix = None # settable with -P option
|
||||
extensions = []
|
||||
exclude = [] # settable with -x option
|
||||
addn_link = [] # settable with -l, but only honored under Windows.
|
||||
path = sys.path[:]
|
||||
modargs = 0
|
||||
debug = 1
|
||||
odir = ''
|
||||
win = sys.platform[:3] == 'win'
|
||||
replace_paths = [] # settable with -r option
|
||||
error_if_any_missing = 0
|
||||
|
||||
# default the exclude list for each platform
|
||||
if win: exclude = exclude + [
|
||||
'dos', 'dospath', 'mac', 'macpath', 'macfs', 'MACFS', 'posix', ]
|
||||
|
||||
fail_import = exclude[:]
|
||||
|
||||
# output files
|
||||
frozen_c = 'frozen.c'
|
||||
config_c = 'config.c'
|
||||
target = 'a.out' # normally derived from script name
|
||||
makefile = 'Makefile'
|
||||
subsystem = 'console'
|
||||
|
||||
# parse command line by first replacing any "-i" options with the
|
||||
# file contents.
|
||||
pos = 1
|
||||
while pos < len(sys.argv)-1:
|
||||
# last option can not be "-i", so this ensures "pos+1" is in range!
|
||||
if sys.argv[pos] == '-i':
|
||||
try:
|
||||
options = open(sys.argv[pos+1]).read().split()
|
||||
except IOError as why:
|
||||
usage("File name '%s' specified with the -i option "
|
||||
"can not be read - %s" % (sys.argv[pos+1], why) )
|
||||
# Replace the '-i' and the filename with the read params.
|
||||
sys.argv[pos:pos+2] = options
|
||||
pos = pos + len(options) - 1 # Skip the name and the included args.
|
||||
pos = pos + 1
|
||||
|
||||
# Now parse the command line with the extras inserted.
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'r:a:dEe:hmo:p:P:qs:wX:x:l:')
|
||||
except getopt.error as msg:
|
||||
usage('getopt error: ' + str(msg))
|
||||
|
||||
# process option arguments
|
||||
for o, a in opts:
|
||||
if o == '-h':
|
||||
print(__doc__)
|
||||
return
|
||||
if o == '-d':
|
||||
debug = debug + 1
|
||||
if o == '-e':
|
||||
extensions.append(a)
|
||||
if o == '-m':
|
||||
modargs = 1
|
||||
if o == '-o':
|
||||
odir = a
|
||||
if o == '-p':
|
||||
prefix = a
|
||||
if o == '-P':
|
||||
exec_prefix = a
|
||||
if o == '-q':
|
||||
debug = 0
|
||||
if o == '-w':
|
||||
win = not win
|
||||
if o == '-s':
|
||||
if not win:
|
||||
usage("-s subsystem option only on Windows")
|
||||
subsystem = a
|
||||
if o == '-x':
|
||||
exclude.append(a)
|
||||
if o == '-X':
|
||||
exclude.append(a)
|
||||
fail_import.append(a)
|
||||
if o == '-E':
|
||||
error_if_any_missing = 1
|
||||
if o == '-l':
|
||||
addn_link.append(a)
|
||||
if o == '-a':
|
||||
modulefinder.AddPackagePath(*a.split("=", 2))
|
||||
if o == '-r':
|
||||
f,r = a.split("=", 2)
|
||||
replace_paths.append( (f,r) )
|
||||
|
||||
# modules that are imported by the Python runtime
|
||||
implicits = []
|
||||
for module in ('site', 'warnings', 'encodings.utf_8', 'encodings.latin_1'):
|
||||
if module not in exclude:
|
||||
implicits.append(module)
|
||||
|
||||
# default prefix and exec_prefix
|
||||
if not exec_prefix:
|
||||
if prefix:
|
||||
exec_prefix = prefix
|
||||
else:
|
||||
exec_prefix = sys.exec_prefix
|
||||
if not prefix:
|
||||
prefix = sys.prefix
|
||||
|
||||
# determine whether -p points to the Python source tree
|
||||
ishome = os.path.exists(os.path.join(prefix, 'Python', 'ceval.c'))
|
||||
|
||||
# locations derived from options
|
||||
version = '%d.%d' % sys.version_info[:2]
|
||||
flagged_version = version + sys.abiflags
|
||||
if win:
|
||||
extensions_c = 'frozen_extensions.c'
|
||||
if ishome:
|
||||
print("(Using Python source directory)")
|
||||
binlib = exec_prefix
|
||||
incldir = os.path.join(prefix, 'Include')
|
||||
config_h_dir = exec_prefix
|
||||
config_c_in = os.path.join(prefix, 'Modules', 'config.c.in')
|
||||
frozenmain_c = os.path.join(prefix, 'Python', 'frozenmain.c')
|
||||
makefile_in = os.path.join(exec_prefix, 'Makefile')
|
||||
if win:
|
||||
frozendllmain_c = os.path.join(exec_prefix, 'Pc\\frozen_dllmain.c')
|
||||
else:
|
||||
binlib = os.path.join(exec_prefix,
|
||||
'lib', 'python%s' % version,
|
||||
'config-%s' % flagged_version)
|
||||
incldir = os.path.join(prefix, 'include', 'python%s' % flagged_version)
|
||||
config_h_dir = os.path.join(exec_prefix, 'include',
|
||||
'python%s' % flagged_version)
|
||||
config_c_in = os.path.join(binlib, 'config.c.in')
|
||||
frozenmain_c = os.path.join(binlib, 'frozenmain.c')
|
||||
makefile_in = os.path.join(binlib, 'Makefile')
|
||||
frozendllmain_c = os.path.join(binlib, 'frozen_dllmain.c')
|
||||
supp_sources = []
|
||||
defines = []
|
||||
includes = ['-I' + incldir, '-I' + config_h_dir]
|
||||
|
||||
# sanity check of directories and files
|
||||
check_dirs = [prefix, exec_prefix, binlib, incldir]
|
||||
if not win:
|
||||
# These are not directories on Windows.
|
||||
check_dirs = check_dirs + extensions
|
||||
for dir in check_dirs:
|
||||
if not os.path.exists(dir):
|
||||
usage('needed directory %s not found' % dir)
|
||||
if not os.path.isdir(dir):
|
||||
usage('%s: not a directory' % dir)
|
||||
if win:
|
||||
files = supp_sources + extensions # extensions are files on Windows.
|
||||
else:
|
||||
files = [config_c_in, makefile_in] + supp_sources
|
||||
for file in supp_sources:
|
||||
if not os.path.exists(file):
|
||||
usage('needed file %s not found' % file)
|
||||
if not os.path.isfile(file):
|
||||
usage('%s: not a plain file' % file)
|
||||
if not win:
|
||||
for dir in extensions:
|
||||
setup = os.path.join(dir, 'Setup')
|
||||
if not os.path.exists(setup):
|
||||
usage('needed file %s not found' % setup)
|
||||
if not os.path.isfile(setup):
|
||||
usage('%s: not a plain file' % setup)
|
||||
|
||||
# check that enough arguments are passed
|
||||
if not args:
|
||||
usage('at least one filename argument required')
|
||||
|
||||
# check that file arguments exist
|
||||
for arg in args:
|
||||
if arg == '-m':
|
||||
break
|
||||
# if user specified -m on the command line before _any_
|
||||
# file names, then nothing should be checked (as the
|
||||
# very first file should be a module name)
|
||||
if modargs:
|
||||
break
|
||||
if not os.path.exists(arg):
|
||||
usage('argument %s not found' % arg)
|
||||
if not os.path.isfile(arg):
|
||||
usage('%s: not a plain file' % arg)
|
||||
|
||||
# process non-option arguments
|
||||
scriptfile = args[0]
|
||||
modules = args[1:]
|
||||
|
||||
# derive target name from script name
|
||||
base = os.path.basename(scriptfile)
|
||||
base, ext = os.path.splitext(base)
|
||||
if base:
|
||||
if base != scriptfile:
|
||||
target = base
|
||||
else:
|
||||
target = base + '.bin'
|
||||
|
||||
# handle -o option
|
||||
base_frozen_c = frozen_c
|
||||
base_config_c = config_c
|
||||
base_target = target
|
||||
if odir and not os.path.isdir(odir):
|
||||
try:
|
||||
os.mkdir(odir)
|
||||
print("Created output directory", odir)
|
||||
except OSError as msg:
|
||||
usage('%s: mkdir failed (%s)' % (odir, str(msg)))
|
||||
base = ''
|
||||
if odir:
|
||||
base = os.path.join(odir, '')
|
||||
frozen_c = os.path.join(odir, frozen_c)
|
||||
config_c = os.path.join(odir, config_c)
|
||||
target = os.path.join(odir, target)
|
||||
makefile = os.path.join(odir, makefile)
|
||||
if win: extensions_c = os.path.join(odir, extensions_c)
|
||||
|
||||
# Handle special entry point requirements
|
||||
# (on Windows, some frozen programs do not use __main__, but
|
||||
# import the module directly. Eg, DLLs, Services, etc
|
||||
custom_entry_point = None # Currently only used on Windows
|
||||
python_entry_is_main = 1 # Is the entry point called __main__?
|
||||
# handle -s option on Windows
|
||||
if win:
|
||||
import winmakemakefile
|
||||
try:
|
||||
custom_entry_point, python_entry_is_main = \
|
||||
winmakemakefile.get_custom_entry_point(subsystem)
|
||||
except ValueError as why:
|
||||
usage(why)
|
||||
|
||||
|
||||
# Actual work starts here...
|
||||
|
||||
# collect all modules of the program
|
||||
dir = os.path.dirname(scriptfile)
|
||||
path[0] = dir
|
||||
mf = modulefinder.ModuleFinder(path, debug, exclude, replace_paths)
|
||||
|
||||
if win and subsystem=='service':
|
||||
# If a Windows service, then add the "built-in" module.
|
||||
mod = mf.add_module("servicemanager")
|
||||
mod.__file__="dummy.pyd" # really built-in to the resulting EXE
|
||||
|
||||
for mod in implicits:
|
||||
mf.import_hook(mod)
|
||||
for mod in modules:
|
||||
if mod == '-m':
|
||||
modargs = 1
|
||||
continue
|
||||
if modargs:
|
||||
if mod[-2:] == '.*':
|
||||
mf.import_hook(mod[:-2], None, ["*"])
|
||||
else:
|
||||
mf.import_hook(mod)
|
||||
else:
|
||||
mf.load_file(mod)
|
||||
|
||||
# Alias "importlib._bootstrap" to "_frozen_importlib" so that the
|
||||
# import machinery can bootstrap. Do the same for
|
||||
# importlib._bootstrap_external.
|
||||
mf.modules["_frozen_importlib"] = mf.modules["importlib._bootstrap"]
|
||||
mf.modules["_frozen_importlib_external"] = mf.modules["importlib._bootstrap_external"]
|
||||
|
||||
# Add the main script as either __main__, or the actual module name.
|
||||
if python_entry_is_main:
|
||||
mf.run_script(scriptfile)
|
||||
else:
|
||||
mf.load_file(scriptfile)
|
||||
|
||||
if debug > 0:
|
||||
mf.report()
|
||||
print()
|
||||
dict = mf.modules
|
||||
|
||||
if error_if_any_missing:
|
||||
missing = mf.any_missing()
|
||||
if missing:
|
||||
sys.exit("There are some missing modules: %r" % missing)
|
||||
|
||||
# generate output for frozen modules
|
||||
files = makefreeze.makefreeze(base, dict, debug, custom_entry_point,
|
||||
fail_import)
|
||||
|
||||
# look for unfrozen modules (builtin and of unknown origin)
|
||||
builtins = []
|
||||
unknown = []
|
||||
mods = sorted(dict.keys())
|
||||
for mod in mods:
|
||||
if dict[mod].__code__:
|
||||
continue
|
||||
if not dict[mod].__file__:
|
||||
builtins.append(mod)
|
||||
else:
|
||||
unknown.append(mod)
|
||||
|
||||
# search for unknown modules in extensions directories (not on Windows)
|
||||
addfiles = []
|
||||
frozen_extensions = [] # Windows list of modules.
|
||||
if unknown or (not win and builtins):
|
||||
if not win:
|
||||
addfiles, addmods = \
|
||||
checkextensions.checkextensions(unknown+builtins,
|
||||
extensions)
|
||||
for mod in addmods:
|
||||
if mod in unknown:
|
||||
unknown.remove(mod)
|
||||
builtins.append(mod)
|
||||
else:
|
||||
# Do the windows thang...
|
||||
import checkextensions_win32
|
||||
# Get a list of CExtension instances, each describing a module
|
||||
# (including its source files)
|
||||
frozen_extensions = checkextensions_win32.checkextensions(
|
||||
unknown, extensions, prefix)
|
||||
for mod in frozen_extensions:
|
||||
unknown.remove(mod.name)
|
||||
|
||||
# report unknown modules
|
||||
if unknown:
|
||||
sys.stderr.write('Warning: unknown modules remain: %s\n' %
|
||||
' '.join(unknown))
|
||||
|
||||
# windows gets different treatment
|
||||
if win:
|
||||
# Taking a shortcut here...
|
||||
import winmakemakefile, checkextensions_win32
|
||||
checkextensions_win32.write_extension_table(extensions_c,
|
||||
frozen_extensions)
|
||||
# Create a module definition for the bootstrap C code.
|
||||
xtras = [frozenmain_c, os.path.basename(frozen_c),
|
||||
frozendllmain_c, os.path.basename(extensions_c)] + files
|
||||
maindefn = checkextensions_win32.CExtension( '__main__', xtras )
|
||||
frozen_extensions.append( maindefn )
|
||||
with open(makefile, 'w') as outfp:
|
||||
winmakemakefile.makemakefile(outfp,
|
||||
locals(),
|
||||
frozen_extensions,
|
||||
os.path.basename(target))
|
||||
return
|
||||
|
||||
# generate config.c and Makefile
|
||||
builtins.sort()
|
||||
with open(config_c_in) as infp, bkfile.open(config_c, 'w') as outfp:
|
||||
makeconfig.makeconfig(infp, outfp, builtins)
|
||||
|
||||
cflags = ['$(OPT)']
|
||||
cppflags = defines + includes
|
||||
libs = [os.path.join(binlib, '$(LDLIBRARY)')]
|
||||
|
||||
somevars = {}
|
||||
if os.path.exists(makefile_in):
|
||||
makevars = parsesetup.getmakevars(makefile_in)
|
||||
for key in makevars:
|
||||
somevars[key] = makevars[key]
|
||||
|
||||
somevars['CFLAGS'] = ' '.join(cflags) # override
|
||||
somevars['CPPFLAGS'] = ' '.join(cppflags) # override
|
||||
files = [base_config_c, base_frozen_c] + \
|
||||
files + supp_sources + addfiles + libs + \
|
||||
['$(MODLIBS)', '$(LIBS)', '$(SYSLIBS)']
|
||||
|
||||
with bkfile.open(makefile, 'w') as outfp:
|
||||
makemakefile.makemakefile(outfp, somevars, files, base_target)
|
||||
|
||||
# Done!
|
||||
|
||||
if odir:
|
||||
print('Now run "make" in', odir, end=' ')
|
||||
print('to build the target:', base_target)
|
||||
else:
|
||||
print('Now run "make" to build the target:', base_target)
|
||||
|
||||
|
||||
# Print usage message and exit
|
||||
|
||||
def usage(msg):
|
||||
sys.stdout = sys.stderr
|
||||
print("Error:", msg)
|
||||
print("Use ``%s -h'' for help" % sys.argv[0])
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
main()
|
1
third_party/python/Tools/freeze/hello.py
vendored
Normal file
1
third_party/python/Tools/freeze/hello.py
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
print('Hello world...')
|
59
third_party/python/Tools/freeze/makeconfig.py
vendored
Normal file
59
third_party/python/Tools/freeze/makeconfig.py
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
import re
|
||||
import sys
|
||||
|
||||
# Write the config.c file
|
||||
|
||||
never = ['marshal', '_imp', '_ast', '__main__', 'builtins',
|
||||
'sys', 'gc', '_warnings']
|
||||
|
||||
def makeconfig(infp, outfp, modules, with_ifdef=0):
|
||||
m1 = re.compile('-- ADDMODULE MARKER 1 --')
|
||||
m2 = re.compile('-- ADDMODULE MARKER 2 --')
|
||||
for line in infp:
|
||||
outfp.write(line)
|
||||
if m1 and m1.search(line):
|
||||
m1 = None
|
||||
for mod in modules:
|
||||
if mod in never:
|
||||
continue
|
||||
if with_ifdef:
|
||||
outfp.write("#ifndef PyInit_%s\n"%mod)
|
||||
outfp.write('extern PyObject* PyInit_%s(void);\n' % mod)
|
||||
if with_ifdef:
|
||||
outfp.write("#endif\n")
|
||||
elif m2 and m2.search(line):
|
||||
m2 = None
|
||||
for mod in modules:
|
||||
if mod in never:
|
||||
continue
|
||||
outfp.write('\t{"%s", PyInit_%s},\n' %
|
||||
(mod, mod))
|
||||
if m1:
|
||||
sys.stderr.write('MARKER 1 never found\n')
|
||||
elif m2:
|
||||
sys.stderr.write('MARKER 2 never found\n')
|
||||
|
||||
|
||||
# Test program.
|
||||
|
||||
def test():
|
||||
if not sys.argv[3:]:
|
||||
print('usage: python makeconfig.py config.c.in outputfile', end=' ')
|
||||
print('modulename ...')
|
||||
sys.exit(2)
|
||||
if sys.argv[1] == '-':
|
||||
infp = sys.stdin
|
||||
else:
|
||||
infp = open(sys.argv[1])
|
||||
if sys.argv[2] == '-':
|
||||
outfp = sys.stdout
|
||||
else:
|
||||
outfp = open(sys.argv[2], 'w')
|
||||
makeconfig(infp, outfp, sys.argv[3:])
|
||||
if outfp != sys.stdout:
|
||||
outfp.close()
|
||||
if infp != sys.stdin:
|
||||
infp.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
test()
|
87
third_party/python/Tools/freeze/makefreeze.py
vendored
Normal file
87
third_party/python/Tools/freeze/makefreeze.py
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
import marshal
|
||||
import bkfile
|
||||
|
||||
|
||||
# Write a file containing frozen code for the modules in the dictionary.
|
||||
|
||||
header = """
|
||||
#include "Python.h"
|
||||
|
||||
static struct _frozen _PyImport_FrozenModules[] = {
|
||||
"""
|
||||
trailer = """\
|
||||
{0, 0, 0} /* sentinel */
|
||||
};
|
||||
"""
|
||||
|
||||
# if __debug__ == 0 (i.e. -O option given), set Py_OptimizeFlag in frozen app.
|
||||
default_entry_point = """
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
extern int Py_FrozenMain(int, char **);
|
||||
""" + ((not __debug__ and """
|
||||
Py_OptimizeFlag++;
|
||||
""") or "") + """
|
||||
PyImport_FrozenModules = _PyImport_FrozenModules;
|
||||
return Py_FrozenMain(argc, argv);
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
def makefreeze(base, dict, debug=0, entry_point=None, fail_import=()):
|
||||
if entry_point is None: entry_point = default_entry_point
|
||||
done = []
|
||||
files = []
|
||||
mods = sorted(dict.keys())
|
||||
for mod in mods:
|
||||
m = dict[mod]
|
||||
mangled = "__".join(mod.split("."))
|
||||
if m.__code__:
|
||||
file = 'M_' + mangled + '.c'
|
||||
with bkfile.open(base + file, 'w') as outfp:
|
||||
files.append(file)
|
||||
if debug:
|
||||
print("freezing", mod, "...")
|
||||
str = marshal.dumps(m.__code__)
|
||||
size = len(str)
|
||||
if m.__path__:
|
||||
# Indicate package by negative size
|
||||
size = -size
|
||||
done.append((mod, mangled, size))
|
||||
writecode(outfp, mangled, str)
|
||||
if debug:
|
||||
print("generating table of frozen modules")
|
||||
with bkfile.open(base + 'frozen.c', 'w') as outfp:
|
||||
for mod, mangled, size in done:
|
||||
outfp.write('extern unsigned char M_%s[];\n' % mangled)
|
||||
outfp.write(header)
|
||||
for mod, mangled, size in done:
|
||||
outfp.write('\t{"%s", M_%s, %d},\n' % (mod, mangled, size))
|
||||
outfp.write('\n')
|
||||
# The following modules have a NULL code pointer, indicating
|
||||
# that the frozen program should not search for them on the host
|
||||
# system. Importing them will *always* raise an ImportError.
|
||||
# The zero value size is never used.
|
||||
for mod in fail_import:
|
||||
outfp.write('\t{"%s", NULL, 0},\n' % (mod,))
|
||||
outfp.write(trailer)
|
||||
outfp.write(entry_point)
|
||||
return files
|
||||
|
||||
|
||||
|
||||
# Write a C initializer for a module containing the frozen python code.
|
||||
# The array is called M_<mod>.
|
||||
|
||||
def writecode(outfp, mod, str):
|
||||
outfp.write('unsigned char M_%s[] = {' % mod)
|
||||
for i in range(0, len(str), 16):
|
||||
outfp.write('\n\t')
|
||||
for c in bytes(str[i:i+16]):
|
||||
outfp.write('%d,' % c)
|
||||
outfp.write('\n};\n')
|
||||
|
||||
## def writecode(outfp, mod, str):
|
||||
## outfp.write('unsigned char M_%s[%d] = "%s";\n' % (mod, len(str),
|
||||
## '\\"'.join(map(lambda s: repr(s)[1:-1], str.split('"')))))
|
28
third_party/python/Tools/freeze/makemakefile.py
vendored
Normal file
28
third_party/python/Tools/freeze/makemakefile.py
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Write the actual Makefile.
|
||||
|
||||
import os
|
||||
|
||||
def makemakefile(outfp, makevars, files, target):
|
||||
outfp.write("# Makefile generated by freeze.py script\n\n")
|
||||
|
||||
keys = sorted(makevars.keys())
|
||||
for key in keys:
|
||||
outfp.write("%s=%s\n" % (key, makevars[key]))
|
||||
outfp.write("\nall: %s\n\n" % target)
|
||||
|
||||
deps = []
|
||||
for i in range(len(files)):
|
||||
file = files[i]
|
||||
if file[-2:] == '.c':
|
||||
base = os.path.basename(file)
|
||||
dest = base[:-2] + '.o'
|
||||
outfp.write("%s: %s\n" % (dest, file))
|
||||
outfp.write("\t$(CC) $(PY_CFLAGS) $(PY_CPPFLAGS) -c %s\n" % file)
|
||||
files[i] = dest
|
||||
deps.append(dest)
|
||||
|
||||
outfp.write("\n%s: %s\n" % (target, ' '.join(deps)))
|
||||
outfp.write("\t$(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) %s -o %s $(LDLAST)\n" %
|
||||
(' '.join(files), target))
|
||||
|
||||
outfp.write("\nclean:\n\t-rm -f *.o %s\n" % target)
|
111
third_party/python/Tools/freeze/parsesetup.py
vendored
Normal file
111
third_party/python/Tools/freeze/parsesetup.py
vendored
Normal file
|
@ -0,0 +1,111 @@
|
|||
# Parse Makefiles and Python Setup(.in) files.
|
||||
|
||||
import re
|
||||
|
||||
|
||||
# Extract variable definitions from a Makefile.
|
||||
# Return a dictionary mapping names to values.
|
||||
# May raise IOError.
|
||||
|
||||
makevardef = re.compile('^([a-zA-Z0-9_]+)[ \t]*=(.*)')
|
||||
|
||||
def getmakevars(filename):
|
||||
variables = {}
|
||||
fp = open(filename)
|
||||
pendingline = ""
|
||||
try:
|
||||
while 1:
|
||||
line = fp.readline()
|
||||
if pendingline:
|
||||
line = pendingline + line
|
||||
pendingline = ""
|
||||
if not line:
|
||||
break
|
||||
if line.endswith('\\\n'):
|
||||
pendingline = line[:-2]
|
||||
matchobj = makevardef.match(line)
|
||||
if not matchobj:
|
||||
continue
|
||||
(name, value) = matchobj.group(1, 2)
|
||||
# Strip trailing comment
|
||||
i = value.find('#')
|
||||
if i >= 0:
|
||||
value = value[:i]
|
||||
value = value.strip()
|
||||
variables[name] = value
|
||||
finally:
|
||||
fp.close()
|
||||
return variables
|
||||
|
||||
|
||||
# Parse a Python Setup(.in) file.
|
||||
# Return two dictionaries, the first mapping modules to their
|
||||
# definitions, the second mapping variable names to their values.
|
||||
# May raise IOError.
|
||||
|
||||
setupvardef = re.compile('^([a-zA-Z0-9_]+)=(.*)')
|
||||
|
||||
def getsetupinfo(filename):
|
||||
modules = {}
|
||||
variables = {}
|
||||
fp = open(filename)
|
||||
pendingline = ""
|
||||
try:
|
||||
while 1:
|
||||
line = fp.readline()
|
||||
if pendingline:
|
||||
line = pendingline + line
|
||||
pendingline = ""
|
||||
if not line:
|
||||
break
|
||||
# Strip comments
|
||||
i = line.find('#')
|
||||
if i >= 0:
|
||||
line = line[:i]
|
||||
if line.endswith('\\\n'):
|
||||
pendingline = line[:-2]
|
||||
continue
|
||||
matchobj = setupvardef.match(line)
|
||||
if matchobj:
|
||||
(name, value) = matchobj.group(1, 2)
|
||||
variables[name] = value.strip()
|
||||
else:
|
||||
words = line.split()
|
||||
if words:
|
||||
modules[words[0]] = words[1:]
|
||||
finally:
|
||||
fp.close()
|
||||
return modules, variables
|
||||
|
||||
|
||||
# Test the above functions.
|
||||
|
||||
def test():
|
||||
import sys
|
||||
import os
|
||||
if not sys.argv[1:]:
|
||||
print('usage: python parsesetup.py Makefile*|Setup* ...')
|
||||
sys.exit(2)
|
||||
for arg in sys.argv[1:]:
|
||||
base = os.path.basename(arg)
|
||||
if base[:8] == 'Makefile':
|
||||
print('Make style parsing:', arg)
|
||||
v = getmakevars(arg)
|
||||
prdict(v)
|
||||
elif base[:5] == 'Setup':
|
||||
print('Setup style parsing:', arg)
|
||||
m, v = getsetupinfo(arg)
|
||||
prdict(m)
|
||||
prdict(v)
|
||||
else:
|
||||
print(arg, 'is neither a Makefile nor a Setup file')
|
||||
print('(name must begin with "Makefile" or "Setup")')
|
||||
|
||||
def prdict(d):
|
||||
keys = sorted(d.keys())
|
||||
for key in keys:
|
||||
value = d[key]
|
||||
print("%-15s" % key, str(value))
|
||||
|
||||
if __name__ == '__main__':
|
||||
test()
|
2
third_party/python/Tools/freeze/test/ok.py
vendored
Normal file
2
third_party/python/Tools/freeze/test/ok.py
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
import sys
|
||||
sys.exit(0)
|
119
third_party/python/Tools/freeze/win32.html
vendored
Normal file
119
third_party/python/Tools/freeze/win32.html
vendored
Normal file
|
@ -0,0 +1,119 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
|
||||
<META NAME="Generator" CONTENT="Microsoft Word 97">
|
||||
<TITLE>win32</TITLE>
|
||||
<META NAME="Version" CONTENT="8.0.3410">
|
||||
<META NAME="Date" CONTENT="10/11/96">
|
||||
<META NAME="Template" CONTENT="D:\Program Files\Microsoft Office\Office\HTML.DOT">
|
||||
</HEAD>
|
||||
<BODY TEXT="#000000" BGCOLOR="#ffffff">
|
||||
|
||||
<H1>Freeze for Win32</H1>
|
||||
<P>This document describes how to use Freeze for the Win32 platform. </P>
|
||||
<P>Freeze itself is a Python tool for creating stand-alone executables from Python source code. This document does not attempt to document freeze itself - only the win32 specific changes.</P>
|
||||
<H2>Frozen programs under Win32</H2>
|
||||
<P>Frozen programs under Win32 can (theoretically) freeze any type of program supported by Python on Win32 - At the moment, Console .EXE and NT Service .EXE programs are supported. GUI Python programs and COM .EXE programs are very nearly all ready to go.</P>
|
||||
<H3>Program Dependencies</H3>
|
||||
<P>The person freezing the program has control over what external DLLs are required by a frozen program. The following dependencies are supported:</P>
|
||||
<H4>Minimal frozen programs</H4>
|
||||
<P>These programs freeze only .py files in your program. All external DLLs are required at run-time. This includes all .pyd/.dll modules used by your program, Python20.dll, and msvcrt.dll. </P>
|
||||
<P>A small Python program would typically create a .EXE around 300kb.</P>
|
||||
<H4>Frozen Extension programs</H4>
|
||||
<B><I><P>Note:</B></I> For Python1.5.1, you must get a patch from Guido to import.c for this to work.</P>
|
||||
<P>These programs also freeze in the sources from all .pyd and .dll files used at runtime. This means the resulting .EXE is only dependent on Python20.dll and msvcrt.dll.</P>
|
||||
<P>A small Python program using win32api, win32con and one or 2 other win32 extensions would typically create a .EXE around 400kb.</P>
|
||||
<H4>Completely frozen programs</H4>
|
||||
<P>Completely stand-alone programs, as is the default on Unix systems. These are currently not supported, mainly as the size of a decent Python program gets very large. However, by tweaking the existing Unix support, this would not be difficult to do.</P>
|
||||
<H2>Freezing Extension Modules</H2>
|
||||
<P>By default, a file in the main "freeze" directory called "extensions_win32.ini" is used to obtain information about frozen extensions. A typical entry is:</P>
|
||||
<CODE><P>[win32api]</P>
|
||||
<P>dsp=%PYTHONEX%\win32\win32api.dsp</P>
|
||||
<P>cl=/I %PYTHONEX%\win32\src</P>
|
||||
<P>libs=kernel32.lib user32.lib shell32.lib advapi32.lib</P>
|
||||
</CODE><P> </P>
|
||||
<P>This entry indicates that the win32api extension module is defined in the MSVC project file "<CODE>%PYTHONEX%\win32\win32api.dsp</CODE>". Note the use of<CODE> </CODE>"<CODE>%PYTHONEX%" </CODE>- most strings are substituted with environment variables. In this case, it is assumed variable PYTHONEX points to the main "Python Extensions" source directory (which is assumed to be in the same structure as the release of the extension sources).</P>
|
||||
<P>An entry in a .INI file can also control specific compiler options, and also the .lib files necessary to be linked with the application.</P>
|
||||
<H3>Freezing Extension Module Considerations</H3>
|
||||
<P>To prevent freezing extension modules, simply exclude that module using the freeze "-x" switch.</P>
|
||||
<P>Occasionally, it will be necessary to explicitly include dependent modules. For example, many win32 modules are dependent on the "pywintypes" module - for example, the win32api module. In this case, the module may be explicitly included using the freeze "-m" option.</P>
|
||||
<H3>Freezing win32com and PythonCOM</H3>
|
||||
<P>PythonCOM.dll can be frozen as long as you are not implementing COM Servers. Ie, you can freeze programs which control other applications, but can not implement programs that are themselves controlled by other applications.</P>
|
||||
<P>If you use any of the win32com .pyd extensions (ex, axscript, mapi, internet, axcontrol), then you will need to specify an additional "-a" option to point to the win32comext directory. There is an example below.</P>
|
||||
<P>The use of the "win32com.client.gencache" module is not supported (although could be quite easily??)</P>
|
||||
<H2>Examples</H2>
|
||||
<P>Before we start, we must:</P>
|
||||
<CODE><P>D:\temp\delme>set PYTHONEX=d:\src\pythonex</P>
|
||||
</CODE><H3>Helloworld.py</H3>
|
||||
<H4>Source Code</H4><DIR>
|
||||
<DIR>
|
||||
|
||||
<CODE><P>import sys</P>
|
||||
<P> </P>
|
||||
<P>print " ".join( ["Hello", "world"] + sys.argv[1:] )</P></DIR>
|
||||
</DIR>
|
||||
|
||||
</CODE><H4>Command Line used</H4><DIR>
|
||||
<DIR>
|
||||
|
||||
<FONT FACE="Courier New" SIZE=2><P>\src\python-1.5.1\tools\freeze\freeze.py helloworld.py</P>
|
||||
<P>nmake</P></DIR>
|
||||
</DIR>
|
||||
|
||||
</FONT><P>Resulting helloworld.exe: 114,688 bytes.</P>
|
||||
<H3>Helloworld2.py</H3>
|
||||
<P>Uses win32api. Demonstrates requirement for pywintypes, and difference between freezing extensions and not.</P>
|
||||
<H4>Source Code</H4><DIR>
|
||||
<DIR>
|
||||
|
||||
<P>import win32api</P>
|
||||
<P>print "Hello from", win32api.GetComputerName()</P></DIR>
|
||||
</DIR>
|
||||
|
||||
<H4>Command Line used</H4>
|
||||
<P>By default, win32api will be frozen in with the .EXE. If you do not provide the "pywintypes" inclusion, then the link step will fail looking for all the pywintypes modules.</P><DIR>
|
||||
<DIR>
|
||||
|
||||
<FONT FACE="Courier New" SIZE=2><P>\src\python-1.5.1\tools\freeze\freeze.py helloworld2.py -m pywintypes</P>
|
||||
<P>nmake</P></DIR>
|
||||
</DIR>
|
||||
|
||||
</FONT><P>Resulting helloworld2.exe: 167,936 bytes</P>
|
||||
<P>Simply adding win32con to the mix gives an EXE of size: 352,768 bytes.</P>
|
||||
<H4>Command Line used</H4>
|
||||
<P>Using this build, we are dependent at runtime on the win32api.pyd and pywintypes15.dll files.</P><DIR>
|
||||
<DIR>
|
||||
|
||||
<P>\src\python-1.5.1\tools\freeze\freeze.py -x win32api helloworld.py</P></DIR>
|
||||
</DIR>
|
||||
|
||||
<P>Resulting helloworld2.exe: 114,688</P>
|
||||
<P>Adding win32con to this build results in a size of: 252,928</P>
|
||||
<H3>Testmapi.py</H3>
|
||||
<P>Uses MAPI, a PythonCOM extension, and win32api.</P>
|
||||
<H4>Source Code</H4>
|
||||
<P>from win32com.mapi import mapi</P>
|
||||
<P>import win32api</P>
|
||||
<P>mapi.MAPIInitialize( (mapi.MAPI_INIT_VERSION, 0) )</P>
|
||||
<P>print "Hello from", win32api.GetComputerName()</P>
|
||||
<P>mapi.MAPIUninitialize()</P>
|
||||
<H4>Command Line used</H4>
|
||||
<P>As it does not import pythoncom or pywintypes itself, they must be specified. As it uses the win32comext directory, -a must be used. If you have built the win32com extensions from sources, then the second -a is required.</P><DIR>
|
||||
<DIR>
|
||||
|
||||
<CODE><P>\src\python-1.5.1\tools\freeze\freeze.py -a win32com=%PYTHONEX%\com\win32comext -a win32com.mapi=%PYTHONEX%\com\build\release testmapi.py -m pywintypes -m pythoncom</P></DIR>
|
||||
</DIR>
|
||||
|
||||
</CODE><P>Resulting testmapi.exe: 352,768 bytes</P>
|
||||
<H3>PipeTestService.py</H3>
|
||||
<P>This is a standard Python demo in the Win32 extensions. It can be found in the "win32\demos\service" directory.</P>
|
||||
<H4>Command Line used</H4>
|
||||
<P>This will create a native NT Service EXE, dependent only on the main Python20.dll. All other modules are built-in to the final .EXE</P><DIR>
|
||||
<DIR>
|
||||
|
||||
<CODE><P>\src\python-1.5.1\tools\freeze\freeze.py -s service %PYTHONEX%\win32\demos\service\pipeTestService.py</P></DIR>
|
||||
</DIR>
|
||||
|
||||
<P>Resulting pipeTestService.exe: </CODE><FONT FACE="Courier New" SIZE=2>533,504 bytes.</P></FONT></BODY>
|
||||
</HTML>
|
||||
|
148
third_party/python/Tools/freeze/winmakemakefile.py
vendored
Normal file
148
third_party/python/Tools/freeze/winmakemakefile.py
vendored
Normal file
|
@ -0,0 +1,148 @@
|
|||
import sys, os
|
||||
|
||||
# Template used then the program is a GUI program
|
||||
WINMAINTEMPLATE = """
|
||||
#include <windows.h>
|
||||
|
||||
int WINAPI WinMain(
|
||||
HINSTANCE hInstance, // handle to current instance
|
||||
HINSTANCE hPrevInstance, // handle to previous instance
|
||||
LPSTR lpCmdLine, // pointer to command line
|
||||
int nCmdShow // show state of window
|
||||
)
|
||||
{
|
||||
extern int Py_FrozenMain(int, char **);
|
||||
PyImport_FrozenModules = _PyImport_FrozenModules;
|
||||
return Py_FrozenMain(__argc, __argv);
|
||||
}
|
||||
"""
|
||||
|
||||
SERVICETEMPLATE = """
|
||||
extern int PythonService_main(int, char **);
|
||||
|
||||
int main( int argc, char **argv)
|
||||
{
|
||||
PyImport_FrozenModules = _PyImport_FrozenModules;
|
||||
return PythonService_main(argc, argv);
|
||||
}
|
||||
"""
|
||||
|
||||
subsystem_details = {
|
||||
# -s flag : (C entry point template), (is it __main__?), (is it a DLL?)
|
||||
'console' : (None, 1, 0),
|
||||
'windows' : (WINMAINTEMPLATE, 1, 0),
|
||||
'service' : (SERVICETEMPLATE, 0, 0),
|
||||
'com_dll' : ("", 0, 1),
|
||||
}
|
||||
|
||||
def get_custom_entry_point(subsystem):
|
||||
try:
|
||||
return subsystem_details[subsystem][:2]
|
||||
except KeyError:
|
||||
raise ValueError("The subsystem %s is not known" % subsystem)
|
||||
|
||||
|
||||
def makemakefile(outfp, vars, files, target):
|
||||
save = sys.stdout
|
||||
try:
|
||||
sys.stdout = outfp
|
||||
realwork(vars, files, target)
|
||||
finally:
|
||||
sys.stdout = save
|
||||
|
||||
def realwork(vars, moddefns, target):
|
||||
version_suffix = "%r%r" % sys.version_info[:2]
|
||||
print("# Makefile for Microsoft Visual C++ generated by freeze.py script")
|
||||
print()
|
||||
print('target = %s' % target)
|
||||
print('pythonhome = %s' % vars['prefix'])
|
||||
print()
|
||||
print('DEBUG=0 # Set to 1 to use the _d versions of Python.')
|
||||
print('!IF $(DEBUG)')
|
||||
print('debug_suffix=_d')
|
||||
print('c_debug=/Zi /Od /DDEBUG /D_DEBUG')
|
||||
print('l_debug=/DEBUG')
|
||||
print('temp_dir=Build\\Debug')
|
||||
print('!ELSE')
|
||||
print('debug_suffix=')
|
||||
print('c_debug=/Ox')
|
||||
print('l_debug=')
|
||||
print('temp_dir=Build\\Release')
|
||||
print('!ENDIF')
|
||||
print()
|
||||
|
||||
print('# The following line assumes you have built Python using the standard instructions')
|
||||
print('# Otherwise fix the following line to point to the library.')
|
||||
print('pythonlib = "$(pythonhome)/pcbuild/python%s$(debug_suffix).lib"' % version_suffix)
|
||||
print()
|
||||
|
||||
# We only ever write one "entry point" symbol - either
|
||||
# "main" or "WinMain". Therefore, there is no need to
|
||||
# pass a subsystem switch to the linker as it works it
|
||||
# out all by itself. However, the subsystem _does_ determine
|
||||
# the file extension and additional linker flags.
|
||||
target_link_flags = ""
|
||||
target_ext = ".exe"
|
||||
if subsystem_details[vars['subsystem']][2]:
|
||||
target_link_flags = "-dll"
|
||||
target_ext = ".dll"
|
||||
|
||||
|
||||
print("# As the target uses Python%s.dll, we must use this compiler option!" % version_suffix)
|
||||
print("cdl = /MD")
|
||||
print()
|
||||
print("all: $(target)$(debug_suffix)%s" % (target_ext))
|
||||
print()
|
||||
|
||||
print('$(temp_dir):')
|
||||
print(r' if not exist $(temp_dir)\. mkdir $(temp_dir)')
|
||||
print()
|
||||
|
||||
objects = []
|
||||
libs = ["shell32.lib", "comdlg32.lib", "wsock32.lib", "user32.lib", "oleaut32.lib"]
|
||||
for moddefn in moddefns:
|
||||
print("# Module", moddefn.name)
|
||||
for file in moddefn.sourceFiles:
|
||||
base = os.path.basename(file)
|
||||
base, ext = os.path.splitext(base)
|
||||
objects.append(base + ".obj")
|
||||
print(r'$(temp_dir)\%s.obj: "%s"' % (base, file))
|
||||
print("\t@$(CC) -c -nologo /Fo$* $(cdl) $(c_debug) /D BUILD_FREEZE", end=' ')
|
||||
print('"-I$(pythonhome)/Include" "-I$(pythonhome)/PC" \\')
|
||||
print("\t\t$(cflags) $(cdebug) $(cinclude) \\")
|
||||
extra = moddefn.GetCompilerOptions()
|
||||
if extra:
|
||||
print("\t\t%s \\" % (' '.join(extra),))
|
||||
print('\t\t"%s"' % file)
|
||||
print()
|
||||
|
||||
# Add .lib files this module needs
|
||||
for modlib in moddefn.GetLinkerLibs():
|
||||
if modlib not in libs:
|
||||
libs.append(modlib)
|
||||
|
||||
print("ADDN_LINK_FILES=", end=' ')
|
||||
for addn in vars['addn_link']: print('"%s"' % (addn), end=' ')
|
||||
print() ; print()
|
||||
|
||||
print("OBJS=", end=' ')
|
||||
for obj in objects: print(r'"$(temp_dir)\%s"' % (obj), end=' ')
|
||||
print() ; print()
|
||||
|
||||
print("LIBS=", end=' ')
|
||||
for lib in libs: print('"%s"' % (lib), end=' ')
|
||||
print() ; print()
|
||||
|
||||
print("$(target)$(debug_suffix)%s: $(temp_dir) $(OBJS)" % (target_ext))
|
||||
print("\tlink -out:$(target)$(debug_suffix)%s %s" %
|
||||
(target_ext, target_link_flags), "@<<")
|
||||
print("\t$(OBJS)")
|
||||
print("\t$(LIBS)")
|
||||
print("\t$(ADDN_LINK_FILES)")
|
||||
print("\t$(pythonlib) $(lcustom) $(l_debug)")
|
||||
print("\t$(resources)")
|
||||
print("<<")
|
||||
print()
|
||||
print("clean:")
|
||||
print("\t-del /f *.obj")
|
||||
print("\t-del /f $(target).exe")
|
1959
third_party/python/Tools/gdb/libpython.py
vendored
Executable file
1959
third_party/python/Tools/gdb/libpython.py
vendored
Executable file
File diff suppressed because it is too large
Load diff
150
third_party/python/Tools/i18n/makelocalealias.py
vendored
Executable file
150
third_party/python/Tools/i18n/makelocalealias.py
vendored
Executable file
|
@ -0,0 +1,150 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Convert the X11 locale.alias file into a mapping dictionary suitable
|
||||
for locale.py.
|
||||
|
||||
Written by Marc-Andre Lemburg <mal@genix.com>, 2004-12-10.
|
||||
|
||||
"""
|
||||
import locale
|
||||
import sys
|
||||
_locale = locale
|
||||
|
||||
# Location of the X11 alias file.
|
||||
LOCALE_ALIAS = '/usr/share/X11/locale/locale.alias'
|
||||
# Location of the glibc SUPPORTED locales file.
|
||||
SUPPORTED = '/usr/share/i18n/SUPPORTED'
|
||||
|
||||
def parse(filename):
|
||||
|
||||
with open(filename, encoding='latin1') as f:
|
||||
lines = list(f)
|
||||
data = {}
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
if line[:1] == '#':
|
||||
continue
|
||||
locale, alias = line.split()
|
||||
# Fix non-standard locale names, e.g. ks_IN@devanagari.UTF-8
|
||||
if '@' in alias:
|
||||
alias_lang, _, alias_mod = alias.partition('@')
|
||||
if '.' in alias_mod:
|
||||
alias_mod, _, alias_enc = alias_mod.partition('.')
|
||||
alias = alias_lang + '.' + alias_enc + '@' + alias_mod
|
||||
# Strip ':'
|
||||
if locale[-1] == ':':
|
||||
locale = locale[:-1]
|
||||
# Lower-case locale
|
||||
locale = locale.lower()
|
||||
# Ignore one letter locale mappings (except for 'c')
|
||||
if len(locale) == 1 and locale != 'c':
|
||||
continue
|
||||
# Normalize encoding, if given
|
||||
if '.' in locale:
|
||||
lang, encoding = locale.split('.')[:2]
|
||||
encoding = encoding.replace('-', '')
|
||||
encoding = encoding.replace('_', '')
|
||||
locale = lang + '.' + encoding
|
||||
data[locale] = alias
|
||||
return data
|
||||
|
||||
def parse_glibc_supported(filename):
|
||||
|
||||
with open(filename, encoding='latin1') as f:
|
||||
lines = list(f)
|
||||
data = {}
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
if line[:1] == '#':
|
||||
continue
|
||||
line = line.replace('/', ' ').strip()
|
||||
line = line.rstrip('\\').rstrip()
|
||||
words = line.split()
|
||||
if len(words) != 2:
|
||||
continue
|
||||
alias, alias_encoding = words
|
||||
# Lower-case locale
|
||||
locale = alias.lower()
|
||||
# Normalize encoding, if given
|
||||
if '.' in locale:
|
||||
lang, encoding = locale.split('.')[:2]
|
||||
encoding = encoding.replace('-', '')
|
||||
encoding = encoding.replace('_', '')
|
||||
locale = lang + '.' + encoding
|
||||
# Add an encoding to alias
|
||||
alias, _, modifier = alias.partition('@')
|
||||
alias = _locale._replace_encoding(alias, alias_encoding)
|
||||
if modifier and not (modifier == 'euro' and alias_encoding == 'ISO-8859-15'):
|
||||
alias += '@' + modifier
|
||||
data[locale] = alias
|
||||
return data
|
||||
|
||||
def pprint(data):
|
||||
items = sorted(data.items())
|
||||
for k, v in items:
|
||||
print(' %-40s%a,' % ('%a:' % k, v))
|
||||
|
||||
def print_differences(data, olddata):
|
||||
items = sorted(olddata.items())
|
||||
for k, v in items:
|
||||
if k not in data:
|
||||
print('# removed %a' % k)
|
||||
elif olddata[k] != data[k]:
|
||||
print('# updated %a -> %a to %a' % \
|
||||
(k, olddata[k], data[k]))
|
||||
# Additions are not mentioned
|
||||
|
||||
def optimize(data):
|
||||
locale_alias = locale.locale_alias
|
||||
locale.locale_alias = data.copy()
|
||||
for k, v in data.items():
|
||||
del locale.locale_alias[k]
|
||||
if locale.normalize(k) != v:
|
||||
locale.locale_alias[k] = v
|
||||
newdata = locale.locale_alias
|
||||
errors = check(data)
|
||||
locale.locale_alias = locale_alias
|
||||
if errors:
|
||||
sys.exit(1)
|
||||
return newdata
|
||||
|
||||
def check(data):
|
||||
# Check that all alias definitions from the X11 file
|
||||
# are actually mapped to the correct alias locales.
|
||||
errors = 0
|
||||
for k, v in data.items():
|
||||
if locale.normalize(k) != v:
|
||||
print('ERROR: %a -> %a != %a' % (k, locale.normalize(k), v),
|
||||
file=sys.stderr)
|
||||
errors += 1
|
||||
return errors
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--locale-alias', default=LOCALE_ALIAS,
|
||||
help='location of the X11 alias file '
|
||||
'(default: %a)' % LOCALE_ALIAS)
|
||||
parser.add_argument('--glibc-supported', default=SUPPORTED,
|
||||
help='location of the glibc SUPPORTED locales file '
|
||||
'(default: %a)' % SUPPORTED)
|
||||
args = parser.parse_args()
|
||||
|
||||
data = locale.locale_alias.copy()
|
||||
data.update(parse_glibc_supported(args.glibc_supported))
|
||||
data.update(parse(args.locale_alias))
|
||||
while True:
|
||||
# Repeat optimization while the size is decreased.
|
||||
n = len(data)
|
||||
data = optimize(data)
|
||||
if len(data) == n:
|
||||
break
|
||||
print_differences(data, locale.locale_alias)
|
||||
print()
|
||||
print('locale_alias = {')
|
||||
pprint(data)
|
||||
print('}')
|
238
third_party/python/Tools/i18n/msgfmt.py
vendored
Executable file
238
third_party/python/Tools/i18n/msgfmt.py
vendored
Executable file
|
@ -0,0 +1,238 @@
|
|||
#! /usr/bin/env python3
|
||||
# Written by Martin v. Löwis <loewis@informatik.hu-berlin.de>
|
||||
|
||||
"""Generate binary message catalog from textual translation description.
|
||||
|
||||
This program converts a textual Uniforum-style message catalog (.po file) into
|
||||
a binary GNU catalog (.mo file). This is essentially the same function as the
|
||||
GNU msgfmt program, however, it is a simpler implementation.
|
||||
|
||||
Usage: msgfmt.py [OPTIONS] filename.po
|
||||
|
||||
Options:
|
||||
-o file
|
||||
--output-file=file
|
||||
Specify the output file to write to. If omitted, output will go to a
|
||||
file named filename.mo (based off the input file name).
|
||||
|
||||
-h
|
||||
--help
|
||||
Print this message and exit.
|
||||
|
||||
-V
|
||||
--version
|
||||
Display version information and exit.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import ast
|
||||
import getopt
|
||||
import struct
|
||||
import array
|
||||
from email.parser import HeaderParser
|
||||
|
||||
__version__ = "1.1"
|
||||
|
||||
MESSAGES = {}
|
||||
|
||||
|
||||
|
||||
def usage(code, msg=''):
|
||||
print(__doc__, file=sys.stderr)
|
||||
if msg:
|
||||
print(msg, file=sys.stderr)
|
||||
sys.exit(code)
|
||||
|
||||
|
||||
|
||||
def add(id, str, fuzzy):
|
||||
"Add a non-fuzzy translation to the dictionary."
|
||||
global MESSAGES
|
||||
if not fuzzy and str:
|
||||
MESSAGES[id] = str
|
||||
|
||||
|
||||
|
||||
def generate():
|
||||
"Return the generated output."
|
||||
global MESSAGES
|
||||
# the keys are sorted in the .mo file
|
||||
keys = sorted(MESSAGES.keys())
|
||||
offsets = []
|
||||
ids = strs = b''
|
||||
for id in keys:
|
||||
# For each string, we need size and file offset. Each string is NUL
|
||||
# terminated; the NUL does not count into the size.
|
||||
offsets.append((len(ids), len(id), len(strs), len(MESSAGES[id])))
|
||||
ids += id + b'\0'
|
||||
strs += MESSAGES[id] + b'\0'
|
||||
output = ''
|
||||
# The header is 7 32-bit unsigned integers. We don't use hash tables, so
|
||||
# the keys start right after the index tables.
|
||||
# translated string.
|
||||
keystart = 7*4+16*len(keys)
|
||||
# and the values start after the keys
|
||||
valuestart = keystart + len(ids)
|
||||
koffsets = []
|
||||
voffsets = []
|
||||
# The string table first has the list of keys, then the list of values.
|
||||
# Each entry has first the size of the string, then the file offset.
|
||||
for o1, l1, o2, l2 in offsets:
|
||||
koffsets += [l1, o1+keystart]
|
||||
voffsets += [l2, o2+valuestart]
|
||||
offsets = koffsets + voffsets
|
||||
output = struct.pack("Iiiiiii",
|
||||
0x950412de, # Magic
|
||||
0, # Version
|
||||
len(keys), # # of entries
|
||||
7*4, # start of key index
|
||||
7*4+len(keys)*8, # start of value index
|
||||
0, 0) # size and offset of hash table
|
||||
output += array.array("i", offsets).tobytes()
|
||||
output += ids
|
||||
output += strs
|
||||
return output
|
||||
|
||||
|
||||
|
||||
def make(filename, outfile):
|
||||
ID = 1
|
||||
STR = 2
|
||||
|
||||
# Compute .mo name from .po name and arguments
|
||||
if filename.endswith('.po'):
|
||||
infile = filename
|
||||
else:
|
||||
infile = filename + '.po'
|
||||
if outfile is None:
|
||||
outfile = os.path.splitext(infile)[0] + '.mo'
|
||||
|
||||
try:
|
||||
with open(infile, 'rb') as f:
|
||||
lines = f.readlines()
|
||||
except IOError as msg:
|
||||
print(msg, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
section = None
|
||||
fuzzy = 0
|
||||
|
||||
# Start off assuming Latin-1, so everything decodes without failure,
|
||||
# until we know the exact encoding
|
||||
encoding = 'latin-1'
|
||||
|
||||
# Parse the catalog
|
||||
lno = 0
|
||||
for l in lines:
|
||||
l = l.decode(encoding)
|
||||
lno += 1
|
||||
# If we get a comment line after a msgstr, this is a new entry
|
||||
if l[0] == '#' and section == STR:
|
||||
add(msgid, msgstr, fuzzy)
|
||||
section = None
|
||||
fuzzy = 0
|
||||
# Record a fuzzy mark
|
||||
if l[:2] == '#,' and 'fuzzy' in l:
|
||||
fuzzy = 1
|
||||
# Skip comments
|
||||
if l[0] == '#':
|
||||
continue
|
||||
# Now we are in a msgid section, output previous section
|
||||
if l.startswith('msgid') and not l.startswith('msgid_plural'):
|
||||
if section == STR:
|
||||
add(msgid, msgstr, fuzzy)
|
||||
if not msgid:
|
||||
# See whether there is an encoding declaration
|
||||
p = HeaderParser()
|
||||
charset = p.parsestr(msgstr.decode(encoding)).get_content_charset()
|
||||
if charset:
|
||||
encoding = charset
|
||||
section = ID
|
||||
l = l[5:]
|
||||
msgid = msgstr = b''
|
||||
is_plural = False
|
||||
# This is a message with plural forms
|
||||
elif l.startswith('msgid_plural'):
|
||||
if section != ID:
|
||||
print('msgid_plural not preceded by msgid on %s:%d' % (infile, lno),
|
||||
file=sys.stderr)
|
||||
sys.exit(1)
|
||||
l = l[12:]
|
||||
msgid += b'\0' # separator of singular and plural
|
||||
is_plural = True
|
||||
# Now we are in a msgstr section
|
||||
elif l.startswith('msgstr'):
|
||||
section = STR
|
||||
if l.startswith('msgstr['):
|
||||
if not is_plural:
|
||||
print('plural without msgid_plural on %s:%d' % (infile, lno),
|
||||
file=sys.stderr)
|
||||
sys.exit(1)
|
||||
l = l.split(']', 1)[1]
|
||||
if msgstr:
|
||||
msgstr += b'\0' # Separator of the various plural forms
|
||||
else:
|
||||
if is_plural:
|
||||
print('indexed msgstr required for plural on %s:%d' % (infile, lno),
|
||||
file=sys.stderr)
|
||||
sys.exit(1)
|
||||
l = l[6:]
|
||||
# Skip empty lines
|
||||
l = l.strip()
|
||||
if not l:
|
||||
continue
|
||||
l = ast.literal_eval(l)
|
||||
if section == ID:
|
||||
msgid += l.encode(encoding)
|
||||
elif section == STR:
|
||||
msgstr += l.encode(encoding)
|
||||
else:
|
||||
print('Syntax error on %s:%d' % (infile, lno), \
|
||||
'before:', file=sys.stderr)
|
||||
print(l, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
# Add last entry
|
||||
if section == STR:
|
||||
add(msgid, msgstr, fuzzy)
|
||||
|
||||
# Compute output
|
||||
output = generate()
|
||||
|
||||
try:
|
||||
with open(outfile,"wb") as f:
|
||||
f.write(output)
|
||||
except IOError as msg:
|
||||
print(msg, file=sys.stderr)
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'hVo:',
|
||||
['help', 'version', 'output-file='])
|
||||
except getopt.error as msg:
|
||||
usage(1, msg)
|
||||
|
||||
outfile = None
|
||||
# parse options
|
||||
for opt, arg in opts:
|
||||
if opt in ('-h', '--help'):
|
||||
usage(0)
|
||||
elif opt in ('-V', '--version'):
|
||||
print("msgfmt.py", __version__)
|
||||
sys.exit(0)
|
||||
elif opt in ('-o', '--output-file'):
|
||||
outfile = arg
|
||||
# do it
|
||||
if not args:
|
||||
print('No input file given', file=sys.stderr)
|
||||
print("Try `msgfmt --help' for more information.", file=sys.stderr)
|
||||
return
|
||||
|
||||
for filename in args:
|
||||
make(filename, outfile)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
631
third_party/python/Tools/i18n/pygettext.py
vendored
Executable file
631
third_party/python/Tools/i18n/pygettext.py
vendored
Executable file
|
@ -0,0 +1,631 @@
|
|||
#! /usr/bin/env python3
|
||||
# -*- coding: iso-8859-1 -*-
|
||||
# Originally written by Barry Warsaw <barry@python.org>
|
||||
#
|
||||
# Minimally patched to make it even more xgettext compatible
|
||||
# by Peter Funk <pf@artcom-gmbh.de>
|
||||
#
|
||||
# 2002-11-22 Jürgen Hermann <jh@web.de>
|
||||
# Added checks that _() only contains string literals, and
|
||||
# command line args are resolved to module lists, i.e. you
|
||||
# can now pass a filename, a module or package name, or a
|
||||
# directory (including globbing chars, important for Win32).
|
||||
# Made docstring fit in 80 chars wide displays using pydoc.
|
||||
#
|
||||
|
||||
# for selftesting
|
||||
try:
|
||||
import fintl
|
||||
_ = fintl.gettext
|
||||
except ImportError:
|
||||
_ = lambda s: s
|
||||
|
||||
__doc__ = _("""pygettext -- Python equivalent of xgettext(1)
|
||||
|
||||
Many systems (Solaris, Linux, Gnu) provide extensive tools that ease the
|
||||
internationalization of C programs. Most of these tools are independent of
|
||||
the programming language and can be used from within Python programs.
|
||||
Martin von Loewis' work[1] helps considerably in this regard.
|
||||
|
||||
There's one problem though; xgettext is the program that scans source code
|
||||
looking for message strings, but it groks only C (or C++). Python
|
||||
introduces a few wrinkles, such as dual quoting characters, triple quoted
|
||||
strings, and raw strings. xgettext understands none of this.
|
||||
|
||||
Enter pygettext, which uses Python's standard tokenize module to scan
|
||||
Python source code, generating .pot files identical to what GNU xgettext[2]
|
||||
generates for C and C++ code. From there, the standard GNU tools can be
|
||||
used.
|
||||
|
||||
A word about marking Python strings as candidates for translation. GNU
|
||||
xgettext recognizes the following keywords: gettext, dgettext, dcgettext,
|
||||
and gettext_noop. But those can be a lot of text to include all over your
|
||||
code. C and C++ have a trick: they use the C preprocessor. Most
|
||||
internationalized C source includes a #define for gettext() to _() so that
|
||||
what has to be written in the source is much less. Thus these are both
|
||||
translatable strings:
|
||||
|
||||
gettext("Translatable String")
|
||||
_("Translatable String")
|
||||
|
||||
Python of course has no preprocessor so this doesn't work so well. Thus,
|
||||
pygettext searches only for _() by default, but see the -k/--keyword flag
|
||||
below for how to augment this.
|
||||
|
||||
[1] http://www.python.org/workshops/1997-10/proceedings/loewis.html
|
||||
[2] http://www.gnu.org/software/gettext/gettext.html
|
||||
|
||||
NOTE: pygettext attempts to be option and feature compatible with GNU
|
||||
xgettext where ever possible. However some options are still missing or are
|
||||
not fully implemented. Also, xgettext's use of command line switches with
|
||||
option arguments is broken, and in these cases, pygettext just defines
|
||||
additional switches.
|
||||
|
||||
Usage: pygettext [options] inputfile ...
|
||||
|
||||
Options:
|
||||
|
||||
-a
|
||||
--extract-all
|
||||
Extract all strings.
|
||||
|
||||
-d name
|
||||
--default-domain=name
|
||||
Rename the default output file from messages.pot to name.pot.
|
||||
|
||||
-E
|
||||
--escape
|
||||
Replace non-ASCII characters with octal escape sequences.
|
||||
|
||||
-D
|
||||
--docstrings
|
||||
Extract module, class, method, and function docstrings. These do
|
||||
not need to be wrapped in _() markers, and in fact cannot be for
|
||||
Python to consider them docstrings. (See also the -X option).
|
||||
|
||||
-h
|
||||
--help
|
||||
Print this help message and exit.
|
||||
|
||||
-k word
|
||||
--keyword=word
|
||||
Keywords to look for in addition to the default set, which are:
|
||||
%(DEFAULTKEYWORDS)s
|
||||
|
||||
You can have multiple -k flags on the command line.
|
||||
|
||||
-K
|
||||
--no-default-keywords
|
||||
Disable the default set of keywords (see above). Any keywords
|
||||
explicitly added with the -k/--keyword option are still recognized.
|
||||
|
||||
--no-location
|
||||
Do not write filename/lineno location comments.
|
||||
|
||||
-n
|
||||
--add-location
|
||||
Write filename/lineno location comments indicating where each
|
||||
extracted string is found in the source. These lines appear before
|
||||
each msgid. The style of comments is controlled by the -S/--style
|
||||
option. This is the default.
|
||||
|
||||
-o filename
|
||||
--output=filename
|
||||
Rename the default output file from messages.pot to filename. If
|
||||
filename is `-' then the output is sent to standard out.
|
||||
|
||||
-p dir
|
||||
--output-dir=dir
|
||||
Output files will be placed in directory dir.
|
||||
|
||||
-S stylename
|
||||
--style stylename
|
||||
Specify which style to use for location comments. Two styles are
|
||||
supported:
|
||||
|
||||
Solaris # File: filename, line: line-number
|
||||
GNU #: filename:line
|
||||
|
||||
The style name is case insensitive. GNU style is the default.
|
||||
|
||||
-v
|
||||
--verbose
|
||||
Print the names of the files being processed.
|
||||
|
||||
-V
|
||||
--version
|
||||
Print the version of pygettext and exit.
|
||||
|
||||
-w columns
|
||||
--width=columns
|
||||
Set width of output to columns.
|
||||
|
||||
-x filename
|
||||
--exclude-file=filename
|
||||
Specify a file that contains a list of strings that are not be
|
||||
extracted from the input files. Each string to be excluded must
|
||||
appear on a line by itself in the file.
|
||||
|
||||
-X filename
|
||||
--no-docstrings=filename
|
||||
Specify a file that contains a list of files (one per line) that
|
||||
should not have their docstrings extracted. This is only useful in
|
||||
conjunction with the -D option above.
|
||||
|
||||
If `inputfile' is -, standard input is read.
|
||||
""")
|
||||
|
||||
import os
|
||||
import importlib.machinery
|
||||
import importlib.util
|
||||
import sys
|
||||
import glob
|
||||
import time
|
||||
import getopt
|
||||
import token
|
||||
import tokenize
|
||||
|
||||
__version__ = '1.5'
|
||||
|
||||
default_keywords = ['_']
|
||||
DEFAULTKEYWORDS = ', '.join(default_keywords)
|
||||
|
||||
EMPTYSTRING = ''
|
||||
|
||||
|
||||
|
||||
# The normal pot-file header. msgmerge and Emacs's po-mode work better if it's
|
||||
# there.
|
||||
pot_header = _('''\
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\\n"
|
||||
"POT-Creation-Date: %(time)s\\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\\n"
|
||||
"MIME-Version: 1.0\\n"
|
||||
"Content-Type: text/plain; charset=%(charset)s\\n"
|
||||
"Content-Transfer-Encoding: %(encoding)s\\n"
|
||||
"Generated-By: pygettext.py %(version)s\\n"
|
||||
|
||||
''')
|
||||
|
||||
|
||||
def usage(code, msg=''):
|
||||
print(__doc__ % globals(), file=sys.stderr)
|
||||
if msg:
|
||||
print(msg, file=sys.stderr)
|
||||
sys.exit(code)
|
||||
|
||||
|
||||
|
||||
def make_escapes(pass_nonascii):
|
||||
global escapes, escape
|
||||
if pass_nonascii:
|
||||
# Allow non-ascii characters to pass through so that e.g. 'msgid
|
||||
# "Höhe"' would result not result in 'msgid "H\366he"'. Otherwise we
|
||||
# escape any character outside the 32..126 range.
|
||||
mod = 128
|
||||
escape = escape_ascii
|
||||
else:
|
||||
mod = 256
|
||||
escape = escape_nonascii
|
||||
escapes = [r"\%03o" % i for i in range(mod)]
|
||||
for i in range(32, 127):
|
||||
escapes[i] = chr(i)
|
||||
escapes[ord('\\')] = r'\\'
|
||||
escapes[ord('\t')] = r'\t'
|
||||
escapes[ord('\r')] = r'\r'
|
||||
escapes[ord('\n')] = r'\n'
|
||||
escapes[ord('\"')] = r'\"'
|
||||
|
||||
|
||||
def escape_ascii(s, encoding):
|
||||
return ''.join(escapes[ord(c)] if ord(c) < 128 else c for c in s)
|
||||
|
||||
def escape_nonascii(s, encoding):
|
||||
return ''.join(escapes[b] for b in s.encode(encoding))
|
||||
|
||||
|
||||
def is_literal_string(s):
|
||||
return s[0] in '\'"' or (s[0] in 'rRuU' and s[1] in '\'"')
|
||||
|
||||
|
||||
def safe_eval(s):
|
||||
# unwrap quotes, safely
|
||||
return eval(s, {'__builtins__':{}}, {})
|
||||
|
||||
|
||||
def normalize(s, encoding):
|
||||
# This converts the various Python string types into a format that is
|
||||
# appropriate for .po files, namely much closer to C style.
|
||||
lines = s.split('\n')
|
||||
if len(lines) == 1:
|
||||
s = '"' + escape(s, encoding) + '"'
|
||||
else:
|
||||
if not lines[-1]:
|
||||
del lines[-1]
|
||||
lines[-1] = lines[-1] + '\n'
|
||||
for i in range(len(lines)):
|
||||
lines[i] = escape(lines[i], encoding)
|
||||
lineterm = '\\n"\n"'
|
||||
s = '""\n"' + lineterm.join(lines) + '"'
|
||||
return s
|
||||
|
||||
|
||||
def containsAny(str, set):
|
||||
"""Check whether 'str' contains ANY of the chars in 'set'"""
|
||||
return 1 in [c in str for c in set]
|
||||
|
||||
|
||||
def getFilesForName(name):
|
||||
"""Get a list of module files for a filename, a module or package name,
|
||||
or a directory.
|
||||
"""
|
||||
if not os.path.exists(name):
|
||||
# check for glob chars
|
||||
if containsAny(name, "*?[]"):
|
||||
files = glob.glob(name)
|
||||
list = []
|
||||
for file in files:
|
||||
list.extend(getFilesForName(file))
|
||||
return list
|
||||
|
||||
# try to find module or package
|
||||
try:
|
||||
spec = importlib.util.find_spec(name)
|
||||
name = spec.origin
|
||||
except ImportError:
|
||||
name = None
|
||||
if not name:
|
||||
return []
|
||||
|
||||
if os.path.isdir(name):
|
||||
# find all python files in directory
|
||||
list = []
|
||||
# get extension for python source files
|
||||
_py_ext = importlib.machinery.SOURCE_SUFFIXES[0]
|
||||
for root, dirs, files in os.walk(name):
|
||||
# don't recurse into CVS directories
|
||||
if 'CVS' in dirs:
|
||||
dirs.remove('CVS')
|
||||
# add all *.py files to list
|
||||
list.extend(
|
||||
[os.path.join(root, file) for file in files
|
||||
if os.path.splitext(file)[1] == _py_ext]
|
||||
)
|
||||
return list
|
||||
elif os.path.exists(name):
|
||||
# a single file
|
||||
return [name]
|
||||
|
||||
return []
|
||||
|
||||
|
||||
class TokenEater:
|
||||
def __init__(self, options):
|
||||
self.__options = options
|
||||
self.__messages = {}
|
||||
self.__state = self.__waiting
|
||||
self.__data = []
|
||||
self.__lineno = -1
|
||||
self.__freshmodule = 1
|
||||
self.__curfile = None
|
||||
self.__enclosurecount = 0
|
||||
|
||||
def __call__(self, ttype, tstring, stup, etup, line):
|
||||
# dispatch
|
||||
## import token
|
||||
## print('ttype:', token.tok_name[ttype], 'tstring:', tstring,
|
||||
## file=sys.stderr)
|
||||
self.__state(ttype, tstring, stup[0])
|
||||
|
||||
def __waiting(self, ttype, tstring, lineno):
|
||||
opts = self.__options
|
||||
# Do docstring extractions, if enabled
|
||||
if opts.docstrings and not opts.nodocstrings.get(self.__curfile):
|
||||
# module docstring?
|
||||
if self.__freshmodule:
|
||||
if ttype == tokenize.STRING and is_literal_string(tstring):
|
||||
self.__addentry(safe_eval(tstring), lineno, isdocstring=1)
|
||||
self.__freshmodule = 0
|
||||
elif ttype not in (tokenize.COMMENT, tokenize.NL):
|
||||
self.__freshmodule = 0
|
||||
return
|
||||
# class or func/method docstring?
|
||||
if ttype == tokenize.NAME and tstring in ('class', 'def'):
|
||||
self.__state = self.__suiteseen
|
||||
return
|
||||
if ttype == tokenize.NAME and tstring in opts.keywords:
|
||||
self.__state = self.__keywordseen
|
||||
|
||||
def __suiteseen(self, ttype, tstring, lineno):
|
||||
# skip over any enclosure pairs until we see the colon
|
||||
if ttype == tokenize.OP:
|
||||
if tstring == ':' and self.__enclosurecount == 0:
|
||||
# we see a colon and we're not in an enclosure: end of def
|
||||
self.__state = self.__suitedocstring
|
||||
elif tstring in '([{':
|
||||
self.__enclosurecount += 1
|
||||
elif tstring in ')]}':
|
||||
self.__enclosurecount -= 1
|
||||
|
||||
def __suitedocstring(self, ttype, tstring, lineno):
|
||||
# ignore any intervening noise
|
||||
if ttype == tokenize.STRING and is_literal_string(tstring):
|
||||
self.__addentry(safe_eval(tstring), lineno, isdocstring=1)
|
||||
self.__state = self.__waiting
|
||||
elif ttype not in (tokenize.NEWLINE, tokenize.INDENT,
|
||||
tokenize.COMMENT):
|
||||
# there was no class docstring
|
||||
self.__state = self.__waiting
|
||||
|
||||
def __keywordseen(self, ttype, tstring, lineno):
|
||||
if ttype == tokenize.OP and tstring == '(':
|
||||
self.__data = []
|
||||
self.__lineno = lineno
|
||||
self.__state = self.__openseen
|
||||
else:
|
||||
self.__state = self.__waiting
|
||||
|
||||
def __openseen(self, ttype, tstring, lineno):
|
||||
if ttype == tokenize.OP and tstring == ')':
|
||||
# We've seen the last of the translatable strings. Record the
|
||||
# line number of the first line of the strings and update the list
|
||||
# of messages seen. Reset state for the next batch. If there
|
||||
# were no strings inside _(), then just ignore this entry.
|
||||
if self.__data:
|
||||
self.__addentry(EMPTYSTRING.join(self.__data))
|
||||
self.__state = self.__waiting
|
||||
elif ttype == tokenize.STRING and is_literal_string(tstring):
|
||||
self.__data.append(safe_eval(tstring))
|
||||
elif ttype not in [tokenize.COMMENT, token.INDENT, token.DEDENT,
|
||||
token.NEWLINE, tokenize.NL]:
|
||||
# warn if we see anything else than STRING or whitespace
|
||||
print(_(
|
||||
'*** %(file)s:%(lineno)s: Seen unexpected token "%(token)s"'
|
||||
) % {
|
||||
'token': tstring,
|
||||
'file': self.__curfile,
|
||||
'lineno': self.__lineno
|
||||
}, file=sys.stderr)
|
||||
self.__state = self.__waiting
|
||||
|
||||
def __addentry(self, msg, lineno=None, isdocstring=0):
|
||||
if lineno is None:
|
||||
lineno = self.__lineno
|
||||
if not msg in self.__options.toexclude:
|
||||
entry = (self.__curfile, lineno)
|
||||
self.__messages.setdefault(msg, {})[entry] = isdocstring
|
||||
|
||||
def set_filename(self, filename):
|
||||
self.__curfile = filename
|
||||
self.__freshmodule = 1
|
||||
|
||||
def write(self, fp):
|
||||
options = self.__options
|
||||
timestamp = time.strftime('%Y-%m-%d %H:%M%z')
|
||||
encoding = fp.encoding if fp.encoding else 'UTF-8'
|
||||
print(pot_header % {'time': timestamp, 'version': __version__,
|
||||
'charset': encoding,
|
||||
'encoding': '8bit'}, file=fp)
|
||||
# Sort the entries. First sort each particular entry's keys, then
|
||||
# sort all the entries by their first item.
|
||||
reverse = {}
|
||||
for k, v in self.__messages.items():
|
||||
keys = sorted(v.keys())
|
||||
reverse.setdefault(tuple(keys), []).append((k, v))
|
||||
rkeys = sorted(reverse.keys())
|
||||
for rkey in rkeys:
|
||||
rentries = reverse[rkey]
|
||||
rentries.sort()
|
||||
for k, v in rentries:
|
||||
# If the entry was gleaned out of a docstring, then add a
|
||||
# comment stating so. This is to aid translators who may wish
|
||||
# to skip translating some unimportant docstrings.
|
||||
isdocstring = any(v.values())
|
||||
# k is the message string, v is a dictionary-set of (filename,
|
||||
# lineno) tuples. We want to sort the entries in v first by
|
||||
# file name and then by line number.
|
||||
v = sorted(v.keys())
|
||||
if not options.writelocations:
|
||||
pass
|
||||
# location comments are different b/w Solaris and GNU:
|
||||
elif options.locationstyle == options.SOLARIS:
|
||||
for filename, lineno in v:
|
||||
d = {'filename': filename, 'lineno': lineno}
|
||||
print(_(
|
||||
'# File: %(filename)s, line: %(lineno)d') % d, file=fp)
|
||||
elif options.locationstyle == options.GNU:
|
||||
# fit as many locations on one line, as long as the
|
||||
# resulting line length doesn't exceed 'options.width'
|
||||
locline = '#:'
|
||||
for filename, lineno in v:
|
||||
d = {'filename': filename, 'lineno': lineno}
|
||||
s = _(' %(filename)s:%(lineno)d') % d
|
||||
if len(locline) + len(s) <= options.width:
|
||||
locline = locline + s
|
||||
else:
|
||||
print(locline, file=fp)
|
||||
locline = "#:" + s
|
||||
if len(locline) > 2:
|
||||
print(locline, file=fp)
|
||||
if isdocstring:
|
||||
print('#, docstring', file=fp)
|
||||
print('msgid', normalize(k, encoding), file=fp)
|
||||
print('msgstr ""\n', file=fp)
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
global default_keywords
|
||||
try:
|
||||
opts, args = getopt.getopt(
|
||||
sys.argv[1:],
|
||||
'ad:DEhk:Kno:p:S:Vvw:x:X:',
|
||||
['extract-all', 'default-domain=', 'escape', 'help',
|
||||
'keyword=', 'no-default-keywords',
|
||||
'add-location', 'no-location', 'output=', 'output-dir=',
|
||||
'style=', 'verbose', 'version', 'width=', 'exclude-file=',
|
||||
'docstrings', 'no-docstrings',
|
||||
])
|
||||
except getopt.error as msg:
|
||||
usage(1, msg)
|
||||
|
||||
# for holding option values
|
||||
class Options:
|
||||
# constants
|
||||
GNU = 1
|
||||
SOLARIS = 2
|
||||
# defaults
|
||||
extractall = 0 # FIXME: currently this option has no effect at all.
|
||||
escape = 0
|
||||
keywords = []
|
||||
outpath = ''
|
||||
outfile = 'messages.pot'
|
||||
writelocations = 1
|
||||
locationstyle = GNU
|
||||
verbose = 0
|
||||
width = 78
|
||||
excludefilename = ''
|
||||
docstrings = 0
|
||||
nodocstrings = {}
|
||||
|
||||
options = Options()
|
||||
locations = {'gnu' : options.GNU,
|
||||
'solaris' : options.SOLARIS,
|
||||
}
|
||||
|
||||
# parse options
|
||||
for opt, arg in opts:
|
||||
if opt in ('-h', '--help'):
|
||||
usage(0)
|
||||
elif opt in ('-a', '--extract-all'):
|
||||
options.extractall = 1
|
||||
elif opt in ('-d', '--default-domain'):
|
||||
options.outfile = arg + '.pot'
|
||||
elif opt in ('-E', '--escape'):
|
||||
options.escape = 1
|
||||
elif opt in ('-D', '--docstrings'):
|
||||
options.docstrings = 1
|
||||
elif opt in ('-k', '--keyword'):
|
||||
options.keywords.append(arg)
|
||||
elif opt in ('-K', '--no-default-keywords'):
|
||||
default_keywords = []
|
||||
elif opt in ('-n', '--add-location'):
|
||||
options.writelocations = 1
|
||||
elif opt in ('--no-location',):
|
||||
options.writelocations = 0
|
||||
elif opt in ('-S', '--style'):
|
||||
options.locationstyle = locations.get(arg.lower())
|
||||
if options.locationstyle is None:
|
||||
usage(1, _('Invalid value for --style: %s') % arg)
|
||||
elif opt in ('-o', '--output'):
|
||||
options.outfile = arg
|
||||
elif opt in ('-p', '--output-dir'):
|
||||
options.outpath = arg
|
||||
elif opt in ('-v', '--verbose'):
|
||||
options.verbose = 1
|
||||
elif opt in ('-V', '--version'):
|
||||
print(_('pygettext.py (xgettext for Python) %s') % __version__)
|
||||
sys.exit(0)
|
||||
elif opt in ('-w', '--width'):
|
||||
try:
|
||||
options.width = int(arg)
|
||||
except ValueError:
|
||||
usage(1, _('--width argument must be an integer: %s') % arg)
|
||||
elif opt in ('-x', '--exclude-file'):
|
||||
options.excludefilename = arg
|
||||
elif opt in ('-X', '--no-docstrings'):
|
||||
fp = open(arg)
|
||||
try:
|
||||
while 1:
|
||||
line = fp.readline()
|
||||
if not line:
|
||||
break
|
||||
options.nodocstrings[line[:-1]] = 1
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
# calculate escapes
|
||||
make_escapes(not options.escape)
|
||||
|
||||
# calculate all keywords
|
||||
options.keywords.extend(default_keywords)
|
||||
|
||||
# initialize list of strings to exclude
|
||||
if options.excludefilename:
|
||||
try:
|
||||
fp = open(options.excludefilename)
|
||||
options.toexclude = fp.readlines()
|
||||
fp.close()
|
||||
except IOError:
|
||||
print(_(
|
||||
"Can't read --exclude-file: %s") % options.excludefilename, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
else:
|
||||
options.toexclude = []
|
||||
|
||||
# resolve args to module lists
|
||||
expanded = []
|
||||
for arg in args:
|
||||
if arg == '-':
|
||||
expanded.append(arg)
|
||||
else:
|
||||
expanded.extend(getFilesForName(arg))
|
||||
args = expanded
|
||||
|
||||
# slurp through all the files
|
||||
eater = TokenEater(options)
|
||||
for filename in args:
|
||||
if filename == '-':
|
||||
if options.verbose:
|
||||
print(_('Reading standard input'))
|
||||
fp = sys.stdin.buffer
|
||||
closep = 0
|
||||
else:
|
||||
if options.verbose:
|
||||
print(_('Working on %s') % filename)
|
||||
fp = open(filename, 'rb')
|
||||
closep = 1
|
||||
try:
|
||||
eater.set_filename(filename)
|
||||
try:
|
||||
tokens = tokenize.tokenize(fp.readline)
|
||||
for _token in tokens:
|
||||
eater(*_token)
|
||||
except tokenize.TokenError as e:
|
||||
print('%s: %s, line %d, column %d' % (
|
||||
e.args[0], filename, e.args[1][0], e.args[1][1]),
|
||||
file=sys.stderr)
|
||||
finally:
|
||||
if closep:
|
||||
fp.close()
|
||||
|
||||
# write the output
|
||||
if options.outfile == '-':
|
||||
fp = sys.stdout
|
||||
closep = 0
|
||||
else:
|
||||
if options.outpath:
|
||||
options.outfile = os.path.join(options.outpath, options.outfile)
|
||||
fp = open(options.outfile, 'w')
|
||||
closep = 1
|
||||
try:
|
||||
eater.write(fp)
|
||||
finally:
|
||||
if closep:
|
||||
fp.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
# some more test strings
|
||||
# this one creates a warning
|
||||
_('*** Seen unexpected token "%(token)s"') % {'token': 'test'}
|
||||
_('more' 'than' 'one' 'string')
|
6
third_party/python/Tools/importbench/README
vendored
Normal file
6
third_party/python/Tools/importbench/README
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
Importbench is a set of micro-benchmarks for various import scenarios.
|
||||
|
||||
It should not be used as an overall benchmark of import performance, but rather
|
||||
an easy way to measure impact of possible code changes. For a real-world
|
||||
benchmark of import, use the normal_startup benchmark from
|
||||
https://github.com/python/performance
|
244
third_party/python/Tools/importbench/importbench.py
vendored
Normal file
244
third_party/python/Tools/importbench/importbench.py
vendored
Normal file
|
@ -0,0 +1,244 @@
|
|||
"""Benchmark some basic import use-cases.
|
||||
|
||||
The assumption is made that this benchmark is run in a fresh interpreter and
|
||||
thus has no external changes made to import-related attributes in sys.
|
||||
|
||||
"""
|
||||
from test.test_importlib import util
|
||||
import decimal
|
||||
import imp
|
||||
import importlib
|
||||
import importlib.machinery
|
||||
import json
|
||||
import os
|
||||
import py_compile
|
||||
import sys
|
||||
import tabnanny
|
||||
import timeit
|
||||
|
||||
|
||||
def bench(name, cleanup=lambda: None, *, seconds=1, repeat=3):
|
||||
"""Bench the given statement as many times as necessary until total
|
||||
executions take one second."""
|
||||
stmt = "__import__({!r})".format(name)
|
||||
timer = timeit.Timer(stmt)
|
||||
for x in range(repeat):
|
||||
total_time = 0
|
||||
count = 0
|
||||
while total_time < seconds:
|
||||
try:
|
||||
total_time += timer.timeit(1)
|
||||
finally:
|
||||
cleanup()
|
||||
count += 1
|
||||
else:
|
||||
# One execution too far
|
||||
if total_time > seconds:
|
||||
count -= 1
|
||||
yield count // seconds
|
||||
|
||||
def from_cache(seconds, repeat):
|
||||
"""sys.modules"""
|
||||
name = '<benchmark import>'
|
||||
module = imp.new_module(name)
|
||||
module.__file__ = '<test>'
|
||||
module.__package__ = ''
|
||||
with util.uncache(name):
|
||||
sys.modules[name] = module
|
||||
yield from bench(name, repeat=repeat, seconds=seconds)
|
||||
|
||||
|
||||
def builtin_mod(seconds, repeat):
|
||||
"""Built-in module"""
|
||||
name = 'errno'
|
||||
if name in sys.modules:
|
||||
del sys.modules[name]
|
||||
# Relying on built-in importer being implicit.
|
||||
yield from bench(name, lambda: sys.modules.pop(name), repeat=repeat,
|
||||
seconds=seconds)
|
||||
|
||||
|
||||
def source_wo_bytecode(seconds, repeat):
|
||||
"""Source w/o bytecode: small"""
|
||||
sys.dont_write_bytecode = True
|
||||
try:
|
||||
name = '__importlib_test_benchmark__'
|
||||
# Clears out sys.modules and puts an entry at the front of sys.path.
|
||||
with util.create_modules(name) as mapping:
|
||||
assert not os.path.exists(imp.cache_from_source(mapping[name]))
|
||||
sys.meta_path.append(importlib.machinery.PathFinder)
|
||||
loader = (importlib.machinery.SourceFileLoader,
|
||||
importlib.machinery.SOURCE_SUFFIXES)
|
||||
sys.path_hooks.append(importlib.machinery.FileFinder.path_hook(loader))
|
||||
yield from bench(name, lambda: sys.modules.pop(name), repeat=repeat,
|
||||
seconds=seconds)
|
||||
finally:
|
||||
sys.dont_write_bytecode = False
|
||||
|
||||
|
||||
def _wo_bytecode(module):
|
||||
name = module.__name__
|
||||
def benchmark_wo_bytecode(seconds, repeat):
|
||||
"""Source w/o bytecode: {}"""
|
||||
bytecode_path = imp.cache_from_source(module.__file__)
|
||||
if os.path.exists(bytecode_path):
|
||||
os.unlink(bytecode_path)
|
||||
sys.dont_write_bytecode = True
|
||||
try:
|
||||
yield from bench(name, lambda: sys.modules.pop(name),
|
||||
repeat=repeat, seconds=seconds)
|
||||
finally:
|
||||
sys.dont_write_bytecode = False
|
||||
|
||||
benchmark_wo_bytecode.__doc__ = benchmark_wo_bytecode.__doc__.format(name)
|
||||
return benchmark_wo_bytecode
|
||||
|
||||
tabnanny_wo_bytecode = _wo_bytecode(tabnanny)
|
||||
decimal_wo_bytecode = _wo_bytecode(decimal)
|
||||
|
||||
|
||||
def source_writing_bytecode(seconds, repeat):
|
||||
"""Source writing bytecode: small"""
|
||||
assert not sys.dont_write_bytecode
|
||||
name = '__importlib_test_benchmark__'
|
||||
with util.create_modules(name) as mapping:
|
||||
sys.meta_path.append(importlib.machinery.PathFinder)
|
||||
loader = (importlib.machinery.SourceFileLoader,
|
||||
importlib.machinery.SOURCE_SUFFIXES)
|
||||
sys.path_hooks.append(importlib.machinery.FileFinder.path_hook(loader))
|
||||
def cleanup():
|
||||
sys.modules.pop(name)
|
||||
os.unlink(imp.cache_from_source(mapping[name]))
|
||||
for result in bench(name, cleanup, repeat=repeat, seconds=seconds):
|
||||
assert not os.path.exists(imp.cache_from_source(mapping[name]))
|
||||
yield result
|
||||
|
||||
|
||||
def _writing_bytecode(module):
|
||||
name = module.__name__
|
||||
def writing_bytecode_benchmark(seconds, repeat):
|
||||
"""Source writing bytecode: {}"""
|
||||
assert not sys.dont_write_bytecode
|
||||
def cleanup():
|
||||
sys.modules.pop(name)
|
||||
os.unlink(imp.cache_from_source(module.__file__))
|
||||
yield from bench(name, cleanup, repeat=repeat, seconds=seconds)
|
||||
|
||||
writing_bytecode_benchmark.__doc__ = (
|
||||
writing_bytecode_benchmark.__doc__.format(name))
|
||||
return writing_bytecode_benchmark
|
||||
|
||||
tabnanny_writing_bytecode = _writing_bytecode(tabnanny)
|
||||
decimal_writing_bytecode = _writing_bytecode(decimal)
|
||||
|
||||
|
||||
def source_using_bytecode(seconds, repeat):
|
||||
"""Source w/ bytecode: small"""
|
||||
name = '__importlib_test_benchmark__'
|
||||
with util.create_modules(name) as mapping:
|
||||
sys.meta_path.append(importlib.machinery.PathFinder)
|
||||
loader = (importlib.machinery.SourceFileLoader,
|
||||
importlib.machinery.SOURCE_SUFFIXES)
|
||||
sys.path_hooks.append(importlib.machinery.FileFinder.path_hook(loader))
|
||||
py_compile.compile(mapping[name])
|
||||
assert os.path.exists(imp.cache_from_source(mapping[name]))
|
||||
yield from bench(name, lambda: sys.modules.pop(name), repeat=repeat,
|
||||
seconds=seconds)
|
||||
|
||||
|
||||
def _using_bytecode(module):
|
||||
name = module.__name__
|
||||
def using_bytecode_benchmark(seconds, repeat):
|
||||
"""Source w/ bytecode: {}"""
|
||||
py_compile.compile(module.__file__)
|
||||
yield from bench(name, lambda: sys.modules.pop(name), repeat=repeat,
|
||||
seconds=seconds)
|
||||
|
||||
using_bytecode_benchmark.__doc__ = (
|
||||
using_bytecode_benchmark.__doc__.format(name))
|
||||
return using_bytecode_benchmark
|
||||
|
||||
tabnanny_using_bytecode = _using_bytecode(tabnanny)
|
||||
decimal_using_bytecode = _using_bytecode(decimal)
|
||||
|
||||
|
||||
def main(import_, options):
|
||||
if options.source_file:
|
||||
with options.source_file:
|
||||
prev_results = json.load(options.source_file)
|
||||
else:
|
||||
prev_results = {}
|
||||
__builtins__.__import__ = import_
|
||||
benchmarks = (from_cache, builtin_mod,
|
||||
source_writing_bytecode,
|
||||
source_wo_bytecode, source_using_bytecode,
|
||||
tabnanny_writing_bytecode,
|
||||
tabnanny_wo_bytecode, tabnanny_using_bytecode,
|
||||
decimal_writing_bytecode,
|
||||
decimal_wo_bytecode, decimal_using_bytecode,
|
||||
)
|
||||
if options.benchmark:
|
||||
for b in benchmarks:
|
||||
if b.__doc__ == options.benchmark:
|
||||
benchmarks = [b]
|
||||
break
|
||||
else:
|
||||
print('Unknown benchmark: {!r}'.format(options.benchmark,
|
||||
file=sys.stderr))
|
||||
sys.exit(1)
|
||||
seconds = 1
|
||||
seconds_plural = 's' if seconds > 1 else ''
|
||||
repeat = 3
|
||||
header = ('Measuring imports/second over {} second{}, best out of {}\n'
|
||||
'Entire benchmark run should take about {} seconds\n'
|
||||
'Using {!r} as __import__\n')
|
||||
print(header.format(seconds, seconds_plural, repeat,
|
||||
len(benchmarks) * seconds * repeat, __import__))
|
||||
new_results = {}
|
||||
for benchmark in benchmarks:
|
||||
print(benchmark.__doc__, "[", end=' ')
|
||||
sys.stdout.flush()
|
||||
results = []
|
||||
for result in benchmark(seconds=seconds, repeat=repeat):
|
||||
results.append(result)
|
||||
print(result, end=' ')
|
||||
sys.stdout.flush()
|
||||
assert not sys.dont_write_bytecode
|
||||
print("]", "best is", format(max(results), ',d'))
|
||||
new_results[benchmark.__doc__] = results
|
||||
if prev_results:
|
||||
print('\n\nComparing new vs. old\n')
|
||||
for benchmark in benchmarks:
|
||||
benchmark_name = benchmark.__doc__
|
||||
old_result = max(prev_results[benchmark_name])
|
||||
new_result = max(new_results[benchmark_name])
|
||||
result = '{:,d} vs. {:,d} ({:%})'.format(new_result,
|
||||
old_result,
|
||||
new_result/old_result)
|
||||
print(benchmark_name, ':', result)
|
||||
if options.dest_file:
|
||||
with options.dest_file:
|
||||
json.dump(new_results, options.dest_file, indent=2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-b', '--builtin', dest='builtin', action='store_true',
|
||||
default=False, help="use the built-in __import__")
|
||||
parser.add_argument('-r', '--read', dest='source_file',
|
||||
type=argparse.FileType('r'),
|
||||
help='file to read benchmark data from to compare '
|
||||
'against')
|
||||
parser.add_argument('-w', '--write', dest='dest_file',
|
||||
type=argparse.FileType('w'),
|
||||
help='file to write benchmark data to')
|
||||
parser.add_argument('--benchmark', dest='benchmark',
|
||||
help='specific benchmark to run')
|
||||
options = parser.parse_args()
|
||||
import_ = __import__
|
||||
if not options.builtin:
|
||||
import_ = importlib.__import__
|
||||
|
||||
main(import_, options)
|
556
third_party/python/Tools/iobench/iobench.py
vendored
Normal file
556
third_party/python/Tools/iobench/iobench.py
vendored
Normal file
|
@ -0,0 +1,556 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# This file should be kept compatible with both Python 2.6 and Python >= 3.0.
|
||||
|
||||
import itertools
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
from optparse import OptionParser
|
||||
|
||||
out = sys.stdout
|
||||
|
||||
TEXT_ENCODING = 'utf8'
|
||||
NEWLINES = 'lf'
|
||||
|
||||
# Compatibility
|
||||
try:
|
||||
xrange
|
||||
except NameError:
|
||||
xrange = range
|
||||
|
||||
def text_open(fn, mode, encoding=None):
|
||||
try:
|
||||
return open(fn, mode, encoding=encoding or TEXT_ENCODING)
|
||||
except TypeError:
|
||||
if 'r' in mode:
|
||||
mode += 'U' # 'U' mode is needed only in Python 2.x
|
||||
return open(fn, mode)
|
||||
|
||||
def get_file_sizes():
|
||||
for s in ['20 KB', '400 KB', '10 MB']:
|
||||
size, unit = s.split()
|
||||
size = int(size) * {'KB': 1024, 'MB': 1024 ** 2}[unit]
|
||||
yield s.replace(' ', ''), size
|
||||
|
||||
def get_binary_files():
|
||||
return ((name + ".bin", size) for name, size in get_file_sizes())
|
||||
|
||||
def get_text_files():
|
||||
return (("%s-%s-%s.txt" % (name, TEXT_ENCODING, NEWLINES), size)
|
||||
for name, size in get_file_sizes())
|
||||
|
||||
def with_open_mode(mode):
|
||||
def decorate(f):
|
||||
f.file_open_mode = mode
|
||||
return f
|
||||
return decorate
|
||||
|
||||
def with_sizes(*sizes):
|
||||
def decorate(f):
|
||||
f.file_sizes = sizes
|
||||
return f
|
||||
return decorate
|
||||
|
||||
|
||||
# Here begin the tests
|
||||
|
||||
@with_open_mode("r")
|
||||
@with_sizes("medium")
|
||||
def read_bytewise(f):
|
||||
""" read one unit at a time """
|
||||
f.seek(0)
|
||||
while f.read(1):
|
||||
pass
|
||||
|
||||
@with_open_mode("r")
|
||||
@with_sizes("medium")
|
||||
def read_small_chunks(f):
|
||||
""" read 20 units at a time """
|
||||
f.seek(0)
|
||||
while f.read(20):
|
||||
pass
|
||||
|
||||
@with_open_mode("r")
|
||||
@with_sizes("medium")
|
||||
def read_big_chunks(f):
|
||||
""" read 4096 units at a time """
|
||||
f.seek(0)
|
||||
while f.read(4096):
|
||||
pass
|
||||
|
||||
@with_open_mode("r")
|
||||
@with_sizes("small", "medium", "large")
|
||||
def read_whole_file(f):
|
||||
""" read whole contents at once """
|
||||
f.seek(0)
|
||||
while f.read():
|
||||
pass
|
||||
|
||||
@with_open_mode("rt")
|
||||
@with_sizes("medium")
|
||||
def read_lines(f):
|
||||
""" read one line at a time """
|
||||
f.seek(0)
|
||||
for line in f:
|
||||
pass
|
||||
|
||||
@with_open_mode("r")
|
||||
@with_sizes("medium")
|
||||
def seek_forward_bytewise(f):
|
||||
""" seek forward one unit at a time """
|
||||
f.seek(0, 2)
|
||||
size = f.tell()
|
||||
f.seek(0, 0)
|
||||
for i in xrange(0, size - 1):
|
||||
f.seek(i, 0)
|
||||
|
||||
@with_open_mode("r")
|
||||
@with_sizes("medium")
|
||||
def seek_forward_blockwise(f):
|
||||
""" seek forward 1000 units at a time """
|
||||
f.seek(0, 2)
|
||||
size = f.tell()
|
||||
f.seek(0, 0)
|
||||
for i in xrange(0, size - 1, 1000):
|
||||
f.seek(i, 0)
|
||||
|
||||
@with_open_mode("rb")
|
||||
@with_sizes("medium")
|
||||
def read_seek_bytewise(f):
|
||||
""" alternate read & seek one unit """
|
||||
f.seek(0)
|
||||
while f.read(1):
|
||||
f.seek(1, 1)
|
||||
|
||||
@with_open_mode("rb")
|
||||
@with_sizes("medium")
|
||||
def read_seek_blockwise(f):
|
||||
""" alternate read & seek 1000 units """
|
||||
f.seek(0)
|
||||
while f.read(1000):
|
||||
f.seek(1000, 1)
|
||||
|
||||
|
||||
@with_open_mode("w")
|
||||
@with_sizes("small")
|
||||
def write_bytewise(f, source):
|
||||
""" write one unit at a time """
|
||||
for i in xrange(0, len(source)):
|
||||
f.write(source[i:i+1])
|
||||
|
||||
@with_open_mode("w")
|
||||
@with_sizes("medium")
|
||||
def write_small_chunks(f, source):
|
||||
""" write 20 units at a time """
|
||||
for i in xrange(0, len(source), 20):
|
||||
f.write(source[i:i+20])
|
||||
|
||||
@with_open_mode("w")
|
||||
@with_sizes("medium")
|
||||
def write_medium_chunks(f, source):
|
||||
""" write 4096 units at a time """
|
||||
for i in xrange(0, len(source), 4096):
|
||||
f.write(source[i:i+4096])
|
||||
|
||||
@with_open_mode("w")
|
||||
@with_sizes("large")
|
||||
def write_large_chunks(f, source):
|
||||
""" write 1e6 units at a time """
|
||||
for i in xrange(0, len(source), 1000000):
|
||||
f.write(source[i:i+1000000])
|
||||
|
||||
|
||||
@with_open_mode("w+")
|
||||
@with_sizes("small")
|
||||
def modify_bytewise(f, source):
|
||||
""" modify one unit at a time """
|
||||
f.seek(0)
|
||||
for i in xrange(0, len(source)):
|
||||
f.write(source[i:i+1])
|
||||
|
||||
@with_open_mode("w+")
|
||||
@with_sizes("medium")
|
||||
def modify_small_chunks(f, source):
|
||||
""" modify 20 units at a time """
|
||||
f.seek(0)
|
||||
for i in xrange(0, len(source), 20):
|
||||
f.write(source[i:i+20])
|
||||
|
||||
@with_open_mode("w+")
|
||||
@with_sizes("medium")
|
||||
def modify_medium_chunks(f, source):
|
||||
""" modify 4096 units at a time """
|
||||
f.seek(0)
|
||||
for i in xrange(0, len(source), 4096):
|
||||
f.write(source[i:i+4096])
|
||||
|
||||
@with_open_mode("wb+")
|
||||
@with_sizes("medium")
|
||||
def modify_seek_forward_bytewise(f, source):
|
||||
""" alternate write & seek one unit """
|
||||
f.seek(0)
|
||||
for i in xrange(0, len(source), 2):
|
||||
f.write(source[i:i+1])
|
||||
f.seek(i+2)
|
||||
|
||||
@with_open_mode("wb+")
|
||||
@with_sizes("medium")
|
||||
def modify_seek_forward_blockwise(f, source):
|
||||
""" alternate write & seek 1000 units """
|
||||
f.seek(0)
|
||||
for i in xrange(0, len(source), 2000):
|
||||
f.write(source[i:i+1000])
|
||||
f.seek(i+2000)
|
||||
|
||||
# XXX the 2 following tests don't work with py3k's text IO
|
||||
@with_open_mode("wb+")
|
||||
@with_sizes("medium")
|
||||
def read_modify_bytewise(f, source):
|
||||
""" alternate read & write one unit """
|
||||
f.seek(0)
|
||||
for i in xrange(0, len(source), 2):
|
||||
f.read(1)
|
||||
f.write(source[i+1:i+2])
|
||||
|
||||
@with_open_mode("wb+")
|
||||
@with_sizes("medium")
|
||||
def read_modify_blockwise(f, source):
|
||||
""" alternate read & write 1000 units """
|
||||
f.seek(0)
|
||||
for i in xrange(0, len(source), 2000):
|
||||
f.read(1000)
|
||||
f.write(source[i+1000:i+2000])
|
||||
|
||||
|
||||
read_tests = [
|
||||
read_bytewise, read_small_chunks, read_lines, read_big_chunks,
|
||||
None, read_whole_file, None,
|
||||
seek_forward_bytewise, seek_forward_blockwise,
|
||||
read_seek_bytewise, read_seek_blockwise,
|
||||
]
|
||||
|
||||
write_tests = [
|
||||
write_bytewise, write_small_chunks, write_medium_chunks, write_large_chunks,
|
||||
]
|
||||
|
||||
modify_tests = [
|
||||
modify_bytewise, modify_small_chunks, modify_medium_chunks,
|
||||
None,
|
||||
modify_seek_forward_bytewise, modify_seek_forward_blockwise,
|
||||
read_modify_bytewise, read_modify_blockwise,
|
||||
]
|
||||
|
||||
def run_during(duration, func):
|
||||
_t = time.time
|
||||
n = 0
|
||||
start = os.times()
|
||||
start_timestamp = _t()
|
||||
real_start = start[4] or start_timestamp
|
||||
while True:
|
||||
func()
|
||||
n += 1
|
||||
if _t() - start_timestamp > duration:
|
||||
break
|
||||
end = os.times()
|
||||
real = (end[4] if start[4] else time.time()) - real_start
|
||||
return n, real, sum(end[0:2]) - sum(start[0:2])
|
||||
|
||||
def warm_cache(filename):
|
||||
with open(filename, "rb") as f:
|
||||
f.read()
|
||||
|
||||
|
||||
def run_all_tests(options):
|
||||
def print_label(filename, func):
|
||||
name = re.split(r'[-.]', filename)[0]
|
||||
out.write(
|
||||
("[%s] %s... "
|
||||
% (name.center(7), func.__doc__.strip())
|
||||
).ljust(52))
|
||||
out.flush()
|
||||
|
||||
def print_results(size, n, real, cpu):
|
||||
bw = n * float(size) / 1024 ** 2 / real
|
||||
bw = ("%4d MB/s" if bw > 100 else "%.3g MB/s") % bw
|
||||
out.write(bw.rjust(12) + "\n")
|
||||
if cpu < 0.90 * real:
|
||||
out.write(" warning: test above used only %d%% CPU, "
|
||||
"result may be flawed!\n" % (100.0 * cpu / real))
|
||||
|
||||
def run_one_test(name, size, open_func, test_func, *args):
|
||||
mode = test_func.file_open_mode
|
||||
print_label(name, test_func)
|
||||
if "w" not in mode or "+" in mode:
|
||||
warm_cache(name)
|
||||
with open_func(name) as f:
|
||||
n, real, cpu = run_during(1.5, lambda: test_func(f, *args))
|
||||
print_results(size, n, real, cpu)
|
||||
|
||||
def run_test_family(tests, mode_filter, files, open_func, *make_args):
|
||||
for test_func in tests:
|
||||
if test_func is None:
|
||||
out.write("\n")
|
||||
continue
|
||||
if mode_filter in test_func.file_open_mode:
|
||||
continue
|
||||
for s in test_func.file_sizes:
|
||||
name, size = files[size_names[s]]
|
||||
#name += file_ext
|
||||
args = tuple(f(name, size) for f in make_args)
|
||||
run_one_test(name, size,
|
||||
open_func, test_func, *args)
|
||||
|
||||
size_names = {
|
||||
"small": 0,
|
||||
"medium": 1,
|
||||
"large": 2,
|
||||
}
|
||||
|
||||
print("Python %s" % sys.version)
|
||||
if sys.version_info < (3, 3):
|
||||
if sys.maxunicode > 0xffff:
|
||||
text = "UCS-4 (wide build)"
|
||||
else:
|
||||
text = "UTF-16 (narrow build)"
|
||||
else:
|
||||
text = "PEP 393"
|
||||
print("Unicode: %s" % text)
|
||||
print(platform.platform())
|
||||
binary_files = list(get_binary_files())
|
||||
text_files = list(get_text_files())
|
||||
if "b" in options:
|
||||
print("Binary unit = one byte")
|
||||
if "t" in options:
|
||||
print("Text unit = one character (%s-decoded)" % TEXT_ENCODING)
|
||||
|
||||
# Binary reads
|
||||
if "b" in options and "r" in options:
|
||||
print("\n** Binary input **\n")
|
||||
run_test_family(read_tests, "t", binary_files, lambda fn: open(fn, "rb"))
|
||||
|
||||
# Text reads
|
||||
if "t" in options and "r" in options:
|
||||
print("\n** Text input **\n")
|
||||
run_test_family(read_tests, "b", text_files, lambda fn: text_open(fn, "r"))
|
||||
|
||||
# Binary writes
|
||||
if "b" in options and "w" in options:
|
||||
print("\n** Binary append **\n")
|
||||
def make_test_source(name, size):
|
||||
with open(name, "rb") as f:
|
||||
return f.read()
|
||||
run_test_family(write_tests, "t", binary_files,
|
||||
lambda fn: open(os.devnull, "wb"), make_test_source)
|
||||
|
||||
# Text writes
|
||||
if "t" in options and "w" in options:
|
||||
print("\n** Text append **\n")
|
||||
def make_test_source(name, size):
|
||||
with text_open(name, "r") as f:
|
||||
return f.read()
|
||||
run_test_family(write_tests, "b", text_files,
|
||||
lambda fn: text_open(os.devnull, "w"), make_test_source)
|
||||
|
||||
# Binary overwrites
|
||||
if "b" in options and "w" in options:
|
||||
print("\n** Binary overwrite **\n")
|
||||
def make_test_source(name, size):
|
||||
with open(name, "rb") as f:
|
||||
return f.read()
|
||||
run_test_family(modify_tests, "t", binary_files,
|
||||
lambda fn: open(fn, "r+b"), make_test_source)
|
||||
|
||||
# Text overwrites
|
||||
if "t" in options and "w" in options:
|
||||
print("\n** Text overwrite **\n")
|
||||
def make_test_source(name, size):
|
||||
with text_open(name, "r") as f:
|
||||
return f.read()
|
||||
run_test_family(modify_tests, "b", text_files,
|
||||
lambda fn: text_open(fn, "r+"), make_test_source)
|
||||
|
||||
|
||||
def prepare_files():
|
||||
print("Preparing files...")
|
||||
# Binary files
|
||||
for name, size in get_binary_files():
|
||||
if os.path.isfile(name) and os.path.getsize(name) == size:
|
||||
continue
|
||||
with open(name, "wb") as f:
|
||||
f.write(os.urandom(size))
|
||||
# Text files
|
||||
chunk = []
|
||||
with text_open(__file__, "r", encoding='utf8') as f:
|
||||
for line in f:
|
||||
if line.startswith("# <iobench text chunk marker>"):
|
||||
break
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"Couldn't find chunk marker in %s !" % __file__)
|
||||
if NEWLINES == "all":
|
||||
it = itertools.cycle(["\n", "\r", "\r\n"])
|
||||
else:
|
||||
it = itertools.repeat(
|
||||
{"cr": "\r", "lf": "\n", "crlf": "\r\n"}[NEWLINES])
|
||||
chunk = "".join(line.replace("\n", next(it)) for line in f)
|
||||
if isinstance(chunk, bytes):
|
||||
chunk = chunk.decode('utf8')
|
||||
chunk = chunk.encode(TEXT_ENCODING)
|
||||
for name, size in get_text_files():
|
||||
if os.path.isfile(name) and os.path.getsize(name) == size:
|
||||
continue
|
||||
head = chunk * (size // len(chunk))
|
||||
tail = chunk[:size % len(chunk)]
|
||||
# Adjust tail to end on a character boundary
|
||||
while True:
|
||||
try:
|
||||
tail.decode(TEXT_ENCODING)
|
||||
break
|
||||
except UnicodeDecodeError:
|
||||
tail = tail[:-1]
|
||||
with open(name, "wb") as f:
|
||||
f.write(head)
|
||||
f.write(tail)
|
||||
|
||||
def main():
|
||||
global TEXT_ENCODING, NEWLINES
|
||||
|
||||
usage = "usage: %prog [-h|--help] [options]"
|
||||
parser = OptionParser(usage=usage)
|
||||
parser.add_option("-b", "--binary",
|
||||
action="store_true", dest="binary", default=False,
|
||||
help="run binary I/O tests")
|
||||
parser.add_option("-t", "--text",
|
||||
action="store_true", dest="text", default=False,
|
||||
help="run text I/O tests")
|
||||
parser.add_option("-r", "--read",
|
||||
action="store_true", dest="read", default=False,
|
||||
help="run read tests")
|
||||
parser.add_option("-w", "--write",
|
||||
action="store_true", dest="write", default=False,
|
||||
help="run write & modify tests")
|
||||
parser.add_option("-E", "--encoding",
|
||||
action="store", dest="encoding", default=None,
|
||||
help="encoding for text tests (default: %s)" % TEXT_ENCODING)
|
||||
parser.add_option("-N", "--newlines",
|
||||
action="store", dest="newlines", default='lf',
|
||||
help="line endings for text tests "
|
||||
"(one of: {lf (default), cr, crlf, all})")
|
||||
parser.add_option("-m", "--io-module",
|
||||
action="store", dest="io_module", default=None,
|
||||
help="io module to test (default: builtin open())")
|
||||
options, args = parser.parse_args()
|
||||
if args:
|
||||
parser.error("unexpected arguments")
|
||||
NEWLINES = options.newlines.lower()
|
||||
if NEWLINES not in ('lf', 'cr', 'crlf', 'all'):
|
||||
parser.error("invalid 'newlines' option: %r" % NEWLINES)
|
||||
|
||||
test_options = ""
|
||||
if options.read:
|
||||
test_options += "r"
|
||||
if options.write:
|
||||
test_options += "w"
|
||||
elif not options.read:
|
||||
test_options += "rw"
|
||||
if options.text:
|
||||
test_options += "t"
|
||||
if options.binary:
|
||||
test_options += "b"
|
||||
elif not options.text:
|
||||
test_options += "tb"
|
||||
|
||||
if options.encoding:
|
||||
TEXT_ENCODING = options.encoding
|
||||
|
||||
if options.io_module:
|
||||
globals()['open'] = __import__(options.io_module, {}, {}, ['open']).open
|
||||
|
||||
prepare_files()
|
||||
run_all_tests(test_options)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
||||
# -- This part to exercise text reading. Don't change anything! --
|
||||
# <iobench text chunk marker>
|
||||
|
||||
"""
|
||||
1.
|
||||
Gáttir allar,
|
||||
áðr gangi fram,
|
||||
um skoðask skyli,
|
||||
um skyggnast skyli,
|
||||
því at óvíst er at vita,
|
||||
hvar óvinir
|
||||
sitja á fleti fyrir.
|
||||
|
||||
2.
|
||||
Gefendr heilir!
|
||||
Gestr er inn kominn,
|
||||
hvar skal sitja sjá?
|
||||
Mjök er bráðr,
|
||||
sá er á bröndum skal
|
||||
síns of freista frama.
|
||||
|
||||
3.
|
||||
Elds er þörf,
|
||||
þeims inn er kominn
|
||||
ok á kné kalinn;
|
||||
matar ok váða
|
||||
er manni þörf,
|
||||
þeim er hefr um fjall farit.
|
||||
|
||||
4.
|
||||
Vatns er þörf,
|
||||
þeim er til verðar kemr,
|
||||
þerru ok þjóðlaðar,
|
||||
góðs of æðis,
|
||||
ef sér geta mætti,
|
||||
orðs ok endrþögu.
|
||||
|
||||
5.
|
||||
Vits er þörf,
|
||||
þeim er víða ratar;
|
||||
dælt er heima hvat;
|
||||
at augabragði verðr,
|
||||
sá er ekki kann
|
||||
ok með snotrum sitr.
|
||||
|
||||
6.
|
||||
At hyggjandi sinni
|
||||
skyli-t maðr hræsinn vera,
|
||||
heldr gætinn at geði;
|
||||
þá er horskr ok þögull
|
||||
kemr heimisgarða til,
|
||||
sjaldan verðr víti vörum,
|
||||
því at óbrigðra vin
|
||||
fær maðr aldregi
|
||||
en mannvit mikit.
|
||||
|
||||
7.
|
||||
Inn vari gestr,
|
||||
er til verðar kemr,
|
||||
þunnu hljóði þegir,
|
||||
eyrum hlýðir,
|
||||
en augum skoðar;
|
||||
svá nýsisk fróðra hverr fyrir.
|
||||
|
||||
8.
|
||||
Hinn er sæll,
|
||||
er sér of getr
|
||||
lof ok líknstafi;
|
||||
ódælla er við þat,
|
||||
er maðr eiga skal
|
||||
annars brjóstum í.
|
||||
"""
|
||||
|
||||
"""
|
||||
C'est revenir tard, je le sens, sur un sujet trop rebattu et déjà presque oublié. Mon état, qui ne me permet plus aucun travail suivi, mon aversion pour le genre polémique, ont causé ma lenteur à écrire et ma répugnance à publier. J'aurais même tout à fait supprimé ces Lettres, ou plutôt je lie les aurais point écrites, s'il n'eût été question que de moi : Mais ma patrie ne m'est pas tellement devenue étrangère que je puisse voir tranquillement opprimer ses citoyens, surtout lorsqu'ils n'ont compromis leurs droits qu'en défendant ma cause. Je serais le dernier des hommes si dans une telle occasion j'écoutais un sentiment qui n'est plus ni douceur ni patience, mais faiblesse et lâcheté, dans celui qu'il empêche de remplir son devoir.
|
||||
Rien de moins important pour le public, j'en conviens, que la matière de ces lettres. La constitution d'une petite République, le sort d'un petit particulier, l'exposé de quelques injustices, la réfutation de quelques sophismes ; tout cela n'a rien en soi d'assez considérable pour mériter beaucoup de lecteurs : mais si mes sujets sont petits mes objets sont grands, et dignes de l'attention de tout honnête homme. Laissons Genève à sa place, et Rousseau dans sa dépression ; mais la religion, mais la liberté, la justice ! voilà, qui que vous soyez, ce qui n'est pas au-dessous de vous.
|
||||
Qu'on ne cherche pas même ici dans le style le dédommagement de l'aridité de la matière. Ceux que quelques traits heureux de ma plume ont si fort irrités trouveront de quoi s'apaiser dans ces lettres, L'honneur de défendre un opprimé eût enflammé mon coeur si j'avais parlé pour un autre. Réduit au triste emploi de me défendre moi-même, j'ai dû me borner à raisonner ; m'échauffer eût été m'avilir. J'aurai donc trouvé grâce en ce point devant ceux qui s'imaginent qu'il est essentiel à la vérité d'être dite froidement ; opinion que pourtant j'ai peine à comprendre. Lorsqu'une vive persuasion nous anime, le moyen d'employer un langage glacé ? Quand Archimède tout transporté courait nu dans les rues de Syracuse, en avait-il moins trouvé la vérité parce qu'il se passionnait pour elle ? Tout au contraire, celui qui la sent ne peut s'abstenir de l'adorer ; celui qui demeure froid ne l'a pas vue.
|
||||
Quoi qu'il en soit, je prie les lecteurs de vouloir bien mettre à part mon beau style, et d'examiner seulement si je raisonne bien ou mal ; car enfin, de cela seul qu'un auteur s'exprime en bons termes, je ne vois pas comment il peut s'ensuivre que cet auteur ne sait ce qu'il dit.
|
||||
"""
|
543
third_party/python/Tools/msi/README.txt
vendored
Normal file
543
third_party/python/Tools/msi/README.txt
vendored
Normal file
|
@ -0,0 +1,543 @@
|
|||
Quick Build Info
|
||||
================
|
||||
|
||||
For testing, the installer should be built with the Tools/msi/build.bat
|
||||
script:
|
||||
|
||||
build.bat [-x86] [-x64] [--doc]
|
||||
|
||||
For an official release, the installer should be built with the
|
||||
Tools/msi/buildrelease.bat script and environment variables:
|
||||
|
||||
set PYTHON=<path to Python 2.7 or 3.4>
|
||||
set SPHINXBUILD=<path to sphinx-build.exe>
|
||||
set PATH=<path to Mercurial (hg.exe)>;
|
||||
<path to HTML Help Compiler (hhc.exe)>;%PATH%
|
||||
|
||||
buildrelease.bat [-x86] [-x64] [-D] [-B]
|
||||
[-o <output directory>] [-c <certificate name>]
|
||||
|
||||
See the Building the Installer section for more information.
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
Python is distributed on Windows as an installer that will configure the
|
||||
user's system. This allows users to have a functioning copy of Python
|
||||
without having to build it themselves.
|
||||
|
||||
The main tasks of the installer are:
|
||||
|
||||
* copy required files into the expected layout
|
||||
* configure system settings so the installation can be located by
|
||||
other programs
|
||||
* add entry points for modifying, repairing and uninstalling Python
|
||||
* make it easy to launch Python, its documentation, and IDLE
|
||||
|
||||
Each of these is discussed in a later section of this document.
|
||||
|
||||
Structure of the Installer
|
||||
==========================
|
||||
|
||||
The installer is structured as a 'layout', which consists of a number of
|
||||
CAB and MSI files and a single EXE.
|
||||
|
||||
The EXE is the main entry point into the installer. It contains the UI
|
||||
and command-line logic, as well as the ability to locate and optionally
|
||||
download other parts of the layout.
|
||||
|
||||
Each MSI contains the logic required to install a component or feature
|
||||
of Python. These MSIs should not be launched directly by users. MSIs can
|
||||
be embedded into the EXE or automatically downloaded as needed.
|
||||
|
||||
Each CAB contains the files making up a Python installation. CABs are
|
||||
embedded into their associated MSI and are never seen by users.
|
||||
|
||||
MSIs are only required when the related feature or component is being
|
||||
installed. When components are not selected for installation, the
|
||||
associated MSI is not downloaded. This allows the installer to offer
|
||||
options to install debugging symbols and binaries without increasing
|
||||
the initial download size by separating them into their own MSIs.
|
||||
|
||||
Building the Installer
|
||||
======================
|
||||
|
||||
Before building the installer, download extra build dependencies using
|
||||
Tools\msi\get_externals.bat. (Note that this is in addition to the
|
||||
similarly named file in PCBuild.)
|
||||
|
||||
One of the dependencies used in builds is WiX, a toolset that lets developers
|
||||
create installers for Windows Installer, the Windows installation engine. WiX
|
||||
has a dependency on the Microsoft .NET Framework Version 3.5 (which may not be
|
||||
configured on recent versions of Windows, such as Windows 10). If you are
|
||||
building on a recent Windows version, use the Control Panel (Programs | Programs
|
||||
and Features | Turn Windows Features on or off) and ensure that the entry
|
||||
".NET Framework 3.5 (includes .NET 2.0 and 3.0)" is enabled.
|
||||
|
||||
For testing, the installer should be built with the Tools/msi/build.bat
|
||||
script:
|
||||
|
||||
build.bat [-x86] [-x64] [--doc] [--test-marker] [--pack]
|
||||
|
||||
This script will build the required configurations of Python and
|
||||
generate an installer layout in PCBuild/(win32|amd64)/en-us.
|
||||
|
||||
Specify -x86 and/or -x64 to build for each platform. If neither is
|
||||
specified, both platforms will be built. Currently, both the debug and
|
||||
release versions of Python are required for the installer.
|
||||
|
||||
Specify --doc to build the documentation (.chm) file. If the file is not
|
||||
available, it will simply be excluded from the installer. Ensure
|
||||
%PYTHON% and %SPHINXBUILD% are set when passing this option. You may
|
||||
also set %HTMLHELP% to the Html Help Compiler (hhc.exe), or put HHC on
|
||||
your PATH or in externals/.
|
||||
|
||||
Specify --test-marker to build an installer that works side-by-side with
|
||||
an official Python release. All registry keys and install locations will
|
||||
include an extra marker to avoid overwriting files. This marker is
|
||||
currently an 'x' prefix, but may change at any time.
|
||||
|
||||
Specify --pack to build an installer that does not require all MSIs to
|
||||
be available alongside. This takes longer, but is easier to share.
|
||||
|
||||
|
||||
For an official release, the installer should be built with the
|
||||
Tools/msi/buildrelease.bat script:
|
||||
|
||||
set PYTHON=<path to Python 2.7 or 3.4>
|
||||
set SPHINXBUILD=<path to sphinx-build.exe>
|
||||
set PATH=<path to Mercurial (hg.exe)>;
|
||||
<path to HTML Help Compiler (hhc.exe)>;%PATH%
|
||||
|
||||
buildrelease.bat [-x86] [-x64] [-D] [-B]
|
||||
[-o <output directory>] [-c <certificate name>]
|
||||
|
||||
Specify -x86 and/or -x64 to build for each platform. If neither is
|
||||
specified, both platforms will be built. Currently, both the debug and
|
||||
release versions of Python are required for the installer.
|
||||
|
||||
Specify -D to skip rebuilding the documentation. The documentation is
|
||||
required for a release and the build will fail if it is not available.
|
||||
|
||||
Specify -B to skip rebuilding Python. This is useful to only rebuild the
|
||||
installer layout after a previous call to buildrelease.bat.
|
||||
|
||||
Specify -o to set an output directory. The installer layouts will be
|
||||
copied to platform-specific subdirectories of this path.
|
||||
|
||||
Specify -c to choose a code-signing certificate to be used for all the
|
||||
signable binaries in Python as well as each file making up the
|
||||
installer. Official releases of Python must be signed.
|
||||
|
||||
Ensure %PYTHON% and %SPHINXBUILD% are set when passing this option. You
|
||||
may also set %HTMLHELP% to the Html Help Compiler (hhc.exe), or put HHC
|
||||
on your PATH or in externals/. You will also need Mercurial (hg.exe) on
|
||||
your PATH.
|
||||
|
||||
If WiX is not found on your system, it will be automatically downloaded
|
||||
and extracted to the externals/ directory.
|
||||
|
||||
To manually build layouts of the installer, build one of the projects in
|
||||
the bundle folder.
|
||||
|
||||
msbuild bundle\snapshot.wixproj
|
||||
msbuild bundle\releaseweb.wixproj
|
||||
msbuild bundle\releaselocal.wixproj
|
||||
msbuild bundle\full.wixproj
|
||||
|
||||
snapshot.wixproj produces a test installer versioned based on the date.
|
||||
|
||||
releaseweb.wixproj produces a release installer that does not embed any
|
||||
of the layout.
|
||||
|
||||
releaselocal.wixproj produces a release installer that embeds the files
|
||||
required for a default installation.
|
||||
|
||||
full.wixproj produces a test installer that embeds the entire layout.
|
||||
|
||||
The following properties may be passed when building these projects.
|
||||
|
||||
/p:BuildForRelease=(true|false)
|
||||
When true, adds extra verification to ensure a complete installer is
|
||||
produced. For example, binutils is required when building for a release
|
||||
to generate MinGW-compatible libraries, and the build will be aborted if
|
||||
this fails. Defaults to false.
|
||||
|
||||
/p:ReleaseUri=(any URI)
|
||||
Used to generate unique IDs for the installers to allow side-by-side
|
||||
installation. Forks of Python can use the same installer infrastructure
|
||||
by providing a unique URI for this property. It does not need to be an
|
||||
active internet address. Defaults to $(ComputerName).
|
||||
|
||||
Official releases use http://www.python.org/(architecture name)
|
||||
|
||||
/p:DownloadUrlBase=(any URI)
|
||||
Specifies the base of a URL where missing parts of the installer layout
|
||||
can be downloaded from. The build version and architecture will be
|
||||
appended to create the full address. If omitted, missing components will
|
||||
not be automatically downloaded.
|
||||
|
||||
/p:DownloadUrl=(any URI)
|
||||
Specifies the full URL where missing parts of the installer layout can
|
||||
be downloaded from. Should normally include '{2}', which will be
|
||||
substituted for the filename. If omitted, missing components will not be
|
||||
automatically downloaded. If specified, this value overrides
|
||||
DownloadUrlBase.
|
||||
|
||||
/p:SigningCertificate=(certificate name)
|
||||
Specifies the certificate to sign the installer layout with. If omitted,
|
||||
the layout will not be signed.
|
||||
|
||||
/p:RebuildAll=(true|false)
|
||||
When true, rebuilds all of the MSIs making up the layout. Defaults to
|
||||
true.
|
||||
|
||||
Uploading the Installer
|
||||
=======================
|
||||
|
||||
For official releases, the uploadrelease.bat script should be used.
|
||||
|
||||
You will require PuTTY so that plink.exe and pscp.exe can be used, and your
|
||||
SSH key can be activated in pageant.exe. PuTTY should be either on your path
|
||||
or in %ProgramFiles(x86)%\PuTTY.
|
||||
|
||||
To include signatures for each uploaded file, you will need gpg2.exe on your
|
||||
path or have run get_externals.bat. You may also need to "gpg2.exe --import"
|
||||
your key before running the upload script.
|
||||
|
||||
uploadrelease.bat --host <host> --user <username> [--dry-run] [--no-gpg]
|
||||
|
||||
The host is the URL to the server. This can be provided by the Release
|
||||
Manager. You should be able to SSH to this address.
|
||||
|
||||
The username is your own username, which you have permission to SSH into
|
||||
the server containing downloads.
|
||||
|
||||
Use --dry-run to display the generated upload commands without executing
|
||||
them. Signatures for each file will be generated but not uploaded unless
|
||||
--no-gpg is also passed.
|
||||
|
||||
Use --no-gpg to suppress signature generation and upload.
|
||||
|
||||
The default target directory (which appears in uploadrelease.proj) is
|
||||
correct for official Python releases, but may be overridden with
|
||||
--target <path> for other purposes. This path should generally not include
|
||||
any version specifier, as that will be added automatically.
|
||||
|
||||
Modifying the Installer
|
||||
=======================
|
||||
|
||||
The code for the installer is divided into three main groups: packages,
|
||||
the bundle and the bootstrap application.
|
||||
|
||||
Packages
|
||||
--------
|
||||
|
||||
Packages appear as subdirectories of Tools/msi (other than the bundle/
|
||||
directory). The project file is a .wixproj and the build output is a
|
||||
single MSI. Packages are built with the WiX Toolset. Some project files
|
||||
share source files and use preprocessor directives to enable particular
|
||||
features. These are typically used to keep the sources close when the
|
||||
files are related, but produce multiple independent packages.
|
||||
|
||||
A package is the smallest element that may be independently installed or
|
||||
uninstalled (as used in this installer). For example, the test suite has
|
||||
its own package, as users can choose to add or remove it after the
|
||||
initial installation.
|
||||
|
||||
All the files installed by a single package should be related, though
|
||||
some packages may not install any files. For example, the pip package
|
||||
executes the ensurepip package, but does not add or remove any of its
|
||||
own files. (It is represented as a package because of its
|
||||
installed/uninstalled nature, as opposed to the "precompile standard
|
||||
library" option, for example.) Dependencies between packages are handled
|
||||
by the bundle, but packages should detect when dependencies are missing
|
||||
and raise an error.
|
||||
|
||||
Packages that include a lot of files may use an InstallFiles element in
|
||||
the .wixproj file to generate sources. See lib/lib.wixproj for an
|
||||
example, and msi.targets and csv_to_wxs.py for the implementation. This
|
||||
element is also responsible for generating the code for cleaning up and
|
||||
removing __pycache__ folders in any directory containing .py files.
|
||||
|
||||
All packages are built with the Tools/msi/common.wxs file, and so any
|
||||
directory or property in this file may be referenced. Of particular
|
||||
interest:
|
||||
|
||||
REGISTRYKEY (property)
|
||||
The registry key for the current installation.
|
||||
|
||||
InstallDirectory (directory)
|
||||
The root install directory for the current installation. Subdirectories
|
||||
are also specified in this file (DLLs, Lib, etc.)
|
||||
|
||||
MenuDir (directory)
|
||||
The Start Menu folder for the current installation.
|
||||
|
||||
UpgradeTable (property)
|
||||
Every package should reference this property to include upgrade
|
||||
information.
|
||||
|
||||
OptionalFeature (Component)
|
||||
Packages that may be enabled or disabled should reference this component
|
||||
and have an OPTIONAL_FEATURES entry in the bootstrap application to
|
||||
properly handle Modify and Upgrade.
|
||||
|
||||
The .wxl_template file is specially handled by the build system for this
|
||||
project to perform {{substitutions}} as defined in msi.targets. They
|
||||
should be included in projects as <WxlTemplate> items, where .wxl files
|
||||
are normally included as <EmbeddedResource> items.
|
||||
|
||||
Bundle
|
||||
------
|
||||
|
||||
The bundle is compiled to the main EXE entry point that for most users
|
||||
will represent the Python installer. It is built from Tools/msi/bundle
|
||||
with packages references in Tools/msi/bundle/packagegroups.
|
||||
|
||||
Build logic for the bundle is in bundle.targets, but should be invoked
|
||||
through one of the .wixproj files as described in Building the
|
||||
Installer.
|
||||
|
||||
The UI is separated between Default.thm (UI layout), Default.wxl
|
||||
(strings), bundle.wxs (properties) and the bootstrap application.
|
||||
Bundle.wxs also contains the chain, which is the list of packages to
|
||||
install and the order they should be installed in. These refer to named
|
||||
package groups in bundle/packagegroups.
|
||||
|
||||
Each package group specifies one or more packages to install. Most
|
||||
packages require two separate entries to support both per-user and
|
||||
all-users installations. Because these reuse the same package, it does
|
||||
not increase the overall size of the package.
|
||||
|
||||
Package groups refer to payload groups, which allow better control over
|
||||
embedding and downloading files than the default settings. Whether files
|
||||
are embedded and where they are downloaded from depends on settings
|
||||
created by the project files.
|
||||
|
||||
Package references can include install conditions that determine when to
|
||||
install the package. When a package is a dependency for others, the
|
||||
condition should be crafted to ensure it is installed.
|
||||
|
||||
MSI packages are installed or uninstalled based on their current state
|
||||
and the install condition. This makes them most suitable for features
|
||||
that are clearly present or absent from the user's machine.
|
||||
|
||||
EXE packages are executed based on a customisable condition that can be
|
||||
omitted. This makes them suitable for pre- or post-install tasks that
|
||||
need to run regardless of whether features have been added or removed.
|
||||
|
||||
Bootstrap Application
|
||||
---------------------
|
||||
|
||||
The bootstrap application is a C++ application that controls the UI and
|
||||
installation. While it does not directly compile into the main EXE of
|
||||
the installer, it forms the main active component. Most of the
|
||||
installation functionality is provided by WiX, and so the bootstrap
|
||||
application is predominantly responsible for the code behind the UI that
|
||||
is defined in the Default.thm file. The bootstrap application code is in
|
||||
bundle/bootstrap and is built automatically when building the bundle.
|
||||
|
||||
Installation Layout
|
||||
===================
|
||||
|
||||
There are two installation layouts for Python on Windows, with the only
|
||||
differences being supporting files. A layout is selected implicitly
|
||||
based on whether the install is for all users of the machine or just for
|
||||
the user performing the installation.
|
||||
|
||||
The default installation location when installing for all users is
|
||||
"%ProgramFiles%\Python3X" for the 64-bit interpreter and
|
||||
"%ProgramFiles(x86)%\Python3X-32" for the 32-bit interpreter. (Note that
|
||||
the latter path is equivalent to "%ProgramFiles%\Python3X-32" when
|
||||
running a 32-bit version of Windows.) This location requires
|
||||
administrative privileges to install or later modify the installation.
|
||||
|
||||
The default installation location when installing for the current user
|
||||
is "%LocalAppData%\Programs\Python\Python3X" for the 64-bit interpreter
|
||||
and "%LocalAppData%\Programs\Python\Python3X-32" for the 32-bit
|
||||
interpreter. Only the current user can access this location. This
|
||||
provides a suitable level of protection against malicious modification
|
||||
of Python's files.
|
||||
|
||||
(Default installation locations are set in Tools\msi\bundle\bundle.wxs.)
|
||||
|
||||
Within this install directory is the following approximate layout:
|
||||
|
||||
.\python[w].exe The core executable files
|
||||
.\DLLs Stdlib extensions (*.pyd) and dependencies
|
||||
.\Doc Documentation (*.chm)
|
||||
.\include Development headers (*.h)
|
||||
.\Lib Standard library
|
||||
.\Lib\test Test suite
|
||||
.\libs Development libraries (*.lib)
|
||||
.\Scripts Launcher scripts (*.exe, *.py)
|
||||
.\tcl Tcl dependencies (*.dll, *.tcl and others)
|
||||
.\Tools Tool scripts (*.py)
|
||||
|
||||
When installed for all users, the following files are installed to
|
||||
either "%SystemRoot%\System32" or "%SystemRoot%\SysWOW64" as
|
||||
appropriate. For the current user, they are installed in the Python
|
||||
install directory.
|
||||
|
||||
.\python3x.dll The core interpreter
|
||||
.\python3.dll The stable ABI reference
|
||||
|
||||
When installed for all users, the following files are installed to
|
||||
"%SystemRoot%" (typically "C:\Windows") to ensure they are always
|
||||
available on PATH. (See Launching Python below.) For the current user,
|
||||
they are installed in "%LocalAppData%\Programs\Python\PyLauncher".
|
||||
|
||||
.\py[w].exe PEP 397 launcher
|
||||
|
||||
System Settings
|
||||
===============
|
||||
|
||||
On installation, registry keys are created so that other applications
|
||||
can locate and identify installations of Python. The locations of these
|
||||
keys vary based on the install type.
|
||||
|
||||
For 64-bit interpreters installed for all users, the root key is:
|
||||
HKEY_LOCAL_MACHINE\Software\Python\PythonCore\3.X
|
||||
|
||||
For 32-bit interpreters installed for all users on a 64-bit operating
|
||||
system, the root key is:
|
||||
HKEY_LOCAL_MACHINE\Software\Wow6432Node\Python\PythonCore\3.X-32
|
||||
|
||||
For 32-bit interpreters installed for all users on a 32-bit operating
|
||||
system, the root key is:
|
||||
HKEY_LOCAL_MACHINE\Software\Python\PythonCore\3.X-32
|
||||
|
||||
For 64-bit interpreters installed for the current user:
|
||||
HKEY_CURRENT_USER\Software\Python\PythonCore\3.X
|
||||
|
||||
For 32-bit interpreters installed for the current user:
|
||||
HKEY_CURRENT_USER\Software\Python\PythonCore\3.X-32
|
||||
|
||||
When the core Python executables are installed, a key "InstallPath" is
|
||||
created within the root key with its default value set to the
|
||||
executable's install directory. A value named "ExecutablePath" is added
|
||||
with the full path to the main Python interpreter, and a key
|
||||
"InstallGroup" is created with its default value set to the product
|
||||
name "Python 3.X".
|
||||
|
||||
When the Python standard library is installed, a key "PythonPath" is
|
||||
created within the root key with its default value set to the full path
|
||||
to the Lib folder followed by the path to the DLLs folder, separated by
|
||||
a semicolon.
|
||||
|
||||
When the documentation is installed, a key "Help" is created within the
|
||||
root key, with a subkey "Main Python Documentation" with its default
|
||||
value set to the full path to the installed CHM file.
|
||||
|
||||
|
||||
The py.exe launcher is installed as part of a regular Python install,
|
||||
but using a separate mechanism that allows it to more easily span
|
||||
versions of Python. As a result, it has different root keys for its
|
||||
registry entries:
|
||||
|
||||
When installed for all users on a 64-bit operating system, the
|
||||
launcher's root key is:
|
||||
HKEY_LOCAL_MACHINE\Software\Wow6432Node\Python\Launcher
|
||||
|
||||
When installed for all users on a 32-bit operating system, the
|
||||
launcher's root key is:
|
||||
HKEY_LOCAL_MACHINE\Software\Python\Launcher
|
||||
|
||||
When installed for the current user:
|
||||
HKEY_CURRENT_USER\Software\Python\Launcher
|
||||
|
||||
When the launcher is installed, a key "InstallPath" is created within
|
||||
its root key with its default value set to the launcher's install
|
||||
directory. File associations are also created for .py, .pyw, .pyc and
|
||||
.pyo files.
|
||||
|
||||
Launching Python
|
||||
================
|
||||
|
||||
When a feature offering user entry points in the Start Menu is
|
||||
installed, a folder "Python 3.X" is created. Every shortcut should be
|
||||
created within this folder, and each shortcut should include the version
|
||||
and platform to allow users to identify the shortcut in a search results
|
||||
page.
|
||||
|
||||
The core Python executables creates a shortcut "Python 3.X (32-bit)" or
|
||||
"Python 3.X (64-bit)" depending on the interpreter.
|
||||
|
||||
The documentation creates a shortcut "Python 3.X 32-bit Manuals" or
|
||||
"Python 3.X 64-bit Manuals". The documentation is identical for all
|
||||
platforms, but the shortcuts need to be separate to avoid uninstallation
|
||||
conflicts.
|
||||
|
||||
Installing IDLE creates a shortcut "IDLE (Python 3.X 32-bit)" or "IDLE
|
||||
(Python 3.X 64-bit)" depending on the interpreter.
|
||||
|
||||
|
||||
For users who often launch Python from a Command Prompt, an option is
|
||||
provided to add the directory containing python.exe to the user or
|
||||
system PATH variable. If the option is selected, the install directory
|
||||
and the Scripts directory will be added at the start of the system PATH
|
||||
for an all users install and the user PATH for a per-user install.
|
||||
|
||||
When the user only has one version of Python installed, this will behave
|
||||
as expected. However, because Windows searches the system PATH before
|
||||
the user PATH, users cannot override a system-wide installation of
|
||||
Python on their PATH. Further, because the installer can only prepend to
|
||||
the path, later installations of Python will take precedence over
|
||||
earlier installations, regardless of interpreter version.
|
||||
|
||||
Because it is not possible to automatically create a sensible PATH
|
||||
configuration, users are recommended to use the py.exe launcher and
|
||||
manually modify their PATH variable to add Scripts directories in their
|
||||
preferred order. System-wide installations of Python should consider not
|
||||
modifying PATH, or using an alternative technology to modify their
|
||||
users' PATH variables.
|
||||
|
||||
|
||||
The py.exe launcher is recommended because it uses a consistent and
|
||||
sensible search order for Python installations. User installations are
|
||||
preferred over system-wide installs, and later versions are preferred
|
||||
regardless of installation order (with the exception that py.exe
|
||||
currently prefers 2.x versions over 3.x versions without the -3 command
|
||||
line argument).
|
||||
|
||||
For both 32-bit and 64-bit interpreters, the 32-bit version of the
|
||||
launcher is installed. This ensures that the search order is always
|
||||
consistent (as the 64-bit launcher is subtly different from the 32-bit
|
||||
launcher) and also avoids the need to install it multiple times. Future
|
||||
versions of Python will upgrade the launcher in-place, using Windows
|
||||
Installer's upgrade functionality to avoid conflicts with earlier
|
||||
installed versions.
|
||||
|
||||
When installed, file associations are created for .py, .pyc and .pyo
|
||||
files to launch with py.exe and .pyw files to launch with pyw.exe. This
|
||||
makes Python files respect shebang lines by default and also avoids
|
||||
conflicts between multiple Python installations.
|
||||
|
||||
|
||||
Repair, Modify and Uninstall
|
||||
============================
|
||||
|
||||
After installation, Python may be modified, repaired or uninstalled by
|
||||
running the original EXE again or via the Programs and Features applet
|
||||
(formerly known as Add or Remove Programs).
|
||||
|
||||
Modifications allow features to be added or removed. The install
|
||||
directory and kind (all users/single user) cannot be modified. Because
|
||||
Windows Installer caches installation packages, removing features will
|
||||
not require internet access unless the package cache has been corrupted
|
||||
or deleted. Adding features that were not previously installed and are
|
||||
not embedded or otherwise available will require internet access.
|
||||
|
||||
Repairing will rerun the installation for all currently installed
|
||||
features, restoring files and registry keys that have been modified or
|
||||
removed. This operation generally will not redownload any files unless
|
||||
the cached packages have been corrupted or deleted.
|
||||
|
||||
Removing Python will clean up all the files and registry keys that were
|
||||
created by the installer, as well as __pycache__ folders that are
|
||||
explicitly handled by the installer. Python packages installed later
|
||||
using a tool like pip will not be removed. Some components may be
|
||||
installed by other installers and these will not be removed if another
|
||||
product has a dependency on them.
|
||||
|
79
third_party/python/Tools/msi/build.bat
vendored
Normal file
79
third_party/python/Tools/msi/build.bat
vendored
Normal file
|
@ -0,0 +1,79 @@
|
|||
@echo off
|
||||
setlocal
|
||||
set D=%~dp0
|
||||
set PCBUILD=%D%..\..\PCBuild\
|
||||
|
||||
set BUILDX86=
|
||||
set BUILDX64=
|
||||
set BUILDDOC=
|
||||
set BUILDTEST=--test-marker
|
||||
set BUILDPACK=
|
||||
set REBUILD=
|
||||
|
||||
:CheckOpts
|
||||
if "%~1" EQU "-h" goto Help
|
||||
if "%~1" EQU "-x86" (set BUILDX86=1) && shift && goto CheckOpts
|
||||
if "%~1" EQU "-x64" (set BUILDX64=1) && shift && goto CheckOpts
|
||||
if "%~1" EQU "--doc" (set BUILDDOC=1) && shift && goto CheckOpts
|
||||
if "%~1" EQU "--no-test-marker" (set BUILDTEST=) && shift && goto CheckOpts
|
||||
if "%~1" EQU "--pack" (set BUILDPACK=1) && shift && goto CheckOpts
|
||||
if "%~1" EQU "-r" (set REBUILD=-r) && shift && goto CheckOpts
|
||||
|
||||
if not defined BUILDX86 if not defined BUILDX64 (set BUILDX86=1) && (set BUILDX64=1)
|
||||
|
||||
call "%D%get_externals.bat"
|
||||
call "%PCBUILD%find_msbuild.bat" %MSBUILD%
|
||||
if ERRORLEVEL 1 (echo Cannot locate MSBuild.exe on PATH or as MSBUILD variable & exit /b 2)
|
||||
|
||||
if defined BUILDX86 (
|
||||
call "%PCBUILD%build.bat" -d -e %REBUILD% %BUILDTEST%
|
||||
if errorlevel 1 goto :eof
|
||||
call "%PCBUILD%build.bat" -e %REBUILD% %BUILDTEST%
|
||||
if errorlevel 1 goto :eof
|
||||
)
|
||||
if defined BUILDX64 (
|
||||
call "%PCBUILD%build.bat" -p x64 -d -e %REBUILD% %BUILDTEST%
|
||||
if errorlevel 1 goto :eof
|
||||
call "%PCBUILD%build.bat" -p x64 -e %REBUILD% %BUILDTEST%
|
||||
if errorlevel 1 goto :eof
|
||||
)
|
||||
|
||||
if defined BUILDDOC (
|
||||
call "%PCBUILD%..\Doc\make.bat" htmlhelp
|
||||
if errorlevel 1 goto :eof
|
||||
)
|
||||
|
||||
rem Build the launcher MSI separately
|
||||
%MSBUILD% "%D%launcher\launcher.wixproj" /p:Platform=x86
|
||||
|
||||
set BUILD_CMD="%D%bundle\snapshot.wixproj"
|
||||
if defined BUILDTEST (
|
||||
set BUILD_CMD=%BUILD_CMD% /p:UseTestMarker=true
|
||||
)
|
||||
if defined BUILDPACK (
|
||||
set BUILD_CMD=%BUILD_CMD% /p:Pack=true
|
||||
)
|
||||
if defined REBUILD (
|
||||
set BUILD_CMD=%BUILD_CMD% /t:Rebuild
|
||||
)
|
||||
|
||||
if defined BUILDX86 (
|
||||
%MSBUILD% %BUILD_CMD%
|
||||
if errorlevel 1 goto :eof
|
||||
)
|
||||
if defined BUILDX64 (
|
||||
%MSBUILD% /p:Platform=x64 %BUILD_CMD%
|
||||
if errorlevel 1 goto :eof
|
||||
)
|
||||
|
||||
exit /B 0
|
||||
|
||||
:Help
|
||||
echo build.bat [-x86] [-x64] [--doc] [-h] [--no-test-marker] [--pack] [-r]
|
||||
echo.
|
||||
echo -x86 Build x86 installers
|
||||
echo -x64 Build x64 installers
|
||||
echo --doc Build CHM documentation
|
||||
echo --no-test-marker Build without test markers
|
||||
echo --pack Embed core MSIs into installer
|
||||
echo -r Rebuild rather than incremental build
|
234
third_party/python/Tools/msi/buildrelease.bat
vendored
Normal file
234
third_party/python/Tools/msi/buildrelease.bat
vendored
Normal file
|
@ -0,0 +1,234 @@
|
|||
@setlocal
|
||||
@echo off
|
||||
|
||||
rem This script is intended for building official releases of Python.
|
||||
rem To use it to build alternative releases, you should clone this file
|
||||
rem and modify the following three URIs.
|
||||
|
||||
rem These two will ensure that your release can be installed
|
||||
rem alongside an official Python release, by modifying the GUIDs used
|
||||
rem for all components.
|
||||
rem
|
||||
rem The following substitutions will be applied to the release URI:
|
||||
rem Variable Description Example
|
||||
rem {arch} architecture amd64, win32
|
||||
set RELEASE_URI=http://www.python.org/{arch}
|
||||
|
||||
rem This is the URL that will be used to download installation files.
|
||||
rem The files available from the default URL *will* conflict with your
|
||||
rem installer. Trust me, you don't want them, even if it seems like a
|
||||
rem good idea.
|
||||
rem
|
||||
rem The following substitutions will be applied to the download URL:
|
||||
rem Variable Description Example
|
||||
rem {version} version number 3.5.0
|
||||
rem {arch} architecture amd64, win32
|
||||
rem {releasename} release name a1, b2, rc3 (or blank for final)
|
||||
rem {msi} MSI filename core.msi
|
||||
set DOWNLOAD_URL=https://www.python.org/ftp/python/{version}/{arch}{releasename}/{msi}
|
||||
|
||||
set D=%~dp0
|
||||
set PCBUILD=%D%..\..\PCBuild\
|
||||
if "%Py_OutDir%"=="" set Py_OutDir=%PCBUILD%
|
||||
set EXTERNALS=%D%..\..\externals\windows-installer\
|
||||
|
||||
set BUILDX86=
|
||||
set BUILDX64=
|
||||
set TARGET=Rebuild
|
||||
set TESTTARGETDIR=
|
||||
set PGO=-m test -q --pgo
|
||||
set BUILDNUGET=1
|
||||
set BUILDZIP=1
|
||||
|
||||
|
||||
:CheckOpts
|
||||
if "%1" EQU "-h" goto Help
|
||||
if "%1" EQU "-c" (set CERTNAME=%~2) && shift && shift && goto CheckOpts
|
||||
if "%1" EQU "--certificate" (set CERTNAME=%~2) && shift && shift && goto CheckOpts
|
||||
if "%1" EQU "-o" (set OUTDIR=%~2) && shift && shift && goto CheckOpts
|
||||
if "%1" EQU "--out" (set OUTDIR=%~2) && shift && shift && goto CheckOpts
|
||||
if "%1" EQU "-D" (set SKIPDOC=1) && shift && goto CheckOpts
|
||||
if "%1" EQU "--skip-doc" (set SKIPDOC=1) && shift && goto CheckOpts
|
||||
if "%1" EQU "-B" (set SKIPBUILD=1) && shift && goto CheckOpts
|
||||
if "%1" EQU "--skip-build" (set SKIPBUILD=1) && shift && goto CheckOpts
|
||||
if "%1" EQU "--download" (set DOWNLOAD_URL=%~2) && shift && shift && goto CheckOpts
|
||||
if "%1" EQU "--test" (set TESTTARGETDIR=%~2) && shift && shift && goto CheckOpts
|
||||
if "%1" EQU "-b" (set TARGET=Build) && shift && goto CheckOpts
|
||||
if "%1" EQU "--build" (set TARGET=Build) && shift && goto CheckOpts
|
||||
if "%1" EQU "-x86" (set BUILDX86=1) && shift && goto CheckOpts
|
||||
if "%1" EQU "-x64" (set BUILDX64=1) && shift && goto CheckOpts
|
||||
if "%1" EQU "--pgo" (set PGO=%~2) && shift && shift && goto CheckOpts
|
||||
if "%1" EQU "--skip-pgo" (set PGO=) && shift && goto CheckOpts
|
||||
if "%1" EQU "--skip-nuget" (set BUILDNUGET=) && shift && goto CheckOpts
|
||||
if "%1" EQU "--skip-zip" (set BUILDZIP=) && shift && goto CheckOpts
|
||||
|
||||
if "%1" NEQ "" echo Invalid option: "%1" && exit /B 1
|
||||
|
||||
if not defined BUILDX86 if not defined BUILDX64 (set BUILDX86=1) && (set BUILDX64=1)
|
||||
|
||||
if not exist "%GIT%" where git > "%TEMP%\git.loc" 2> nul && set /P GIT= < "%TEMP%\git.loc" & del "%TEMP%\git.loc"
|
||||
if not exist "%GIT%" echo Cannot find Git on PATH && exit /B 1
|
||||
|
||||
call "%D%get_externals.bat"
|
||||
call "%PCBUILD%find_msbuild.bat" %MSBUILD%
|
||||
if ERRORLEVEL 1 (echo Cannot locate MSBuild.exe on PATH or as MSBUILD variable & exit /b 2)
|
||||
|
||||
:builddoc
|
||||
if "%SKIPBUILD%" EQU "1" goto skipdoc
|
||||
if "%SKIPDOC%" EQU "1" goto skipdoc
|
||||
|
||||
call "%D%..\..\doc\make.bat" htmlhelp
|
||||
if errorlevel 1 goto :eof
|
||||
:skipdoc
|
||||
|
||||
where dlltool /q && goto skipdlltoolsearch
|
||||
set _DLLTOOL_PATH=
|
||||
where /R "%EXTERNALS%\" dlltool > "%TEMP%\dlltool.loc" 2> nul && set /P _DLLTOOL_PATH= < "%TEMP%\dlltool.loc" & del "%TEMP%\dlltool.loc"
|
||||
if not exist "%_DLLTOOL_PATH%" echo Cannot find binutils on PATH or in external && exit /B 1
|
||||
for %%f in (%_DLLTOOL_PATH%) do set PATH=%PATH%;%%~dpf
|
||||
set _DLLTOOL_PATH=
|
||||
:skipdlltoolsearch
|
||||
|
||||
if defined BUILDX86 (
|
||||
call :build x86
|
||||
if errorlevel 1 exit /B
|
||||
)
|
||||
|
||||
if defined BUILDX64 (
|
||||
call :build x64 "%PGO%"
|
||||
if errorlevel 1 exit /B
|
||||
)
|
||||
|
||||
if defined TESTTARGETDIR (
|
||||
call "%D%testrelease.bat" -t "%TESTTARGETDIR%"
|
||||
)
|
||||
|
||||
exit /B 0
|
||||
|
||||
:build
|
||||
@setlocal
|
||||
@echo off
|
||||
|
||||
if "%1" EQU "x86" (
|
||||
set PGO=
|
||||
set BUILD=%Py_OutDir%win32\
|
||||
set BUILD_PLAT=Win32
|
||||
set OUTDIR_PLAT=win32
|
||||
set OBJDIR_PLAT=x86
|
||||
) else (
|
||||
set BUILD=%Py_OutDir%amd64\
|
||||
set PGO=%~2
|
||||
set BUILD_PLAT=x64
|
||||
set OUTDIR_PLAT=amd64
|
||||
set OBJDIR_PLAT=x64
|
||||
)
|
||||
|
||||
if exist "%BUILD%en-us" (
|
||||
echo Deleting %BUILD%en-us
|
||||
rmdir /q/s "%BUILD%en-us"
|
||||
if errorlevel 1 exit /B
|
||||
)
|
||||
|
||||
if exist "%D%obj\Debug_%OBJDIR_PLAT%" (
|
||||
echo Deleting "%D%obj\Debug_%OBJDIR_PLAT%"
|
||||
rmdir /q/s "%D%obj\Debug_%OBJDIR_PLAT%"
|
||||
if errorlevel 1 exit /B
|
||||
)
|
||||
|
||||
if exist "%D%obj\Release_%OBJDIR_PLAT%" (
|
||||
echo Deleting "%D%obj\Release_%OBJDIR_PLAT%"
|
||||
rmdir /q/s "%D%obj\Release_%OBJDIR_PLAT%"
|
||||
if errorlevel 1 exit /B
|
||||
)
|
||||
|
||||
if not "%CERTNAME%" EQU "" (
|
||||
set CERTOPTS="/p:SigningCertificate=%CERTNAME%"
|
||||
) else (
|
||||
set CERTOPTS=
|
||||
)
|
||||
if not "%PGO%" EQU "" (
|
||||
set PGOOPTS=--pgo-job "%PGO%"
|
||||
) else (
|
||||
set PGOOPTS=
|
||||
)
|
||||
if not "%SKIPBUILD%" EQU "1" (
|
||||
@echo call "%PCBUILD%build.bat" -e -p %BUILD_PLAT% -t %TARGET% %PGOOPTS% %CERTOPTS%
|
||||
@call "%PCBUILD%build.bat" -e -p %BUILD_PLAT% -t %TARGET% %PGOOPTS% %CERTOPTS%
|
||||
@if errorlevel 1 exit /B
|
||||
@rem build.bat turns echo back on, so we disable it again
|
||||
@echo off
|
||||
|
||||
@echo call "%PCBUILD%build.bat" -d -e -p %BUILD_PLAT% -t %TARGET%
|
||||
@call "%PCBUILD%build.bat" -d -e -p %BUILD_PLAT% -t %TARGET%
|
||||
@if errorlevel 1 exit /B
|
||||
@rem build.bat turns echo back on, so we disable it again
|
||||
@echo off
|
||||
)
|
||||
|
||||
if "%OUTDIR_PLAT%" EQU "win32" (
|
||||
%MSBUILD% "%D%launcher\launcher.wixproj" /p:Platform=x86 %CERTOPTS% /p:ReleaseUri=%RELEASE_URI%
|
||||
if errorlevel 1 exit /B
|
||||
) else if not exist "%Py_OutDir%win32\en-us\launcher.msi" (
|
||||
%MSBUILD% "%D%launcher\launcher.wixproj" /p:Platform=x86 %CERTOPTS% /p:ReleaseUri=%RELEASE_URI%
|
||||
if errorlevel 1 exit /B
|
||||
)
|
||||
|
||||
set BUILDOPTS=/p:Platform=%1 /p:BuildForRelease=true /p:DownloadUrl=%DOWNLOAD_URL% /p:DownloadUrlBase=%DOWNLOAD_URL_BASE% /p:ReleaseUri=%RELEASE_URI%
|
||||
%MSBUILD% "%D%bundle\releaselocal.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=true
|
||||
if errorlevel 1 exit /B
|
||||
%MSBUILD% "%D%bundle\releaseweb.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=false
|
||||
if errorlevel 1 exit /B
|
||||
|
||||
if defined BUILDZIP (
|
||||
%MSBUILD% "%D%make_zip.proj" /t:Build %BUILDOPTS% %CERTOPTS% /p:OutputPath="%BUILD%en-us"
|
||||
if errorlevel 1 exit /B
|
||||
)
|
||||
|
||||
if defined BUILDNUGET (
|
||||
%MSBUILD% "%D%..\nuget\make_pkg.proj" /t:Build /p:Configuration=Release /p:Platform=%1 /p:OutputPath="%BUILD%en-us"
|
||||
if errorlevel 1 exit /B
|
||||
)
|
||||
|
||||
if not "%OUTDIR%" EQU "" (
|
||||
mkdir "%OUTDIR%\%OUTDIR_PLAT%"
|
||||
mkdir "%OUTDIR%\%OUTDIR_PLAT%\binaries"
|
||||
mkdir "%OUTDIR%\%OUTDIR_PLAT%\symbols"
|
||||
robocopy "%BUILD%en-us" "%OUTDIR%\%OUTDIR_PLAT%" /XF "*.wixpdb"
|
||||
robocopy "%BUILD%\" "%OUTDIR%\%OUTDIR_PLAT%\binaries" *.exe *.dll *.pyd /XF "_test*" /XF "*_d.*" /XF "_freeze*" /XF "tcl*" /XF "tk*" /XF "*_test.*"
|
||||
robocopy "%BUILD%\" "%OUTDIR%\%OUTDIR_PLAT%\symbols" *.pdb /XF "_test*" /XF "*_d.*" /XF "_freeze*" /XF "tcl*" /XF "tk*" /XF "*_test.*"
|
||||
)
|
||||
|
||||
exit /B 0
|
||||
|
||||
:Help
|
||||
echo buildrelease.bat [--out DIR] [-x86] [-x64] [--certificate CERTNAME] [--build] [--pgo COMMAND]
|
||||
echo [--skip-build] [--skip-doc] [--skip-nuget] [--skip-zip] [--skip-pgo]
|
||||
echo [--download DOWNLOAD URL] [--test TARGETDIR]
|
||||
echo [-h]
|
||||
echo.
|
||||
echo --out (-o) Specify an additional output directory for installers
|
||||
echo -x86 Build x86 installers
|
||||
echo -x64 Build x64 installers
|
||||
echo --build (-b) Incrementally build Python rather than rebuilding
|
||||
echo --skip-build (-B) Do not build Python (just do the installers)
|
||||
echo --skip-doc (-D) Do not build documentation
|
||||
echo --pgo Specify PGO command for x64 installers
|
||||
echo --skip-pgo Build x64 installers without using PGO
|
||||
echo --skip-nuget Do not build Nuget packages
|
||||
echo --skip-zip Do not build embeddable package
|
||||
echo --download Specify the full download URL for MSIs
|
||||
echo --test Specify the test directory to run the installer tests
|
||||
echo -h Display this help information
|
||||
echo.
|
||||
echo If no architecture is specified, all architectures will be built.
|
||||
echo If --test is not specified, the installer tests are not run.
|
||||
echo.
|
||||
echo For the --pgo option, any Python command line can be used, or 'default' to
|
||||
echo use the default task (-m test --pgo).
|
||||
echo.
|
||||
echo The following substitutions will be applied to the download URL:
|
||||
echo Variable Description Example
|
||||
echo {version} version number 3.5.0
|
||||
echo {arch} architecture amd64, win32
|
||||
echo {releasename} release name a1, b2, rc3 (or blank for final)
|
||||
echo {msi} MSI filename core.msi
|
137
third_party/python/Tools/msi/bundle/Default.thm
vendored
Normal file
137
third_party/python/Tools/msi/bundle/Default.thm
vendored
Normal file
|
@ -0,0 +1,137 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Theme xmlns="http://wixtoolset.org/schemas/thmutil/2010">
|
||||
<Window Width="670" Height="412" HexStyle="100a0000" FontId="0">#(loc.Caption)</Window>
|
||||
<Font Id="0" Height="-14" Weight="500" Foreground="000000" Background="ffffff">Segoe UI</Font>
|
||||
<Font Id="1" Height="-26" Weight="500" Foreground="000000" Background="ffffff">Segoe UI</Font>
|
||||
<Font Id="2" Height="-24" Weight="500" Foreground="808080" Background="ffffff">Segoe UI</Font>
|
||||
<Font Id="3" Height="-14" Weight="500" Foreground="000000" Background="ffffff">Segoe UI</Font>
|
||||
<Font Id="4" Height="-14" Weight="500" Foreground="ff0000" Background="ffffff" Underline="yes">Segoe UI</Font>
|
||||
<Font Id="5" Height="-14" Weight="500" Foreground="808080" Background="ffffff">Segoe UI</Font>
|
||||
|
||||
<Page Name="Help">
|
||||
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.HelpHeader)</Text>
|
||||
<Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
|
||||
|
||||
<Hypertext X="185" Y="50" Width="-11" Height="-35" FontId="3" DisablePrefix="yes">#(loc.HelpText)</Hypertext>
|
||||
<Button Name="SuccessCancelButton" X="-11" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CloseButton)</Button>
|
||||
</Page>
|
||||
<Page Name="Install">
|
||||
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.InstallHeader)</Text>
|
||||
<Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
|
||||
|
||||
<Text X="185" Y="50" Width="-11" Height="50" FontId="3" TabStop="yes">#(loc.InstallMessage)</Text>
|
||||
|
||||
<Button Name="InstallButton" X="185" Y="101" Width="-11" Height="109" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.InstallButton)</Button>
|
||||
<Button Name="InstallCustomButton" X="185" Y="221" Width="-11" Height="59" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.InstallCustomButton)</Button>
|
||||
|
||||
<Checkbox Name="InstallLauncherAllUsers" X="185" Y="-37" Width="-100" Height="24" TabStop="yes" FontId="3">#(loc.ShortInstallLauncherAllUsersLabel)</Checkbox>
|
||||
<Checkbox Name="PrependPath" X="185" Y="-13" Width="-100" Height="24" TabStop="yes" FontId="3">#(loc.ShortPrependPathLabel)</Checkbox>
|
||||
|
||||
<Button Name="InstallCancelButton" X="-11" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
|
||||
</Page>
|
||||
<Page Name="Upgrade">
|
||||
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.InstallUpgradeHeader)</Text>
|
||||
<Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
|
||||
|
||||
<Text X="185" Y="50" Width="-11" Height="50" FontId="3" TabStop="yes">#(loc.InstallUpgradeMessage)</Text>
|
||||
|
||||
<Button Name="InstallUpgradeButton" X="185" Y="101" Width="-11" Height="129" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.InstallUpgradeButton)</Button>
|
||||
<Button Name="InstallUpgradeCustomButton" X="185" Y="241" Width="-11" Height="59" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.InstallUpgradeCustomButton)</Button>
|
||||
|
||||
<Button Name="InstallCancelButton" X="-11" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
|
||||
</Page>
|
||||
<Page Name="SimpleInstall">
|
||||
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.InstallHeader)</Text>
|
||||
<Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
|
||||
|
||||
<Button Name="InstallSimpleButton" X="185" Y="101" Width="-11" Height="129" TabStop="yes" FontId="3" HideWhenDisabled="yes" HexStyle="0xF">#(loc.InstallSimpleButton)</Button>
|
||||
|
||||
<Button Name="InstallCancelButton" X="-11" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
|
||||
</Page>
|
||||
<Page Name="Custom1">
|
||||
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.Custom1Header)</Text>
|
||||
<Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
|
||||
|
||||
<Checkbox Name="Include_doc" X="185" Y="51" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.Include_docLabel)</Checkbox>
|
||||
<Text X="205" Y="76" Width="-11" Height="24" TabStop="no" FontId="5">#(loc.Include_docHelpLabel)</Text>
|
||||
|
||||
<Checkbox Name="Include_pip" X="185" Y="101" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.Include_pipLabel)</Checkbox>
|
||||
<Text X="205" Y="126" Width="-11" Height="24" TabStop="no" FontId="5">#(loc.Include_pipHelpLabel)</Text>
|
||||
|
||||
<Checkbox Name="Include_tcltk" X="185" Y="151" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.Include_tcltkLabel)</Checkbox>
|
||||
<Text X="205" Y="176" Width="-11" Height="24" TabStop="no" FontId="5">#(loc.Include_tcltkHelpLabel)</Text>
|
||||
|
||||
<Checkbox Name="Include_test" X="185" Y="201" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.Include_testLabel)</Checkbox>
|
||||
<Text X="205" Y="226" Width="-11" Height="24" TabStop="no" FontId="5">#(loc.Include_testHelpLabel)</Text>
|
||||
|
||||
<Checkbox Name="Include_launcher" X="185" Y="251" Width="100" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.Include_launcherLabel)</Checkbox>
|
||||
<Checkbox Name="CustomInstallLauncherAllUsers" X="285" Y="251" Width="-11" Height="24" TabStop="yes" FontId="3">#(loc.InstallLauncherAllUsersLabel)</Checkbox>
|
||||
<Text Name="Include_launcherHelp" X="205" Y="276" Width="-11" Height="24" TabStop="no" FontId="5"></Text>
|
||||
|
||||
<Button Name="Custom1BackButton" X="185" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CustomBackButton)</Button>
|
||||
<Button Name="CustomNextButton" X="-101" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CustomNextButton)</Button>
|
||||
<Button Name="Custom1CancelButton" X="-11" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
|
||||
</Page>
|
||||
<Page Name="Custom2">
|
||||
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.Custom2Header)</Text>
|
||||
<Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
|
||||
|
||||
<Checkbox Name="InstallAllUsers" X="185" Y="51" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.InstallAllUsersLabel)</Checkbox>
|
||||
<Checkbox Name="AssociateFiles" X="185" Y="76" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.AssociateFilesLabel)</Checkbox>
|
||||
<Checkbox Name="Shortcuts" X="185" Y="101" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.ShortcutsLabel)</Checkbox>
|
||||
<Checkbox Name="PrependPath" X="185" Y="126" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.PrependPathLabel)</Checkbox>
|
||||
<Checkbox Name="CompileAll" X="185" Y="151" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.PrecompileLabel)</Checkbox>
|
||||
<Checkbox Name="Include_symbols" X="185" Y="176" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.Include_symbolsLabel)</Checkbox>
|
||||
<Checkbox Name="Include_debug" X="185" Y="201" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.Include_debugLabel)</Checkbox>
|
||||
|
||||
<Text X="185" Y="256" Width="-11" Height="17" FontId="3">#(loc.CustomLocationLabel)</Text>
|
||||
<Editbox Name="TargetDir" X="185" Y="277" Width="-101" Height="27" TabStop="yes" FontId="3" FileSystemAutoComplete="yes" />
|
||||
<Button Name="CustomBrowseButton" X="-11" Y="276" Width="85" Height="27" TabStop="yes" FontId="3">#(loc.CustomBrowseButton)</Button>
|
||||
<Text Name="CustomBrowseButtonLabel" X="185" Y="306" Width="-91" Height="35" FontId="5" HideWhenDisabled="yes">#(loc.CustomLocationHelpLabel)</Text>
|
||||
|
||||
<Button Name="Custom2BackButton" X="185" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CustomBackButton)</Button>
|
||||
<Button Name="CustomInstallButton" X="-101" Y="-11" Width="95" Height="27" TabStop="yes" FontId="0">#(loc.CustomInstallButton)</Button>
|
||||
<Button Name="Custom2CancelButton" X="-11" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
|
||||
</Page>
|
||||
<Page Name="Progress">
|
||||
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.ProgressHeader)</Text>
|
||||
<Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
|
||||
|
||||
<Text X="185" Y="111" Width="-11" Height="20" FontId="3" DisablePrefix="yes">#(loc.ProgressLabel)</Text>
|
||||
<Text Name="OverallProgressPackageText" X="185" Y="146" Width="-11" Height="20" FontId="3" DisablePrefix="yes">#(loc.OverallProgressPackageText)</Text>
|
||||
<Progressbar Name="OverallCalculatedProgressbar" X="185" Y="171" Width="-11" Height="24" />
|
||||
<Button Name="ProgressCancelButton" X="-11" Y="-11" Width="95" Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
|
||||
</Page>
|
||||
<Page Name="Modify">
|
||||
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.ModifyHeader)</Text>
|
||||
<Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
|
||||
|
||||
<Button Name="ModifyButton" X="185" Y="101" Width="-11" Height="59" TabStop="yes" FontId="3" HexStyle="0xF">#(loc.ModifyModifyButton)</Button>
|
||||
<Button Name="RepairButton" X="185" Y="171" Width="-11" Height="59" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.ModifyRepairButton)</Button>
|
||||
<Button Name="UninstallButton" X="185" Y="241" Width="-11" Height="59" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.ModifyUninstallButton)</Button>
|
||||
|
||||
<Button Name="ModifyCancelButton" X="-11" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CancelButton)</Button>
|
||||
</Page>
|
||||
<Page Name="Success">
|
||||
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.SuccessHeader)</Text>
|
||||
<Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
|
||||
|
||||
<Hypertext Name="SuccessText" X="205" Y="71" Width="-71" Height="150" FontId="3" DisablePrefix="yes"></Hypertext>
|
||||
|
||||
<Button Name="SuccessMaxPathButton" X="185" Y="-70" Width="-11" Height="81" TabStop="yes" FontId="3" HexStyle="0xE" HideWhenDisabled="yes">#(loc.SuccessMaxPathButton)</Button>
|
||||
|
||||
<Text Name="SuccessRestartText" X="205" Y="-40" Width="-11" Height="34" FontId="3" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.SuccessRestartText)</Text>
|
||||
<Button Name="SuccessRestartButton" X="-101" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessRestartButton)</Button>
|
||||
<Button Name="SuccessCancelButton" X="-11" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CloseButton)</Button>
|
||||
</Page>
|
||||
<Page Name="Failure">
|
||||
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.FailureHeader)</Text>
|
||||
<Image X="0" Y="0" Width="178" Height="382" ImageFile="SideBar.png"/>
|
||||
|
||||
<Hypertext Name="FailureLogFileLink" X="205" Y="71" Width="-11" Height="60" FontId="3" TabStop="yes" HideWhenDisabled="yes">#(loc.FailureHyperlinkLogText)</Hypertext>
|
||||
<Hypertext Name="FailureMessageText" X="205" Y="151" Width="-11" Height="120" FontId="3" TabStop="yes" HideWhenDisabled="yes"></Hypertext>
|
||||
<Text Name="FailureRestartText" X="205" Y="-40" Width="-11" Height="34" FontId="3" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureRestartText)</Text>
|
||||
<Button Name="FailureRestartButton" X="-101" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FailureRestartButton)</Button>
|
||||
<Button Name="FailureCancelButton" X="-11" Y="-11" Width="85" Height="27" TabStop="yes" FontId="0">#(loc.CloseButton)</Button>
|
||||
</Page>
|
||||
</Theme>
|
148
third_party/python/Tools/msi/bundle/Default.wxl
vendored
Normal file
148
third_party/python/Tools/msi/bundle/Default.wxl
vendored
Normal file
|
@ -0,0 +1,148 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<WixLocalization Culture="en-us" Language="1033" xmlns="http://schemas.microsoft.com/wix/2006/localization">
|
||||
<String Id="Caption">[WixBundleName] Setup</String>
|
||||
<String Id="Title">[WixBundleName]</String>
|
||||
<String Id="Installing">Installing</String>
|
||||
<String Id="Installation">Setup</String>
|
||||
<String Id="Modifying">Updating</String>
|
||||
<String Id="Modification">Modify</String>
|
||||
<String Id="Repairing">Repairing</String>
|
||||
<String Id="Repair">Repair</String>
|
||||
<String Id="Uninstalling">Removing</String>
|
||||
<String Id="Uninstallation">Uninstall</String>
|
||||
|
||||
<String Id="ElevateForCRTInstall">You will be prompted for Administrator privileges to install a C Runtime Library update (KB2999226).
|
||||
|
||||
|
||||
Continue?</String>
|
||||
|
||||
<String Id="CancelButton">&Cancel</String>
|
||||
<String Id="CloseButton">&Close</String>
|
||||
<String Id="InstallHeader">Install [WixBundleName]</String>
|
||||
<String Id="InstallMessage">Select Install Now to install Python with default settings, or choose Customize to enable or disable features.</String>
|
||||
<String Id="InstallVersion">Version [WixBundleVersion]</String>
|
||||
<String Id="InstallUpgradeHeader">Upgrade to [WixBundleName]</String>
|
||||
<String Id="InstallUpgradeMessage">Select Upgrade Now to keep your current settings, or choose Customize to enable or disable features.</String>
|
||||
<String Id="ConfirmCancelMessage">Are you sure you want to cancel?</String>
|
||||
<String Id="ExecuteUpgradeRelatedBundleMessage">Previous version</String>
|
||||
<String Id="HelpHeader">Setup Help</String>
|
||||
<String Id="HelpText">Visit <a href="http://docs.python.org/[ShortVersion]/using/windows.html">docs.python.org/[ShortVersion]/using/windows.html</a> for the full list of options, including the ability to enable and disable specific features.
|
||||
|
||||
"/passive" to display progress without requiring user interaction
|
||||
|
||||
"/quiet" to install/uninstall without displaying any UI
|
||||
|
||||
"/simple" to prevent user customization
|
||||
|
||||
"/uninstall" to remove Python (without confirmation)
|
||||
|
||||
"/layout [\[]directory[\]]" to pre-download all components
|
||||
|
||||
"/log [\[]filename[\]]" to specify log files location</String>
|
||||
<String Id="InstallLicenseLinkText">[WixBundleName] <a href="#">license terms</a>.</String>
|
||||
<String Id="InstallAcceptCheckbox">I &agree to the license terms and conditions</String>
|
||||
<String Id="InstallButton">&Install Now</String>
|
||||
<String Id="InstallButtonNote">[TargetDir]
|
||||
|
||||
Includes IDLE, pip and documentation
|
||||
Creates shortcuts and file associations</String>
|
||||
<String Id="InstallCustomButton">C&ustomize installation</String>
|
||||
<String Id="InstallCustomButtonNote">Choose location and features</String>
|
||||
<String Id="InstallSimpleButton">&Install</String>
|
||||
<String Id="InstallSimpleButtonNote">Use settings preselected by your administrator
|
||||
|
||||
[SimpleInstallDescription]</String>
|
||||
<String Id="InstallUpgradeButton">Up&grade Now</String>
|
||||
<String Id="InstallUpgradeButtonNote">[TargetDir]
|
||||
|
||||
Replaces your existing installation without changing settings.
|
||||
Select Customize to review current options.</String>
|
||||
<String Id="InstallUpgradeCustomButton">C&ustomize installation</String>
|
||||
<String Id="InstallUpgradeCustomButtonNote">Choose location and features</String>
|
||||
<String Id="Custom1Header">Optional Features</String>
|
||||
<String Id="Custom2Header">Advanced Options</String>
|
||||
<String Id="CustomLocationLabel">Customize install location</String>
|
||||
<String Id="CustomLocationHelpLabel">You will require write permissions for the selected location.</String>
|
||||
<String Id="CustomInstallButton">&Install</String>
|
||||
<String Id="CustomNextButton">&Next</String>
|
||||
<String Id="CustomBackButton">&Back</String>
|
||||
<String Id="CustomBrowseButton">B&rowse</String>
|
||||
<String Id="Include_docLabel">&Documentation</String>
|
||||
<String Id="Include_docHelpLabel">Installs the Python documentation file.</String>
|
||||
<String Id="Include_pipLabel">&pip</String>
|
||||
<String Id="Include_pipHelpLabel">Installs pip, which can download and install other Python packages.</String>
|
||||
<String Id="Include_tcltkLabel">tcl/tk and &IDLE</String>
|
||||
<String Id="Include_tcltkHelpLabel">Installs tkinter and the IDLE development environment.</String>
|
||||
<String Id="Include_testLabel">Python &test suite</String>
|
||||
<String Id="Include_testHelpLabel">Installs the standard library test suite.</String>
|
||||
<String Id="Include_launcherLabel">py &launcher</String>
|
||||
<String Id="Include_launcherHelp">Installs the global 'py' launcher to make it easier to start Python.</String>
|
||||
<String Id="Include_launcherRemove">Use Programs and Features to remove the 'py' launcher.</String>
|
||||
<String Id="Include_launcherUpgrade">Upgrades the global 'py' launcher from the previous version.</String>
|
||||
|
||||
<String Id="AssociateFilesLabel">Associate &files with Python (requires the py launcher)</String>
|
||||
<String Id="ShortcutsLabel">Create shortcuts for installed applications</String>
|
||||
<String Id="PrependPathLabel">Add Python to &environment variables</String>
|
||||
<String Id="ShortPrependPathLabel">Add &Python [ShortVersion] to PATH</String>
|
||||
<String Id="InstallAllUsersLabel">Install for &all users</String>
|
||||
<String Id="InstallLauncherAllUsersLabel">for &all users (requires elevation)</String>
|
||||
<String Id="ShortInstallLauncherAllUsersLabel">Install &launcher for all users (recommended)</String>
|
||||
<String Id="PrecompileLabel">&Precompile standard library</String>
|
||||
<String Id="Include_symbolsLabel">Download debugging &symbols</String>
|
||||
<String Id="Include_debugLabel">Download debu&g binaries (requires VS 2015 or later)</String>
|
||||
|
||||
<String Id="ProgressHeader">[ActionLikeInstallation] Progress</String>
|
||||
<String Id="ProgressLabel">[ActionLikeInstalling]:</String>
|
||||
<String Id="OverallProgressPackageText">Initializing...</String>
|
||||
<String Id="ModifyHeader">Modify Setup</String>
|
||||
<String Id="ModifyModifyButton">&Modify</String>
|
||||
<String Id="ModifyButtonNote">Add or remove individual features.</String>
|
||||
<String Id="ModifyRepairButton">&Repair</String>
|
||||
<String Id="RepairButtonNote">Ensure all current features are correctly installed.</String>
|
||||
<String Id="ModifyUninstallButton">&Uninstall</String>
|
||||
<String Id="UninstallButtonNote">Remove the entire [WixBundleName] installation.</String>
|
||||
<String Id="SuccessHeader">[ActionLikeInstallation] was successful</String>
|
||||
<String Id="SuccessLaunchButton">&Launch</String>
|
||||
<String Id="SuccessRestartText">You may need to restart your computer to finish updating files.</String>
|
||||
<String Id="SuccessRestartButton">&Restart</String>
|
||||
<String Id="SuccessInstallMessage">Special thanks to Mark Hammond, without whose years of freely shared Windows expertise, Python for Windows would still be Python for DOS.
|
||||
|
||||
New to Python? Start with the <a href="https://docs.python.org/[ShortVersion]/tutorial/index.html">online tutorial</a> and <a href="https://docs.python.org/[ShortVersion]/index.html">documentation</a>.
|
||||
|
||||
See <a href="https://docs.python.org/[ShortVersion]/whatsnew/[ShortVersion].html">what's new</a> in this release.</String>
|
||||
<String Id="SuccessModifyMessage">Thank you for using [WixBundleName].</String>
|
||||
<String Id="SuccessRepairMessage">Thank you for using [WixBundleName].
|
||||
|
||||
Feel free to email <a href="mailto:python-list@python.org">python-list@python.org</a> if you continue to encounter issues.</String>
|
||||
<String Id="SuccessRemoveMessage">Thank you for using [WixBundleName].
|
||||
|
||||
Feel free to email <a href="mailto:python-list@python.org">python-list@python.org</a> if you encountered problems.</String>
|
||||
<String Id="FailureHeader">Setup failed</String>
|
||||
<String Id="FailureHyperlinkLogText">One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the <a href="#">log file</a>.</String>
|
||||
<String Id="FailureRestartText">You must restart your computer to complete the rollback of the software.</String>
|
||||
<String Id="FailureRestartButton">&Restart</String>
|
||||
<String Id="FailureExistingInstall">Unable to install [WixBundleName] due to an existing install. Use Programs and Features to modify, repair or remove [WixBundleName].</String>
|
||||
|
||||
<String Id="FailureWin7MissingSP1">Windows 7 Service Pack 1 and all applicable updates are required to install [WixBundleName].
|
||||
|
||||
Please <a href="https://www.bing.com/search?q=how%20to%20install%20windows%207%20service%20pack%201">update your machine</a> and then restart the installation.</String>
|
||||
<String Id="FailureVistaMissingSP2">Windows Vista Service Pack 2 and all applicable updates are required to install [WixBundleName].
|
||||
|
||||
Please <a href="https://www.bing.com/search?q=how%20to%20install%20windows%20vista%20service%20pack%202">update your machine</a> and then restart the installation.</String>
|
||||
<String Id="FailureXPOrEarlier">Windows Vista or later is required to install and use [WixBundleName].
|
||||
|
||||
Visit <a href="https://www.python.org/">python.org</a> to download Python 3.4.</String>
|
||||
|
||||
<String Id="FailureWS2K8R2MissingSP1">Windows Server 2008 R2 Service Pack 1 and all applicable updates are required to install [WixBundleName].
|
||||
|
||||
Please <a href="https://www.bing.com/search?q=how%20to%20install%20windows%20server%202008%20r2%20service%20pack%201">update your machine</a> and then restart the installation.</String>
|
||||
<String Id="FailureWS2K8MissingSP2">Windows Server 2008 Service Pack 2 and all applicable updates are required to install [WixBundleName].
|
||||
|
||||
Please <a href="https://www.bing.com/search?q=how%20to%20install%20windows%20server%202008%20service%20pack%202">update your machine</a> and then restart the installation.</String>
|
||||
<String Id="FailureWS2K3OrEarlier">Windows Server 2008 SP2 or later is required to install and use [WixBundleName].
|
||||
|
||||
Visit <a href="https://www.python.org/">python.org</a> to download Python 3.4.</String>
|
||||
|
||||
<String Id="SuccessMaxPathButton">Disable path length limit</String>
|
||||
<String Id="SuccessMaxPathButtonNote">Changes your machine configuration to allow programs, including Python, to bypass the 260 character "MAX_PATH" limitation.</String>
|
||||
</WixLocalization>
|
BIN
third_party/python/Tools/msi/bundle/SideBar.png
vendored
Normal file
BIN
third_party/python/Tools/msi/bundle/SideBar.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
25
third_party/python/Tools/msi/bundle/bootstrap/LICENSE.txt
vendored
Normal file
25
third_party/python/Tools/msi/bundle/bootstrap/LICENSE.txt
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
This license applies to the bootstrapper application that is embedded within the installer. It has no impact on the licensing for the rest of the installer or Python itself, as no code covered by this license exists in any other part of the product.
|
||||
|
||||
---
|
||||
|
||||
Microsoft Reciprocal License (MS-RL)
|
||||
|
||||
This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.
|
||||
|
||||
1. Definitions
|
||||
The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law.
|
||||
A "contribution" is the original software, or any additions or changes to the software.
|
||||
A "contributor" is any person that distributes its contribution under this license.
|
||||
"Licensed patents" are a contributor's patent claims that read directly on its contribution.
|
||||
|
||||
2. Grant of Rights
|
||||
(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
|
||||
(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
|
||||
|
||||
3. Conditions and Limitations
|
||||
(A) Reciprocal Grants- For any file you distribute that contains code from the software (in source code or binary format), you must provide recipients the source code to that file along with a copy of this license, which license will govern that file. You may license other files that are entirely your own work and do not contain code from the software under any terms you choose.
|
||||
(B) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
|
||||
(C) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
|
||||
(D) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
|
||||
(E) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
|
||||
(F) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
|
3273
third_party/python/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp
vendored
Normal file
3273
third_party/python/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
third_party/python/Tools/msi/bundle/bootstrap/pch.cpp
vendored
Normal file
1
third_party/python/Tools/msi/bundle/bootstrap/pch.cpp
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
#include "pch.h"
|
60
third_party/python/Tools/msi/bundle/bootstrap/pch.h
vendored
Normal file
60
third_party/python/Tools/msi/bundle/bootstrap/pch.h
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
//-------------------------------------------------------------------------------------------------
|
||||
// <copyright file="precomp.h" company="Outercurve Foundation">
|
||||
// Copyright (c) 2004, Outercurve Foundation.
|
||||
// This software is released under Microsoft Reciprocal License (MS-RL).
|
||||
// The license and further copyright text can be found in the file
|
||||
// LICENSE.TXT at the root directory of the distribution.
|
||||
// </copyright>
|
||||
//
|
||||
// <summary>
|
||||
// Precompiled header for standard bootstrapper application.
|
||||
// </summary>
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <gdiplus.h>
|
||||
#include <Uxtheme.h>
|
||||
#include <msiquery.h>
|
||||
#include <objbase.h>
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi.h>
|
||||
#include <stdlib.h>
|
||||
#include <strsafe.h>
|
||||
#include <stddef.h>
|
||||
#include <versionhelpers.h>
|
||||
|
||||
#include "dutil.h"
|
||||
#include "memutil.h"
|
||||
#include "dictutil.h"
|
||||
#include "dirutil.h"
|
||||
#include "fileutil.h"
|
||||
#include "locutil.h"
|
||||
#include "logutil.h"
|
||||
#include "pathutil.h"
|
||||
#include "resrutil.h"
|
||||
#include "shelutil.h"
|
||||
#include "strutil.h"
|
||||
#include "thmutil.h"
|
||||
#include "uriutil.h"
|
||||
#include "xmlutil.h"
|
||||
|
||||
#include "IBootstrapperEngine.h"
|
||||
#include "IBootstrapperApplication.h"
|
||||
|
||||
#include "BalBaseBootstrapperApplication.h"
|
||||
#include "balinfo.h"
|
||||
#include "balcondition.h"
|
||||
|
||||
HRESULT CreateBootstrapperApplication(
|
||||
__in HMODULE hModule,
|
||||
__in BOOL fPrereq,
|
||||
__in HRESULT hrHostInitialization,
|
||||
__in IBootstrapperEngine* pEngine,
|
||||
__in const BOOTSTRAPPER_COMMAND* pCommand,
|
||||
__out IBootstrapperApplication** ppApplication
|
||||
);
|
||||
|
||||
#include "IBootstrapperBAFunction.h"
|
||||
|
76
third_party/python/Tools/msi/bundle/bootstrap/pythonba.cpp
vendored
Normal file
76
third_party/python/Tools/msi/bundle/bootstrap/pythonba.cpp
vendored
Normal file
|
@ -0,0 +1,76 @@
|
|||
//-------------------------------------------------------------------------------------------------
|
||||
// <copyright file="wixstdba.cpp" company="Outercurve Foundation">
|
||||
// Copyright (c) 2004, Outercurve Foundation.
|
||||
// This software is released under Microsoft Reciprocal License (MS-RL).
|
||||
// The license and further copyright text can be found in the file
|
||||
// LICENSE.TXT at the root directory of the distribution.
|
||||
// </copyright>
|
||||
//
|
||||
// <summary>
|
||||
// Setup chainer/bootstrapper standard UI for WiX toolset.
|
||||
// </summary>
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
static HINSTANCE vhInstance = NULL;
|
||||
|
||||
extern "C" BOOL WINAPI DllMain(
|
||||
IN HINSTANCE hInstance,
|
||||
IN DWORD dwReason,
|
||||
IN LPVOID /* pvReserved */
|
||||
)
|
||||
{
|
||||
switch(dwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
::DisableThreadLibraryCalls(hInstance);
|
||||
vhInstance = hInstance;
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
vhInstance = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
extern "C" HRESULT WINAPI BootstrapperApplicationCreate(
|
||||
__in IBootstrapperEngine* pEngine,
|
||||
__in const BOOTSTRAPPER_COMMAND* pCommand,
|
||||
__out IBootstrapperApplication** ppApplication
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
BalInitialize(pEngine);
|
||||
|
||||
hr = CreateBootstrapperApplication(vhInstance, FALSE, S_OK, pEngine, pCommand, ppApplication);
|
||||
BalExitOnFailure(hr, "Failed to create bootstrapper application interface.");
|
||||
|
||||
LExit:
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
extern "C" void WINAPI BootstrapperApplicationDestroy()
|
||||
{
|
||||
BalUninitialize();
|
||||
}
|
||||
|
||||
|
||||
extern "C" HRESULT WINAPI MbaPrereqBootstrapperApplicationCreate(
|
||||
__in HRESULT hrHostInitialization,
|
||||
__in IBootstrapperEngine* pEngine,
|
||||
__in const BOOTSTRAPPER_COMMAND* pCommand,
|
||||
__out IBootstrapperApplication** ppApplication
|
||||
)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
|
||||
extern "C" void WINAPI MbaPrereqBootstrapperApplicationDestroy()
|
||||
{ }
|
18
third_party/python/Tools/msi/bundle/bootstrap/pythonba.def
vendored
Normal file
18
third_party/python/Tools/msi/bundle/bootstrap/pythonba.def
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
;-------------------------------------------------------------------------------------------------
|
||||
; <copyright file="wixstdba.def" company="Outercurve Foundation">
|
||||
; Copyright (c) 2004, Outercurve Foundation.
|
||||
; This software is released under Microsoft Reciprocal License (MS-RL).
|
||||
; The license and further copyright text can be found in the file
|
||||
; LICENSE.TXT at the root directory of the distribution.
|
||||
; </copyright>
|
||||
;
|
||||
; <summary>
|
||||
; WiX Standard Bootstrapper Application DLL entry points.
|
||||
; </summary>
|
||||
;-------------------------------------------------------------------------------------------------
|
||||
|
||||
EXPORTS
|
||||
BootstrapperApplicationCreate
|
||||
BootstrapperApplicationDestroy
|
||||
MbaPrereqBootstrapperApplicationCreate
|
||||
MbaPrereqBootstrapperApplicationDestroy
|
22
third_party/python/Tools/msi/bundle/bootstrap/pythonba.sln
vendored
Normal file
22
third_party/python/Tools/msi/bundle/bootstrap/pythonba.sln
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.30501.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pythonba", "pythonba.vcxproj", "{7A09B132-B3EE-499B-A700-A4B2157FEA3D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{7A09B132-B3EE-499B-A700-A4B2157FEA3D}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{7A09B132-B3EE-499B-A700-A4B2157FEA3D}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{7A09B132-B3EE-499B-A700-A4B2157FEA3D}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{7A09B132-B3EE-499B-A700-A4B2157FEA3D}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
71
third_party/python/Tools/msi/bundle/bootstrap/pythonba.vcxproj
vendored
Normal file
71
third_party/python/Tools/msi/bundle/bootstrap/pythonba.vcxproj
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
<copyright file="wixstdba.vcxproj" company="Outercurve Foundation">
|
||||
Copyright (c) 2004, Outercurve Foundation.
|
||||
This software is released under Microsoft Reciprocal License (MS-RL).
|
||||
The license and further copyright text can be found in the file
|
||||
LICENSE.TXT at the root directory of the distribution.
|
||||
</copyright>
|
||||
-->
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<Configuration Condition="'$(Configuration)' == ''">Release</Configuration>
|
||||
<Platform Condition="'$(Platform)' == ''">Win32</Platform>
|
||||
<PlatformToolset Condition="'$(PlatformToolset)' == '' and '$(VCTargetsPath14)' != ''">v140</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(PlatformToolset)' == '' and '$(VCTargetsPath12)' != ''">v120</PlatformToolset>
|
||||
<ProjectGuid>{7A09B132-B3EE-499B-A700-A4B2157FEA3D}</ProjectGuid>
|
||||
<TargetName>PythonBA</TargetName>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\wix.props" />
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<Py_IntDir Condition="'$(Py_IntDir)' == ''">$(PySourcePath)PCbuild\obj\</Py_IntDir>
|
||||
<IntDir>$(Py_IntDir)\$(MajorVersionNumber)$(MinorVersionNumber)$(ArchName)_$(Configuration)\msi_$(ProjectName)\</IntDir>
|
||||
<IntDir>$(IntDir.Replace(`\\`, `\`))</IntDir>
|
||||
<OutDir>$(IntDir)</OutDir>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_CRT_STDIO_LEGACY_WIDE_SPECIFIERS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(WixInstallPath)sdk\inc</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>comctl32.lib;gdiplus.lib;msimg32.lib;shlwapi.lib;wininet.lib;dutil.lib;balutil.lib;version.lib;uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories Condition="'$(PlatformToolset)' == 'v140'">$(WixInstallPath)sdk\vs2015\lib\x86</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories Condition="'$(PlatformToolset)' == 'v120'">$(WixInstallPath)sdk\vs2013\lib\x86</AdditionalLibraryDirectories>
|
||||
<ModuleDefinitionFile>pythonba.def</ModuleDefinitionFile>
|
||||
<GenerateDebugInformation Condition="'$(Configuration)'=='Debug'">true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="PythonBootstrapperApplication.cpp" />
|
||||
<ClCompile Include="pythonba.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="pythonba.def" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
25
third_party/python/Tools/msi/bundle/bootstrap/resource.h
vendored
Normal file
25
third_party/python/Tools/msi/bundle/bootstrap/resource.h
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
//-------------------------------------------------------------------------------------------------
|
||||
// <copyright file="resource.h" company="Outercurve Foundation">
|
||||
// Copyright (c) 2004, Outercurve Foundation.
|
||||
// This software is released under Microsoft Reciprocal License (MS-RL).
|
||||
// The license and further copyright text can be found in the file
|
||||
// LICENSE.TXT at the root directory of the distribution.
|
||||
// </copyright>
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
//
|
||||
#define IDC_STATIC -1
|
||||
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 102
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1003
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
106
third_party/python/Tools/msi/bundle/bundle.targets
vendored
Normal file
106
third_party/python/Tools/msi/bundle/bundle.targets
vendored
Normal file
|
@ -0,0 +1,106 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" TreatAsLocalProperty="DownloadUrl">
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<OutputType>Bundle</OutputType>
|
||||
|
||||
<BootstrapConfiguration Condition="'$(BootstrapConfiguration)' == ''">Release</BootstrapConfiguration>
|
||||
<LinkerSuppressSpecificWarnings>1132;1135;1140</LinkerSuppressSpecificWarnings>
|
||||
<OutputName Condition="$(BuildForRelease)">$(OutputName)-$(PythonVersion)</OutputName>
|
||||
<OutputName Condition="!$(BuildForRelease)">$(OutputName)-$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber).$(RevisionNumber)</OutputName>
|
||||
<OutputName Condition="$(Platform) == 'x64'">$(OutputName)-amd64</OutputName>
|
||||
<OutputName Condition="'$(OutputSuffix)' != ''">$(OutputName)-$(OutputSuffix)</OutputName>
|
||||
<OutputName Condition="'$(Configuration)' == 'Debug'">$(OutputName)-d</OutputName>
|
||||
<TargetName>$(OutputName)</TargetName>
|
||||
|
||||
<OutputPath>$(OutputPath)en-us\</OutputPath>
|
||||
<OutDir>$(OutputPath)</OutDir>
|
||||
|
||||
<!-- See Tools/msi/buildrelease.bat for help on configuring the download URL -->
|
||||
<DownloadUrl Condition="'$(DownloadUrl)' == '' and '$(DownloadUrlBase)' != ''">$(DownloadUrlBase.TrimEnd(`/`))/{version}/{arch}{releasename}/{msi}</DownloadUrl>
|
||||
<DefineConstants Condition="'$(DownloadUrl)' != ''">$(DefineConstants);DownloadUrl=$(DownloadUrl.Replace(`{version}`, `$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber)`).Replace(`{arch}`, `$(ArchName)`).Replace(`{releasename}`, `$(ReleaseLevelName)`).Replace(`{msi}`, `{2}`))</DefineConstants>
|
||||
<DefineConstants Condition="'$(DownloadUrl)' == ''">$(DefineConstants);DownloadUrl={2}</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<WixExtension Include="WixUtilExtension">
|
||||
<HintPath>WixUtilExtension</HintPath>
|
||||
<Name>WixUtilExtension</Name>
|
||||
</WixExtension>
|
||||
<WixExtension Include="WixDependencyExtension">
|
||||
<HintPath>WixDependencyExtension</HintPath>
|
||||
<Name>WixDependencyExtension</Name>
|
||||
</WixExtension>
|
||||
<WixExtension Include="WixBalExtension">
|
||||
<HintPath>WixBalExtension</HintPath>
|
||||
<Name>WixBalExtension</Name>
|
||||
</WixExtension>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="bundle.wxs" />
|
||||
<Compile Include="packagegroups\*.wxs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Default.thm" />
|
||||
<Content Include="Default.wxl" />
|
||||
<Content Include="SideBar.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="bundle.wxl" />
|
||||
<WxlTemplate Include="*_en-US.wxl_template" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<LinkerBindInputPaths Include="$(OutputPath)">
|
||||
<BindName></BindName>
|
||||
</LinkerBindInputPaths>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<Package>
|
||||
<Properties>BuildForRelease=$(BuildForRelease)</Properties>
|
||||
</Package>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<Package Include="..\core\core*.wixproj" />
|
||||
<Package Include="..\dev\dev*.wixproj" />
|
||||
<Package Include="..\doc\doc*.wixproj" />
|
||||
<Package Include="..\exe\exe*.wixproj" />
|
||||
<Package Include="..\lib\lib*.wixproj" />
|
||||
<Package Include="..\path\path*.wixproj" />
|
||||
<Package Include="..\pip\pip*.wixproj" />
|
||||
<Package Include="..\tcltk\tcltk*.wixproj" />
|
||||
<Package Include="..\test\test*.wixproj" />
|
||||
<Package Include="..\tools\tools*.wixproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<BuildPackagesTargets>Build</BuildPackagesTargets>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="_SetRebuildTarget" BeforeTargets="BeforeRebuild">
|
||||
<PropertyGroup>
|
||||
<BuildPackagesTargets>Rebuild</BuildPackagesTargets>
|
||||
</PropertyGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="BuildPackages" BeforeTargets="BeforeBuild" Condition="'$(RebuildAll)' != 'false'">
|
||||
<MSBuild Projects="@(Package)" Targets="$(BuildPackagesTargets)" BuildInParallel="true" />
|
||||
</Target>
|
||||
|
||||
<Target Name="BuildBootstrapApplication" BeforeTargets="BeforeBuild">
|
||||
<Message Text="Building bootstrap app" Importance="high" />
|
||||
|
||||
<MSBuild Projects="bootstrap\pythonba.vcxproj"
|
||||
Targets="Build;GetNativeTargetPath"
|
||||
UseResultsCache="true"
|
||||
Properties="Configuration=$(BootstrapConfiguration);Platform=Win32">
|
||||
<Output TaskParameter="TargetOutputs" PropertyName="BootstrapAppPath" />
|
||||
</MSBuild>
|
||||
|
||||
<PropertyGroup>
|
||||
<DefineConstants>$(DefineConstants);BootstrapApp=$(BootstrapAppPath)</DefineConstants>
|
||||
</PropertyGroup>
|
||||
</Target>
|
||||
|
||||
<Import Project="..\msi.targets" />
|
||||
</Project>
|
7
third_party/python/Tools/msi/bundle/bundle.wxl
vendored
Normal file
7
third_party/python/Tools/msi/bundle/bundle.wxl
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
|
||||
<String Id="CRTDescription">C Runtime Update (KB2999226)</String>
|
||||
<String Id="CompileAllDescription">Precompiling standard library</String>
|
||||
<String Id="CompileAllODescription">Precompiling standard library (-O)</String>
|
||||
<String Id="CompileAllOODescription">Precompiling standard library (-OO)</String>
|
||||
</WixLocalization>
|
112
third_party/python/Tools/msi/bundle/bundle.wxs
vendored
Normal file
112
third_party/python/Tools/msi/bundle/bundle.wxs
vendored
Normal file
|
@ -0,0 +1,112 @@
|
|||
<?xml version="1.0"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
|
||||
xmlns:bal="http://schemas.microsoft.com/wix/BalExtension"
|
||||
xmlns:dep="http://schemas.microsoft.com/wix/DependencyExtension">
|
||||
<Bundle Name="!(loc.FullProductName)"
|
||||
UpgradeCode="$(var.CoreUpgradeCode)"
|
||||
Version="$(var.Version)"
|
||||
IconSourceFile="..\..\..\PC\icons\setup.ico"
|
||||
Manufacturer="!(loc.Manufacturer)"
|
||||
AboutUrl="http://www.python.org/"
|
||||
Compressed="no"
|
||||
dep:ProviderKey="CPython-$(var.MajorVersionNumber).$(var.MinorVersionNumber)$(var.PyArchExt)$(var.PyTestExt)">
|
||||
<BootstrapperApplication Id="PythonBA" SourceFile="$(var.BootstrapApp)">
|
||||
<Payload Compressed='yes' SourceFile='Default.thm' />
|
||||
<Payload Compressed='yes' SourceFile='Default.wxl' />
|
||||
<Payload Compressed='yes' SourceFile='SideBar.png' />
|
||||
</BootstrapperApplication>
|
||||
|
||||
<!-- May be set to "Removing" or "Repairing" -->
|
||||
<Variable Name="ActionLikeInstalling" Value="Installing" />
|
||||
<!-- May be set to "Uninstallation" or "Repair" -->
|
||||
<Variable Name="ActionLikeInstallation" Value="Setup" />
|
||||
|
||||
<Variable Name="ShortVersion" Value="$(var.MajorVersionNumber).$(var.MinorVersionNumber)" />
|
||||
<Variable Name="ShortVersionNoDot" Value="$(var.MajorVersionNumber)$(var.MinorVersionNumber)" />
|
||||
<Variable Name="WinVer" Value="$(var.MajorVersionNumber).$(var.MinorVersionNumber)$(var.PyArchExt)$(var.PyTestExt)" />
|
||||
<Variable Name="WinVerNoDot" Value="$(var.MajorVersionNumber)$(var.MinorVersionNumber)$(var.PyArchExt)$(var.PyTestExt)" />
|
||||
|
||||
<Variable Name="InstallAllUsers" Value="0" bal:Overridable="yes" />
|
||||
<?if "$(var.PyTestExt)"="" ?>
|
||||
<Variable Name="InstallLauncherAllUsers" Value="1" bal:Overridable="yes" />
|
||||
<?else ?>
|
||||
<Variable Name="InstallLauncherAllUsers" Value="0" />
|
||||
<?endif ?>
|
||||
<Variable Name="TargetDir" Value="" bal:Overridable="yes" />
|
||||
<?if $(var.Platform)~="x64" ?>
|
||||
<Variable Name="DefaultAllUsersTargetDir" Value="[ProgramFiles64Folder]Python[WinVerNoDot]" bal:Overridable="yes" />
|
||||
<Variable Name="TargetPlatform" Value="x64" />
|
||||
<?else ?>
|
||||
<Variable Name="DefaultAllUsersTargetDir" Value="[ProgramFilesFolder]Python[WinVerNoDot]" bal:Overridable="yes" />
|
||||
<Variable Name="TargetPlatform" Value="x86" />
|
||||
<?endif ?>
|
||||
<Variable Name="DefaultJustForMeTargetDir" Value="[LocalAppDataFolder]Programs\Python\Python[WinVerNoDot]" bal:Overridable="yes" />
|
||||
<Variable Name="OptionalFeaturesRegistryKey" Value="Software\Python\PythonCore\[WinVer]\InstalledFeatures" />
|
||||
<Variable Name="TargetDirRegistryKey" Value="Software\Python\PythonCore\[WinVer]\InstallPath" />
|
||||
|
||||
<!--
|
||||
An empty string will use the other defaults based on InstallAllUsers
|
||||
(and switch dynamically in the UI). To get the old default, pass
|
||||
this property on the command line:
|
||||
DefaultCustomTargetDir=[WindowsVolume]Python[ShortVersionNoDot]
|
||||
-->
|
||||
<Variable Name="DefaultCustomTargetDir" Value="" bal:Overridable="yes" />
|
||||
|
||||
<Variable Name="InstallAllUsersState" Value="enabled" bal:Overridable="yes" />
|
||||
<?if "$(var.PyTestExt)"="" ?>
|
||||
<Variable Name="InstallLauncherAllUsersState" Value="enabled" bal:Overridable="yes" />
|
||||
<?else ?>
|
||||
<Variable Name="InstallLauncherAllUsersState" Value="disable" bal:Overridable="yes" />
|
||||
<?endif ?>
|
||||
<Variable Name="CustomInstallLauncherAllUsersState" Value="[InstallLauncherAllUsersState]" />
|
||||
<Variable Name="TargetDirState" Value="enabled" />
|
||||
<Variable Name="CustomBrowseButtonState" Value="enabled" />
|
||||
|
||||
<Variable Name="Include_core" Value="1" />
|
||||
<Variable Name="Include_exe" Value="1" bal:Overridable="yes" />
|
||||
<Variable Name="Include_dev" Value="1" bal:Overridable="yes" />
|
||||
<Variable Name="Include_lib" Value="1" bal:Overridable="yes" />
|
||||
<Variable Name="Include_test" Value="1" bal:Overridable="yes" />
|
||||
<Variable Name="Include_doc" Value="1" bal:Overridable="yes" />
|
||||
<Variable Name="Include_tools" Value="1" bal:Overridable="yes" />
|
||||
<Variable Name="Include_tcltk" Value="1" bal:Overridable="yes" />
|
||||
<Variable Name="Include_pip" Value="1" bal:Overridable="yes" />
|
||||
<?if "$(var.PyTestExt)"="" ?>
|
||||
<Variable Name="Include_launcher" Value="1" bal:Overridable="yes" />
|
||||
<Variable Name="Include_launcherState" Value="enabled" bal:Overridable="yes" />
|
||||
<?else ?>
|
||||
<Variable Name="Include_launcher" Value="0" />
|
||||
<Variable Name="Include_launcherState" Value="disable" />
|
||||
<?endif ?>
|
||||
<Variable Name="Include_symbols" Value="0" bal:Overridable="yes" />
|
||||
<Variable Name="Include_debug" Value="0" bal:Overridable="yes" />
|
||||
|
||||
<Variable Name="LauncherOnly" Value="0" bal:Overridable="yes" />
|
||||
<Variable Name="DetectedLauncher" Value="0" />
|
||||
<Variable Name="DetectedOldLauncher" Value="0" />
|
||||
|
||||
<Variable Name="AssociateFiles" Value="1" bal:Overridable="yes" />
|
||||
<Variable Name="Shortcuts" Value="1" bal:Overridable="yes" />
|
||||
<Variable Name="PrependPath" Value="0" bal:Overridable="yes" />
|
||||
<Variable Name="CompileAll" Value="0" bal:Overridable="yes" />
|
||||
|
||||
<Variable Name="SimpleInstall" Value="0" bal:Overridable="yes" />
|
||||
<Variable Name="SimpleInstallDescription" Value="" bal:Overridable="yes" />
|
||||
|
||||
<Chain ParallelCache="yes">
|
||||
<PackageGroupRef Id="crt" />
|
||||
<PackageGroupRef Id="core" />
|
||||
<PackageGroupRef Id="dev" />
|
||||
<PackageGroupRef Id="exe" />
|
||||
<PackageGroupRef Id="lib" />
|
||||
<PackageGroupRef Id="test" />
|
||||
<PackageGroupRef Id="doc" />
|
||||
<PackageGroupRef Id="tools" />
|
||||
<PackageGroupRef Id="tcltk" />
|
||||
<PackageGroupRef Id="launcher" />
|
||||
<PackageGroupRef Id="pip" />
|
||||
<PackageGroupRef Id="packageinstall" />
|
||||
<PackageGroupRef Id="postinstall" />
|
||||
</Chain>
|
||||
</Bundle>
|
||||
</Wix>
|
21
third_party/python/Tools/msi/bundle/full.wixproj
vendored
Normal file
21
third_party/python/Tools/msi/bundle/full.wixproj
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{3E204ADD-238D-4D10-852C-4F859325C839}</ProjectGuid>
|
||||
<OutputName>python</OutputName>
|
||||
<OutputSuffix>full</OutputSuffix>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\msi.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<DefineConstants>
|
||||
$(DefineConstants);
|
||||
CompressMSI=yes;
|
||||
CompressPDB=yes;
|
||||
CompressMSI_D=yes;
|
||||
</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="bundle.targets" />
|
||||
</Project>
|
62
third_party/python/Tools/msi/bundle/packagegroups/core.wxs
vendored
Normal file
62
third_party/python/Tools/msi/bundle/packagegroups/core.wxs
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Fragment>
|
||||
<PackageGroup Id="core">
|
||||
<MsiPackage Id="core_AllUsers"
|
||||
SourceFile="core.msi"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="yes"
|
||||
InstallCondition="InstallAllUsers and (Include_core or Include_exe or Include_launcher or Include_pip) and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="core_AllUsers_pdb"
|
||||
SourceFile="core_pdb.msi"
|
||||
Compressed="$(var.CompressPDB)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="yes"
|
||||
InstallCondition="InstallAllUsers and (Include_core or Include_exe or Include_launcher or Include_pip) and Include_symbols and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="core_AllUsers_d"
|
||||
SourceFile="core_d.msi"
|
||||
Compressed="$(var.CompressMSI_D)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="yes"
|
||||
InstallCondition="InstallAllUsers and (Include_core or Include_exe or Include_launcher or Include_pip) and Include_debug and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
|
||||
<MsiPackage Id="core_JustForMe"
|
||||
SourceFile="core.msi"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="no"
|
||||
InstallCondition="not InstallAllUsers and (Include_core or Include_exe or Include_launcher or Include_pip) and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="core_JustForMe_pdb"
|
||||
SourceFile="core_pdb.msi"
|
||||
Compressed="$(var.CompressPDB)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="no"
|
||||
InstallCondition="not InstallAllUsers and (Include_core or Include_exe or Include_launcher or Include_pip) and Include_symbols and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="core_JustForMe_d"
|
||||
SourceFile="core_d.msi"
|
||||
Compressed="$(var.CompressMSI_D)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="no"
|
||||
InstallCondition="not InstallAllUsers and (Include_core or Include_exe or Include_launcher or Include_pip) and Include_debug and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
</PackageGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
49
third_party/python/Tools/msi/bundle/packagegroups/crt.wxs
vendored
Normal file
49
third_party/python/Tools/msi/bundle/packagegroups/crt.wxs
vendored
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Fragment>
|
||||
<PackageGroup Id="crt">
|
||||
<PackageGroupRef Id="crt_14.0_v6.0" />
|
||||
<PackageGroupRef Id="crt_14.0_v6.1" />
|
||||
<PackageGroupRef Id="crt_14.0_v6.2" />
|
||||
<PackageGroupRef Id="crt_14.0_v6.3" />
|
||||
</PackageGroup>
|
||||
</Fragment>
|
||||
|
||||
<?foreach ver in v6.0;v6.1;v6.2;v6.3 ?>
|
||||
<?if "$(var.ver)" = "v6.0" ?>
|
||||
<?define msuver=6.0 ?>
|
||||
<?elseif "$(var.ver)" = "v6.1" ?>
|
||||
<?define msuver=6.1 ?>
|
||||
<?elseif "$(var.ver)" = "v6.2" ?>
|
||||
<?define msuver=8-RT ?>
|
||||
<?elseif "$(var.ver)" = "v6.3" ?>
|
||||
<?define msuver=8.1 ?>
|
||||
<?else ?>
|
||||
<?error unknown version $(var.ver) ?>
|
||||
<?endif ?>
|
||||
|
||||
<Fragment>
|
||||
<PackageGroup Id="crt_14.0_$(var.ver)">
|
||||
<MsuPackage Id="crt_14.0_$(var.ver)_x86"
|
||||
KB="2999226"
|
||||
SourceFile="!(bindpath.redist)\Windows$(var.msuver)-KB2999226-x86.msu"
|
||||
DisplayName="!(loc.CRTDescription)"
|
||||
Description="!(loc.CRTDescription)"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
InstallCondition="not CRTInstalled and VersionNT = $(var.ver) and not VersionNT64 and (Include_core or Include_exe or Include_launcher or Include_pip) and not LauncherOnly" />
|
||||
|
||||
<MsuPackage Id="crt_14.0_$(var.ver)_x64"
|
||||
KB="2999226"
|
||||
SourceFile="!(bindpath.redist)\Windows$(var.msuver)-KB2999226-x64.msu"
|
||||
DisplayName="!(loc.CRTDescription)"
|
||||
Description="!(loc.CRTDescription)"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
InstallCondition="not CRTInstalled and VersionNT64 = $(var.ver) and (Include_core or Include_exe or Include_launcher or Include_pip) and not LauncherOnly" />
|
||||
</PackageGroup>
|
||||
</Fragment>
|
||||
|
||||
<?undef msuver ?>
|
||||
<?endforeach ?>
|
||||
</Wix>
|
44
third_party/python/Tools/msi/bundle/packagegroups/dev.wxs
vendored
Normal file
44
third_party/python/Tools/msi/bundle/packagegroups/dev.wxs
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Fragment>
|
||||
<PackageGroup Id="dev">
|
||||
<MsiPackage Id="dev_AllUsers"
|
||||
SourceFile="dev.msi"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="yes"
|
||||
InstallCondition="InstallAllUsers and Include_dev and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="dev_AllUsers_d"
|
||||
SourceFile="dev_d.msi"
|
||||
Compressed="$(var.CompressMSI_D)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="yes"
|
||||
InstallCondition="InstallAllUsers and Include_dev and Include_debug and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
|
||||
<MsiPackage Id="dev_JustForMe"
|
||||
SourceFile="dev.msi"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="no"
|
||||
InstallCondition="not InstallAllUsers and Include_dev and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="dev_JustForMe_d"
|
||||
SourceFile="dev_d.msi"
|
||||
Compressed="$(var.CompressMSI_D)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="no"
|
||||
InstallCondition="not InstallAllUsers and Include_dev and Include_debug and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
</PackageGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
28
third_party/python/Tools/msi/bundle/packagegroups/doc.wxs
vendored
Normal file
28
third_party/python/Tools/msi/bundle/packagegroups/doc.wxs
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Fragment>
|
||||
<PackageGroup Id="doc">
|
||||
<MsiPackage Id="doc_AllUsers"
|
||||
SourceFile="doc.msi"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
EnableFeatureSelection="yes"
|
||||
ForcePerMachine="yes"
|
||||
InstallCondition="InstallAllUsers and Include_doc and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
|
||||
<MsiPackage Id="doc_JustForMe"
|
||||
SourceFile="doc.msi"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
EnableFeatureSelection="yes"
|
||||
ForcePerMachine="no"
|
||||
InstallCondition="not InstallAllUsers and Include_doc and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
</PackageGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
64
third_party/python/Tools/msi/bundle/packagegroups/exe.wxs
vendored
Normal file
64
third_party/python/Tools/msi/bundle/packagegroups/exe.wxs
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
<?xml version="1.0"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Fragment>
|
||||
<PackageGroup Id="exe">
|
||||
<MsiPackage Id="exe_AllUsers"
|
||||
SourceFile="exe.msi"
|
||||
ForcePerMachine="yes"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
EnableFeatureSelection="yes"
|
||||
InstallCondition="InstallAllUsers and (Include_exe or Include_launcher or Include_pip) and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="exe_AllUsers_pdb"
|
||||
SourceFile="exe_pdb.msi"
|
||||
ForcePerMachine="yes"
|
||||
Compressed="$(var.CompressPDB)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
InstallCondition="InstallAllUsers and (Include_exe or Include_launcher or Include_pip) and Include_symbols and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="exe_AllUsers_d"
|
||||
SourceFile="exe_d.msi"
|
||||
ForcePerMachine="yes"
|
||||
Compressed="$(var.CompressMSI_D)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
InstallCondition="InstallAllUsers and (Include_exe or Include_launcher or Include_pip) and Include_debug and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
|
||||
<MsiPackage Id="exe_JustForMe"
|
||||
SourceFile="exe.msi"
|
||||
ForcePerMachine="no"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
EnableFeatureSelection="yes"
|
||||
InstallCondition="not InstallAllUsers and (Include_exe or Include_launcher or Include_pip) and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="exe_JustForMe_pdb"
|
||||
SourceFile="exe_pdb.msi"
|
||||
ForcePerMachine="no"
|
||||
Compressed="$(var.CompressPDB)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
InstallCondition="not InstallAllUsers and (Include_exe or Include_launcher or Include_pip) and Include_symbols and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="exe_JustForMe_d"
|
||||
SourceFile="exe_d.msi"
|
||||
ForcePerMachine="no"
|
||||
Compressed="$(var.CompressMSI_D)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
InstallCondition="not InstallAllUsers and (Include_exe or Include_launcher or Include_pip) and Include_debug and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
</PackageGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
27
third_party/python/Tools/msi/bundle/packagegroups/launcher.wxs
vendored
Normal file
27
third_party/python/Tools/msi/bundle/packagegroups/launcher.wxs
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Fragment>
|
||||
<PackageGroup Id="launcher">
|
||||
<!-- The All Users launcher is always the 32-bit version -->
|
||||
<MsiPackage Id="launcher_AllUsers"
|
||||
SourceFile="!(bindpath.build32)en-us\launcher.msi"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="yes"
|
||||
EnableFeatureSelection="yes"
|
||||
Permanent="yes"
|
||||
Visible="yes"
|
||||
InstallCondition="(InstallAllUsers or InstallLauncherAllUsers) and Include_launcher and not DetectedLauncher" />
|
||||
|
||||
<MsiPackage Id="launcher_JustForMe"
|
||||
SourceFile="!(bindpath.build32)en-us\launcher.msi"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="no"
|
||||
EnableFeatureSelection="yes"
|
||||
Permanent="yes"
|
||||
Visible="yes"
|
||||
InstallCondition="not (InstallAllUsers or InstallLauncherAllUsers) and Include_launcher and not DetectedLauncher" />
|
||||
</PackageGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
62
third_party/python/Tools/msi/bundle/packagegroups/lib.wxs
vendored
Normal file
62
third_party/python/Tools/msi/bundle/packagegroups/lib.wxs
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Fragment>
|
||||
<PackageGroup Id="lib">
|
||||
<MsiPackage Id="lib_AllUsers"
|
||||
SourceFile="lib.msi"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="yes"
|
||||
InstallCondition="InstallAllUsers and Include_lib and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="lib_AllUsers_pdb"
|
||||
SourceFile="lib_pdb.msi"
|
||||
Compressed="$(var.CompressPDB)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="yes"
|
||||
InstallCondition="InstallAllUsers and Include_lib and Include_symbols and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="lib_AllUsers_d"
|
||||
SourceFile="lib_d.msi"
|
||||
Compressed="$(var.CompressMSI_D)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="yes"
|
||||
InstallCondition="InstallAllUsers and Include_lib and Include_debug and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
|
||||
<MsiPackage Id="lib_JustForMe"
|
||||
SourceFile="lib.msi"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="no"
|
||||
InstallCondition="not InstallAllUsers and Include_lib and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="lib_JustForMe_pdb"
|
||||
SourceFile="lib_pdb.msi"
|
||||
Compressed="$(var.CompressPDB)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="no"
|
||||
InstallCondition="not InstallAllUsers and Include_lib and Include_symbols and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="lib_JustForMe_d"
|
||||
SourceFile="lib_d.msi"
|
||||
Compressed="$(var.CompressMSI_D)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="no"
|
||||
InstallCondition="not InstallAllUsers and Include_lib and Include_debug and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
</PackageGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
26
third_party/python/Tools/msi/bundle/packagegroups/packageinstall.wxs
vendored
Normal file
26
third_party/python/Tools/msi/bundle/packagegroups/packageinstall.wxs
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Fragment>
|
||||
<PackageGroup Id="packageinstall">
|
||||
<!--
|
||||
This is an example of installing a package using pip as part of main install.
|
||||
|
||||
For a network-only install, remove the Payload element and change the install
|
||||
command to specify the package and (optionally) version specifier.
|
||||
|
||||
<ExePackage Id="requests"
|
||||
SourceFile="py.exe"
|
||||
Compressed="yes"
|
||||
DisplayName="!(loc.CompileAllDescription)"
|
||||
InstallCommand='-[WinVer] -m pip install requests-2.7.0-py2.py3-none-any.whl'
|
||||
UninstallCommand='-[WinVer] -m pip uninstall -y requests'
|
||||
Vital="no"
|
||||
InstallCondition="Include_pip and not LauncherOnly">
|
||||
<Payload SourceFile="requests-2.7.0-py2.py3-none-any.whl"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)" />
|
||||
</ExePackage>
|
||||
-->
|
||||
</PackageGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
25
third_party/python/Tools/msi/bundle/packagegroups/pip.wxs
vendored
Normal file
25
third_party/python/Tools/msi/bundle/packagegroups/pip.wxs
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Fragment>
|
||||
<PackageGroup Id="pip">
|
||||
<MsiPackage Id="pip_AllUsers"
|
||||
SourceFile="pip.msi"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="yes"
|
||||
InstallCondition="InstallAllUsers and Include_pip and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="pip_JustForMe"
|
||||
SourceFile="pip.msi"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="no"
|
||||
InstallCondition="not InstallAllUsers and Include_pip and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
</PackageGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
88
third_party/python/Tools/msi/bundle/packagegroups/postinstall.wxs
vendored
Normal file
88
third_party/python/Tools/msi/bundle/packagegroups/postinstall.wxs
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
<?xml version="1.0"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Fragment>
|
||||
<PackageGroup Id="postinstall">
|
||||
<MsiPackage Id="path_AllUsers"
|
||||
SourceFile="path.msi"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="yes"
|
||||
InstallCondition="InstallAllUsers and PrependPath and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="path_JustForMe"
|
||||
SourceFile="path.msi"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="no"
|
||||
InstallCondition="not InstallAllUsers and PrependPath and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
|
||||
<?define CompileAllCommand=-E -s -Wi "[TargetDir]\Lib\compileall.py" -f -x "bad_coding|badsyntax|site-packages|py2_|lib2to3\\tests|venv\\scripts" "[TargetDir]\Lib"?>
|
||||
<ExePackage Id="compileall_AllUsers"
|
||||
SourceFile="py.exe"
|
||||
Compressed="yes"
|
||||
DisplayName="!(loc.CompileAllDescription)"
|
||||
InstallCommand='-[WinVer] $(var.CompileAllCommand)'
|
||||
RepairCommand='-[WinVer] $(var.CompileAllCommand)'
|
||||
Permanent="yes"
|
||||
PerMachine="yes"
|
||||
Vital="no"
|
||||
InstallCondition="InstallAllUsers and CompileAll and not LauncherOnly" />
|
||||
<ExePackage Id="compileallO_AllUsers"
|
||||
SourceFile="py.exe"
|
||||
Compressed="yes"
|
||||
DisplayName="!(loc.CompileAllODescription)"
|
||||
InstallCommand='-[WinVer] -O $(var.CompileAllCommand)'
|
||||
RepairCommand='-[WinVer] -O $(var.CompileAllCommand)'
|
||||
Permanent="yes"
|
||||
PerMachine="yes"
|
||||
Vital="no"
|
||||
InstallCondition="InstallAllUsers and CompileAll and not LauncherOnly" />
|
||||
<ExePackage Id="compileallOO_AllUsers"
|
||||
SourceFile="py.exe"
|
||||
Compressed="yes"
|
||||
DisplayName="!(loc.CompileAllOODescription)"
|
||||
InstallCommand='-[WinVer] -OO $(var.CompileAllCommand)'
|
||||
RepairCommand='-[WinVer] -OO $(var.CompileAllCommand)'
|
||||
Permanent="yes"
|
||||
PerMachine="yes"
|
||||
Vital="no"
|
||||
InstallCondition="InstallAllUsers and CompileAll and not LauncherOnly" />
|
||||
|
||||
<ExePackage Id="compileall_JustForMe"
|
||||
SourceFile="py.exe"
|
||||
Compressed="yes"
|
||||
DisplayName="!(loc.CompileAllDescription)"
|
||||
InstallCommand='-[WinVer] $(var.CompileAllCommand)'
|
||||
RepairCommand='-[WinVer] $(var.CompileAllCommand)'
|
||||
Permanent="yes"
|
||||
PerMachine="no"
|
||||
Vital="no"
|
||||
InstallCondition="not InstallAllUsers and CompileAll and not LauncherOnly" />
|
||||
<ExePackage Id="compileallO_JustForMe"
|
||||
SourceFile="py.exe"
|
||||
Compressed="yes"
|
||||
DisplayName="!(loc.CompileAllODescription)"
|
||||
InstallCommand='-[WinVer] -O $(var.CompileAllCommand)'
|
||||
RepairCommand='-[WinVer] -O $(var.CompileAllCommand)'
|
||||
Permanent="yes"
|
||||
PerMachine="no"
|
||||
Vital="no"
|
||||
InstallCondition="not InstallAllUsers and CompileAll and not LauncherOnly" />
|
||||
<ExePackage Id="compileallOO_JustForMe"
|
||||
SourceFile="py.exe"
|
||||
Compressed="yes"
|
||||
DisplayName="!(loc.CompileAllOODescription)"
|
||||
InstallCommand='-[WinVer] -OO $(var.CompileAllCommand)'
|
||||
RepairCommand='-[WinVer] -OO $(var.CompileAllCommand)'
|
||||
Permanent="yes"
|
||||
PerMachine="no"
|
||||
Vital="no"
|
||||
InstallCondition="not InstallAllUsers and CompileAll and not LauncherOnly" />
|
||||
</PackageGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
68
third_party/python/Tools/msi/bundle/packagegroups/tcltk.wxs
vendored
Normal file
68
third_party/python/Tools/msi/bundle/packagegroups/tcltk.wxs
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Fragment>
|
||||
<PackageGroup Id="tcltk">
|
||||
<MsiPackage Id="tcltk_AllUsers"
|
||||
SourceFile="tcltk.msi"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="yes"
|
||||
EnableFeatureSelection="yes"
|
||||
InstallCondition="InstallAllUsers and Include_tcltk and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="tcltk_AllUsers_pdb"
|
||||
SourceFile="tcltk_pdb.msi"
|
||||
Compressed="$(var.CompressPDB)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="yes"
|
||||
EnableFeatureSelection="yes"
|
||||
InstallCondition="InstallAllUsers and Include_tcltk and Include_symbols and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="tcltk_AllUsers_d"
|
||||
SourceFile="tcltk_d.msi"
|
||||
Compressed="$(var.CompressMSI_D)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="yes"
|
||||
EnableFeatureSelection="yes"
|
||||
InstallCondition="InstallAllUsers and Include_tcltk and Include_debug and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
|
||||
<MsiPackage Id="tcltk_JustForMe"
|
||||
SourceFile="tcltk.msi"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="no"
|
||||
EnableFeatureSelection="yes"
|
||||
InstallCondition="not InstallAllUsers and Include_tcltk and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="tcltk_JustForMe_pdb"
|
||||
SourceFile="tcltk_pdb.msi"
|
||||
Compressed="$(var.CompressPDB)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="no"
|
||||
EnableFeatureSelection="yes"
|
||||
InstallCondition="not InstallAllUsers and Include_tcltk and Include_symbols and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="tcltk_JustForMe_d"
|
||||
SourceFile="tcltk_d.msi"
|
||||
Compressed="$(var.CompressMSI_D)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="no"
|
||||
EnableFeatureSelection="yes"
|
||||
InstallCondition="not InstallAllUsers and Include_tcltk and Include_debug and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
</PackageGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
62
third_party/python/Tools/msi/bundle/packagegroups/test.wxs
vendored
Normal file
62
third_party/python/Tools/msi/bundle/packagegroups/test.wxs
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Fragment>
|
||||
<PackageGroup Id="test">
|
||||
<MsiPackage Id="test_AllUsers"
|
||||
SourceFile="test.msi"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="yes"
|
||||
InstallCondition="InstallAllUsers and Include_test and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="test_AllUsers_pdb"
|
||||
SourceFile="test_pdb.msi"
|
||||
Compressed="$(var.CompressPDB)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="yes"
|
||||
InstallCondition="InstallAllUsers and Include_test and Include_symbols and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="test_AllUsers_d"
|
||||
SourceFile="test_d.msi"
|
||||
Compressed="$(var.CompressMSI_D)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="yes"
|
||||
InstallCondition="InstallAllUsers and Include_test and Include_debug and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
|
||||
<MsiPackage Id="test_JustForMe"
|
||||
SourceFile="test.msi"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="no"
|
||||
InstallCondition="not InstallAllUsers and Include_test and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="test_JustForMe_pdb"
|
||||
SourceFile="test_pdb.msi"
|
||||
Compressed="$(var.CompressPDB)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="no"
|
||||
InstallCondition="not InstallAllUsers and Include_test and Include_symbols and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
<MsiPackage Id="test_JustForMe_d"
|
||||
SourceFile="test_d.msi"
|
||||
Compressed="$(var.CompressMSI_D)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="no"
|
||||
InstallCondition="not InstallAllUsers and Include_test and Include_debug and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
</PackageGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
26
third_party/python/Tools/msi/bundle/packagegroups/tools.wxs
vendored
Normal file
26
third_party/python/Tools/msi/bundle/packagegroups/tools.wxs
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Fragment>
|
||||
<PackageGroup Id="tools">
|
||||
<MsiPackage Id="tools_AllUsers"
|
||||
SourceFile="tools.msi"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="yes"
|
||||
InstallCondition="InstallAllUsers and Include_tools and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
|
||||
<MsiPackage Id="tools_JustForMe"
|
||||
SourceFile="tools.msi"
|
||||
Compressed="$(var.CompressMSI)"
|
||||
DownloadUrl="$(var.DownloadUrl)"
|
||||
ForcePerMachine="no"
|
||||
InstallCondition="not InstallAllUsers and Include_tools and not LauncherOnly">
|
||||
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
|
||||
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
|
||||
</MsiPackage>
|
||||
</PackageGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
21
third_party/python/Tools/msi/bundle/releaselocal.wixproj
vendored
Normal file
21
third_party/python/Tools/msi/bundle/releaselocal.wixproj
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{FCD43AC9-969F-49A1-8AC5-EDC27599D1EB}</ProjectGuid>
|
||||
<OutputName>python</OutputName>
|
||||
<OutputSuffix></OutputSuffix>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\msi.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<DefineConstants>
|
||||
$(DefineConstants);
|
||||
CompressMSI=yes;
|
||||
CompressPDB=no;
|
||||
CompressMSI_D=no
|
||||
</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="bundle.targets" />
|
||||
</Project>
|
21
third_party/python/Tools/msi/bundle/releaseweb.wixproj
vendored
Normal file
21
third_party/python/Tools/msi/bundle/releaseweb.wixproj
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{71CDE213-CB39-4BD9-B89D-BBB878689144}</ProjectGuid>
|
||||
<OutputName>python</OutputName>
|
||||
<OutputSuffix>webinstall</OutputSuffix>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\msi.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<DefineConstants>
|
||||
$(DefineConstants);
|
||||
CompressMSI=no;
|
||||
CompressPDB=no;
|
||||
CompressMSI_D=no
|
||||
</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="bundle.targets" />
|
||||
</Project>
|
26
third_party/python/Tools/msi/bundle/snapshot.wixproj
vendored
Normal file
26
third_party/python/Tools/msi/bundle/snapshot.wixproj
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{8A4A1162-4BF9-4FF6-9A98-315F01E44932}</ProjectGuid>
|
||||
<OutputName>python</OutputName>
|
||||
<OutputSuffix></OutputSuffix>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\msi.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<DefineConstants Condition="'$(Pack)' != 'true'">
|
||||
$(DefineConstants);CompressMSI=no;
|
||||
</DefineConstants>
|
||||
<DefineConstants Condition="'$(Pack)' == 'true'">
|
||||
$(DefineConstants);CompressMSI=yes;
|
||||
</DefineConstants>
|
||||
<DefineConstants>
|
||||
$(DefineConstants);
|
||||
CompressPDB=no;
|
||||
CompressMSI_D=no;
|
||||
</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="bundle.targets" />
|
||||
</Project>
|
122
third_party/python/Tools/msi/common.wxs
vendored
Normal file
122
third_party/python/Tools/msi/common.wxs
vendored
Normal file
|
@ -0,0 +1,122 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Fragment>
|
||||
<Property Id="ROOTREGISTRYKEY" Value="Software\Python\PythonCore" />
|
||||
</Fragment>
|
||||
|
||||
<Fragment>
|
||||
<Property Id="REGISTRYKEY" Value="Software\Python\PythonCore\$(var.ShortVersion)$(var.PyArchExt)$(var.PyTestExt)" />
|
||||
</Fragment>
|
||||
|
||||
<Fragment>
|
||||
<Component Id="OptionalFeature" Guid="*" Directory="InstallDirectory">
|
||||
<Condition>OPTIONALFEATURESREGISTRYKEY</Condition>
|
||||
<RegistryKey Root="HKMU" Key="[OPTIONALFEATURESREGISTRYKEY]">
|
||||
<RegistryValue Type="string" Name="$(var.OptionalFeatureName)" Value="$(var.Version)" KeyPath="yes" />
|
||||
</RegistryKey>
|
||||
</Component>
|
||||
</Fragment>
|
||||
|
||||
<Fragment>
|
||||
<Property Id="UpgradeTable" Value="1" />
|
||||
|
||||
<?ifndef SuppressUpgradeTable ?>
|
||||
<Upgrade Id="$(var.UpgradeCode)">
|
||||
<UpgradeVersion Property="DOWNGRADE" Minimum="$(var.Version)" IncludeMinimum="no" OnlyDetect="yes" />
|
||||
<UpgradeVersion Property="UPGRADE" Minimum="$(var.UpgradeMinimumVersion)" IncludeMinimum="yes" Maximum="$(var.Version)" IncludeMaximum="no" />
|
||||
</Upgrade>
|
||||
<?endif ?>
|
||||
|
||||
<?ifdef CoreUpgradeCode ?>
|
||||
<?if $(var.UpgradeCode)!=$(var.CoreUpgradeCode) ?>
|
||||
<Upgrade Id="$(var.CoreUpgradeCode)">
|
||||
<UpgradeVersion Property="MISSING_CORE" Minimum="$(var.Version)" IncludeMinimum="yes" Maximum="$(var.Version)" IncludeMaximum="yes" OnlyDetect="yes" />
|
||||
</Upgrade>
|
||||
<Condition Message="!(loc.IncorrectCore)">Installed OR NOT MISSING_CORE</Condition>
|
||||
<?endif ?>
|
||||
<?endif ?>
|
||||
|
||||
<Condition Message="!(loc.NoDowngrade)">Installed OR NOT DOWNGRADE</Condition>
|
||||
<Condition Message="!(loc.NoTargetDir)">Installed OR TARGETDIR OR Suppress_TARGETDIR_Check</Condition>
|
||||
|
||||
<InstallExecuteSequence>
|
||||
<RemoveExistingProducts After="InstallInitialize" Overridable="yes">UPGRADE</RemoveExistingProducts>
|
||||
</InstallExecuteSequence>
|
||||
</Fragment>
|
||||
|
||||
<Fragment>
|
||||
<!-- Include an icon for the Programs and Features dialog -->
|
||||
<Icon Id="ARPIcon" SourceFile="!(bindpath.src)PC\icons\python.ico" />
|
||||
<Property Id="ARPPRODUCTICON" Value="ARPIcon" />
|
||||
<Property Id="ARPNOMODIFY" Value="1" />
|
||||
<Property Id="DISABLEADVTSHORTCUTS" Value="1" />
|
||||
</Fragment>
|
||||
|
||||
<Fragment>
|
||||
<?ifdef InstallDirectoryGuidSeed ?>
|
||||
<Directory Id="TARGETDIR" Name="SourceDir">
|
||||
<Directory Id="InstallDirectory" ComponentGuidGenerationSeed="$(var.InstallDirectoryGuidSeed)" />
|
||||
</Directory>
|
||||
<?endif ?>
|
||||
</Fragment>
|
||||
|
||||
<!-- Top-level directories -->
|
||||
<Fragment>
|
||||
<DirectoryRef Id="InstallDirectory">
|
||||
<Directory Id="DLLs" Name="DLLs">
|
||||
<Directory Id="Catalogs" />
|
||||
</Directory>
|
||||
</DirectoryRef>
|
||||
</Fragment>
|
||||
|
||||
<Fragment>
|
||||
<DirectoryRef Id="InstallDirectory">
|
||||
<Directory Id="Doc" Name="Doc" />
|
||||
</DirectoryRef>
|
||||
</Fragment>
|
||||
|
||||
<Fragment>
|
||||
<DirectoryRef Id="InstallDirectory">
|
||||
<Directory Id="include" Name="include" />
|
||||
</DirectoryRef>
|
||||
</Fragment>
|
||||
|
||||
<Fragment>
|
||||
<DirectoryRef Id="InstallDirectory">
|
||||
<Directory Id="Lib" Name="Lib" />
|
||||
</DirectoryRef>
|
||||
</Fragment>
|
||||
|
||||
<Fragment>
|
||||
<DirectoryRef Id="InstallDirectory">
|
||||
<Directory Id="libs" Name="libs" />
|
||||
</DirectoryRef>
|
||||
</Fragment>
|
||||
|
||||
<Fragment>
|
||||
<DirectoryRef Id="InstallDirectory">
|
||||
<Directory Id="Scripts" Name="Scripts" />
|
||||
</DirectoryRef>
|
||||
</Fragment>
|
||||
|
||||
<Fragment>
|
||||
<DirectoryRef Id="InstallDirectory">
|
||||
<Directory Id="tcl" Name="tcl" />
|
||||
</DirectoryRef>
|
||||
</Fragment>
|
||||
|
||||
<Fragment>
|
||||
<DirectoryRef Id="InstallDirectory">
|
||||
<Directory Id="Tools" Name="Tools" />
|
||||
</DirectoryRef>
|
||||
</Fragment>
|
||||
|
||||
<!-- Start Menu folder -->
|
||||
<Fragment>
|
||||
<DirectoryRef Id="TARGETDIR">
|
||||
<Directory Id="ProgramMenuFolder">
|
||||
<Directory Id="MenuDir" Name="!(loc.ProductName)" />
|
||||
</Directory>
|
||||
</DirectoryRef>
|
||||
</Fragment>
|
||||
</Wix>
|
18
third_party/python/Tools/msi/common_en-US.wxl_template
vendored
Normal file
18
third_party/python/Tools/msi/common_en-US.wxl_template
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
|
||||
<String Id="LCID">1033</String>
|
||||
<String Id="Culture">en-us</String>
|
||||
<String Id="ProductName">Python {{ShortVersion}}</String>
|
||||
<String Id="FullProductName">Python {{LongVersion}} ({{Bitness}})</String>
|
||||
<String Id="Title">Python {{LongVersion}} !(loc.Descriptor) ({{Bitness}})</String>
|
||||
<String Id="Description">Python {{LongVersion}} !(loc.Descriptor) ({{Bitness}})</String>
|
||||
<String Id="TitlePdb">Python {{LongVersion}} !(loc.Descriptor) ({{Bitness}} symbols)</String>
|
||||
<String Id="DescriptionPdb">Python {{LongVersion}} !(loc.Descriptor) ({{Bitness}} symbols)</String>
|
||||
<String Id="Title_d">Python {{LongVersion}} !(loc.Descriptor) ({{Bitness}} debug)</String>
|
||||
<String Id="Description_d">Python {{LongVersion}} !(loc.Descriptor) ({{Bitness}} debug)</String>
|
||||
<String Id="Manufacturer">Python Software Foundation</String>
|
||||
<String Id="NoDowngrade">A newer version of !(loc.ProductName) is already installed.</String>
|
||||
<String Id="IncorrectCore">An incorrect version of a prerequisite package is installed. Please uninstall any other versions of !(loc.ProductName) and try installing this again.</String>
|
||||
<String Id="NoTargetDir">The TARGETDIR variable must be provided when invoking this installer.</String>
|
||||
<String Id="ManufacturerSupportUrl">http://www.python.org/</String>
|
||||
</WixLocalization>
|
127
third_party/python/Tools/msi/csv_to_wxs.py
vendored
Normal file
127
third_party/python/Tools/msi/csv_to_wxs.py
vendored
Normal file
|
@ -0,0 +1,127 @@
|
|||
'''
|
||||
Processes a CSV file containing a list of files into a WXS file with
|
||||
components for each listed file.
|
||||
|
||||
The CSV columns are:
|
||||
source of file, target for file, group name
|
||||
|
||||
Usage::
|
||||
py txt_to_wxs.py [path to file list .csv] [path to destination .wxs]
|
||||
|
||||
This is necessary to handle structures where some directories only
|
||||
contain other directories. MSBuild is not able to generate the
|
||||
Directory entries in the WXS file correctly, as it operates on files.
|
||||
Python, however, can easily fill in the gap.
|
||||
'''
|
||||
|
||||
__author__ = "Steve Dower <steve.dower@microsoft.com>"
|
||||
|
||||
import csv
|
||||
import re
|
||||
import sys
|
||||
|
||||
from collections import defaultdict
|
||||
from itertools import chain, zip_longest
|
||||
from pathlib import PureWindowsPath
|
||||
from uuid import uuid1
|
||||
|
||||
ID_CHAR_SUBS = {
|
||||
'-': '_',
|
||||
'+': '_P',
|
||||
}
|
||||
|
||||
def make_id(path):
|
||||
return re.sub(
|
||||
r'[^A-Za-z0-9_.]',
|
||||
lambda m: ID_CHAR_SUBS.get(m.group(0), '_'),
|
||||
str(path).rstrip('/\\'),
|
||||
flags=re.I
|
||||
)
|
||||
|
||||
DIRECTORIES = set()
|
||||
|
||||
def main(file_source, install_target):
|
||||
with open(file_source, 'r', newline='') as f:
|
||||
files = list(csv.reader(f))
|
||||
|
||||
assert len(files) == len(set(make_id(f[1]) for f in files)), "Duplicate file IDs exist"
|
||||
|
||||
directories = defaultdict(set)
|
||||
cache_directories = defaultdict(set)
|
||||
groups = defaultdict(list)
|
||||
for source, target, group, disk_id, condition in files:
|
||||
target = PureWindowsPath(target)
|
||||
groups[group].append((source, target, disk_id, condition))
|
||||
|
||||
if target.suffix.lower() in {".py", ".pyw"}:
|
||||
cache_directories[group].add(target.parent)
|
||||
|
||||
for dirname in target.parents:
|
||||
parent = make_id(dirname.parent)
|
||||
if parent and parent != '.':
|
||||
directories[parent].add(dirname.name)
|
||||
|
||||
lines = [
|
||||
'<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">',
|
||||
' <Fragment>',
|
||||
]
|
||||
for dir_parent in sorted(directories):
|
||||
lines.append(' <DirectoryRef Id="{}">'.format(dir_parent))
|
||||
for dir_name in sorted(directories[dir_parent]):
|
||||
lines.append(' <Directory Id="{}_{}" Name="{}" />'.format(dir_parent, make_id(dir_name), dir_name))
|
||||
lines.append(' </DirectoryRef>')
|
||||
for dir_parent in (make_id(d) for group in cache_directories.values() for d in group):
|
||||
lines.append(' <DirectoryRef Id="{}">'.format(dir_parent))
|
||||
lines.append(' <Directory Id="{}___pycache__" Name="__pycache__" />'.format(dir_parent))
|
||||
lines.append(' </DirectoryRef>')
|
||||
lines.append(' </Fragment>')
|
||||
|
||||
for group in sorted(groups):
|
||||
lines.extend([
|
||||
' <Fragment>',
|
||||
' <ComponentGroup Id="{}">'.format(group),
|
||||
])
|
||||
for source, target, disk_id, condition in groups[group]:
|
||||
lines.append(' <Component Id="{}" Directory="{}" Guid="*">'.format(make_id(target), make_id(target.parent)))
|
||||
if condition:
|
||||
lines.append(' <Condition>{}</Condition>'.format(condition))
|
||||
|
||||
if disk_id:
|
||||
lines.append(' <File Id="{}" Name="{}" Source="{}" DiskId="{}" />'.format(make_id(target), target.name, source, disk_id))
|
||||
else:
|
||||
lines.append(' <File Id="{}" Name="{}" Source="{}" />'.format(make_id(target), target.name, source))
|
||||
lines.append(' </Component>')
|
||||
|
||||
create_folders = {make_id(p) + "___pycache__" for p in cache_directories[group]}
|
||||
remove_folders = {make_id(p2) for p1 in cache_directories[group] for p2 in chain((p1,), p1.parents)}
|
||||
create_folders.discard(".")
|
||||
remove_folders.discard(".")
|
||||
if create_folders or remove_folders:
|
||||
lines.append(' <Component Id="{}__pycache__folders" Directory="TARGETDIR" Guid="{}">'.format(group, uuid1()))
|
||||
lines.extend(' <CreateFolder Directory="{}" />'.format(p) for p in create_folders)
|
||||
lines.extend(' <RemoveFile Id="Remove_{0}_files" Name="*" On="uninstall" Directory="{0}" />'.format(p) for p in create_folders)
|
||||
lines.extend(' <RemoveFolder Id="Remove_{0}_folder" On="uninstall" Directory="{0}" />'.format(p) for p in create_folders | remove_folders)
|
||||
lines.append(' </Component>')
|
||||
|
||||
lines.extend([
|
||||
' </ComponentGroup>',
|
||||
' </Fragment>',
|
||||
])
|
||||
lines.append('</Wix>')
|
||||
|
||||
# Check if the file matches. If so, we don't want to touch it so
|
||||
# that we can skip rebuilding.
|
||||
try:
|
||||
with open(install_target, 'r') as f:
|
||||
if all(x.rstrip('\r\n') == y for x, y in zip_longest(f, lines)):
|
||||
print('File is up to date')
|
||||
return
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
with open(install_target, 'w') as f:
|
||||
f.writelines(line + '\n' for line in lines)
|
||||
print('Wrote {} lines to {}'.format(len(lines), install_target))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1], sys.argv[2])
|
49
third_party/python/Tools/msi/dev/dev.wixproj
vendored
Normal file
49
third_party/python/Tools/msi/dev/dev.wixproj
vendored
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{5F23F608-D74B-4259-A0CE-8DC65CC7FE53}</ProjectGuid>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<OutputName Condition="'$(OutputName)' == ''">dev</OutputName>
|
||||
<OutputType>Package</OutputType>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\msi.props" />
|
||||
<PropertyGroup>
|
||||
<DefineConstants Condition="$(BuildForRelease)">
|
||||
$(DefineConstants);
|
||||
IncludeMinGWLib=1;
|
||||
</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="dev.wxs" />
|
||||
<Compile Include="dev_files.wxs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="*.wxl" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<InstallFiles Include="$(PySourcePath)include\*.h">
|
||||
<SourceBase>$(PySourcePath)</SourceBase>
|
||||
<Source>!(bindpath.src)</Source>
|
||||
<TargetBase>$(PySourcePath)</TargetBase>
|
||||
<Target_></Target_>
|
||||
<Group>dev_include</Group>
|
||||
</InstallFiles>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="BuildMinGWLib"
|
||||
Inputs="$(BuildPath)$(PyDllName).dll"
|
||||
Outputs="$(BuildPath)lib$(PyDllName).a"
|
||||
AfterTargets="PrepareForBuild"
|
||||
Condition="$(BuildForRelease)">
|
||||
<!-- Build libpython##.a as part of this project. This requires gendef and dlltool on the path. -->
|
||||
<PropertyGroup>
|
||||
<_DllToolOpts>-m i386 --as-flags=--32</_DllToolOpts>
|
||||
<_DllToolOpts Condition="$(Platform) == 'x64'">-m i386:x86-64</_DllToolOpts>
|
||||
</PropertyGroup>
|
||||
|
||||
<Exec Command='gendef - "$(BuildPath)$(PyDllName).dll" > "$(IntermediateOutputPath)mingwlib.def"' ContinueOnError="false" />
|
||||
<Exec Command='dlltool --dllname $(PyDllName).dll --def "$(IntermediateOutputPath)mingwlib.def" --output-lib "$(BuildPath)lib$(PyDllName).a" $(_DllToolOpts)' />
|
||||
</Target>
|
||||
|
||||
<Import Project="..\msi.targets" />
|
||||
</Project>
|
19
third_party/python/Tools/msi/dev/dev.wxs
vendored
Normal file
19
third_party/python/Tools/msi/dev/dev.wxs
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Product Id="*" Language="!(loc.LCID)" Name="!(loc.Title)" Version="$(var.Version)" Manufacturer="!(loc.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
|
||||
<Package InstallerVersion="300" Compressed="yes" InstallScope="perUser" Platform="$(var.Platform)" />
|
||||
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
|
||||
|
||||
<PropertyRef Id="UpgradeTable" />
|
||||
|
||||
<Feature Id="DefaultFeature" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
|
||||
<ComponentGroupRef Id="dev_include" />
|
||||
<ComponentGroupRef Id="dev_pyconfig" />
|
||||
<ComponentGroupRef Id="dev_libs" />
|
||||
<?ifdef IncludeMinGWLib ?>
|
||||
<ComponentGroupRef Id="dev_mingw" />
|
||||
<?endif ?>
|
||||
<ComponentRef Id="OptionalFeature" />
|
||||
</Feature>
|
||||
</Product>
|
||||
</Wix>
|
19
third_party/python/Tools/msi/dev/dev_d.wixproj
vendored
Normal file
19
third_party/python/Tools/msi/dev/dev_d.wixproj
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{C11B4945-76BD-4137-B2E3-649460117A77}</ProjectGuid>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<OutputName>dev_d</OutputName>
|
||||
<OutputType>Package</OutputType>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\msi.props" />
|
||||
<ItemGroup>
|
||||
<Compile Include="dev_d.wxs" />
|
||||
<Compile Include="dev_files.wxs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="*.wxl" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="..\msi.targets" />
|
||||
</Project>
|
13
third_party/python/Tools/msi/dev/dev_d.wxs
vendored
Normal file
13
third_party/python/Tools/msi/dev/dev_d.wxs
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Product Id="*" Language="!(loc.LCID)" Name="!(loc.Title_d)" Version="$(var.Version)" Manufacturer="!(loc.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
|
||||
<Package InstallerVersion="300" Compressed="yes" InstallScope="perUser" Platform="$(var.Platform)" />
|
||||
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
|
||||
|
||||
<PropertyRef Id="UpgradeTable" />
|
||||
|
||||
<Feature Id="DebugBinaries" AllowAdvertise="no" Title="!(loc.Title_d)" Description="!(loc.Description_d)">
|
||||
<ComponentGroupRef Id="dev_libs_d" />
|
||||
</Feature>
|
||||
</Product>
|
||||
</Wix>
|
5
third_party/python/Tools/msi/dev/dev_en-US.wxl
vendored
Normal file
5
third_party/python/Tools/msi/dev/dev_en-US.wxl
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
|
||||
<String Id="Descriptor">Development Libraries</String>
|
||||
<String Id="ShortDescriptor">dev</String>
|
||||
</WixLocalization>
|
42
third_party/python/Tools/msi/dev/dev_files.wxs
vendored
Normal file
42
third_party/python/Tools/msi/dev/dev_files.wxs
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Fragment>
|
||||
<ComponentGroup Id="dev_pyconfig">
|
||||
<Component Id="include_pyconfig.h" Directory="include" Guid="*">
|
||||
<File Id="include_pyconfig.h" Name="pyconfig.h" Source="!(bindpath.src)PC\pyconfig.h" KeyPath="yes" />
|
||||
</Component>
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
|
||||
<Fragment>
|
||||
<ComponentGroup Id="dev_libs">
|
||||
<Component Id="libs_python3.lib" Directory="libs" Guid="*">
|
||||
<File Id="libs_python_stable.lib" Name="python$(var.MajorVersionNumber).lib" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="libs_python.lib" Directory="libs" Guid="*">
|
||||
<File Id="libs_python.lib" Name="python$(var.MajorVersionNumber)$(var.MinorVersionNumber).lib" KeyPath="yes" />
|
||||
</Component>
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
|
||||
<Fragment>
|
||||
<ComponentGroup Id="dev_libs_d">
|
||||
<Component Id="libs_python3_d.lib" Directory="libs" Guid="*">
|
||||
<File Id="libs_python_stable_d.lib" Name="python$(var.MajorVersionNumber)_d.lib" />
|
||||
</Component>
|
||||
<Component Id="libs_python_d.lib" Directory="libs" Guid="*">
|
||||
<File Id="libs_python_d.lib" Name="python$(var.MajorVersionNumber)$(var.MinorVersionNumber)_d.lib" />
|
||||
</Component>
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
|
||||
<?ifdef IncludeMinGWLib ?>
|
||||
<Fragment>
|
||||
<ComponentGroup Id="dev_mingw">
|
||||
<Component Id="libs_libpython.a" Directory="libs" Guid="*">
|
||||
<File Id="libs_libpython.a" Name="libpython$(var.MajorVersionNumber)$(var.MinorVersionNumber).a" KeyPath="yes" />
|
||||
</Component>
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
<?endif ?>
|
||||
</Wix>
|
23
third_party/python/Tools/msi/distutils.command.bdist_wininst.py
vendored
Normal file
23
third_party/python/Tools/msi/distutils.command.bdist_wininst.py
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
"""distutils.command.bdist_wininst
|
||||
|
||||
Suppresses the 'bdist_wininst' command, while still allowing
|
||||
setuptools to import it without breaking."""
|
||||
|
||||
from distutils.core import Command
|
||||
from distutils.errors import DistutilsPlatformError
|
||||
|
||||
class bdist_wininst(Command):
|
||||
description = "create an executable installer for MS Windows"
|
||||
|
||||
# Marker for tests that we have the unsupported bdist_wininst
|
||||
_unsupported = True
|
||||
|
||||
def initialize_options(self):
|
||||
pass
|
||||
|
||||
def finalize_options(self):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
raise DistutilsPlatformError("bdist_wininst is not supported "
|
||||
"in this Python distribution")
|
30
third_party/python/Tools/msi/doc/doc.wixproj
vendored
Normal file
30
third_party/python/Tools/msi/doc/doc.wixproj
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{0D62A2BB-5F71-4447-8C8C-9708407B3674}</ProjectGuid>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<OutputName>doc</OutputName>
|
||||
<OutputType>Package</OutputType>
|
||||
<!-- Shortcut validation is not necessary -->
|
||||
<SuppressICEs>ICE43</SuppressICEs>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\msi.props" />
|
||||
<PropertyGroup>
|
||||
<DocFilename>python$(MajorVersionNumber)$(MinorVersionNumber)$(MicroVersionNumber)$(ReleaseLevelName).chm</DocFilename>
|
||||
<IncludeDocFile>false</IncludeDocFile>
|
||||
<IncludeDocFile Condition="$(BuildForRelease) or Exists('$(PySourcePath)Doc\build\htmlhelp\$(DocFilename)')">true</IncludeDocFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$(IncludeDocFile)">
|
||||
<DefineConstants>$(DefineConstants);DocFilename=$(DocFilename);</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="doc.wxs" />
|
||||
<Compile Include="doc_files.wxs" Condition="$(IncludeDocFile)" />
|
||||
<Compile Include="doc_no_files.wxs" Condition="!$(IncludeDocFile)" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<WxlTemplate Include="*.wxl_template" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="..\msi.targets" />
|
||||
</Project>
|
41
third_party/python/Tools/msi/doc/doc.wxs
vendored
Normal file
41
third_party/python/Tools/msi/doc/doc.wxs
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Product Id="*" Language="!(loc.LCID)" Name="!(loc.Title)" Version="$(var.Version)" Manufacturer="!(loc.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
|
||||
<Package InstallerVersion="300" Compressed="yes" InstallScope="perUser" Platform="$(var.Platform)" />
|
||||
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
|
||||
|
||||
<PropertyRef Id="UpgradeTable" />
|
||||
<PropertyRef Id="REGISTRYKEY" />
|
||||
|
||||
<Property Id="HHExe" Value="C:\Windows\hh.exe" />
|
||||
<CustomAction Id="SetHHExe" Property="HHCExe" Value='[WindowsFolder]\hh.exe' Execute="immediate" />
|
||||
<InstallExecuteSequence>
|
||||
<Custom Action="SetHHExe" Before="CostFinalize">1</Custom>
|
||||
</InstallExecuteSequence>
|
||||
|
||||
<Feature Id="DefaultFeature" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
|
||||
<ComponentGroupRef Id="doc" Primary="yes" />
|
||||
<ComponentRef Id="OptionalFeature" />
|
||||
</Feature>
|
||||
<Feature Id="Shortcuts" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
|
||||
<ComponentGroupRef Id="doc" />
|
||||
|
||||
<?ifdef DocFilename ?>
|
||||
<Component Id="doc_shortcut" Directory="MenuDir" Guid="*">
|
||||
<RegistryKey Root="HKMU" Key="[OPTIONALFEATURESREGISTRYKEY]">
|
||||
<RegistryValue Name="$(var.OptionalFeatureName)_shortcut" Type="string" Value="$(var.Version)" KeyPath="yes" />
|
||||
</RegistryKey>
|
||||
<Shortcut Id="python.chm"
|
||||
Target="[HHExe]"
|
||||
Arguments="[#python.chm]"
|
||||
Name="!(loc.ShortcutName)"
|
||||
Description="!(loc.ShortcutDescription)"
|
||||
WorkingDirectory="InstallDirectory"
|
||||
Show="maximized" />
|
||||
<RemoveFolder Id="Remove_MenuDir" On="uninstall" />
|
||||
</Component>
|
||||
<?endif ?>
|
||||
|
||||
</Feature>
|
||||
</Product>
|
||||
</Wix>
|
7
third_party/python/Tools/msi/doc/doc_en-US.wxl_template
vendored
Normal file
7
third_party/python/Tools/msi/doc/doc_en-US.wxl_template
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
|
||||
<String Id="ShortDescriptor">doc</String>
|
||||
<String Id="Descriptor">Documentation</String>
|
||||
<String Id="ShortcutName">Python {{ShortVersion}} Manuals ({{Bitness}})</String>
|
||||
<String Id="ShortcutDescription">View the !(loc.ProductName) documentation.</String>
|
||||
</WixLocalization>
|
15
third_party/python/Tools/msi/doc/doc_files.wxs
vendored
Normal file
15
third_party/python/Tools/msi/doc/doc_files.wxs
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Fragment>
|
||||
<PropertyRef Id="REGISTRYKEY" />
|
||||
|
||||
<ComponentGroup Id="doc">
|
||||
<Component Id="python.chm" Directory="Doc" Guid="*">
|
||||
<File Id="python.chm" Name="$(var.DocFilename)" KeyPath="yes" />
|
||||
<RegistryKey Root="HKMU" Key="[REGISTRYKEY]">
|
||||
<RegistryValue Key="Help\Main Python Documentation" Type="string" Value="[#python.chm]" />
|
||||
</RegistryKey>
|
||||
</Component>
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
17
third_party/python/Tools/msi/doc/doc_no_files.wxs
vendored
Normal file
17
third_party/python/Tools/msi/doc/doc_no_files.wxs
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Fragment>
|
||||
<ComponentGroup Id="doc">
|
||||
<!--
|
||||
This file is included when the CHM is not available.
|
||||
|
||||
This way, snapshot builds can succeed without having to
|
||||
build the docs.
|
||||
-->
|
||||
<Component Id="EmptyDocFolder" Directory="Doc" Guid="{22FD42DB-EC66-4B1C-B1FC-44E0CF7B2462}">
|
||||
<CreateFolder />
|
||||
<RemoveFolder Id="Remove_EmptyDocFolder" On="uninstall" />
|
||||
</Component>
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
41
third_party/python/Tools/msi/exe/crtlicense.txt
vendored
Normal file
41
third_party/python/Tools/msi/exe/crtlicense.txt
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
|
||||
|
||||
Additional Conditions for this Windows binary build
|
||||
---------------------------------------------------
|
||||
|
||||
This program is linked with and uses Microsoft Distributable Code,
|
||||
copyrighted by Microsoft Corporation. The Microsoft Distributable Code
|
||||
is embedded in each .exe, .dll and .pyd file as a result of running
|
||||
the code through a linker.
|
||||
|
||||
If you further distribute programs that include the Microsoft
|
||||
Distributable Code, you must comply with the restrictions on
|
||||
distribution specified by Microsoft. In particular, you must require
|
||||
distributors and external end users to agree to terms that protect the
|
||||
Microsoft Distributable Code at least as much as Microsoft's own
|
||||
requirements for the Distributable Code. See Microsoft's documentation
|
||||
(included in its developer tools and on its website at microsoft.com)
|
||||
for specific details.
|
||||
|
||||
Redistribution of the Windows binary build of the Python interpreter
|
||||
complies with this agreement, provided that you do not:
|
||||
|
||||
- alter any copyright, trademark or patent notice in Microsoft's
|
||||
Distributable Code;
|
||||
|
||||
- use Microsoft's trademarks in your programs' names or in a way that
|
||||
suggests your programs come from or are endorsed by Microsoft;
|
||||
|
||||
- distribute Microsoft's Distributable Code to run on a platform other
|
||||
than Microsoft operating systems, run-time technologies or application
|
||||
platforms; or
|
||||
|
||||
- include Microsoft Distributable Code in malicious, deceptive or
|
||||
unlawful programs.
|
||||
|
||||
These restrictions apply only to the Microsoft Distributable Code as
|
||||
defined above, not to Python itself or any programs running on the
|
||||
Python interpreter. The redistribution of the Python interpreter and
|
||||
libraries is governed by the Python Software License included with this
|
||||
file, or by other licenses as marked.
|
||||
|
66
third_party/python/Tools/msi/exe/exe.wixproj
vendored
Normal file
66
third_party/python/Tools/msi/exe/exe.wixproj
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{6BD53305-B03E-49DC-85FB-5551B8CCC843}</ProjectGuid>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<OutputName>exe</OutputName>
|
||||
<OutputType>Package</OutputType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<!-- Shortcut validation is not necessary -->
|
||||
<SuppressICEs>ICE43</SuppressICEs>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\msi.props" />
|
||||
<ItemGroup>
|
||||
<Compile Include="exe.wxs" />
|
||||
<Compile Include="exe_files.wxs" />
|
||||
<Compile Include="exe_reg.wxs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="*.wxl" />
|
||||
<WxlTemplate Include="*.wxl_template" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="_GenerateLicense" AfterTargets="PrepareForBuild">
|
||||
<ItemGroup>
|
||||
<LicenseFiles Include="$(PySourcePath)LICENSE;
|
||||
crtlicense.txt;
|
||||
$(bz2Dir)LICENSE;
|
||||
$(opensslDir)LICENSE;
|
||||
$(tclDir)license.terms;
|
||||
$(tkDir)license.terms;
|
||||
$(tixDir)license.terms" />
|
||||
<_LicenseFiles Include="@(LicenseFiles)">
|
||||
<Content>$([System.IO.File]::ReadAllText(%(FullPath)))</Content>
|
||||
</_LicenseFiles>
|
||||
</ItemGroup>
|
||||
|
||||
<WriteLinesToFile File="$(BuildPath)LICENSE"
|
||||
Overwrite="true"
|
||||
Lines="@(_LicenseFiles->'%(Content)')" />
|
||||
</Target>
|
||||
|
||||
<Target Name="_CopyMiscNews" AfterTargets="PrepareForBuild" Condition="Exists('$(PySourcePath)Misc\NEWS')">
|
||||
<Copy SourceFiles="$(PySourcePath)Misc\NEWS" DestinationFiles="$(BuildPath)NEWS.txt" />
|
||||
</Target>
|
||||
|
||||
<Target Name="_MergeMiscNewsWithBlurb" AfterTargets="PrepareForBuild" Condition="$(Blurb) != '' and !Exists('$(PySourcePath)Misc\NEWS')">
|
||||
<Exec Command="$(Blurb) merge -f "$(BuildPath)NEWS.txt"" WorkingDirectory="$(PCBuild)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="_MergeMiscNewsWithPython" AfterTargets="PrepareForBuild" Condition="$(Blurb) == '' and !Exists('$(PySourcePath)Misc\NEWS')">
|
||||
<ItemGroup>
|
||||
<HostPython Include="$(ExternalsDir)python*\tools\python.exe" />
|
||||
<HostPython Include="@(HostPython)" Condition="Exists(%(FullPath))" />
|
||||
<HostPython Include="py" Condition="@(HostPython) == ''" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<HostPython>@(HostPython)</HostPython>
|
||||
<HostPython Condition="$(HostPython.Contains(';'))">$(HostPython.Remove($(HostPython.IndexOf(';'))))</HostPython>
|
||||
</PropertyGroup>
|
||||
<Exec Command=""$(HostPython)" -m pip install -U blurb" WorkingDirectory="$(PCBuild)" />
|
||||
<Exec Command=""$(HostPython)" -m blurb merge -f "$(BuildPath)NEWS.txt"" WorkingDirectory="$(PCBuild)" />
|
||||
</Target>
|
||||
|
||||
<Import Project="..\msi.targets" />
|
||||
</Project>
|
33
third_party/python/Tools/msi/exe/exe.wxs
vendored
Normal file
33
third_party/python/Tools/msi/exe/exe.wxs
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Product Id="*" Language="!(loc.LCID)" Name="!(loc.Title)" Version="$(var.Version)" Manufacturer="!(loc.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
|
||||
<Package InstallerVersion="300" Compressed="yes" InstallScope="perUser" Platform="$(var.Platform)" />
|
||||
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
|
||||
|
||||
<PropertyRef Id="UpgradeTable" />
|
||||
<PropertyRef Id="REGISTRYKEY" />
|
||||
|
||||
<Feature Id="DefaultFeature" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
|
||||
<ComponentGroupRef Id="exe_python" Primary="yes" />
|
||||
<ComponentGroupRef Id="exe_reg" Primary="yes" />
|
||||
<ComponentGroupRef Id="exe_txt" />
|
||||
<ComponentGroupRef Id="exe_icons" />
|
||||
<ComponentRef Id="OptionalFeature" />
|
||||
</Feature>
|
||||
|
||||
<Feature Id="Shortcuts" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
|
||||
<ComponentGroupRef Id="exe_python" />
|
||||
<Component Id="exe_shortcut" Directory="MenuDir" Guid="*">
|
||||
<Shortcut Id="python.exe"
|
||||
Target="[#python.exe]"
|
||||
Name="!(loc.ShortcutName)"
|
||||
Description="!(loc.ShortcutDescription)"
|
||||
WorkingDirectory="InstallDirectory" />
|
||||
<RemoveFolder Id="Remove_MenuDir" Directory="MenuDir" On="uninstall" />
|
||||
<RegistryKey Root="HKMU" Key="[REGISTRYKEY]">
|
||||
<RegistryValue Key="InstalledFeatures" Name="Shortcuts" Type="string" Value="$(var.Version)" />
|
||||
</RegistryKey>
|
||||
</Component>
|
||||
</Feature>
|
||||
</Product>
|
||||
</Wix>
|
21
third_party/python/Tools/msi/exe/exe_d.wixproj
vendored
Normal file
21
third_party/python/Tools/msi/exe/exe_d.wixproj
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{B1CA739C-8DB0-403B-9010-D79507507CE9}</ProjectGuid>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<OutputName>exe_d</OutputName>
|
||||
<OutputType>Package</OutputType>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\msi.props" />
|
||||
<ItemGroup>
|
||||
<Compile Include="exe_d.wxs" />
|
||||
<Compile Include="exe_files.wxs" />
|
||||
<Compile Include="exe_reg.wxs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="*.wxl" />
|
||||
<WxlTemplate Include="*.wxl_template" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="..\msi.targets" />
|
||||
</Project>
|
13
third_party/python/Tools/msi/exe/exe_d.wxs
vendored
Normal file
13
third_party/python/Tools/msi/exe/exe_d.wxs
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Product Id="*" Language="!(loc.LCID)" Name="!(loc.Title_d)" Version="$(var.Version)" Manufacturer="!(loc.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
|
||||
<Package InstallerVersion="300" Compressed="yes" InstallScope="perUser" Platform="$(var.Platform)" />
|
||||
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
|
||||
|
||||
<PropertyRef Id="UpgradeTable" />
|
||||
|
||||
<Feature Id="DebugBinaries" AllowAdvertise="no" Title="!(loc.Title_d)" Description="!(loc.Description_d)">
|
||||
<ComponentGroupRef Id="exe_python_d" />
|
||||
</Feature>
|
||||
</Product>
|
||||
</Wix>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue