-
Notifications
You must be signed in to change notification settings - Fork 3
/
tasks.py
193 lines (171 loc) · 7.77 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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
"""Define invoke tasks."""
import configparser
import getpass
import os
import pathlib
import sys
from django.core.management.utils import get_random_secret_key
from invoke import task
BASE_DIR = os.path.dirname(__file__)
BASE_DIRNAME = os.path.dirname(BASE_DIR)
PROJECT_DIRNAME = os.path.basename(os.path.dirname(__file__))
EMPEROR_MODE = True
VASSALS = f'{BASE_DIRNAME}/vassals'
USERNAME = os.getlogin()
SECRET_FILE = f'{BASE_DIR}/{PROJECT_DIRNAME}/settings/secret.py'
SECRET_KEY = get_random_secret_key()
@task
def init(c):
"""Initialize project."""
try:
VENV_ROOT = str(pathlib.Path(os.environ['VIRTUAL_ENV']).parent).replace("/", "\/") # noqa
except KeyError:
print('Activate your virtualenv and run the inv command again')
return
EMPEROR_MODE = confirm('Do you want to configure your uWSGI vassal in emperor mode? (no=stand-alone)')
if EMPEROR_MODE:
vassals = input(f'We will use "{VASSALS}" as the directory for the vassals, or specify the path: ') or VASSALS
bonjour = confirm('Do you want to use Bonjour for OSX (Yes) or Avahi for Linux (No)? ')
if bonjour:
ZEROCONF = 'bonjour'
ZEROOPTS = 'name=%(project_name).local,cname=localhost'
else:
ZEROCONF = 'avahi'
ZEROOPTS = '%(project_name).local'
python_plugin = input(
f'Specify python plugin to configure uwsgi or blank to use default value (python3): ') or "python3"
database = input(f'We will use "{PROJECT_DIRNAME}" as database name, or specify another name: ') or PROJECT_DIRNAME
username = input(f'Enter the database user name: ')
password = getpass.getpass(f'Enter the database user password: ')
print('Compiling pip file in requirements')
c.run('make pip')
print('Installing libraries in requirements')
c.run('make dev')
if not os.path.exists('templates'):
print('Making templates directory')
c.run('mkdir templates')
if not os.path.exists('static'):
print('Making static directory')
c.run('mkdir static')
if not os.path.exists('media'):
print('Making media directory')
c.run('mkdir media')
ini_dir = f'{BASE_DIR}/uwsgiconf/local'
PYVERSION = f"{sys.version_info[0]}.{sys.version_info[1]}"
WORKAREA_ROOT = BASE_DIRNAME.replace("/", "\/") # noqa
print('Generating uwsgi user file')
if EMPEROR_MODE and not os.path.exists(f'{vassals}/{PROJECT_DIRNAME}.ini'):
c.run(f'cp {ini_dir}/vassal.ini.template {ini_dir}/{USERNAME}.ini')
c.run((
f'sed -i".bak" -e "s/USERNAME/{USERNAME}/g;s/ZEROCONF/{ZEROCONF}/g;s/ZEROOPTS/{ZEROOPTS}/g;" {ini_dir}/'
f'{USERNAME}.ini'))
c.run(f'ln -s {BASE_DIR}/uwsgiconf/local/{USERNAME}.ini {vassals}/{PROJECT_DIRNAME}.ini')
else:
c.run(f'cp {ini_dir}/standalone.ini.template {ini_dir}/{USERNAME}.ini')
c.run(f'sed -i".bak" -e "s/plugin = python3/plugin = {python_plugin}/g;" {ini_dir}/{USERNAME}.ini')
c.run(f'sed -i".bak" -e "s/WORKAREA_ROOT/{WORKAREA_ROOT}/g;" {ini_dir}/{USERNAME}.ini')
c.run(f'sed -i".bak" -e "s/PYVERSION/{PYVERSION}/g;" {ini_dir}/{USERNAME}.ini')
c.run(f'sed -i".bak" -e "s/VENV_ROOT/{VENV_ROOT}/g;" {ini_dir}/{USERNAME}.ini')
print('Installing secret file in settings')
if not os.path.exists(f'{SECRET_FILE}'):
c.run(f'cp {SECRET_FILE}.template {SECRET_FILE}')
c.run((
f'sed -i".bak" -e '
f'"s/database/{database}/g;s/password/{password}/g;s/secretkey/{SECRET_KEY}/g;s/username/{username}/g"'
f' {SECRET_FILE}'
))
else:
c.run(
f'sed -i".bak" -e "s/database/{database}/g;s/password/{password}/g;s/username/{username}/g" {SECRET_FILE}'
)
createdb(c)
print('*** Next steps ***')
print(f'a) Check the uwsgiconf/local/{USERNAME}.ini and verify that you have the correct python plugin')
print('b) Check the uwsgiconf/remote/globlal.ini file and verify that you have the correct python plugin')
print('c) Check the uwsgiconf/remote/alpha.ini file and make sure the domain name is correct')
print('d) Configure the deploy/hosts file with server data')
print('e) Configure the deploy/alpha.yaml file with the correct data')
print(f'f) Configure the file by {PROJECT_DIRNAME}/settings/testing.py with the correct data')
if EMPEROR_MODE:
c.run(f"python -m webbrowser -t http://{PROJECT_DIRNAME}.local/")
@task
def createdb(c):
"""Create database."""
if confirm('Pay attention, you are creating the Postgresql db. Are you sure you want to proceed?'):
db_name, db_host, db_port, db_user = get_db()
c.run(f"createdb -e -h {db_host} -p {db_port} -U {db_user} -O {db_user} {db_name}")
@task
def dropdb(c):
"""Drop database."""
if confirm('Warning, you are deleting the db. Are you sure you want to proceed?'):
db_name, db_host, db_port, db_user = get_db()
c.run(f"dropdb -e -h {db_host} -p {db_port} -U {db_user} {db_name}")
@task
def gitinit(c, git_repository_url):
"""Initialize git repository."""
c.run(f'sed -i".bak" -e "s,GIT_REPOSITORY_URL,{git_repository_url},g;" README.md')
c.run('git init')
c.run('flake8 --install-hook git')
c.run('git config flake8.strict true')
c.run('git add -A')
c.run('git commit -m "Initial commit"')
c.run(f'git remote add origin {git_repository_url}')
c.run('git push -u origin master')
@task
def restart(c):
"""Restart uWSGI instance."""
c.run(f'touch uwsgiconf/local/{USERNAME}.ini')
def get_db():
"""Fetch database credentials."""
with open(SECRET_FILE, 'r') as f:
config_string = '[secret]\n' + f.read()
config = configparser.ConfigParser()
config.read_string(config_string)
db_name = config.get('secret', 'DATABASES_DEFAULT_NAME')
db_host = config.get('secret', 'DATABASES_DEFAULT_HOST')
db_port = config.get('secret', 'DATABASES_DEFAULT_PORT')
db_user = config.get('secret', 'DATABASES_DEFAULT_USER')
return db_name, db_host, db_port, db_user
# NOTE: originally cribbed from fab 1's contrib.console.confirm
def confirm(question, assume_yes=True):
"""
Ask user a yes/no question and return their response as a boolean.
``question`` should be a simple, grammatically complete question such as
"Do you wish to continue?", and will have a string similar to ``" [Y/n] "``
appended automatically. This function will *not* append a question mark for
you.
By default, when the user presses Enter without typing anything, "yes" is
assumed. This can be changed by specifying ``affirmative=False``.
.. note::
If the user does not supplies input that is (case-insensitively) equal
to "y", "yes", "n" or "no", they will be re-prompted until they do.
:param str question: The question part of the input.
:param bool assume_yes:
Whether to assume the affirmative answer by default. Default value:
``True``.
:returns: A `bool`.
"""
# Set up suffix
if assume_yes:
suffix = 'Y/n'
else:
suffix = 'y/N'
# Loop till we get something we like
# TODO: maybe don't do this? It can be annoying. Turn into 'q'-for-quit?
while True:
# TODO: ensure that this is Ctrl-C friendly, ISTR issues with
# raw_input/input on some Python versions blocking KeyboardInterrupt.
response = input('{0} [{1}] '.format(question, suffix))
response = response.lower().strip() # Normalize
# Default
if not response:
return assume_yes
# Yes
if response in ['y', 'yes']:
return True
# No
if response in ['n', 'no']:
return False
# Didn't get empty, yes or no, so complain and loop
err = "I didn't understand you. Please specify '(y)es' or '(n)o'."
print(err, file=sys.stderr)