toolsutils.py
author Julien Cristau <julien.cristau@logilab.fr>
Mon, 12 Oct 2015 18:42:38 +0200
changeset 10782 65bb683d2a51
parent 10688 fa29f3628a1b
child 10966 8909593f46d4
permissions -rw-r--r--
[web/test] Binary eats bytes
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
7879
9aae456abab5 [pylint] fix pylint detected errors and tweak it so that pylint -E will be much less verbose next time (+ update some copyrights on the way)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7301
diff changeset
     1
# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
5421
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5324
diff changeset
     2
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5324
diff changeset
     3
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5324
diff changeset
     4
# This file is part of CubicWeb.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5324
diff changeset
     5
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5324
diff changeset
     6
# CubicWeb is free software: you can redistribute it and/or modify it under the
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5324
diff changeset
     7
# terms of the GNU Lesser General Public License as published by the Free
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5324
diff changeset
     8
# Software Foundation, either version 2.1 of the License, or (at your option)
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5324
diff changeset
     9
# any later version.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5324
diff changeset
    10
#
5424
8ecbcbff9777 replace logilab-common by CubicWeb in disclaimer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5421
diff changeset
    11
# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
5421
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5324
diff changeset
    12
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5324
diff changeset
    13
# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5324
diff changeset
    14
# details.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5324
diff changeset
    15
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5324
diff changeset
    16
# You should have received a copy of the GNU Lesser General Public License along
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5324
diff changeset
    17
# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
6138
65f5e488f983 update to lgc.clcommands 0.51 api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5426
diff changeset
    18
"""some utilities for cubicweb command line tools"""
10589
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10331
diff changeset
    19
from __future__ import print_function
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    20
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    21
__docformat__ = "restructuredtext en"
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    22
2397
cdedc2a32b06 [shell] move toolsutils.confirm() to logilab.common.shellutils
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 2395
diff changeset
    23
# XXX move most of this in logilab.common (shellutils ?)
cdedc2a32b06 [shell] move toolsutils.confirm() to logilab.common.shellutils
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 2395
diff changeset
    24
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    25
import os, sys
4554
2279ba039494 use subprocess instead of os.popen to run diff
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 4212
diff changeset
    26
import subprocess
3115
29262ba01464 minimal steps to have cw running on windows
Aurélien Campéas
parents: 2615
diff changeset
    27
from os import listdir, makedirs, environ, chmod, walk, remove
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    28
from os.path import exists, join, abspath, normpath
9740
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
    29
import re
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
    30
from rlcompleter import Completer
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
    31
try:
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
    32
    import readline
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
    33
except ImportError: # readline not available, no completion
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
    34
    pass
3115
29262ba01464 minimal steps to have cw running on windows
Aurélien Campéas
parents: 2615
diff changeset
    35
try:
29262ba01464 minimal steps to have cw running on windows
Aurélien Campéas
parents: 2615
diff changeset
    36
    from os import symlink
29262ba01464 minimal steps to have cw running on windows
Aurélien Campéas
parents: 2615
diff changeset
    37
except ImportError:
29262ba01464 minimal steps to have cw running on windows
Aurélien Campéas
parents: 2615
diff changeset
    38
    def symlink(*args):
29262ba01464 minimal steps to have cw running on windows
Aurélien Campéas
parents: 2615
diff changeset
    39
        raise NotImplementedError
29262ba01464 minimal steps to have cw running on windows
Aurélien Campéas
parents: 2615
diff changeset
    40
10688
fa29f3628a1b [py3k] use six.add_metaclass
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10614
diff changeset
    41
from six import add_metaclass
fa29f3628a1b [py3k] use six.add_metaclass
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10614
diff changeset
    42
6138
65f5e488f983 update to lgc.clcommands 0.51 api
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5426
diff changeset
    43
from logilab.common.clcommands import Command as BaseCommand
2615
1ea41b7c0836 F [dialog] offer to create backup. refactor to use l.c.shellutils.ASK
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 2476
diff changeset
    44
