Esempio n. 1
0
 def cleanup(self):
     """remove instance's configuration and database"""
     source = self.config.system_source_config
     for msg, step, default in self._cleanup_steps(source):
         if ASK.confirm(msg, default_is_yes=default):
             try:
                 step(source)
             except Exception as exc:
                 print('ERROR', exc)
                 if ASK.confirm('An error occurred. Continue anyway?',
                                default_is_yes=False):
                     continue
                 raise ExecutionError(str(exc))
Esempio n. 2
0
def _remote_dump(host, appid, output, sudo=False):
    # XXX generate unique/portable file name
    from datetime import date
    filename = '%s-%s.tgz' % (appid, date.today().strftime('%Y-%m-%d'))
    dmpcmd = 'cubicweb-ctl db-dump -o /tmp/%s %s' % (filename, appid)
    if sudo:
        dmpcmd = 'sudo %s' % (dmpcmd)
    dmpcmd = 'ssh -t %s "%s"' % (host, dmpcmd)
    print(dmpcmd)
    if os.system(dmpcmd):
        raise ExecutionError('Error while dumping the database')
    if output is None:
        output = filename
    cmd = 'scp %s:/tmp/%s %s' % (host, filename, output)
    print(cmd)
    if os.system(cmd):
        raise ExecutionError('Error while retrieving the dump at /tmp/%s' %
                             filename)
    rmcmd = 'ssh -t %s "rm -f /tmp/%s"' % (host, filename)
    print(rmcmd)
    if os.system(rmcmd) and not ASK.confirm(
            'An error occurred while deleting remote dump at /tmp/%s. '
            'Continue anyway?' % filename):
        raise ExecutionError('Error while deleting remote dump at /tmp/%s' %
                             filename)
Esempio n. 3
0
 def run(self, args):
     check_options_consistency(self.config)
     print('\n' + underline_title('Initializing the system database'))
     from cubicweb.server import init_repository
     appid = args[0]
     config = ServerConfiguration.config_for(appid)
     try:
         system = config.system_source_config
         extra_args = system.get('db-extra-arguments')
         extra = extra_args and {'extra_args': extra_args} or {}
         get_connection(system['db-driver'],
                        database=system['db-name'],
                        host=system.get('db-host'),
                        port=system.get('db-port'),
                        user=system.get('db-user') or '',
                        password=system.get('db-password') or '',
                        schema=system.get('db-namespace'),
                        **extra)
     except Exception as ex:
         raise ConfigurationError(
             'You seem to have provided wrong connection information in '
             'the %s file. Resolve this first (error: %s).' %
             (config.sources_file(), str(ex).strip()))
     init_repository(config, drop=self.config.drop)
     if not self.config.automatic:
         while ASK.confirm('Enter another source ?', default_is_yes=False):
             CWCTL.run([
                 'source-add', '--config-level',
                 str(self.config.config_level), config.appid
             ])
Esempio n. 4
0
def show_diffs(appl_file, ref_file, askconfirm=True):
    """interactivly replace the old file with the new file according to
    user decision
    """
    import shutil
    pipe = subprocess.Popen(['diff', '-u', appl_file, ref_file], stdout=subprocess.PIPE)
    diffs = pipe.stdout.read().decode('utf-8')
    if diffs:
        if askconfirm:
            print()
            print(diffs)
            action = ASK.ask('Replace ?', ('Y', 'n', 'q'), 'Y').lower()
        else:
            action = 'y'
        if action == 'y':
            try:
                shutil.copyfile(ref_file, appl_file)
            except IOError:
                os.system('chmod a+w %s' % appl_file)
                shutil.copyfile(ref_file, appl_file)
            print('replaced')
        elif action == 'q':
            sys.exit(0)
        else:
            copy_file = appl_file + '.default'
            copy = open(copy_file, 'w')
            copy.write(open(ref_file).read())
            copy.close()
            print('keep current version, the new file has been written to', copy_file)
    else:
        print('no diff between %s and %s' % (appl_file, ref_file))
