summaryrefslogtreecommitdiff
path: root/cad/src/processes/Plugins.py
blob: bfb3ebfbcd4bb1512e0d7e01203b214579e200b4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# Copyright 2004-2007 Nanorex, Inc.  See LICENSE file for details.
"""
Plugins.py - a collection of general plugin helper functions for the purpose of
checking and/or verifying that a plugin is enabled and that the path pointed
to by its pref_key is the plugin.

@version: $Id$
@copyright: 2004-2007 Nanorex, Inc.  See LICENSE file for details.

History:

mark 2007-12-01
- split out of qutemol.py

Module classification:  [bruce 071215, 080104]

Contains ui, operations or utility, and io code.
For now, classified as code type of ui, somewhat arbitrarily,
but filed into "processes" package, since it's all about letting
the user maintain info needed to run external processes.
"""

import foundation.env as env
import os
from PyQt4.Qt import QMessageBox
from processes.Process import Process

def _dialogToOfferPluginPrefsFixup(caption, text):
    """
    [private helper for _fixPluginProblem()]

    Offer the user a chance to fix a plugin problem.

    @param caption: The dialog border caption.
    @type  caption: text

    @param text: The dialog text.
    @type  text: text

    @return: 0 if they accept (after letting them try),
             1 if they decline.
    @rtype: int
    """

    win = env.mainwindow()

    ret = QMessageBox.warning(win, caption, text,
        "&OK", "Cancel", "",
        0, 1 )
    if ret == 0: # User clicked "OK"
        win.userPrefs.show(pagename = 'Plug-ins') # Show Preferences | Plug-in.
        return 0 # let caller figure out whether user fixed the problem
    elif ret == 1: # User clicked "Cancel"
        return 1
    pass

def _fixPluginProblem(plugin_name, errortext):
    """
    [private helper for checkPluginPreferences()]

    @param plugin_name: name of plug-in (i.e. "QuteMolX", "GROMACS", etc.)
    @type  plugin_name: text
    """
    caption = "%s Problem" % plugin_name
    text = "Error: %s.\n" % (errortext,) + \
        "  Select OK to fix this now in the Plugins page of\n" \
        "the Preferences dialog and retry rendering, or Cancel."
    return _dialogToOfferPluginPrefsFixup(caption, text)

def verifyExecutable(executable_path):
    if (os.access(executable_path, os.F_OK)):
        if (os.access(executable_path, os.X_OK)):
            return None
        return "%s exists, but is not executable" % executable_path
    return "%s: file does not exist" % executable_path

def _checkPluginPreferences_0(plugin_name,
                              plugin_prefs_keys,
                              insure_executable):
    """
    [private helper for checkPluginPreferences()]

    Checks <plugin_name> to make sure it is enabled and
    that its path points to a file.

    @param plugin_name: name of plug-in (i.e. "QuteMolX", "GROMACS", etc.)
    @type  plugin_name: text

    @param plugin_keys: list containing the plugin enable prefs key and the
                        path prefs key.
    @type  plugin_keys: List

    @return: 0, plugin path on success, or
             1, an error message indicating the problem.
    @rtype:  List
    """

    plugin_enabled_prefs_key, plugin_path_prefs_key = plugin_prefs_keys

    if env.prefs[plugin_enabled_prefs_key]:
        plugin_path = env.prefs[plugin_path_prefs_key]
    else:
        return 1, "%s is not enabled" % plugin_name

    if not plugin_path:
        return 1, "%s plug-in executable path is empty" % plugin_name

    # We'd like to allow arguments to an executable to be specified,
    # but perhaps the executable path itself contains a space in it.
    # So, we break the string at each space and check the first part.
    # If any of those substrings exists, accept it.  We start by
    # checking the whole string.
    executable_path = plugin_path
    while (not os.path.exists(executable_path)):
        last_space = executable_path.rfind(" ")
        # some platform might report that the empty string file name
        # exists, so we don't want to check for it.
        if (last_space <= 0):
            return 1, "%s executable not found at specified path %s" % (plugin_name, plugin_path)
        executable_path = executable_path[0:last_space]

    if (insure_executable):
        message = verifyExecutable(executable_path)
        if (message):
            return 1, message

    ##e should check version of plugin, if we know how

    return 0, plugin_path

def checkPluginPreferences(plugin_name,
                           plugin_prefs_keys,
                           ask_for_help = True,
                           extra_check = None,
                           insure_executable = False):
    """
    Checks I{plugin_name} to make sure it is enabled and that its path points
    to a file. I{ask_for_help} can be set to B{False} if the user shouldn't be
    given a chance to fix the problem via the "Plugin" page in the Preferences
    dialog.

    Note:  this should be refactored to use exceptions.

    Returns :0, plugin path on success, or
             1 and an error message indicating the problem.

    @param plugin_name: name of plug-in (i.e. "QuteMolX", "GROMACS", etc.)
    @type  plugin_name: text

    @param plugin_keys: list containing the plugin enable prefs key and the
                        path prefs key.
    @type  plugin_keys: List

    @param ask_for_help: If True (default), give the user a chance to fix
                         problems via the "Plugin" page of the Preferences
                         dialog (i.e. enable the plugin and set the path to
                         its executable).
    @type  ask_for_help: bool

    @param extra_check: If not None (default is None), is a routine to
                        perform extra validation checks on the plugin
                        path.
    @type extra_check: Function which takes path as argument, and
                       returns either an error message, or None if all
                       is ok.

    @return: 0, plugin path on success, or
             1, an error message indicating the problem.
    @rtype:  List
    """

    # Make sure the other prefs settings are correct; if not, maybe repeat
    # until user fixes them or gives up.
    while 1:
        errorcode, errortext_or_path = \
                 _checkPluginPreferences_0(plugin_name,
                                           plugin_prefs_keys,
                                           insure_executable)
        if (extra_check and not errorcode):
            extra_message = extra_check(errortext_or_path)
            if (extra_message):
                errorcode = 1
                errortext_or_path = extra_message
        if errorcode:
            if not ask_for_help:
                return errorcode, errortext_or_path
            ret = _fixPluginProblem(plugin_name, errortext_or_path)

            if ret == 0: # Subroutine has shown Preferences | Plug-in.
                continue # repeat the checks, to figure out whether user fixed
                         # the problem.
            elif ret == 1: # User declined to try to fix it now
                return errorcode, errortext_or_path
        else:
            return 0, errortext_or_path
    pass # end of checkPluginPreferences


def verifyPluginUsingVersionFlag(plugin_path, version_flag, vstring):
    """
    Verifies a plugin by running it with I{version_flag} as the only
    command line argument and matching the output to I{vstring}.

    @return: 0 if there is a match.  Otherwise, returns 1
    @rtype:  int

    @note: This is only useful if the plug-in supports a version flag arguments.
    """

    if not plugin_path:
        return 1

    if not os.path.exists(plugin_path):
        return 1

    args = [version_flag]

    arguments = []
    for arg in args:
        if arg != "":
            arguments.append(arg)

    p = Process()
    p.start(plugin_path, arguments)

    if not p.waitForFinished (10000): # Wait for 10000 milliseconds = 10 seconds
        return 1

    output = 'Not vstring'

    output = str(p.readAllStandardOutput())

    #print "output=", output
    #print "vstring=", vstring

    if output.find(vstring) == -1:
        return 1
    else:
        return 0 # Match found.