from logilab.common.shellutils import ASK
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    45
7879
9aae456abab5 [pylint] fix pylint detected errors and tweak it so that pylint -E will be much less verbose next time (+ update some copyrights on the way)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7301
diff changeset
    46
from cubicweb import warning # pylint: disable=E0611
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    47
from cubicweb import ConfigurationError, ExecutionError
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    48
2790
968108e16066 move underline_title to toolsutils
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2615
diff changeset
    49
def underline_title(title, car='-'):
968108e16066 move underline_title to toolsutils
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2615
diff changeset
    50
    return title+'\n'+(car*len(title))
968108e16066 move underline_title to toolsutils
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2615
diff changeset
    51
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    52
def iter_dir(directory, condition_file=None, ignore=()):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    53
    """iterate on a directory"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    54
    for sub in listdir(directory):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    55
        if sub in ('CVS', '.svn', '.hg'):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    56
            continue
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    57
        if condition_file is not None and \
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    58
               not exists(join(directory, sub, condition_file)):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    59
            continue
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    60
        if sub in ignore:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    61
            continue
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    62
        yield sub
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    63
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    64
def create_dir(directory):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    65
    """create a directory if it doesn't exist yet"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    66
    try:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    67
        makedirs(directory)
10589
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10331
diff changeset
    68
        print('-> created directory %s' % directory)