Esempio n. 5
0
def copy_skeleton(skeldir, targetdir, context,
                  exclude=SKEL_EXCLUDE, askconfirm=False):
    import shutil
    from fnmatch import fnmatch
    skeldir = normpath(skeldir)
    targetdir = normpath(targetdir)
    for dirpath, dirnames, filenames in walk(skeldir):
        tdirpath = dirpath.replace(skeldir, targetdir)
        if 'cubicweb_CUBENAME' in tdirpath:
            tdirpath = tdirpath.replace('cubicweb_CUBENAME',
                                        'cubicweb_' + context['cubename'])
        create_dir(tdirpath)
        for fname in filenames:
            if any(fnmatch(fname, pat) for pat in exclude):
                continue
            fpath = join(dirpath, fname)
            if 'CUBENAME' in fname:
                tfpath = join(tdirpath, fname.replace('CUBENAME', context['cubename']))
            elif 'DISTNAME' in fname:
                tfpath = join(tdirpath, fname.replace('DISTNAME', context['distname']))
            else:
                tfpath = join(tdirpath, fname)
            if fname.endswith('.tmpl'):
                tfpath = tfpath[:-5]
                if not askconfirm or not exists(tfpath) or \
                        ASK.confirm('%s exists, overwrite?' % tfpath):
                    fill_templated_file(fpath, tfpath, context)
                    print('[generate] %s <-- %s' % (tfpath, fpath))
            elif exists(tfpath):
                show_diffs(tfpath, fpath, askconfirm)
            else:
                shutil.copyfile(fpath, tfpath)
                shutil.copymode(fpath, tfpath)
Esempio n. 6
0
 def bootstrap(self, cubes, automatic=False, inputlevel=0):
     """bootstrap this configuration"""
     if not automatic:
         print('\n' + underline_title('Generic web configuration'))
         config = self.config
         config.input_config('web', inputlevel)
         if ASK.confirm('Allow anonymous access ?', False):
             config.global_set_option('anonymous-user', 'anon')
             config.global_set_option('anonymous-password', 'anon')
Esempio n. 7
0
 def postcreate(self, automatic=False, inputlevel=0):
     if automatic:
         CWCTL.run(['db-create', '--automatic', self.config.appid])
     elif ASK.confirm('Run db-create to create the system database ?'):
         CWCTL.run([
             'db-create', '--config-level',
             str(inputlevel), self.config.appid
         ])
     else:
         print('-> nevermind, you can do it later with '
               '"cubicweb-ctl db-create %s".' % self.config.appid)
Esempio n. 8
0
 def i18nupgrade(self, config):
     # handle i18n upgrade:
     # * install new languages
     # * recompile catalogs
     # XXX search available language in the first cube given
     from cubicweb import i18n
     templdir = cwcfg.cube_dir(config.cubes()[0])
     langs = [lang for lang, _ in i18n.available_catalogs(join(templdir, 'i18n'))]
     errors = config.i18ncompile(langs)
     if errors:
         print('\n'.join(errors))
         if not ASK.confirm('Error while compiling message catalogs, '
                            'continue anyway?'):
             print('-> migration not completed.')
             return False
     return True
Esempio n. 9
0
 def _ask_for_dependencies(self):
     from logilab.common.shellutils import ASK
     from logilab.common.textutils import splitstrip
     depcubes = []
     for cube in ServerConfiguration.available_cubes():
         answer = ASK.ask("Depends on cube %s? " % cube,
                          ('N', 'y', 'skip', 'type'), 'N')
         if answer == 'y':
             depcubes.append(cube)
         if answer == 'type':
             depcubes = splitstrip(input('type dependencies: '))
             break
         elif answer == 'skip':
             break
     return dict(
         ('cubicweb-' + cube, ServerConfiguration.cube_version(cube))
         for cube in depcubes)
Esempio n. 10
0
    def confirm(
            self,
            question,  # pylint: disable=E0202
            shell=True,
            abort=True,
            retry=False,
            pdb=False,
            default='y',
            traceback=None):
        """ask for confirmation and return true on positive answer

        if `retry` is true the r[etry] answer may return 2
        """
        possibleanswers = ['y', 'n']
        if abort:
            possibleanswers.append('abort')
        if pdb:
            possibleanswers.append('pdb')
        if shell:
            possibleanswers.append('shell')
        if retry:
            possibleanswers.append('retry')
        try:
            answer = ASK.ask(question, possibleanswers, default)
        except (EOFError, KeyboardInterrupt):
            answer = 'abort'
        if answer == 'n':
            return False
        if answer == 'retry':
            return 2
        if answer == 'abort':
            raise SystemExit(1)
        if answer == 'shell':
            self.interactive_shell()
            return self.confirm(question, shell, abort, retry, pdb, default,
                                traceback)
        if answer == 'pdb':
            pdb = utils.get_pdb()
            if traceback:
                pdb.post_mortem(traceback)
            else:
                pdb.set_trace()
            return self.confirm(question, shell, abort, retry, pdb, default,
                                traceback)
        return True
