Changes to instance naming:
[mdk.git] / mdk / commands / create.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 """
5 Moodle Development Kit
6
7 Copyright (c) 2013 Frédéric Massart - FMCorz.net
8
9 This program is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
21
22 http://github.com/FMCorz/mdk
23 """
24
25 import re
26 import logging
27
28 from ..db import DB
29 from ..command import Command
30 from ..tools import yesOrNo
31 from ..exceptions import CreateException, InstallException
32
33
34 class CreateCommand(Command):
35
36 _description = 'Creates new instances of Moodle'
37
38 def __init__(self, *args, **kwargs):
39 super(CreateCommand, self).__init__(*args, **kwargs)
40 self._arguments = [
41 (
42 ['-i', '--install'],
43 {
44 'action': 'store_true',
45 'dest': 'install',
46 'help': 'launch the installation script after creating the instance'
47 }
48 ),
49 (
50 ['-e', '--engine'],
51 {
52 'action': 'store',
53 'choices': ['mariadb', 'mysqli', 'pgsql'],
54 'default': self.C.get('defaultEngine'),
55 'help': 'database engine to install the instance on, use with --install',
56 'metavar': 'engine'
57 }
58 ),
59 (
60 ['-p', '--purpose'],
61 {
62 'action': 'store',
63 'choices': ['integration', 'review', 'stable'],
64 'default': 'stable',
65 'help': 'specify what this instance is for',
66 'metavar': 'purpose'
67 }
68 ),
69 (
70 ['-r', '--run'],
71 {
72 'action': 'store',
73 'help': 'scripts to run after installation',
74 'metavar': 'run',
75 'nargs': '*'
76 }
77 ),
78 (
79 ['-n', '--identifier'],
80 {
81 'action': 'store',
82 'default': None,
83 'help': 'use this identifier instead of generating one. The flag --suffix will be used. ' +
84 'Do not use when creating multiple versions at once',
85 'metavar': 'name',
86 }
87 ),
88 (
89 ['-s', '--suffix'],
90 {
91 'action': 'store',
92 'default': [None],
93 'help': 'suffixes for the instance name',
94 'metavar': 'suffix',
95 'nargs': '*'
96 }
97 ),
98 (
99 ['-v', '--version'],
100 {
101 'choices': [str(x) for x in range(13, int(self.C.get('masterBranch')))] + ['master'],
102 'default': ['master'],
103 'help': 'version of Moodle',
104 'metavar': 'version',
105 'nargs': '*'
106 }
107 ),
108 ]
109
110 def run(self, args):
111
112 engine = args.engine
113 versions = args.version
114 suffixes = args.suffix
115 install = args.install
116
117 # Throw an error when --engine is used without --install. The code is currently commented out
118 # because as --engine has a default value, it will always be set, and so it becomes impossible
119 # to create an instance without installing it. I cannot think about a clean fix yet. Removing
120 # the default value will cause --help not to output the default as it should... Let's put more
121 # thoughts into this and perhaps use argument groups.
122 # if engine and not install:
123 # self.argumentError('--engine can only be used with --install.')
124
125 for version in versions:
126 for suffix in suffixes:
127 arguments = {
128 'version': version,
129 'suffix': suffix,
130 'engine': engine,
131 'purpose': args.purpose,
132 'identifier': args.identifier,
133 'install': install,
134 'run': args.run
135 }
136 self.do(arguments)
137 logging.info('')
138
139 logging.info('Process complete!')
140
141 def do(self, args):
142 """Proceeds to the creation of an instance"""
143
144 # TODO Remove these ugly lines, but I'm lazy to rewrite the variables in this method...
145 class Bunch:
146 __init__ = lambda self, **kw: setattr(self, '__dict__', kw)
147 args = Bunch(**args)
148
149 engine = args.engine
150 version = args.version
151 name = self.Wp.generateInstanceName(version, engine=engine, purpose=args.purpose, suffix=args.suffix, identifier=args.identifier)
152
153 # Wording version
154 versionNice = version
155 if version == 'master':
156 versionNice = self.C.get('wording.master')
157
158 # Generating names
159 if args.purpose == 'integration':
160 fullname = self.C.get('wording.integration') + ' ' + versionNice + ' ' + self.C.get('wording.%s' % engine)
161
162 if args.purpose == 'stable':
163 fullname = self.C.get('wording.stable') + ' ' + versionNice + ' ' + self.C.get('wording.%s' % engine)
164
165 if args.purpose == 'review':
166 fullname = self.C.get('wording.review') + ' ' + versionNice + ' ' + self.C.get('wording.%s' % engine)
167
168 # Append the suffix
169 if args.suffix:
170 fullname += ' ' + args.suffix.replace('-', ' ').replace('_', ' ').title()
171
172 # Create the instance
173 logging.info('Creating instance %s...' % name)
174 kwargs = {
175 'name': name,
176 'version': version,
177 'purpose': args.purpose,
178 'engine': engine
179 }
180 try:
181 M = self.Wp.create(**kwargs)
182 except CreateException as e:
183 logging.error('Error creating %s:\n %s' % (name, e))
184 return False
185 except Exception as e:
186 logging.exception('Error creating %s:\n %s' % (name, e))
187 return False
188
189 # Run the install script
190 if args.install:
191
192 # Checking database
193 dbname = re.sub(r'[^a-zA-Z0-9]', '', name).lower()
194 prefixDbname = self.C.get('db.namePrefix')
195 if prefixDbname:
196 dbname = prefixDbname + dbname
197 dbname = dbname[:28]
198 db = DB(engine, self.C.get('db.%s' % engine))
199 dropDb = False
200 if db.dbexists(dbname):
201 logging.info('Database already exists (%s)' % dbname)
202 dropDb = yesOrNo('Do you want to remove it?')
203
204 # Install
205 kwargs = {
206 'engine': engine,
207 'dbname': dbname,
208 'dropDb': dropDb,
209 'fullname': fullname,
210 'dataDir': self.Wp.getPath(name, 'data'),
211 'wwwroot': self.Wp.getUrl(name)
212 }
213 try:
214 M.install(**kwargs)
215 except InstallException as e:
216 logging.warning('Error while installing %s:\n %s' % (name, e))
217 return False
218 except Exception as e:
219 logging.exception('Error while installing %s:\n %s' % (name, e))
220 return False
221
222 # Running scripts
223 if M.isInstalled() and type(args.run) == list:
224 for script in args.run:
225 logging.info('Running script \'%s\'' % (script))
226 try:
227 M.runScript(script)
228 except Exception as e:
229 logging.warning('Error while running the script \'%s\':\ %s' % (script, e))