8695
358d8bed9626 [toward-py3k] rewrite to "except AnException as exc:" (part of #2711624)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 7896
diff changeset
    69
    except OSError as ex:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    70
        import errno
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    71
        if ex.errno != errno.EEXIST:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    72
            raise
10589
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10331
diff changeset
    73
        print('-> no need to create existing directory %s' % directory)
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1138
diff changeset
    74
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    75
def create_symlink(source, target):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    76
    """create a symbolic link"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    77
    if exists(target):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    78
        remove(target)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    79
    symlink(source, target)
10589
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10331
diff changeset
    80
    print('[symlink] %s <-- %s' % (target, source))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    81
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    82
def create_copy(source, target):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    83
    import shutil
10589
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10331
diff changeset
    84
    print('[copy] %s <-- %s' % (target, source))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    85
    shutil.copy2(source, target)
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1138
diff changeset
    86
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    87
def rm(whatever):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    88
    import shutil
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    89
    shutil.rmtree(whatever)
10589
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10331
diff changeset
    90
    print('-> removed %s' % whatever)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    91
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    92
def show_diffs(appl_file, ref_file, askconfirm=True):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    93
    """interactivly replace the old file with the new file according to
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    94
    user decision
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    95
    """
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    96
    import shutil
4554
2279ba039494 use subprocess instead of os.popen to run diff
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 4212
diff changeset
    97
    pipe = subprocess.Popen(['diff', '-u', appl_file, ref_file], stdout=subprocess.PIPE)
2279ba039494 use subprocess instead of os.popen to run diff
Alexandre Fayolle <alexandre.fayolle@logilab.fr>
parents: 4212
diff changeset
    98
    diffs = pipe.stdout.read()
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    99
    if diffs:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   100
        if askconfirm:
10589
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10331
diff changeset
   101
            print()
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10331
diff changeset
   102
            print(diffs)
5324
449cc4fa9c42 [migration] makes Yes the default answer to replace configuration file
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4721
diff changeset
   103
            action = ASK.ask('Replace ?', ('Y', 'n', 'q'), 'Y').lower()
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   104
        else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   105
            action = 'y'
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   106
        if action == 'y':
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   107
            try:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   108
                shutil.copyfile(ref_file, appl_file)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   109
            except IOError:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   110
                os.system('chmod a+w %s' % appl_file)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   111
                shutil.copyfile(ref_file, appl_file)
10589
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10331
diff changeset
   112
            print('replaced')
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   113
        elif action == 'q':
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   114
            sys.exit(0)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   115
        else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   116
            copy_file = appl_file + '.default'
10614
57dfde80df11 [py3k] file → open
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10591
diff changeset
   117
            copy = open(copy_file, 'w')
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   118
            copy.write(open(ref_file).read())
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   119
            copy.close()
10589
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10331
diff changeset
   120
            print('keep current version, the new file has been written to', copy_file)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   121
    else:
10589
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10331
diff changeset
   122
        print('no diff between %s and %s' % (appl_file, ref_file))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   123
5184
955ee1b24756 [c-c newcube] #1192: simpler cubicweb-ctl newcube, and more
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5021
diff changeset
   124
SKEL_EXCLUDE = ('*.py[co]', '*.orig', '*~', '*_flymake.py')
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   125
def copy_skeleton(skeldir, targetdir, context,
5184
955ee1b24756 [c-c newcube] #1192: simpler cubicweb-ctl newcube, and more
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5021
diff changeset
   126
                  exclude=SKEL_EXCLUDE, askconfirm=False):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   127
    import shutil
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   128
    from fnmatch import fnmatch
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   129
    skeldir = normpath(skeldir)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   130
    targetdir = normpath(targetdir)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   131
    for dirpath, dirnames, filenames in walk(skeldir):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   132
        tdirpath = dirpath.replace(skeldir, targetdir)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   133
        create_dir(tdirpath)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   134
        for fname in filenames:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   135
            if any(fnmatch(fname, pat) for pat in exclude):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   136
                continue
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   137
            fpath = join(dirpath, fname)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   138
            if 'CUBENAME' in fname:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   139
                tfpath = join(tdirpath, fname.replace('CUBENAME', context['cubename']))
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   140
            elif 'DISTNAME' in fname:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   141
                tfpath = join(tdirpath, fname.replace('DISTNAME', context['distname']))
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   142
            else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   143
                tfpath = join(tdirpath, fname)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   144
            if fname.endswith('.tmpl'):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   145
                tfpath = tfpath[:-5]
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   146
                if not askconfirm or not exists(tfpath) or \
2615
1ea41b7c0836 F [dialog] offer to create backup. refactor to use l.c.shellutils.ASK
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 2476
diff changeset
   147
                       ASK.confirm('%s exists, overwrite?' % tfpath):
1138
22f634977c95 make pylint happy, fix some bugs on the way
sylvain.thenault@logilab.fr
parents: 1132
diff changeset
   148
                    fill_templated_file(fpath, tfpath, context)
10589
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10331
diff changeset
   149
                    print('[generate] %s <-- %s' % (tfpath, fpath))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   150
            elif exists(tfpath):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   151
                show_diffs(tfpath, fpath, askconfirm)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   152
            else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   153
                shutil.copyfile(fpath, tfpath)
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1138
diff changeset
   154
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   155
def fill_templated_file(fpath, tfpath, context):
10614
57dfde80df11 [py3k] file → open
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10591
diff changeset
   156
    fobj = open(tfpath, 'w')
57dfde80df11 [py3k] file → open
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10591
diff changeset
   157
    templated = open(fpath).read()
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   158
    fobj.write(templated % context)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   159
    fobj.close()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   160
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   161
def restrict_perms_to_user(filepath, log=None):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   162
    """set -rw------- permission on the given file"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   163
    if log:
7155
4bab50b02927 [cwctl] refactor ui messages aiming for consistency and simplicity
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 6495
diff changeset
   164
        log('set permissions to 0600 for %s', filepath)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   165
    else:
10589
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10331
diff changeset
   166
        print('-> set permissions to 0600 for %s' % filepath)
10591
8e46ed1a0b8a [py3k] octals and long
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10589
diff changeset
   167
    chmod(filepath, 0o600)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   168
7301
93e96700e0c0 [configuration] exit with proper message when sources file is unreadable (you usually started cw while logged with a wrong user). Closes #1631238
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7155
diff changeset
   169
def read_config(config_file, raise_if_unreadable=False):
93e96700e0c0 [configuration] exit with proper message when sources file is unreadable (you usually started cw while logged with a wrong user). Closes #1631238
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7155
diff changeset
   170
    """read some simple configuration from `config_file` and return it as a
93e96700e0c0 [configuration] exit with proper message when sources file is unreadable (you usually started cw while logged with a wrong user). Closes #1631238
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7155
diff changeset
   171
    dictionary. If `raise_if_unreadable` is false (the default), an empty
93e96700e0c0 [configuration] exit with proper message when sources file is unreadable (you usually started cw while logged with a wrong user). Closes #1631238
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7155
diff changeset
   172
    dictionary will be returned if the file is inexistant or unreadable, else
93e96700e0c0 [configuration] exit with proper message when sources file is unreadable (you usually started cw while logged with a wrong user). Closes #1631238
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7155
diff changeset
   173
    :exc:`ExecutionError` will be raised.
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   174
    """
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   175
    from logilab.common.fileutils import lines
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   176
    config = current = {}
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   177
    try:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   178
        for line in lines(config_file, comments='#'):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   179
            try:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   180
                option, value = line.split('=', 1)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   181
            except ValueError:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   182
                option = line.strip().lower()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   183
                if option[0] == '[':
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   184
                    # start a section
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   185
                    section = option[1:-1]
8697
574bb05e40a4 [toward py3k] rewrite has_key() (part of #2711624)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 8695
diff changeset
   186
                    assert section not in config, \
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   187
                           'Section %s is defined more than once' % section
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   188
                    config[section] = current = {}
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   189
                    continue
7896
4c954e1e73ef [lint] remove uses of "print >> sys.stderr" (closes #1908571)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 7879
diff changeset
   190
                sys.stderr.write('ignoring malformed line\n%r\n' % line)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   191
                continue
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   192
            option = option.strip().replace(' ', '_')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   193
            value = value.strip()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   194
            current[option] = value or None
8695
358d8bed9626 [toward-py3k] rewrite to "except AnException as exc:" (part of #2711624)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 7896
diff changeset
   195
    except IOError as ex:
7301
93e96700e0c0 [configuration] exit with proper message when sources file is unreadable (you usually started cw while logged with a wrong user). Closes #1631238
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7155
diff changeset
   196
        if raise_if_unreadable:
93e96700e0c0 [configuration] exit with proper message when sources file is unreadable (you usually started cw while logged with a wrong user). Closes #1631238
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7155
diff changeset
   197
            raise ExecutionError('%s. Are you logged with the correct user '
93e96700e0c0 [configuration] exit with proper message when sources file is unreadable (you usually started cw while logged with a wrong user). Closes #1631238
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7155
diff changeset
   198
                                 'to use this instance?' % ex)
93e96700e0c0 [configuration] exit with proper message when sources file is unreadable (you usually started cw while logged with a wrong user). Closes #1631238
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7155
diff changeset
   199
        else:
93e96700e0c0 [configuration] exit with proper message when sources file is unreadable (you usually started cw while logged with a wrong user). Closes #1631238
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7155
diff changeset
   200
            warning('missing or non readable configuration file %s (%s)',
93e96700e0c0 [configuration] exit with proper message when sources file is unreadable (you usually started cw while logged with a wrong user). Closes #1631238
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7155
diff changeset
   201
                    config_file, ex)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   202
    return config
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   203
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   204
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   205
_HDLRS = {}
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   206
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   207
class metacmdhandler(type):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   208
    def __new__(mcs, name, bases, classdict):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   209
        cls = super(metacmdhandler, mcs).__new__(mcs, name, bases, classdict)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   210
        if getattr(cls, 'cfgname', None) and getattr(cls, 'cmdname', None):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   211
            _HDLRS.setdefault(cls.cmdname, []).append(cls)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   212
        return cls
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   213
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   214
10688
fa29f3628a1b [py3k] use six.add_metaclass
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10614
diff changeset
   215
@add_metaclass(metacmdhandler)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   216
class CommandHandler(object):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   217
    """configuration specific helper for cubicweb-ctl commands"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   218
    def __init__(self, config):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   219
        self.config = config
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   220
10688
fa29f3628a1b [py3k] use six.add_metaclass
Rémi Cardona <remi.cardona@logilab.fr>
parents: 10614
diff changeset
   221
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   222
class Command(BaseCommand):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   223
    """base class for cubicweb-ctl commands"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   224
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   225
    def config_helper(self, config, required=True, cmdname=None):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   226
        if cmdname is None:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   227
            cmdname = self.name
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   228
        for helpercls in _HDLRS.get(cmdname, ()):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   229
            if helpercls.cfgname == config.name:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   230
                return helpercls(config)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   231
        if config.name == 'all-in-one':
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   232
            for helpercls in _HDLRS.get(cmdname, ()):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   233
                if helpercls.cfgname == 'repository':
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   234
                    return helpercls(config)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   235
        if required:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   236
            msg = 'No helper for command %s using %s configuration' % (
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   237
                cmdname, config.name)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   238
            raise ConfigurationError(msg)
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1138
diff changeset
   239
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   240
    def fail(self, reason):
10589
7c23b7de2b8d [py3k] print function
Samuel Trégouët <samuel.tregouet@logilab.fr>
parents: 10331
diff changeset
   241
        print("command failed:", reason)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   242
        sys.exit(1)
1802
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1138
diff changeset
   243
d628defebc17 delete-trailing-whitespace + some copyright update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1138
diff changeset
   244
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   245
CONNECT_OPTIONS = (
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   246
    ("user",
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   247
     {'short': 'u', 'type' : 'string', 'metavar': '<user>',
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   248
      'help': 'connect as <user> instead of being prompted to give it.',
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   249
      }
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   250
     ),
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   251
    ("password",
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   252
     {'short': 'p', 'type' : 'password', 'metavar': '<password>',
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   253
      'help': 'automatically give <password> for authentication instead of \
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   254
being prompted to give it.',
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   255
      }),
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   256
    ("host",
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   257
     {'short': 'H', 'type' : 'string', 'metavar': '<hostname>',
541
0d75cfe50f83 fix default value of pyro ns host
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 0
diff changeset
   258
      'default': None,
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   259
      'help': 'specify the name server\'s host name. Will be detected by \
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   260
broadcast if not provided.',
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   261
      }),
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   262
    )
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   263
9740
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   264
## cwshell helpers #############################################################
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   265
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   266
class AbstractMatcher(object):
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   267
    """Abstract class for CWShellCompleter's matchers.
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   268
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   269
    A matcher should implement a ``possible_matches`` method. This
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   270
    method has to return the list of possible completions for user's input.
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   271
    Because of the python / readline interaction, each completion should
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   272
    be a superset of the user's input.
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   273
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   274
    NOTE: readline tokenizes user's input and only passes last token to
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   275
    completers.
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   276
    """
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   277
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   278
    def possible_matches(self, text):
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   279
        """return possible completions for user's input.
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   280
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   281
        Parameters:
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   282
            text: the user's input
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   283
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   284
        Return:
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   285
            a list of completions. Each completion includes the original input.
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   286
        """
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   287
        raise NotImplementedError()
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   288
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   289
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   290
class RQLExecuteMatcher(AbstractMatcher):
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   291
    """Custom matcher for rql queries.
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   292
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   293
    If user's input starts with ``rql(`` or ``session.execute(`` and
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   294
    the corresponding rql query is incomplete, suggest some valid completions.
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   295
    """
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   296
    query_match_rgx = re.compile(
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   297
        r'(?P<func_prefix>\s*(?:rql)'  # match rql, possibly indented
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   298
        r'|'                           # or
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   299
        r'\s*(?:\w+\.execute))'        # match .execute, possibly indented
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   300
        # end of <func_prefix>
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   301
        r'\('                          # followed by a parenthesis
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   302
        r'(?P<quote_delim>["\'])'      # a quote or double quote
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   303
        r'(?P<parameters>.*)')         # and some content
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   304
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   305
    def __init__(self, local_ctx, req):
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   306
        self.local_ctx = local_ctx
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   307
        self.req = req
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   308
        self.schema = req.vreg.schema
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   309
        self.rsb = req.vreg['components'].select('rql.suggestions', req)
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   310
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   311
    @staticmethod
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   312
    def match(text):
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   313
        """check if ``text`` looks like a call to ``rql`` or ``session.execute``
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   314
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   315
        Parameters:
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   316
            text: the user's input
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   317
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   318
        Returns:
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   319
            None if it doesn't match, the query structure otherwise.
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   320
        """
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   321
        query_match = RQLExecuteMatcher.query_match_rgx.match(text)
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   322
        if query_match is None:
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   323
            return None
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   324
        parameters_text = query_match.group('parameters')
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   325
        quote_delim = query_match.group('quote_delim')
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   326
        # first parameter is fully specified, no completion needed
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   327
        if re.match(r"(.*?)%s" % quote_delim, parameters_text) is not None:
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   328
            return None
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   329
        func_prefix = query_match.group('func_prefix')
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   330
        return {
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   331
            # user's input
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   332
            'text': text,
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   333
            # rql( or session.execute(
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   334
            'func_prefix': func_prefix,
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   335
            # offset of rql query
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   336
            'rql_offset': len(func_prefix) + 2,
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   337
            # incomplete rql query
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   338
            'rql_query': parameters_text,
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   339
            }
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   340
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   341
    def possible_matches(self, text):
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   342
        """call ``rql.suggestions`` component to complete user's input.
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   343
        """
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   344
        # readline will only send last token, but we need the entire user's input
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   345
        user_input = readline.get_line_buffer()
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   346
        query_struct = self.match(user_input)
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   347
        if query_struct is None:
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   348
            return []
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   349
        else:
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   350
            # we must only send completions of the last token => compute where it
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   351
            # starts relatively to the rql query itself.
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   352
            completion_offset = readline.get_begidx() - query_struct['rql_offset']
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   353
            rql_query = query_struct['rql_query']
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   354
            return [suggestion[completion_offset:]
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   355
                    for suggestion in self.rsb.build_suggestions(rql_query)]
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   356
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   357
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   358
class DefaultMatcher(AbstractMatcher):
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   359
    """Default matcher: delegate to standard's `rlcompleter.Completer`` class
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   360
    """
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   361
    def __init__(self, local_ctx):
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   362
        self.completer = Completer(local_ctx)
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   363
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   364
    def possible_matches(self, text):
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   365
        if "." in text:
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   366
            return self.completer.attr_matches(text)
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   367
        else:
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   368
            return self.completer.global_matches(text)
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   369
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   370
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   371
class CWShellCompleter(object):
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   372
    """Custom auto-completion helper for cubicweb-ctl shell.
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   373
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   374
    ``CWShellCompleter`` provides a ``complete`` method suitable for
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   375
    ``readline.set_completer``.
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   376
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   377
    Attributes:
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   378
        matchers: the list of ``AbstractMatcher`` instances that will suggest
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   379
                  possible completions
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   380
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   381
    The completion process is the following:
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   382
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   383
    - readline calls the ``complete`` method with user's input,
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   384
    - the ``complete`` method asks for each known matchers if
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   385
      it can suggest completions for user's input.
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   386
    """
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   387
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   388
    def __init__(self, local_ctx):
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   389
        # list of matchers to ask for possible matches on completion
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   390
        self.matchers = [DefaultMatcher(local_ctx)]
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   391
        self.matchers.insert(0, RQLExecuteMatcher(local_ctx, local_ctx['session']))
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   392
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   393
    def complete(self, text, state):
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   394
        """readline's completer method
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   395
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   396
        cf http://docs.python.org/2/library/readline.html#readline.set_completer
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   397
        for more details.
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   398
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   399
        Implementation inspired by `rlcompleter.Completer`
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   400
        """
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   401
        if state == 0:
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   402
            # reset self.matches
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   403
            self.matches = []
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   404
            for matcher in self.matchers:
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   405
                matches = matcher.possible_matches(text)
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   406
                if matches:
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   407
                    self.matches = matches
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   408
                    break
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   409
            else:
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   410
                return None # no matcher able to handle `text`
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   411
        try:
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   412
            return self.matches[state]
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   413
        except IndexError:
c0239d8ae742 [shell] provide autocompletion for rql queries in cubicweb-ctl shell (closes #3560541)
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 8697
diff changeset
   414
            return None