Esempio n. 11
0
def execscript_confirm(scriptpath):
    """asks for confirmation before executing a script and provides the
    ability to show the script's content
    """
    while True:
        answer = ASK.ask('Execute %r ?' % scriptpath,
                         ('Y', 'n', 'show', 'abort'), 'Y')
        if answer == 'abort':
            raise SystemExit(1)
        elif answer == 'n':
            return False
        elif answer == 'show':
            stream = open(scriptpath)
            scriptcontent = stream.read()
            stream.close()
            print()
            print(scriptcontent)
            print()
        else:
            return True
Esempio n. 12
0
    def generate_static_dir(self,
                            config,
                            dest=None,
                            ask_clean=False,
                            repo=None):
        if not dest:
            dest = config['staticdir-path']
        if not dest:
            dest = osp.join(config.appdatahome, 'data')
        if osp.exists(dest):
            if (config.verbosity and
                (not ask_clean or not (config.verbosity and ASK.confirm(
                    'Remove existing data directory %s?' % dest)))):
                raise ExecutionError('Directory %s already exists. '
                                     'Remove it first.' % dest)
            rmtreecontent(dest)
        config.quick_start = True  # notify this is not a regular start
        # list all resources (no matter their order)
        resources = set()
        for datadir in self._datadirs(config, repo=repo):
            for dirpath, dirnames, filenames in os.walk(datadir):
                rel_dirpath = dirpath[len(datadir) + 1:]
                resources.update(osp.join(rel_dirpath, f) for f in filenames)

        # locate resources and copy them to destination
        for resource in resources:
            dest_resource = osp.join(dest, resource)
            dirname = osp.dirname(dest_resource)
            if not osp.isdir(dirname):
                os.makedirs(dirname)
            resource_dir, resource_path = config.locate_resource(resource)
            copy(osp.join(resource_dir, resource_path), dest_resource)
        # handle md5 version subdirectory
        linkdir(dest, osp.join(dest, config.instance_md5_version()))
        # ensure generated files are owned by configured uid
        config.ensure_uid_directory(dest)
        print('You can use apache rewrite rule below :\n'
              'RewriteRule ^/data/(.*) %s/$1 [L]' % dest)
Esempio n. 13
0
    commit()
    drop_relation_definition('CWUniqueTogetherConstraint', 'relations',
                             'CWAttribute')
    drop_relation_definition('CWUniqueTogetherConstraint', 'relations',
                             'CWRelation')

if applcubicwebversion < (3, 5, 0) and cubicwebversion >= (3, 5, 0):
    # check that migration is not doomed
    rset = rql(
        'Any X,Y WHERE X transition_of E, Y transition_of E, '
        'X name N, Y name N, NOT X identity Y',
        ask_confirm=False)
    if rset:
        from logilab.common.shellutils import ASK
        if not ASK.confirm(
                'Migration will fail because of transitions with the same name. '
                'Continue anyway ?'):
            import sys
            sys.exit(1)
    # proceed with migration
    add_entity_type('Workflow')
    add_entity_type('BaseTransition')
    add_entity_type('WorkflowTransition')
    add_entity_type('SubWorkflowExitPoint')
    # drop explicit 'State allowed_transition Transition' since it should be
    # infered due to yams inheritance.  However we've to disable the schema
    # sync hook first to avoid to destroy existing data...
    try:
        from cubicweb.hooks import syncschema
        repo.vreg.unregister(syncschema.AfterDelRelationTypeHook)
        try:
