23 # possible (for cubicweb-ctl reactivity, necessary for instance for usable bash |
23 # possible (for cubicweb-ctl reactivity, necessary for instance for usable bash |
24 # completion). So import locally in command helpers. |
24 # completion). So import locally in command helpers. |
25 import sys |
25 import sys |
26 import os |
26 import os |
27 |
27 |
|
28 from logilab.common import nullobject |
28 from logilab.common.configuration import Configuration |
29 from logilab.common.configuration import Configuration |
29 from logilab.common.shellutils import ASK |
30 from logilab.common.shellutils import ASK |
30 |
31 |
31 from cubicweb import AuthenticationError, ExecutionError, ConfigurationError |
32 from cubicweb import AuthenticationError, ExecutionError, ConfigurationError |
32 from cubicweb.toolsutils import Command, CommandHandler, underline_title |
33 from cubicweb.toolsutils import Command, CommandHandler, underline_title |
54 if dbhost: |
55 if dbhost: |
55 print '%s@%s' % (dbname, dbhost), |
56 print '%s@%s' % (dbname, dbhost), |
56 else: |
57 else: |
57 print dbname, |
58 print dbname, |
58 if dbhelper.users_support: |
59 if dbhelper.users_support: |
59 if not verbose or (not special_privs and source.get('db-user')): |
60 if not special_privs and source.get('db-user'): |
60 user = source['db-user'] |
61 user = source['db-user'] |
61 if verbose: |
62 if verbose: |
62 print 'as', user |
63 print 'as', user |
63 if source.get('db-password'): |
64 password = source.get('db-password') |
64 password = source['db-password'] |
|
65 else: |
|
66 password = getpass('password: ') |
|
67 else: |
65 else: |
68 print |
66 if verbose: |
|
67 print |
69 if special_privs: |
68 if special_privs: |
70 print 'WARNING' |
69 print 'WARNING' |
71 print ('the user will need the following special access rights ' |
70 print ('the user will need the following special access rights ' |
72 'on the database:') |
71 'on the database:') |
73 print special_privs |
72 print special_privs |
74 print |
73 print |
75 default_user = source.get('db-user', os.environ.get('USER', '')) |
74 default_user = source.get('db-user', os.environ.get('USER', '')) |
76 user = raw_input('Connect as user ? [%r]: ' % default_user) |
75 user = raw_input('Connect as user ? [%r]: ' % default_user) |
77 user = user or default_user |
76 user = user.strip() or default_user |
78 if user == source.get('db-user') and source.get('db-password'): |
77 if user == source.get('db-user'): |
79 password = source['db-password'] |
78 password = source['db-password'] |
80 else: |
79 else: |
81 password = getpass('password: ') |
80 password = getpass('password: ') |
82 else: |
81 else: |
83 user = password = None |
82 user = password = None |
106 from logilab.database import get_db_helper |
105 from logilab.database import get_db_helper |
107 system_db = get_db_helper(source['db-driver']).system_database() |
106 system_db = get_db_helper(source['db-driver']).system_database() |
108 return source_cnx(source, system_db, special_privs=special_privs, verbose=verbose) |
107 return source_cnx(source, system_db, special_privs=special_privs, verbose=verbose) |
109 return source_cnx(source, special_privs=special_privs, verbose=verbose) |
108 return source_cnx(source, special_privs=special_privs, verbose=verbose) |
110 |
109 |
111 def _db_sys_cnx(source, what, db=None, user=None, verbose=True): |
110 def _db_sys_cnx(source, special_privs, verbose=True): |
112 """return a connection on the RDMS system table (to create/drop a user |
111 """return a connection on the RDMS system table (to create/drop a user or a |
113 or a database |
112 database) |
114 """ |
113 """ |
115 import logilab.common as lgp |
114 import logilab.common as lgp |
116 from logilab.database import get_db_helper |
115 from logilab.database import get_db_helper |
117 lgp.USE_MX_DATETIME = False |
116 lgp.USE_MX_DATETIME = False |
118 special_privs = '' |
|
119 driver = source['db-driver'] |
117 driver = source['db-driver'] |
120 helper = get_db_helper(driver) |
118 helper = get_db_helper(driver) |
121 if user is not None and helper.users_support: |
|
122 special_privs += '%s USER' % what |
|
123 if db is not None: |
|
124 special_privs += ' %s DATABASE' % what |
|
125 # connect on the dbms system base to create our base |
119 # connect on the dbms system base to create our base |
126 cnx = system_source_cnx(source, True, special_privs=special_privs, verbose=verbose) |
120 cnx = system_source_cnx(source, True, special_privs=special_privs, |
|
121 verbose=verbose) |
127 # disable autocommit (isolation_level(1)) because DROP and |
122 # disable autocommit (isolation_level(1)) because DROP and |
128 # CREATE DATABASE can't be executed in a transaction |
123 # CREATE DATABASE can't be executed in a transaction |
129 try: |
124 try: |
130 cnx.set_isolation_level(0) |
125 cnx.set_isolation_level(0) |
131 except AttributeError: |
126 except AttributeError: |
192 CWCTL.run(['db-create', self.config.appid, '--verbose=%s' % verbosity]) |
187 CWCTL.run(['db-create', self.config.appid, '--verbose=%s' % verbosity]) |
193 else: |
188 else: |
194 print ('-> nevermind, you can do it later with ' |
189 print ('-> nevermind, you can do it later with ' |
195 '"cubicweb-ctl db-create %s".' % self.config.appid) |
190 '"cubicweb-ctl db-create %s".' % self.config.appid) |
196 |
191 |
|
192 ERROR = nullobject() |
|
193 |
|
194 def confirm_on_error_or_die(msg, func, *args, **kwargs): |
|
195 try: |
|
196 return func(*args, **kwargs) |
|
197 except Exception, ex: |
|
198 print 'ERROR', ex |
|
199 if not ASK.confirm('An error occurred while %s. Continue anyway?' % msg): |
|
200 raise ExecutionError(str(ex)) |
|
201 return ERROR |
197 |
202 |
198 class RepositoryDeleteHandler(CommandHandler): |
203 class RepositoryDeleteHandler(CommandHandler): |
199 cmdname = 'delete' |
204 cmdname = 'delete' |
200 cfgname = 'repository' |
205 cfgname = 'repository' |
201 |
206 |
205 source = self.config.sources()['system'] |
210 source = self.config.sources()['system'] |
206 dbname = source['db-name'] |
211 dbname = source['db-name'] |
207 helper = get_db_helper(source['db-driver']) |
212 helper = get_db_helper(source['db-driver']) |
208 if ASK.confirm('Delete database %s ?' % dbname): |
213 if ASK.confirm('Delete database %s ?' % dbname): |
209 if source['db-driver'] == 'sqlite': |
214 if source['db-driver'] == 'sqlite': |
210 os.unlink(source['db-name']) |
215 if confirm_on_error_or_die( |
|
216 'deleting database file %s' % dbname, |
|
217 os.unlink, source['db-name']) is not ERROR: |
|
218 print '-> database %s dropped.' % dbname |
211 return |
219 return |
212 user = source['db-user'] or None |
220 user = source['db-user'] or None |
213 cnx = _db_sys_cnx(source, 'DROP DATABASE', user=user) |
221 cnx = confirm_on_error_or_die('connecting to database %s' % dbname, |
|
222 _db_sys_cnx, source, 'DROP DATABASE', user=user) |
|
223 if cnx is ERROR: |
|
224 return |
214 cursor = cnx.cursor() |
225 cursor = cnx.cursor() |
215 try: |
226 try: |
216 cursor.execute('DROP DATABASE %s' % dbname) |
227 if confirm_on_error_or_die( |
217 print '-> database %s dropped.' % dbname |
228 'dropping database %s' % dbname, |
|
229 cursor.execute, 'DROP DATABASE "%s"' % dbname) is not ERROR: |
|
230 print '-> database %s dropped.' % dbname |
218 # XXX should check we are not connected as user |
231 # XXX should check we are not connected as user |
219 if user and helper.users_support and \ |
232 if user and helper.users_support and \ |
220 ASK.confirm('Delete user %s ?' % user, default_is_yes=False): |
233 ASK.confirm('Delete user %s ?' % user, default_is_yes=False): |
221 cursor.execute('DROP USER %s' % user) |
234 if confirm_on_error_or_die( |
222 print '-> user %s dropped.' % user |
235 'dropping user %s' % user, |
|
236 cursor.execute, 'DROP USER %s' % user) is not ERROR: |
|
237 print '-> user %s dropped.' % user |
223 cnx.commit() |
238 cnx.commit() |
224 except: |
239 except: |
225 cnx.rollback() |
240 cnx.rollback() |
226 raise |
241 raise |
227 |
242 |
311 ASK.confirm('Database %s already exists. Drop it?' % dbname)): |
326 ASK.confirm('Database %s already exists. Drop it?' % dbname)): |
312 os.unlink(dbname) |
327 os.unlink(dbname) |
313 elif self.config.create_db: |
328 elif self.config.create_db: |
314 print '\n'+underline_title('Creating the system database') |
329 print '\n'+underline_title('Creating the system database') |
315 # connect on the dbms system base to create our base |
330 # connect on the dbms system base to create our base |
316 dbcnx = _db_sys_cnx(source, 'CREATE DATABASE and / or USER', verbose=verbose) |
331 dbcnx = _db_sys_cnx(source, 'CREATE/DROP DATABASE and / or USER', verbose=verbose) |
317 cursor = dbcnx.cursor() |
332 cursor = dbcnx.cursor() |
318 try: |
333 try: |
319 if helper.users_support: |
334 if helper.users_support: |
320 user = source['db-user'] |
335 user = source['db-user'] |
321 if not helper.user_exists(cursor, user) and (automatic or \ |
336 if not helper.user_exists(cursor, user) and (automatic or \ |
331 dbcnx.commit() |
346 dbcnx.commit() |
332 print '-> database %s created.' % dbname |
347 print '-> database %s created.' % dbname |
333 except: |
348 except: |
334 dbcnx.rollback() |
349 dbcnx.rollback() |
335 raise |
350 raise |
336 cnx = system_source_cnx(source, special_privs='LANGUAGE C', verbose=verbose) |
351 cnx = system_source_cnx(source, special_privs='CREATE LANGUAGE', |
|
352 verbose=verbose) |
337 cursor = cnx.cursor() |
353 cursor = cnx.cursor() |
338 helper.init_fti_extensions(cursor) |
354 helper.init_fti_extensions(cursor) |
339 # postgres specific stuff |
355 # postgres specific stuff |
340 if driver == 'postgres': |
356 if driver == 'postgres': |
341 # install plpythonu/plpgsql language if not installed by the cube |
357 # install plpythonu/plpgsql language if not installed by the cube |