This repository has been archived by the owner on Dec 1, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathtasks.py
135 lines (100 loc) · 3.1 KB
/
tasks.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import re
import sys
from datetime import date
from invoke import task
from invoke.context import Context
# Docker
IMAGE_NAME = f'europython/workshop'
DOCKER_SERVICE = 'web'
# Tox
DEV_ENV = 'dev'
ACTIVATE_DEV = f'.tox/{DEV_ENV}/bin/activate'
PYTHON_TESTS = 'py36'
LOCAL_ENV = 'local'
# Python
SETUP_FILE = 'setup.py'
# Commands
build_help = {
'erase': "Overwritte previously created container with the same tag.",
}
@task
def build(ctx, erase=False):
"""Build a new Docker container."""
today = date.today().strftime('%Y.%m.%d')
# Build the Docker container.
if erase:
print("Erasing existing Docker image")
command = f'docker rmi {IMAGE_NAME}:{today}'
run(command)
print("Building new Docker image")
command = f'docker build -t {IMAGE_NAME}:{today} -t {IMAGE_NAME}:latest .'
run(command)
# Update application version.
print(f"Updating version in {SETUP_FILE}")
to_replace = [(r"version='\d+.\d+.\d+'", f"version='{today}'")]
replace(to_replace, SETUP_FILE)
demo_help = {
'debug': "Execute a shell inside the Docker container instead.",
}
@task(help=demo_help)
def demo(ctx, debug=False):
"""Launch the demo web API in foreground."""
if debug:
docker_compose_run('sh')
else:
run('docker-compose up')
test_help = {
'debug': "Execute a shell inside the Docker container instead.",
}
@task(help=test_help)
def test(ctx, debug=False):
"""Execute the test suite."""
if debug:
command = f'tox -e {DEV_ENV} && . {ACTIVATE_DEV} && sh'
docker_compose_run(command)
else:
command = f'tox -e {PYTHON_TESTS}'
docker_compose_run(command)
@task
def virtualenv(ctx):
"""Install the web application and its dependencies locally."""
command = f'tox -e {LOCAL_ENV}'
run(command)
# Helpers
def run(command):
"""Execute a command with Invoke."""
ctx = Context()
ctx.run(
command,
echo=True, # To improve User eXperience
pty=True, # To get colors in output
)
def docker_run(command):
"""Execute a command inside a standalone running Docker container."""
cmdline = f'docker run {IMAGE_NAME}:latest {command}'
run(cmdline)
def docker_compose_run(command):
"""Execute a command inside a fully running Docker Compose stack."""
cmdline = (
f'docker-compose run '
f'--entrypoint "sh -c" ' # To run any command
f'--service-ports ' # To expose container's ports on host machine
f'{DOCKER_SERVICE} "{command}"'
)
run(cmdline)
def replace(lines, in_file):
"""Replace lines in a file.
Terminate script execution if lines are not found.
:param lines:
list of string tuples,
with regex expressions to look for and their substitutes.
"""
with open(in_file, 'r+') as f:
content = f.read()
for regex, string in lines:
content, has_been_changed = re.subn(regex, string, content)
if not has_been_changed:
sys.exit(f"Regex not found in {in_file}: {regex}")
f.seek(0)
f.write(content)
f.truncate()