Esempio n. 14
0
 def run(self, args):
     import re
     from logilab.common.shellutils import ASK
     cubename = args[0]
     if not re.match('[_A-Za-z][_A-Za-z0-9]*$', cubename):
         raise BadCommandUsage(
             'cube name must be a valid python module name')
     verbose = self.get('verbose')
     destdir = self.get('directory')
     if not destdir:
         destdir = getcwd()
     elif not osp.isdir(destdir):
         print("-> creating cubes directory", destdir)
         try:
             mkdir(destdir)
         except OSError as err:
             self.fail("failed to create directory %r\n(%s)" %
                       (destdir, err))
     default_name = 'cubicweb-%s' % cubename.lower().replace('_', '-')
     if verbose:
         distname = input('Debian name for your cube ? [%s]): ' %
                          default_name).strip()
         if not distname:
             distname = default_name
         elif not distname.startswith('cubicweb-'):
             if ASK.confirm('Do you mean cubicweb-%s ?' % distname):
                 distname = 'cubicweb-' + distname
     else:
         distname = default_name
     if not re.match('[a-z][-a-z0-9]*$', distname):
         raise BadCommandUsage(
             'cube distname should be a valid debian package name')
     cubedir = osp.join(destdir, distname)
     if osp.exists(cubedir):
         self.fail("%s already exists!" % cubedir)
     skeldir = osp.join(BASEDIR, 'skeleton')
     longdesc = shortdesc = self['short-description'] or input(
         'Enter a short description for your cube: ')
     if verbose:
         longdesc = input(
             'Enter a long description (leave empty to reuse the short one): '
         )
     dependencies = {
         'cubicweb': '>= %s' % cubicwebversion,
     }
     if verbose:
         dependencies.update(self._ask_for_dependencies())
     context = {
         'cubename': cubename,
         'distname': distname,
         'shortdesc': shortdesc,
         'longdesc': longdesc or shortdesc,
         'dependencies': dependencies,
         'version': cubicwebversion,
         'year': str(date.today().year),
         'author': self['author'],
         'author-email': self['author-email'],
         'rfc2822-date':
         datetime.now(tz=UTC).strftime('%a, %d %b %Y %T %z'),
         'author-web-site': self['author-web-site'],
         'license': self['license'],
         'long-license': self.LICENSES[self['license']],
     }
     exclude = SKEL_EXCLUDE
     if self['layout'] == 'simple':
         exclude += ('sobjects.py*', 'precreate.py*', 'realdb_test*',
                     'cubes.*', 'uiprops.py*')
     copy_skeleton(skeldir, cubedir, context, exclude=exclude)
Esempio n. 15
0
 def run(self, args):
     """run the command with its specific arguments"""
     from logilab.common.textutils import splitstrip
     check_options_consistency(self.config)
     configname = self.config.config
     cubes, appid = args
     cubes = splitstrip(cubes)
     # get the configuration and helper
     config = cwcfg.config_for(appid, configname, creating=True)
     cubes = config.expand_cubes(cubes)
     config.init_cubes(cubes)
     helper = self.config_helper(config)
     # check the cube exists
     try:
         templdirs = [cwcfg.cube_dir(cube)
                      for cube in cubes]
     except ConfigurationError as ex:
         print(ex)
         print('\navailable cubes:', end=' ')
         print(', '.join(available_cube_names(cwcfg)))
         return
     # create the registry directory for this instance
     print('\n' + underline_title('Creating the instance %s' % appid))
     create_dir(config.apphome)
     # cubicweb-ctl configuration
     if not self.config.automatic:
         print('\n' + underline_title('Configuring the instance (%s.conf)'
                                      % configname))
         config.input_config('main', self.config.config_level)
     # configuration'specific stuff
     print()
     helper.bootstrap(cubes, self.config.automatic, self.config.config_level)
     # input for cubes specific options
     if not self.config.automatic:
         sections = set(sect.lower() for sect, opt, odict in config.all_options()
                        if 'type' in odict
                        and odict.get('level', 0) <= self.config.config_level)
         for section in sections:
             if section not in ('main', 'email', 'web'):
                 print('\n' + underline_title('%s options' % section))
                 config.input_config(section, self.config.config_level)
     # write down configuration
     config.save()
     print('-> generated config %s' % config.main_config_file())
     # handle i18n files structure
     # in the first cube given
     from cubicweb import i18n
     langs = [lang for lang, _ in i18n.available_catalogs(join(templdirs[0], 'i18n'))]
     errors = config.i18ncompile(langs)
     if errors:
         print('\n'.join(errors))
         if self.config.automatic \
             or not ASK.confirm('error while compiling message catalogs, '
                                'continue anyway ?'):
             print('creation not completed')
             return
     # create the additional data directory for this instance
     if config.appdatahome != config.apphome:  # true in dev mode
         create_dir(config.appdatahome)
     create_dir(join(config.appdatahome, 'backup'))
     if config['uid']:
         from logilab.common.shellutils import chown
         # this directory should be owned by the uid of the server process
         print('set %s as owner of the data directory' % config['uid'])
         chown(config.appdatahome, config['uid'])
     print('\n-> creation done for %s\n' % repr(config.apphome)[1:-1])
     if not self.config.no_db_create:
         helper.postcreate(self.config.automatic, self.config.config_level)
