##// END OF EJS Templates
automation: install Python 3.8.0...
Gregory Szorc -
r43529:252ec4db default
parent child Browse files
Show More
@@ -1,594 +1,594 b''
1 1 # linux.py - Linux specific automation functionality
2 2 #
3 3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 # no-check-code because Python 3 native.
9 9
10 10 import os
11 11 import pathlib
12 12 import shlex
13 13 import subprocess
14 14 import tempfile
15 15
16 16 from .ssh import exec_command
17 17
18 18
19 19 # Linux distributions that are supported.
20 20 DISTROS = {
21 21 'debian9',
22 22 'debian10',
23 23 'ubuntu18.04',
24 24 'ubuntu19.04',
25 25 }
26 26
27 27 INSTALL_PYTHONS = r'''
28 28 PYENV2_VERSIONS="2.7.16 pypy2.7-7.1.1"
29 PYENV3_VERSIONS="3.5.7 3.6.9 3.7.4 3.8-dev pypy3.5-7.0.0 pypy3.6-7.1.1"
29 PYENV3_VERSIONS="3.5.7 3.6.9 3.7.4 3.8.0 pypy3.5-7.0.0 pypy3.6-7.1.1"
30 30
31 31 git clone https://github.com/pyenv/pyenv.git /hgdev/pyenv
32 32 pushd /hgdev/pyenv
33 git checkout 17f44b7cd6f58ea2fa68ec0371fb9e7a826b8be2
33 git checkout d6d6bc8bb08bcdcbf4eb79509aa7061011ade1c4
34 34 popd
35 35
36 36 export PYENV_ROOT="/hgdev/pyenv"
37 37 export PATH="$PYENV_ROOT/bin:$PATH"
38 38
39 39 # pip 19.2.3.
40 40 PIP_SHA256=57e3643ff19f018f8a00dfaa6b7e4620e3c1a7a2171fd218425366ec006b3bfe
41 41 wget -O get-pip.py --progress dot:mega https://github.com/pypa/get-pip/raw/309a56c5fd94bd1134053a541cb4657a4e47e09d/get-pip.py
42 42 echo "${PIP_SHA256} get-pip.py" | sha256sum --check -
43 43
44 44 VIRTUALENV_SHA256=f78d81b62d3147396ac33fc9d77579ddc42cc2a98dd9ea38886f616b33bc7fb2
45 45 VIRTUALENV_TARBALL=virtualenv-16.7.5.tar.gz
46 46 wget -O ${VIRTUALENV_TARBALL} --progress dot:mega https://files.pythonhosted.org/packages/66/f0/6867af06d2e2f511e4e1d7094ff663acdebc4f15d4a0cb0fed1007395124/${VIRTUALENV_TARBALL}
47 47 echo "${VIRTUALENV_SHA256} ${VIRTUALENV_TARBALL}" | sha256sum --check -
48 48
49 49 for v in ${PYENV2_VERSIONS}; do
50 50 pyenv install -v ${v}
51 51 ${PYENV_ROOT}/versions/${v}/bin/python get-pip.py
52 52 ${PYENV_ROOT}/versions/${v}/bin/pip install ${VIRTUALENV_TARBALL}
53 53 ${PYENV_ROOT}/versions/${v}/bin/pip install -r /hgdev/requirements-py2.txt
54 54 done
55 55
56 56 for v in ${PYENV3_VERSIONS}; do
57 57 pyenv install -v ${v}
58 58 ${PYENV_ROOT}/versions/${v}/bin/python get-pip.py
59 59 ${PYENV_ROOT}/versions/${v}/bin/pip install -r /hgdev/requirements-py3.txt
60 60 done
61 61
62 62 pyenv global ${PYENV2_VERSIONS} ${PYENV3_VERSIONS} system
63 63 '''.lstrip().replace(
64 64 '\r\n', '\n'
65 65 )
66 66
67 67
68 68 INSTALL_RUST = r'''
69 69 RUSTUP_INIT_SHA256=a46fe67199b7bcbbde2dcbc23ae08db6f29883e260e23899a88b9073effc9076
70 70 wget -O rustup-init --progress dot:mega https://static.rust-lang.org/rustup/archive/1.18.3/x86_64-unknown-linux-gnu/rustup-init
71 71 echo "${RUSTUP_INIT_SHA256} rustup-init" | sha256sum --check -
72 72
73 73 chmod +x rustup-init
74 74 sudo -H -u hg -g hg ./rustup-init -y
75 75 sudo -H -u hg -g hg /home/hg/.cargo/bin/rustup install 1.31.1 1.34.2
76 76 sudo -H -u hg -g hg /home/hg/.cargo/bin/rustup component add clippy
77 77 '''
78 78
79 79
80 80 BOOTSTRAP_VIRTUALENV = r'''
81 81 /usr/bin/virtualenv /hgdev/venv-bootstrap
82 82
83 83 HG_SHA256=35fc8ba5e0379c1b3affa2757e83fb0509e8ac314cbd9f1fd133cf265d16e49f
84 84 HG_TARBALL=mercurial-5.1.1.tar.gz
85 85
86 86 wget -O ${HG_TARBALL} --progress dot:mega https://www.mercurial-scm.org/release/${HG_TARBALL}
87 87 echo "${HG_SHA256} ${HG_TARBALL}" | sha256sum --check -
88 88
89 89 /hgdev/venv-bootstrap/bin/pip install ${HG_TARBALL}
90 90 '''.lstrip().replace(
91 91 '\r\n', '\n'
92 92 )
93 93
94 94
95 95 BOOTSTRAP_DEBIAN = (
96 96 r'''
97 97 #!/bin/bash
98 98
99 99 set -ex
100 100
101 101 DISTRO=`grep DISTRIB_ID /etc/lsb-release | awk -F= '{{print $2}}'`
102 102 DEBIAN_VERSION=`cat /etc/debian_version`
103 103 LSB_RELEASE=`lsb_release -cs`
104 104
105 105 sudo /usr/sbin/groupadd hg
106 106 sudo /usr/sbin/groupadd docker
107 107 sudo /usr/sbin/useradd -g hg -G sudo,docker -d /home/hg -m -s /bin/bash hg
108 108 sudo mkdir /home/hg/.ssh
109 109 sudo cp ~/.ssh/authorized_keys /home/hg/.ssh/authorized_keys
110 110 sudo chown -R hg:hg /home/hg/.ssh
111 111 sudo chmod 700 /home/hg/.ssh
112 112 sudo chmod 600 /home/hg/.ssh/authorized_keys
113 113
114 114 cat << EOF | sudo tee /etc/sudoers.d/90-hg
115 115 hg ALL=(ALL) NOPASSWD:ALL
116 116 EOF
117 117
118 118 sudo apt-get update
119 119 sudo DEBIAN_FRONTEND=noninteractive apt-get -yq dist-upgrade
120 120
121 121 # Install packages necessary to set up Docker Apt repo.
122 122 sudo DEBIAN_FRONTEND=noninteractive apt-get -yq install --no-install-recommends \
123 123 apt-transport-https \
124 124 gnupg
125 125
126 126 cat > docker-apt-key << EOF
127 127 -----BEGIN PGP PUBLIC KEY BLOCK-----
128 128
129 129 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
186 186 YT90qFF93M3v01BbxP+EIY2/9tiIPbrd
187 187 =0YYh
188 188 -----END PGP PUBLIC KEY BLOCK-----
189 189 EOF
190 190
191 191 sudo apt-key add docker-apt-key
192 192
193 193 if [ "$LSB_RELEASE" = "stretch" ]; then
194 194 cat << EOF | sudo tee -a /etc/apt/sources.list
195 195 # Need backports for clang-format-6.0
196 196 deb http://deb.debian.org/debian stretch-backports main
197 197 EOF
198 198 fi
199 199
200 200 if [ "$LSB_RELEASE" = "stretch" -o "$LSB_RELEASE" = "buster" ]; then
201 201 cat << EOF | sudo tee -a /etc/apt/sources.list
202 202 # Sources are useful if we want to compile things locally.
203 203 deb-src http://deb.debian.org/debian $LSB_RELEASE main
204 204 deb-src http://security.debian.org/debian-security $LSB_RELEASE/updates main
205 205 deb-src http://deb.debian.org/debian $LSB_RELEASE-updates main
206 206 deb-src http://deb.debian.org/debian $LSB_RELEASE-backports main
207 207
208 208 deb [arch=amd64] https://download.docker.com/linux/debian $LSB_RELEASE stable
209 209 EOF
210 210
211 211 elif [ "$DISTRO" = "Ubuntu" ]; then
212 212 cat << EOF | sudo tee -a /etc/apt/sources.list
213 213 deb [arch=amd64] https://download.docker.com/linux/ubuntu $LSB_RELEASE stable
214 214 EOF
215 215
216 216 fi
217 217
218 218 sudo apt-get update
219 219
220 220 PACKAGES="\
221 221 awscli \
222 222 btrfs-progs \
223 223 build-essential \
224 224 bzr \
225 225 clang-format-6.0 \
226 226 cvs \
227 227 darcs \
228 228 debhelper \
229 229 devscripts \
230 230 docker-ce \
231 231 dpkg-dev \
232 232 dstat \
233 233 emacs \
234 234 gettext \
235 235 git \
236 236 htop \
237 237 iotop \
238 238 jfsutils \
239 239 libbz2-dev \
240 240 libexpat1-dev \
241 241 libffi-dev \
242 242 libgdbm-dev \
243 243 liblzma-dev \
244 244 libncurses5-dev \
245 245 libnss3-dev \
246 246 libreadline-dev \
247 247 libsqlite3-dev \
248 248 libssl-dev \
249 249 netbase \
250 250 ntfs-3g \
251 251 nvme-cli \
252 252 pyflakes \
253 253 pyflakes3 \
254 254 pylint \
255 255 pylint3 \
256 256 python-all-dev \
257 257 python-dev \
258 258 python-docutils \
259 259 python-fuzzywuzzy \
260 260 python-pygments \
261 261 python-subversion \
262 262 python-vcr \
263 263 python3-boto3 \
264 264 python3-dev \
265 265 python3-docutils \
266 266 python3-fuzzywuzzy \
267 267 python3-pygments \
268 268 python3-vcr \
269 269 rsync \
270 270 sqlite3 \
271 271 subversion \
272 272 tcl-dev \
273 273 tk-dev \
274 274 tla \
275 275 unzip \
276 276 uuid-dev \
277 277 vim \
278 278 virtualenv \
279 279 wget \
280 280 xfsprogs \
281 281 zip \
282 282 zlib1g-dev"
283 283
284 284 if [ "LSB_RELEASE" = "stretch" ]; then
285 285 PACKAGES="$PACKAGES linux-perf"
286 286 elif [ "$DISTRO" = "Ubuntu" ]; then
287 287 PACKAGES="$PACKAGES linux-tools-common"
288 288 fi
289 289
290 290 # Monotone only available in older releases.
291 291 if [ "$LSB_RELEASE" = "stretch" -o "$LSB_RELEASE" = "xenial" ]; then
292 292 PACKAGES="$PACKAGES monotone"
293 293 fi
294 294
295 295 sudo DEBIAN_FRONTEND=noninteractive apt-get -yq install --no-install-recommends $PACKAGES
296 296
297 297 # Create clang-format symlink so test harness finds it.
298 298 sudo update-alternatives --install /usr/bin/clang-format clang-format \
299 299 /usr/bin/clang-format-6.0 1000
300 300
301 301 sudo mkdir /hgdev
302 302 # Will be normalized to hg:hg later.
303 303 sudo chown `whoami` /hgdev
304 304
305 305 {install_rust}
306 306
307 307 cp requirements-py2.txt /hgdev/requirements-py2.txt
308 308 cp requirements-py3.txt /hgdev/requirements-py3.txt
309 309
310 310 # Disable the pip version check because it uses the network and can
311 311 # be annoying.
312 312 cat << EOF | sudo tee -a /etc/pip.conf
313 313 [global]
314 314 disable-pip-version-check = True
315 315 EOF
316 316
317 317 {install_pythons}
318 318 {bootstrap_virtualenv}
319 319
320 320 /hgdev/venv-bootstrap/bin/hg clone https://www.mercurial-scm.org/repo/hg /hgdev/src
321 321
322 322 # Mark the repo as non-publishing.
323 323 cat >> /hgdev/src/.hg/hgrc << EOF
324 324 [phases]
325 325 publish = false
326 326 EOF
327 327
328 328 sudo chown -R hg:hg /hgdev
329 329 '''.lstrip()
330 330 .format(
331 331 install_rust=INSTALL_RUST,
332 332 install_pythons=INSTALL_PYTHONS,
333 333 bootstrap_virtualenv=BOOTSTRAP_VIRTUALENV,
334 334 )
335 335 .replace('\r\n', '\n')
336 336 )
337 337
338 338
339 339 # Prepares /hgdev for operations.
340 340 PREPARE_HGDEV = '''
341 341 #!/bin/bash
342 342
343 343 set -e
344 344
345 345 FS=$1
346 346
347 347 ensure_device() {
348 348 if [ -z "${DEVICE}" ]; then
349 349 echo "could not find block device to format"
350 350 exit 1
351 351 fi
352 352 }
353 353
354 354 # Determine device to partition for extra filesystem.
355 355 # If only 1 volume is present, it will be the root volume and
356 356 # should be /dev/nvme0. If multiple volumes are present, the
357 357 # root volume could be nvme0 or nvme1. Use whichever one doesn't have
358 358 # a partition.
359 359 if [ -e /dev/nvme1n1 ]; then
360 360 if [ -e /dev/nvme0n1p1 ]; then
361 361 DEVICE=/dev/nvme1n1
362 362 else
363 363 DEVICE=/dev/nvme0n1
364 364 fi
365 365 else
366 366 DEVICE=
367 367 fi
368 368
369 369 sudo mkdir /hgwork
370 370
371 371 if [ "${FS}" != "default" -a "${FS}" != "tmpfs" ]; then
372 372 ensure_device
373 373 echo "creating ${FS} filesystem on ${DEVICE}"
374 374 fi
375 375
376 376 if [ "${FS}" = "default" ]; then
377 377 :
378 378
379 379 elif [ "${FS}" = "btrfs" ]; then
380 380 sudo mkfs.btrfs ${DEVICE}
381 381 sudo mount ${DEVICE} /hgwork
382 382
383 383 elif [ "${FS}" = "ext3" ]; then
384 384 # lazy_journal_init speeds up filesystem creation at the expense of
385 385 # integrity if things crash. We are an ephemeral instance, so we don't
386 386 # care about integrity.
387 387 sudo mkfs.ext3 -E lazy_journal_init=1 ${DEVICE}
388 388 sudo mount ${DEVICE} /hgwork
389 389
390 390 elif [ "${FS}" = "ext4" ]; then
391 391 sudo mkfs.ext4 -E lazy_journal_init=1 ${DEVICE}
392 392 sudo mount ${DEVICE} /hgwork
393 393
394 394 elif [ "${FS}" = "jfs" ]; then
395 395 sudo mkfs.jfs ${DEVICE}
396 396 sudo mount ${DEVICE} /hgwork
397 397
398 398 elif [ "${FS}" = "tmpfs" ]; then
399 399 echo "creating tmpfs volume in /hgwork"
400 400 sudo mount -t tmpfs -o size=1024M tmpfs /hgwork
401 401
402 402 elif [ "${FS}" = "xfs" ]; then
403 403 sudo mkfs.xfs ${DEVICE}
404 404 sudo mount ${DEVICE} /hgwork
405 405
406 406 else
407 407 echo "unsupported filesystem: ${FS}"
408 408 exit 1
409 409 fi
410 410
411 411 echo "/hgwork ready"
412 412
413 413 sudo chown hg:hg /hgwork
414 414 mkdir /hgwork/tmp
415 415 chown hg:hg /hgwork/tmp
416 416
417 417 rsync -a /hgdev/src /hgwork/
418 418 '''.lstrip().replace(
419 419 '\r\n', '\n'
420 420 )
421 421
422 422
423 423 HG_UPDATE_CLEAN = '''
424 424 set -ex
425 425
426 426 HG=/hgdev/venv-bootstrap/bin/hg
427 427
428 428 cd /hgwork/src
429 429 ${HG} --config extensions.purge= purge --all
430 430 ${HG} update -C $1
431 431 ${HG} log -r .
432 432 '''.lstrip().replace(
433 433 '\r\n', '\n'
434 434 )
435 435
436 436
437 437 def prepare_exec_environment(ssh_client, filesystem='default'):
438 438 """Prepare an EC2 instance to execute things.
439 439
440 440 The AMI has an ``/hgdev`` bootstrapped with various Python installs
441 441 and a clone of the Mercurial repo.
442 442
443 443 In EC2, EBS volumes launched from snapshots have wonky performance behavior.
444 444 Notably, blocks have to be copied on first access, which makes volume
445 445 I/O extremely slow on fresh volumes.
446 446
447 447 Furthermore, we may want to run operations, tests, etc on alternative
448 448 filesystems so we examine behavior on different filesystems.
449 449
450 450 This function is used to facilitate executing operations on alternate
451 451 volumes.
452 452 """
453 453 sftp = ssh_client.open_sftp()
454 454
455 455 with sftp.open('/hgdev/prepare-hgdev', 'wb') as fh:
456 456 fh.write(PREPARE_HGDEV)
457 457 fh.chmod(0o0777)
458 458
459 459 command = 'sudo /hgdev/prepare-hgdev %s' % filesystem
460 460 chan, stdin, stdout = exec_command(ssh_client, command)
461 461 stdin.close()
462 462
463 463 for line in stdout:
464 464 print(line, end='')
465 465
466 466 res = chan.recv_exit_status()
467 467
468 468 if res:
469 469 raise Exception('non-0 exit code updating working directory; %d' % res)
470 470
471 471
472 472 def synchronize_hg(
473 473 source_path: pathlib.Path, ec2_instance, revision: str = None
474 474 ):
475 475 """Synchronize a local Mercurial source path to remote EC2 instance."""
476 476
477 477 with tempfile.TemporaryDirectory() as temp_dir:
478 478 temp_dir = pathlib.Path(temp_dir)
479 479
480 480 ssh_dir = temp_dir / '.ssh'
481 481 ssh_dir.mkdir()
482 482 ssh_dir.chmod(0o0700)
483 483
484 484 public_ip = ec2_instance.public_ip_address
485 485
486 486 ssh_config = ssh_dir / 'config'
487 487
488 488 with ssh_config.open('w', encoding='utf-8') as fh:
489 489 fh.write('Host %s\n' % public_ip)
490 490 fh.write(' User hg\n')
491 491 fh.write(' StrictHostKeyChecking no\n')
492 492 fh.write(' UserKnownHostsFile %s\n' % (ssh_dir / 'known_hosts'))
493 493 fh.write(' IdentityFile %s\n' % ec2_instance.ssh_private_key_path)
494 494
495 495 if not (source_path / '.hg').is_dir():
496 496 raise Exception(
497 497 '%s is not a Mercurial repository; synchronization '
498 498 'not yet supported' % source_path
499 499 )
500 500
501 501 env = dict(os.environ)
502 502 env['HGPLAIN'] = '1'
503 503 env['HGENCODING'] = 'utf-8'
504 504
505 505 hg_bin = source_path / 'hg'
506 506
507 507 res = subprocess.run(
508 508 ['python2.7', str(hg_bin), 'log', '-r', revision, '-T', '{node}'],
509 509 cwd=str(source_path),
510 510 env=env,
511 511 check=True,
512 512 capture_output=True,
513 513 )
514 514
515 515 full_revision = res.stdout.decode('ascii')
516 516
517 517 args = [
518 518 'python2.7',
519 519 str(hg_bin),
520 520 '--config',
521 521 'ui.ssh=ssh -F %s' % ssh_config,
522 522 '--config',
523 523 'ui.remotecmd=/hgdev/venv-bootstrap/bin/hg',
524 524 # Also ensure .hgtags changes are present so auto version
525 525 # calculation works.
526 526 'push',
527 527 '-f',
528 528 '-r',
529 529 full_revision,
530 530 '-r',
531 531 'file(.hgtags)',
532 532 'ssh://%s//hgwork/src' % public_ip,
533 533 ]
534 534
535 535 res = subprocess.run(args, cwd=str(source_path), env=env)
536 536
537 537 # Allow 1 (no-op) to not trigger error.
538 538 if res.returncode not in (0, 1):
539 539 res.check_returncode()
540 540
541 541 # TODO support synchronizing dirty working directory.
542 542
543 543 sftp = ec2_instance.ssh_client.open_sftp()
544 544
545 545 with sftp.open('/hgdev/hgup', 'wb') as fh:
546 546 fh.write(HG_UPDATE_CLEAN)
547 547 fh.chmod(0o0700)
548 548
549 549 chan, stdin, stdout = exec_command(
550 550 ec2_instance.ssh_client, '/hgdev/hgup %s' % full_revision
551 551 )
552 552 stdin.close()
553 553
554 554 for line in stdout:
555 555 print(line, end='')
556 556
557 557 res = chan.recv_exit_status()
558 558
559 559 if res:
560 560 raise Exception(
561 561 'non-0 exit code updating working directory; %d' % res
562 562 )
563 563
564 564
565 565 def run_tests(ssh_client, python_version, test_flags=None):
566 566 """Run tests on a remote Linux machine via an SSH client."""
567 567 test_flags = test_flags or []
568 568
569 569 print('running tests')
570 570
571 571 if python_version == 'system2':
572 572 python = '/usr/bin/python2'
573 573 elif python_version == 'system3':
574 574 python = '/usr/bin/python3'
575 575 elif python_version.startswith('pypy'):
576 576 python = '/hgdev/pyenv/shims/%s' % python_version
577 577 else:
578 578 python = '/hgdev/pyenv/shims/python%s' % python_version
579 579
580 580 test_flags = ' '.join(shlex.quote(a) for a in test_flags)
581 581
582 582 command = (
583 583 '/bin/sh -c "export TMPDIR=/hgwork/tmp; '
584 584 'cd /hgwork/src/tests && %s run-tests.py %s"' % (python, test_flags)
585 585 )
586 586
587 587 chan, stdin, stdout = exec_command(ssh_client, command)
588 588
589 589 stdin.close()
590 590
591 591 for line in stdout:
592 592 print(line, end='')
593 593
594 594 return chan.recv_exit_status()
@@ -1,200 +1,200 b''
1 1 # install-dependencies.ps1 - Install Windows dependencies for building Mercurial
2 2 #
3 3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 # This script can be used to bootstrap a Mercurial build environment on
9 9 # Windows.
10 10 #
11 11 # The script makes a lot of assumptions about how things should work.
12 12 # For example, the install location of Python is hardcoded to c:\hgdev\*.
13 13 #
14 14 # The script should be executed from a PowerShell with elevated privileges
15 15 # if you don't want to see a UAC prompt for various installers.
16 16 #
17 17 # The script is tested on Windows 10 and Windows Server 2019 (in EC2).
18 18
19 19 $VS_BUILD_TOOLS_URL = "https://download.visualstudio.microsoft.com/download/pr/a1603c02-8a66-4b83-b821-811e3610a7c4/aa2db8bb39e0cbd23e9940d8951e0bc3/vs_buildtools.exe"
20 20 $VS_BUILD_TOOLS_SHA256 = "911E292B8E6E5F46CBC17003BDCD2D27A70E616E8D5E6E69D5D489A605CAA139"
21 21
22 22 $VC9_PYTHON_URL = "https://download.microsoft.com/download/7/9/6/796EF2E4-801B-4FC4-AB28-B59FBF6D907B/VCForPython27.msi"
23 23 $VC9_PYTHON_SHA256 = "070474db76a2e625513a5835df4595df9324d820f9cc97eab2a596dcbc2f5cbf"
24 24
25 25 $PYTHON27_x64_URL = "https://www.python.org/ftp/python/2.7.16/python-2.7.16.amd64.msi"
26 26 $PYTHON27_x64_SHA256 = "7c0f45993019152d46041a7db4b947b919558fdb7a8f67bcd0535bc98d42b603"
27 27 $PYTHON27_X86_URL = "https://www.python.org/ftp/python/2.7.16/python-2.7.16.msi"
28 28 $PYTHON27_X86_SHA256 = "d57dc3e1ba490aee856c28b4915d09e3f49442461e46e481bc6b2d18207831d7"
29 29
30 30 $PYTHON35_x86_URL = "https://www.python.org/ftp/python/3.5.4/python-3.5.4.exe"
31 31 $PYTHON35_x86_SHA256 = "F27C2D67FD9688E4970F3BFF799BB9D722A0D6C2C13B04848E1F7D620B524B0E"
32 32 $PYTHON35_x64_URL = "https://www.python.org/ftp/python/3.5.4/python-3.5.4-amd64.exe"
33 33 $PYTHON35_x64_SHA256 = "9B7741CC32357573A77D2EE64987717E527628C38FD7EAF3E2AACA853D45A1EE"
34 34
35 35 $PYTHON36_x86_URL = "https://www.python.org/ftp/python/3.6.8/python-3.6.8.exe"
36 36 $PYTHON36_x86_SHA256 = "89871D432BC06E4630D7B64CB1A8451E53C80E68DE29029976B12AAD7DBFA5A0"
37 37 $PYTHON36_x64_URL = "https://www.python.org/ftp/python/3.6.8/python-3.6.8-amd64.exe"
38 38 $PYTHON36_x64_SHA256 = "96088A58B7C43BC83B84E6B67F15E8706C614023DD64F9A5A14E81FF824ADADC"
39 39
40 40 $PYTHON37_x86_URL = "https://www.python.org/ftp/python/3.7.4/python-3.7.4.exe"
41 41 $PYTHON37_x86_SHA256 = "9a30ab5568ba37bfbcae5cdee19e9dc30765c42cf066f605221563ff8b20ee34"
42 42 $PYTHON37_X64_URL = "https://www.python.org/ftp/python/3.7.4/python-3.7.4-amd64.exe"
43 43 $PYTHON37_x64_SHA256 = "bab92f987320975c7826171a072bfd64f8f0941aaf2cdeba6924b7025c9968a3"
44 44
45 $PYTHON38_x86_URL = "https://www.python.org/ftp/python/3.8.0/python-3.8.0rc1.exe"
46 $PYTHON38_x86_SHA256 = "79eb5dd04be8384154ef6767e35ae570ede28188bd6cecce4f18c1aa42d1bb66"
47 $PYTHON38_x64_URL = "https://www.python.org/ftp/python/3.8.0/python-3.8.0rc1-amd64.exe"
48 $PYTHON38_x64_SHA256 = "c9cffbaf11487c08432d3ea9a3ac125f0fee41b41e71062477fb057ca1e5ab40"
45 $PYTHON38_x86_URL = "https://www.python.org/ftp/python/3.8.0/python-3.8.0.exe"
46 $PYTHON38_x86_SHA256 = "b471908de5e10d8fb5c3351a5affb1172da7790c533e0c9ffbaeec9c11611b15"
47 $PYTHON38_x64_URL = "https://www.python.org/ftp/python/3.8.0/python-3.8.0-amd64.exe"
48 $PYTHON38_x64_SHA256 = "a9bbc6088a3e4c7112826e21bfee6277f7b6d93259f7c57176139231bb7071e4"
49 49
50 50 # PIP 19.2.3.
51 51 $PIP_URL = "https://github.com/pypa/get-pip/raw/309a56c5fd94bd1134053a541cb4657a4e47e09d/get-pip.py"
52 52 $PIP_SHA256 = "57e3643ff19f018f8a00dfaa6b7e4620e3c1a7a2171fd218425366ec006b3bfe"
53 53
54 54 $VIRTUALENV_URL = "https://files.pythonhosted.org/packages/66/f0/6867af06d2e2f511e4e1d7094ff663acdebc4f15d4a0cb0fed1007395124/virtualenv-16.7.5.tar.gz"
55 55 $VIRTUALENV_SHA256 = "f78d81b62d3147396ac33fc9d77579ddc42cc2a98dd9ea38886f616b33bc7fb2"
56 56
57 57 $INNO_SETUP_URL = "http://files.jrsoftware.org/is/5/innosetup-5.6.1-unicode.exe"
58 58 $INNO_SETUP_SHA256 = "27D49E9BC769E9D1B214C153011978DB90DC01C2ACD1DDCD9ED7B3FE3B96B538"
59 59
60 60 $MINGW_BIN_URL = "https://osdn.net/frs/redir.php?m=constant&f=mingw%2F68260%2Fmingw-get-0.6.3-mingw32-pre-20170905-1-bin.zip"
61 61 $MINGW_BIN_SHA256 = "2AB8EFD7C7D1FC8EAF8B2FA4DA4EEF8F3E47768284C021599BC7435839A046DF"
62 62
63 63 $MERCURIAL_WHEEL_FILENAME = "mercurial-5.1.2-cp27-cp27m-win_amd64.whl"
64 64 $MERCURIAL_WHEEL_URL = "https://files.pythonhosted.org/packages/6d/47/e031e47f7fe9b16e4e3383da47e2b0a7eae6e603996bc67a03ec4fa1b3f4/$MERCURIAL_WHEEL_FILENAME"
65 65 $MERCURIAL_WHEEL_SHA256 = "1d18c7f6ca1456f0f62ee65c9a50c14cbba48ce6e924930cdb10537f5c9eaf5f"
66 66
67 67 # Writing progress slows down downloads substantially. So disable it.
68 68 $progressPreference = 'silentlyContinue'
69 69
70 70 function Secure-Download($url, $path, $sha256) {
71 71 if (Test-Path -Path $path) {
72 72 Get-FileHash -Path $path -Algorithm SHA256 -OutVariable hash
73 73
74 74 if ($hash.Hash -eq $sha256) {
75 75 Write-Output "SHA256 of $path verified as $sha256"
76 76 return
77 77 }
78 78
79 79 Write-Output "hash mismatch on $path; downloading again"
80 80 }
81 81
82 82 Write-Output "downloading $url to $path"
83 83 Invoke-WebRequest -Uri $url -OutFile $path
84 84 Get-FileHash -Path $path -Algorithm SHA256 -OutVariable hash
85 85
86 86 if ($hash.Hash -ne $sha256) {
87 87 Remove-Item -Path $path
88 88 throw "hash mismatch when downloading $url; got $($hash.Hash), expected $sha256"
89 89 }
90 90 }
91 91
92 92 function Invoke-Process($path, $arguments) {
93 93 $p = Start-Process -FilePath $path -ArgumentList $arguments -Wait -PassThru -WindowStyle Hidden
94 94
95 95 if ($p.ExitCode -ne 0) {
96 96 throw "process exited non-0: $($p.ExitCode)"
97 97 }
98 98 }
99 99
100 100 function Install-Python3($name, $installer, $dest, $pip) {
101 101 Write-Output "installing $name"
102 102
103 103 # We hit this when running the script as part of Simple Systems Manager in
104 104 # EC2. The Python 3 installer doesn't seem to like per-user installs
105 105 # when running as the SYSTEM user. So enable global installs if executed in
106 106 # this mode.
107 107 if ($env:USERPROFILE -eq "C:\Windows\system32\config\systemprofile") {
108 108 Write-Output "running with SYSTEM account; installing for all users"
109 109 $allusers = "1"
110 110 }
111 111 else {
112 112 $allusers = "0"
113 113 }
114 114
115 115 Invoke-Process $installer "/quiet TargetDir=${dest} InstallAllUsers=${allusers} AssociateFiles=0 CompileAll=0 PrependPath=0 Include_doc=0 Include_launcher=0 InstallLauncherAllUsers=0 Include_pip=0 Include_test=0"
116 116 Invoke-Process ${dest}\python.exe $pip
117 117 }
118 118
119 119 function Install-Dependencies($prefix) {
120 120 if (!(Test-Path -Path $prefix\assets)) {
121 121 New-Item -Path $prefix\assets -ItemType Directory
122 122 }
123 123
124 124 $pip = "${prefix}\assets\get-pip.py"
125 125
126 126 Secure-Download $VC9_PYTHON_URL ${prefix}\assets\VCForPython27.msi $VC9_PYTHON_SHA256
127 127 Secure-Download $PYTHON27_x86_URL ${prefix}\assets\python27-x86.msi $PYTHON27_x86_SHA256
128 128 Secure-Download $PYTHON27_x64_URL ${prefix}\assets\python27-x64.msi $PYTHON27_x64_SHA256
129 129 Secure-Download $PYTHON35_x86_URL ${prefix}\assets\python35-x86.exe $PYTHON35_x86_SHA256
130 130 Secure-Download $PYTHON35_x64_URL ${prefix}\assets\python35-x64.exe $PYTHON35_x64_SHA256
131 131 Secure-Download $PYTHON36_x86_URL ${prefix}\assets\python36-x86.exe $PYTHON36_x86_SHA256
132 132 Secure-Download $PYTHON36_x64_URL ${prefix}\assets\python36-x64.exe $PYTHON36_x64_SHA256
133 133 Secure-Download $PYTHON37_x86_URL ${prefix}\assets\python37-x86.exe $PYTHON37_x86_SHA256
134 134 Secure-Download $PYTHON37_x64_URL ${prefix}\assets\python37-x64.exe $PYTHON37_x64_SHA256
135 135 Secure-Download $PYTHON38_x86_URL ${prefix}\assets\python38-x86.exe $PYTHON38_x86_SHA256
136 136 Secure-Download $PYTHON38_x64_URL ${prefix}\assets\python38-x64.exe $PYTHON38_x64_SHA256
137 137 Secure-Download $PIP_URL ${pip} $PIP_SHA256
138 138 Secure-Download $VIRTUALENV_URL ${prefix}\assets\virtualenv.tar.gz $VIRTUALENV_SHA256
139 139 Secure-Download $VS_BUILD_TOOLS_URL ${prefix}\assets\vs_buildtools.exe $VS_BUILD_TOOLS_SHA256
140 140 Secure-Download $INNO_SETUP_URL ${prefix}\assets\InnoSetup.exe $INNO_SETUP_SHA256
141 141 Secure-Download $MINGW_BIN_URL ${prefix}\assets\mingw-get-bin.zip $MINGW_BIN_SHA256
142 142 Secure-Download $MERCURIAL_WHEEL_URL ${prefix}\assets\${MERCURIAL_WHEEL_FILENAME} $MERCURIAL_WHEEL_SHA256
143 143
144 144 Write-Output "installing Python 2.7 32-bit"
145 145 Invoke-Process msiexec.exe "/i ${prefix}\assets\python27-x86.msi /l* ${prefix}\assets\python27-x86.log /q TARGETDIR=${prefix}\python27-x86 ALLUSERS="
146 146 Invoke-Process ${prefix}\python27-x86\python.exe ${prefix}\assets\get-pip.py
147 147 Invoke-Process ${prefix}\python27-x86\Scripts\pip.exe "install ${prefix}\assets\virtualenv.tar.gz"
148 148
149 149 Write-Output "installing Python 2.7 64-bit"
150 150 Invoke-Process msiexec.exe "/i ${prefix}\assets\python27-x64.msi /l* ${prefix}\assets\python27-x64.log /q TARGETDIR=${prefix}\python27-x64 ALLUSERS="
151 151 Invoke-Process ${prefix}\python27-x64\python.exe ${prefix}\assets\get-pip.py
152 152 Invoke-Process ${prefix}\python27-x64\Scripts\pip.exe "install ${prefix}\assets\virtualenv.tar.gz"
153 153
154 154 Install-Python3 "Python 3.5 32-bit" ${prefix}\assets\python35-x86.exe ${prefix}\python35-x86 ${pip}
155 155 Install-Python3 "Python 3.5 64-bit" ${prefix}\assets\python35-x64.exe ${prefix}\python35-x64 ${pip}
156 156 Install-Python3 "Python 3.6 32-bit" ${prefix}\assets\python36-x86.exe ${prefix}\python36-x86 ${pip}
157 157 Install-Python3 "Python 3.6 64-bit" ${prefix}\assets\python36-x64.exe ${prefix}\python36-x64 ${pip}
158 158 Install-Python3 "Python 3.7 32-bit" ${prefix}\assets\python37-x86.exe ${prefix}\python37-x86 ${pip}
159 159 Install-Python3 "Python 3.7 64-bit" ${prefix}\assets\python37-x64.exe ${prefix}\python37-x64 ${pip}
160 160 Install-Python3 "Python 3.8 32-bit" ${prefix}\assets\python38-x86.exe ${prefix}\python38-x86 ${pip}
161 161 Install-Python3 "Python 3.8 64-bit" ${prefix}\assets\python38-x64.exe ${prefix}\python38-x64 ${pip}
162 162
163 163 Write-Output "installing Visual Studio 2017 Build Tools and SDKs"
164 164 Invoke-Process ${prefix}\assets\vs_buildtools.exe "--quiet --wait --norestart --nocache --channelUri https://aka.ms/vs/15/release/channel --add Microsoft.VisualStudio.Workload.MSBuildTools --add Microsoft.VisualStudio.Component.Windows10SDK.17763 --add Microsoft.VisualStudio.Workload.VCTools --add Microsoft.VisualStudio.Component.Windows10SDK --add Microsoft.VisualStudio.Component.VC.140"
165 165
166 166 Write-Output "installing Visual C++ 9.0 for Python 2.7"
167 167 Invoke-Process msiexec.exe "/i ${prefix}\assets\VCForPython27.msi /l* ${prefix}\assets\VCForPython27.log /q"
168 168
169 169 Write-Output "installing Inno Setup"
170 170 Invoke-Process ${prefix}\assets\InnoSetup.exe "/SP- /VERYSILENT /SUPPRESSMSGBOXES"
171 171
172 172 Write-Output "extracting MinGW base archive"
173 173 Expand-Archive -Path ${prefix}\assets\mingw-get-bin.zip -DestinationPath "${prefix}\MinGW" -Force
174 174
175 175 Write-Output "updating MinGW package catalogs"
176 176 Invoke-Process ${prefix}\MinGW\bin\mingw-get.exe "update"
177 177
178 178 Write-Output "installing MinGW packages"
179 179 Invoke-Process ${prefix}\MinGW\bin\mingw-get.exe "install msys-base msys-coreutils msys-diffutils msys-unzip"
180 180
181 181 # Construct a virtualenv useful for bootstrapping. It conveniently contains a
182 182 # Mercurial install.
183 183 Write-Output "creating bootstrap virtualenv with Mercurial"
184 184 Invoke-Process "$prefix\python27-x64\Scripts\virtualenv.exe" "${prefix}\venv-bootstrap"
185 185 Invoke-Process "${prefix}\venv-bootstrap\Scripts\pip.exe" "install ${prefix}\assets\${MERCURIAL_WHEEL_FILENAME}"
186 186 }
187 187
188 188 function Clone-Mercurial-Repo($prefix, $repo_url, $dest) {
189 189 Write-Output "cloning $repo_url to $dest"
190 190 # TODO Figure out why CA verification isn't working in EC2 and remove
191 191 # --insecure.
192 192 Invoke-Process "${prefix}\venv-bootstrap\Scripts\hg.exe" "clone --insecure $repo_url $dest"
193 193
194 194 # Mark repo as non-publishing by default for convenience.
195 195 Add-Content -Path "$dest\.hg\hgrc" -Value "`n[phases]`npublish = false"
196 196 }
197 197
198 198 $prefix = "c:\hgdev"
199 199 Install-Dependencies $prefix
200 200 Clone-Mercurial-Repo $prefix "https://www.mercurial-scm.org/repo/hg" $prefix\src
General Comments 0
You need to be logged in to leave comments. Login now