Esempio n. 16
0
 def run(self, args):
     """run the command with its specific arguments"""
     check_options_consistency(self.config)
     automatic = self.get('automatic')
     appid = args.pop()
     config = ServerConfiguration.config_for(appid)
     source = config.system_source_config
     dbname = source['db-name']
     driver = source['db-driver']
     helper = get_db_helper(driver)
     if driver == 'sqlite':
         if os.path.exists(dbname) and (automatic or ASK.confirm(
                 'Database %s already exists. Drop it?' % dbname)):
             os.unlink(dbname)
     elif self.config.create_db:
         print('\n' + underline_title('Creating the system database'))
         # connect on the dbms system base to create our base
         dbcnx = _db_sys_cnx(source,
                             'CREATE/DROP DATABASE and / or USER',
                             interactive=not automatic)
         cursor = dbcnx.cursor()
         try:
             if helper.users_support:
                 user = source['db-user']
                 if not helper.user_exists(cursor, user) and (
                         automatic
                         or ASK.confirm('Create db user %s ?' % user,
                                        default_is_yes=False)):
                     helper.create_user(source['db-user'],
                                        source.get('db-password'))
                     print('-> user %s created.' % user)
             if dbname in helper.list_databases(cursor):
                 if automatic or ASK.confirm(
                         'Database %s already exists -- '
                         'do you want to drop it ?' % dbname):
                     cursor.execute('DROP DATABASE "%s"' % dbname)
                 else:
                     print('you may want to run "cubicweb-ctl db-init '
                           '--drop %s" manually to continue.' %
                           config.appid)
                     return
             createdb(helper, source, dbcnx, cursor)
             dbcnx.commit()
             print('-> database %s created.' % dbname)
         except BaseException:
             dbcnx.rollback()
             raise
     cnx = system_source_cnx(source,
                             special_privs='CREATE LANGUAGE/SCHEMA',
                             interactive=not automatic)
     cursor = cnx.cursor()
     helper.init_fti_extensions(cursor)
     namespace = source.get('db-namespace')
     if namespace and ASK.confirm('Create schema %s in database %s ?' %
                                  (namespace, dbname)):
         helper.create_schema(cursor, namespace)
     cnx.commit()
     # postgres specific stuff
     if driver == 'postgres':
         # install plpythonu/plpgsql languages
         langs = ('plpythonu', 'plpgsql')
         for extlang in langs:
             if automatic or ASK.confirm('Create language %s ?' % extlang):
                 try:
                     helper.create_language(cursor, extlang)
                 except Exception as exc:
                     print('-> ERROR:', exc)
                     print('-> could not create language %s, '
                           'some stored procedures might be unusable' %
                           extlang)
                     cnx.rollback()
                 else:
                     cnx.commit()
     print(
         '-> database for instance %s created and necessary extensions installed.'
         % appid)
     print()
     if automatic:
         CWCTL.run([
             'db-init', '--automatic', '--config-level', '0', config.appid
         ])
     elif ASK.confirm('Run db-init to initialize the system database ?'):
         CWCTL.run([
             'db-init', '--config-level',
             str(self.config.config_level), config.appid
         ])
     else:
         print('-> nevermind, you can do it later with '
               '"cubicweb-ctl db-init %s".' % config.appid)