Merge lp:~edgar-b-dsouza/acire/snippet_dependency_res_2 into lp:acire
- snippet_dependency_res_2
- Merge into trunk
Status: | Needs review |
---|---|
Proposed branch: | lp:~edgar-b-dsouza/acire/snippet_dependency_res_2 |
Merge into: | lp:acire |
Diff against target: |
873 lines (+812/-2) 6 files modified
acire/README.dep_checker.txt (+123/-0) acire/depchecker.py (+179/-0) acire/distropkgutils.py (+243/-0) acire/install_packages.py (+208/-0) acire/utils.py (+47/-0) bin/acire (+12/-2) |
To merge this branch: | bzr merge lp:~edgar-b-dsouza/acire/snippet_dependency_res_2 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jono Bacon | Needs Fixing | ||
Review via email: mp+24813@code.launchpad.net |
Commit message
Description of the change
Merged in snippet dependency checker against trunk rev 61.
The (newly added) README.
I have tested earlier on Karmic and now on Lucid, with a Clutter script, and it works. Doesn't mean it's bug-free, of course :-) And from the performance viewpoint, I'd hope that contributors could change the check to a regex-based one, which ought to be faster.
Have incorporated your points from https:/
- Firefox-style yellow bar showing atop the GTKSourceView - in fact, the README contains your exact use case, copied from that merge proposal :-) (NB - I have been driven to almost leaving claw marks on the walls by the GtkLabel's wrapping behavior on Karmic and Lucid... every time I think I got it fixed, it springs out in a different way :-/ Somebody who can make that look decent, PLEASE fix the appearance).
- Keeping code out of bin/acire as much as possible - right, have done that, except for the few lines absolutely required to hook it up.
- Mechanism for hackers on other distros to add distro-specific package-handling code (of course, only tested on Ubuntu, may have bugs on other distros, needs to be tried out).
Looking forward to review - hope this one can be accepted to the trunk.
Thanks
Ed.
Ed S (edgar-b-dsouza) wrote : | # |
Hi Jono,
I tried installing Maverick on an old laptop and ran into problems. Since I'm happily (for the most part) using Lucid on my main laptop, I don't want to put Maverick on that. I started installing into a VM to check, but got sidetracked by other stuff.
I hope to get around to debugging this soon. I think the error is probably in (my use of) the modulefinder module; if so, then I'm at a loss as to what to do, other than go the regex way :-( and I find that a bit too hard; could sure use help with that.
Did you try it with any other snippets that tried to import an unavailable module? Did the code work at least once on your system?
And when you tried it on the Zeitgeist snippet, were any messages printed to stdout (presuming you run Acire from a terminal)? Could you please share those, if any?
Thanks,
Ed.
Preview Diff
1 | === added file 'acire/README.dep_checker.txt' | |||
2 | --- acire/README.dep_checker.txt 1970-01-01 00:00:00 +0000 | |||
3 | +++ acire/README.dep_checker.txt 2010-05-06 10:56:27 +0000 | |||
4 | @@ -0,0 +1,123 @@ | |||
5 | 1 | README for the Acire Snippet Dependency Checker feature. | ||
6 | 2 | ========================================================= | ||
7 | 3 | |||
8 | 4 | v. 1 - 03 Apr 2010 - Edgar D'Souza <edgar.b.dsouza@gmail.com> | ||
9 | 5 | |||
10 | 6 | |||
11 | 7 | Original Problem | ||
12 | 8 | ================ | ||
13 | 9 | When a code snippet tried to import a module that was missing on the system, an | ||
14 | 10 | ImportError exception was printed to stdout. Users running Acire full-screen | ||
15 | 11 | (or from an Applications menu entry) didn't even see that. It just failed. | ||
16 | 12 | |||
17 | 13 | Dependency Checker Goal | ||
18 | 14 | ======================= | ||
19 | 15 | Check the snippet for missing modules on load of the snippet into Acire's | ||
20 | 16 | GTKSourceview. Prompt the user about the missing dependencies and offer to | ||
21 | 17 | install the missing module(s), if candidate package(s) can be found (in | ||
22 | 18 | repositories already set up on user's system). | ||
23 | 19 | |||
24 | 20 | Additional Requirements/Goals | ||
25 | 21 | ============================= | ||
26 | 22 | 1. Ensure that code used to interact with the package-management system is | ||
27 | 23 | NOT distribution-specific to Ubuntu, or can be extended for other distros. | ||
28 | 24 | |||
29 | 25 | 2. Have a privilege-elevation mechanism for installation of packages. | ||
30 | 26 | Some distros differ in how they achieve superuser privileges; this should | ||
31 | 27 | also be extendable (add a distro-specific function wherever required). | ||
32 | 28 | |||
33 | 29 | 3a. Try to make the package installation as GUI-centric as possible. | ||
34 | 30 | From a merge request discussion with project founder Jono Bacon, this is | ||
35 | 31 | what he wrote: | ||
36 | 32 | ------------------------------------ | ||
37 | 33 | my recommendation would be the following use case: | ||
38 | 34 | |||
39 | 35 | 1. User loads a snippet that does not have a module installed. | ||
40 | 36 | 2. Above the source view a little bar appears (like the plugin missing bar | ||
41 | 37 | in Firefox) where it says what module(s) are missing and a button called | ||
42 | 38 | 'Install'. | ||
43 | 39 | 3. User clicks the 'Install' button, a dialog box pops up to confirm what | ||
44 | 40 | will be installed, the user clicks the 'OK' button, is asked for password | ||
45 | 41 | and then a dialog displays progress of the installation. | ||
46 | 42 | 4. The bar disappears from the snippet. | ||
47 | 43 | |||
48 | 44 | I would prefer that the code for this feature does not clutter up bin/acire | ||
49 | 45 | if possible. Probably best is that the logic lives in a file called | ||
50 | 46 | moduleinstaller.py and there is a separate .py file with the dialog box. | ||
51 | 47 | ------------------------------------ | ||
52 | 48 | 3b. Some distros may have problems with superuser-priv processes connecting to | ||
53 | 49 | the X server for the ordinary user account. The privilege-elevation | ||
54 | 50 | mechanism is expected to take care of this, or extra code could be added. | ||
55 | 51 | |||
56 | 52 | First-cut implementation specifics | ||
57 | 53 | ================================== | ||
58 | 54 | New files added to Acire by this implementation: | ||
59 | 55 | depchecker.py | ||
60 | 56 | distropkgutils.py | ||
61 | 57 | install_packages.py | ||
62 | 58 | utils.py | ||
63 | 59 | README.dep_checker.txt (this file) | ||
64 | 60 | |||
65 | 61 | The role of each Python file is explained below. | ||
66 | 62 | |||
67 | 63 | The checking code is invoked from bin/acire (the main executable), in the | ||
68 | 64 | snippet_selected() function, via the line beginning with: | ||
69 | 65 | "check_results = depchecker.check_script" | ||
70 | 66 | |||
71 | 67 | The depchecker.py module contains generic (distro-independent, AFAIK) functions | ||
72 | 68 | that use the built-in Python modulefinder module to see if any import | ||
73 | 69 | statements in the snippet use modules that are not installed on the system. | ||
74 | 70 | |||
75 | 71 | depchecker.py imports distropkgutils.py, creates an instance of the | ||
76 | 72 | distropkgutils.DistroPkgUtils class, and calls said class's methods, to | ||
77 | 73 | accomplish distro-specific functionality. It then builds a GTKEventBox (to show | ||
78 | 74 | a yellow background color), and its contained controls (HBox, which in turn | ||
79 | 75 | contains a GTKLabel and GTKButton). Code in this file customizes the message | ||
80 | 76 | that is displayed, and, if there aren't (enough) installation candidates, the | ||
81 | 77 | caption of the GTKButton. If there are enough packages to install to supply the | ||
82 | 78 | missing modules, then the button caption remains "Install", and the label's | ||
83 | 79 | message lists the packages that will be installed. If unable to find packages | ||
84 | 80 | to install, then the label message is changed to reflect this, and the GTKButton | ||
85 | 81 | caption is changed to "More Info" - clicking this will take the user to a wiki | ||
86 | 82 | page (the URL is at the beginning of depchecker.py). | ||
87 | 83 | |||
88 | 84 | depchecker.py has a remove_eventbox() function, which is called internally, | ||
89 | 85 | from the handler for the GTKButton, and also from bin/acire, in the | ||
90 | 86 | snippet_selected() function, to hide & destroy the eventbox if it still exists. | ||
91 | 87 | This gets rid of the eventbox both when user clicks the Install button, or if | ||
92 | 88 | user ignores it and clicks another snippet in the treeview. | ||
93 | 89 | |||
94 | 90 | Class DistroPkgUtils in distropkgutils.py: | ||
95 | 91 | Exposes generically-named methods (see 'Internals' below) to calling code: | ||
96 | 92 | - get_pkg_list(): Returns list of UNinstalled python library packages | ||
97 | 93 | - install_pkgs(pkglist): installs the given packages, as described below. | ||
98 | 94 | |||
99 | 95 | Class & Module Internals -- distropkgutils.py: | ||
100 | 96 | - In __init__(), class checks which distribution it is running under, and looks | ||
101 | 97 | for an appropriate distro-specific package-listing function (in the same | ||
102 | 98 | module) that it exposes as get_pkg_list() to calling code. This is because | ||
103 | 99 | retrieving a list of uninstalled packages does not need superuser privs. | ||
104 | 100 | IF an __get_pkg_list function is not found for the current distro, the | ||
105 | 101 | default implementation of the method simply returns an empty list, warning | ||
106 | 102 | calling code that something is amiss (if it wants to handle this). | ||
107 | 103 | - The install_pkgs() method accepts a list of packages as a parameter, and | ||
108 | 104 | calls a private function, _as_superuser(), to launch install_packages.py | ||
109 | 105 | as a subprocess with superuser privs. The list of packages to install is | ||
110 | 106 | passed on the command-line as arguments. | ||
111 | 107 | - The _as_superuser() function has a default implementation using gksu, | ||
112 | 108 | in this same class. However, __init__() checks for a distro-specific | ||
113 | 109 | implementation of this function; if found, it overwrites the default | ||
114 | 110 | implementation with the found one. This lets you add privilege | ||
115 | 111 | escalation code for different distros (which don't use gksu/sudo). | ||
116 | 112 | |||
117 | 113 | install_packages.py -- contains distro-specific package installation functions. | ||
118 | 114 | As in distropkgutils.py, this script too checks for distro via platform.dist() | ||
119 | 115 | and attempts to retrieve a matching install function from itself. If a callable | ||
120 | 116 | object is obtained, it calls that function, passing the command-line arguments. | ||
121 | 117 | This file expects to be launched with administrative/superuser privileges | ||
122 | 118 | needed to install packages, and does not contain any code for privilege | ||
123 | 119 | escalation. | ||
124 | 120 | |||
125 | 121 | utils.py -- contains a few functions that are used from multiple files, | ||
126 | 122 | and/or are not exclusively related to the package-management code (i.e. could | ||
127 | 123 | be re-used elsewhere). | ||
128 | 0 | \ No newline at end of file | 124 | \ No newline at end of file |
129 | 1 | 125 | ||
130 | === added file 'acire/depchecker.py' | |||
131 | --- acire/depchecker.py 1970-01-01 00:00:00 +0000 | |||
132 | +++ acire/depchecker.py 2010-05-06 10:56:27 +0000 | |||
133 | @@ -0,0 +1,179 @@ | |||
134 | 1 | #! /usr/bin/env python | ||
135 | 2 | #coding=utf-8 | ||
136 | 3 | ### BEGIN LICENSE | ||
137 | 4 | # Copyright (C) 2010 Edgar D'Souza <edgar.b.dsouza@gmail.com> | ||
138 | 5 | #This program is free software: you can redistribute it and/or modify it | ||
139 | 6 | #under the terms of the GNU General Public License version 3, as published | ||
140 | 7 | #by the Free Software Foundation. | ||
141 | 8 | # | ||
142 | 9 | #This program is distributed in the hope that it will be useful, but | ||
143 | 10 | #WITHOUT ANY WARRANTY; without even the implied warranties of | ||
144 | 11 | #MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
145 | 12 | #PURPOSE. See the GNU General Public License for more details. | ||
146 | 13 | # | ||
147 | 14 | #You should have received a copy of the GNU General Public License along | ||
148 | 15 | #with this program. If not, see <http://www.gnu.org/licenses/>. | ||
149 | 16 | ### END LICENSE | ||
150 | 17 | |||
151 | 18 | import modulefinder | ||
152 | 19 | from acire import distropkgutils as dpu | ||
153 | 20 | import webbrowser | ||
154 | 21 | import pygtk | ||
155 | 22 | pygtk.require('2.0') | ||
156 | 23 | import gtk | ||
157 | 24 | |||
158 | 25 | infoURL = "https://wiki.ubuntu.com/PythonSnippets_Dependencies" | ||
159 | 26 | |||
160 | 27 | #Grab a list of packages immediately upon import of this module. | ||
161 | 28 | dp_utils = dpu.DistroPkgUtils() | ||
162 | 29 | python_pkgs = dp_utils.get_pkg_list() | ||
163 | 30 | #Other global vars hold data while waiting for user response through UI | ||
164 | 31 | candidates = [] | ||
165 | 32 | event_box = None | ||
166 | 33 | |||
167 | 34 | def check_script(filename, container_vbox): | ||
168 | 35 | """Entry point for checking a script, to be called when snippet is | ||
169 | 36 | loaded from file into Acire's GTKSourceView. | ||
170 | 37 | filename - path+filename to the Python script to be checked. | ||
171 | 38 | container_vbox - the right-hand pane vbox containing the editor viewport | ||
172 | 39 | and other controls (more controls are built and packed in below). | ||
173 | 40 | """ | ||
174 | 41 | global python_pkgs, candidates, event_box | ||
175 | 42 | |||
176 | 43 | missing_in_main = [] | ||
177 | 44 | candidate_pkgs = [] | ||
178 | 45 | candidates = candidate_pkgs | ||
179 | 46 | |||
180 | 47 | modfinder = modulefinder.ModuleFinder() | ||
181 | 48 | modfinder.run_script(filename) | ||
182 | 49 | missing, maybe = modfinder.any_missing_maybe() | ||
183 | 50 | #Due to bad docs, next 3 lines copied from modulefinder.report() and modded | ||
184 | 51 | if missing: | ||
185 | 52 | for name in missing: | ||
186 | 53 | mods = modfinder.badmodules[name].keys() | ||
187 | 54 | if "__main__" in mods: | ||
188 | 55 | missing_in_main.append(name) | ||
189 | 56 | |||
190 | 57 | #Python's intelligent iteration will just skip the loop(s) below if: | ||
191 | 58 | #a) There are no modulenames in missing_in_main, OR | ||
192 | 59 | #b) There are no python_pkgs (pkg-mgt function for curr distro n/avble) | ||
193 | 60 | for mod in missing_in_main: | ||
194 | 61 | for pkg in python_pkgs: | ||
195 | 62 | if mod in pkg: | ||
196 | 63 | candidate_pkgs.append(pkg) | ||
197 | 64 | #print "Candidate package for module %s: %s" % (mod, pkg) | ||
198 | 65 | |||
199 | 66 | #Build the GUI if there are missing modulenames - even if there | ||
200 | 67 | #aren't any, or sufficient, candidates for installation - because if | ||
201 | 68 | #not, it will look like the dependency was not detected. | ||
202 | 69 | if len(missing_in_main) > 0: | ||
203 | 70 | evbox, alert_label, resolve_button, builder = build_ui() | ||
204 | 71 | event_box = evbox #Put in global var to use in remove_eventbox() | ||
205 | 72 | msg = alert_label.get_text() | ||
206 | 73 | #If num-missing-modules == num-installation-candidates, then we | ||
207 | 74 | #probably have a solution and can propose installation. | ||
208 | 75 | if len(missing_in_main) == len(candidate_pkgs): | ||
209 | 76 | #Store the candidate packages list globally, for use in the | ||
210 | 77 | #resolve_button handler "resolve_deps()". | ||
211 | 78 | candidates = candidate_pkgs | ||
212 | 79 | #Replace placeholder in label text with package list. | ||
213 | 80 | msg = msg % (", ".join(candidate_pkgs)) | ||
214 | 81 | else: | ||
215 | 82 | #Incomplete or no solution: offer to take user to wiki page. | ||
216 | 83 | msg = "This snippet uses modules that aren't installed on your" | ||
217 | 84 | msg += "system, but we cannot find packages to install.\n" | ||
218 | 85 | msg += "Click the More Info button to visit a wiki page." | ||
219 | 86 | resolve_button.set_text(" More _Info ") | ||
220 | 87 | alert_label.set_text(msg) | ||
221 | 88 | resolve_button.connect("clicked", resolve_deps) | ||
222 | 89 | container_vbox.pack_start(evbox, False, False, 3) | ||
223 | 90 | container_vbox.reorder_child(evbox, 0) | ||
224 | 91 | evbox.show_all() | ||
225 | 92 | |||
226 | 93 | def resolve_deps(widget, data=None): | ||
227 | 94 | """Click event handler for resolve_button. """ | ||
228 | 95 | global python_pkgs, candidates, dp_utils, event_box, infoURL | ||
229 | 96 | |||
230 | 97 | #If there are installation candidates, check_script() found that number of | ||
231 | 98 | #candidates matched number of missing modules... install the list of pkgs. | ||
232 | 99 | if len(candidates) > 0: | ||
233 | 100 | dp_utils.install_pkgs(candidates) | ||
234 | 101 | #Refresh the list of uninstalled Python packages. | ||
235 | 102 | python_pkgs = dp_utils.get_pkg_list() | ||
236 | 103 | else: | ||
237 | 104 | #check_script couldn't find a 'complete solution': either the packages | ||
238 | 105 | #available < num-missing-modules, or there were zero candidate pkgs. | ||
239 | 106 | webbrowser.open_new_tab(infoURL) | ||
240 | 107 | remove_eventbox() | ||
241 | 108 | |||
242 | 109 | def remove_eventbox(): | ||
243 | 110 | global event_box | ||
244 | 111 | if event_box is not None: | ||
245 | 112 | event_box.hide() | ||
246 | 113 | event_box.destroy() | ||
247 | 114 | event_box = None | ||
248 | 115 | |||
249 | 116 | def build_ui(): | ||
250 | 117 | ui = '''<interface> | ||
251 | 118 | <object class="GtkEventBox" id="alert_eventbox"> | ||
252 | 119 | <property name="visible">True</property> | ||
253 | 120 | <child> | ||
254 | 121 | <object class="GtkHBox" id="alert_hbox"> | ||
255 | 122 | <child> | ||
256 | 123 | <object class="GtkLabel" id="alert_label"> | ||
257 | 124 | <property name="visible">True</property> | ||
258 | 125 | <property name="wrap">True</property> | ||
259 | 126 | <property name="xpad">5</property> | ||
260 | 127 | <property name="ypad">5</property> | ||
261 | 128 | <property name="label">This snippet uses modules that are not installed on your system. Click the Install button to install these packages: %s</property> | ||
262 | 129 | <property name="track_visited_links">False</property> | ||
263 | 130 | <attributes> | ||
264 | 131 | <attribute name="weight" value="semibold"/> | ||
265 | 132 | <attribute name="gravity" value="north"/> | ||
266 | 133 | <attribute name="gravity-hint" value="natural"/> | ||
267 | 134 | <attribute name="style" value="normal"/> | ||
268 | 135 | <attribute name="gravity" value="east"/> | ||
269 | 136 | </attributes> | ||
270 | 137 | </object> | ||
271 | 138 | <packing> | ||
272 | 139 | <property name="fill">True</property> | ||
273 | 140 | <property name="position">0</property> | ||
274 | 141 | </packing> | ||
275 | 142 | </child> | ||
276 | 143 | <child> | ||
277 | 144 | <object class="GtkButton" id="resolve_button"> | ||
278 | 145 | <property name="label" translatable="yes"> _Install </property> | ||
279 | 146 | <property name="visible">True</property> | ||
280 | 147 | <property name="width_request">100</property> | ||
281 | 148 | <property name="can_focus">True</property> | ||
282 | 149 | <property name="receives_default">True</property> | ||
283 | 150 | <property name="use_underline">True</property> | ||
284 | 151 | <signal name="clicked" handler="resolve_deps"/> | ||
285 | 152 | </object> | ||
286 | 153 | <packing> | ||
287 | 154 | <property name="expand">False</property> | ||
288 | 155 | <property name="fill">False</property> | ||
289 | 156 | <property name="padding">3</property> | ||
290 | 157 | <property name="pack_type">end</property> | ||
291 | 158 | <property name="position">1</property> | ||
292 | 159 | </packing> | ||
293 | 160 | </child> | ||
294 | 161 | </object> | ||
295 | 162 | </child> | ||
296 | 163 | </object> | ||
297 | 164 | </interface>''' | ||
298 | 165 | # Create a GTKBuilder instance | ||
299 | 166 | builder = gtk.Builder() | ||
300 | 167 | # Add a UI description | ||
301 | 168 | builder.add_from_string(ui) | ||
302 | 169 | evbox = builder.get_object("alert_eventbox") | ||
303 | 170 | evbox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#ffff00")) | ||
304 | 171 | alert_label = builder.get_object("alert_label") | ||
305 | 172 | resolve_button = builder.get_object("resolve_button") | ||
306 | 173 | return evbox, alert_label, resolve_button, builder | ||
307 | 174 | |||
308 | 175 | |||
309 | 176 | if __name__ == "__main__": | ||
310 | 177 | print "Import this as a module and run utils.check_script('filename.py')" | ||
311 | 178 | print "to examine the script for dependency modules." | ||
312 | 179 | print "See check_script() docstring for returned dict contents." | ||
313 | 0 | 180 | ||
314 | === added file 'acire/distropkgutils.py' | |||
315 | --- acire/distropkgutils.py 1970-01-01 00:00:00 +0000 | |||
316 | +++ acire/distropkgutils.py 2010-05-06 10:56:27 +0000 | |||
317 | @@ -0,0 +1,243 @@ | |||
318 | 1 | #! /usr/bin/env python | ||
319 | 2 | #coding=utf-8 | ||
320 | 3 | ### BEGIN LICENSE | ||
321 | 4 | # Copyright (C) 2010 Edgar D'Souza <edgar.b.dsouza@gmail.com> (initial version) | ||
322 | 5 | #This program is free software: you can redistribute it and/or modify it | ||
323 | 6 | #under the terms of the GNU General Public License version 3, as published | ||
324 | 7 | #by the Free Software Foundation. | ||
325 | 8 | # | ||
326 | 9 | #This program is distributed in the hope that it will be useful, but | ||
327 | 10 | #WITHOUT ANY WARRANTY; without even the implied warranties of | ||
328 | 11 | #MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
329 | 12 | #PURPOSE. See the GNU General Public License for more details. | ||
330 | 13 | # | ||
331 | 14 | #You should have received a copy of the GNU General Public License along | ||
332 | 15 | #with this program. If not, see <http://www.gnu.org/licenses/>. | ||
333 | 16 | ### END LICENSE | ||
334 | 17 | |||
335 | 18 | ### | ||
336 | 19 | ### | ||
337 | 20 | ### | ||
338 | 21 | ### | ||
339 | 22 | ### | ||
340 | 23 | ### PLEASE READ README.dep_checker.txt before hacking - thanks! :-) | ||
341 | 24 | ### | ||
342 | 25 | ### | ||
343 | 26 | ### | ||
344 | 27 | ### | ||
345 | 28 | ### | ||
346 | 29 | ### | ||
347 | 30 | |||
348 | 31 | import subprocess | ||
349 | 32 | import sys | ||
350 | 33 | import os | ||
351 | 34 | |||
352 | 35 | try: | ||
353 | 36 | from acire import utils | ||
354 | 37 | except: | ||
355 | 38 | #Required when doing singleton-testing of this file (exec it alone) | ||
356 | 39 | sys.path.insert(0, os.getcwd()) | ||
357 | 40 | import utils | ||
358 | 41 | |||
359 | 42 | |||
360 | 43 | class DistroPkgUtils(): | ||
361 | 44 | """Class to abstract distro-specific libraries/commands so that calling | ||
362 | 45 | code can call generically-named methods of this class without bothering | ||
363 | 46 | about which distro is being used. | ||
364 | 47 | """ | ||
365 | 48 | def __init__(self, dummydistname_testingonly=None): | ||
366 | 49 | #Store distro name in lower case (or a dummy name, for testing) | ||
367 | 50 | if dummydistname_testingonly is None: | ||
368 | 51 | self.distname_lower = utils.distro_name() | ||
369 | 52 | else: | ||
370 | 53 | self.distname_lower = dummydistname_testingonly | ||
371 | 54 | #print "Distro name: ", self.distname_lower | ||
372 | 55 | |||
373 | 56 | #Pick up distro-specific functions from this module | ||
374 | 57 | thismodule = sys.modules[__name__] | ||
375 | 58 | getter_name = "__get_pkg_list_%s" % self.distname_lower | ||
376 | 59 | as_superuser_name = "__as_superuser_%s" % self.distname_lower | ||
377 | 60 | #print "Func names sought: ", getter_name, as_superuser_name | ||
378 | 61 | try: | ||
379 | 62 | getter_func = getattr(thismodule, getter_name) | ||
380 | 63 | #print "getter_func: ", getter_func | ||
381 | 64 | if callable(getter_func): | ||
382 | 65 | #Override the default empty-list member of this class with | ||
383 | 66 | #the function containing the actual code. | ||
384 | 67 | self.get_pkg_list = getter_func | ||
385 | 68 | |||
386 | 69 | #the _as_superuser function has a default implementation in this | ||
387 | 70 | #class, but can be overridden, so: | ||
388 | 71 | if hasattr(thismodule, as_superuser_name): | ||
389 | 72 | as_superuser_func = getattr(thismodule, as_superuser_name) | ||
390 | 73 | #print "as_superuser_func: ", as_superuser_func | ||
391 | 74 | if callable(as_superuser_func): | ||
392 | 75 | self.__as_superuser = as_superuser_func | ||
393 | 76 | except Exception, e: | ||
394 | 77 | print "Exception while trying to access functions for %s in %s" % (self.distname_lower, __name__) | ||
395 | 78 | print "Exception was: %s" % str(e) | ||
396 | 79 | |||
397 | 80 | def get_pkg_list(): | ||
398 | 81 | """Default implementation of this function returns an empty list of | ||
399 | 82 | packages, if there is no distro-specific function found.""" | ||
400 | 83 | return [] | ||
401 | 84 | |||
402 | 85 | def __as_superuser(self, pkglist): | ||
403 | 86 | """Shells to a gksu invocation of install_packages.py, waiting till | ||
404 | 87 | it's done. To override, create a _as_superuser_DISTRONAME() below; | ||
405 | 88 | __init__() will find it and replace this with your specific | ||
406 | 89 | implementation.""" | ||
407 | 90 | #Spawn a subprocess with gksu, to run the install_packages.py script. | ||
408 | 91 | try: | ||
409 | 92 | cwd = os.path.dirname(os.path.abspath(__file__)) | ||
410 | 93 | print "cwd: ", cwd | ||
411 | 94 | cc_args = ["/usr/bin/gksu", "--", "python", | ||
412 | 95 | "install_packages.py", "-d", "-i"] | ||
413 | 96 | for item in pkglist: | ||
414 | 97 | cc_args.append('%s' % item) | ||
415 | 98 | print "cc_args: ", cc_args | ||
416 | 99 | #check_call waits for command to complete before returning. | ||
417 | 100 | subprocess.check_call(cc_args, cwd=cwd) | ||
418 | 101 | except subprocess.CalledProcessError, cpe: | ||
419 | 102 | print "CalledProcessError: %s" % repr(cpe) | ||
420 | 103 | raise | ||
421 | 104 | |||
422 | 105 | def install_pkgs(self, pkglist): | ||
423 | 106 | """Method accepts the list of packages to be installed, then calls | ||
424 | 107 | _as_superuser to run install_packages.py with elevated privileges. | ||
425 | 108 | That script does its own distro detection and calls the appropriate | ||
426 | 109 | function with the package list passed on the command line.""" | ||
427 | 110 | self.__as_superuser(pkglist) | ||
428 | 111 | |||
429 | 112 | #------------------------------------------------------------------------------ | ||
430 | 113 | ###Package-management listing functions for different distros. | ||
431 | 114 | ###Some distros may have an optional privilege-elevation function too. | ||
432 | 115 | ### Please read README.dep_checker.txt for explanation. | ||
433 | 116 | |||
434 | 117 | ###Unimplemented function stubs call the "utils.not_implemented()" function | ||
435 | 118 | ### to display a message. Contributions welcome for your favorite distro! | ||
436 | 119 | ###Distros taken from _supported_dists in platform module, have not added stubs | ||
437 | 120 | ### for Mint, PCLinuxOS, Sabayon, Puppy, Arch and many others, since am not | ||
438 | 121 | ### sure what platform.dist() returns on each. | ||
439 | 122 | ### | ||
440 | 123 | ###Function naming convention: | ||
441 | 124 | ### NB: DISTRONAME => the lower-case version of the name returned | ||
442 | 125 | ### by platform.linux_distribution()[0] | ||
443 | 126 | ### - __get_pkg_list_DISTRONAME() | ||
444 | 127 | ### Func to return list of uninstalled python library packages. | ||
445 | 128 | ### Please adjust the filtering code for the package-naming conventions | ||
446 | 129 | ### of the distro for which you're writing the function. | ||
447 | 130 | ### Does not have GUI or other display of this operation. | ||
448 | 131 | ### - (Optional) __as_superuser_DISTRONAME() | ||
449 | 132 | ### Optional override of the default privilege-escalation mechanism | ||
450 | 133 | ### implemented in the class above. | ||
451 | 134 | |||
452 | 135 | def __get_pkg_list_ubuntu(): | ||
453 | 136 | """Run subprocess with aptitude search to fetch a list of package names | ||
454 | 137 | with regex 'python-*'; filter it to keep those which are not installed. | ||
455 | 138 | Returns: list of uninstalled python packages. """ | ||
456 | 139 | |||
457 | 140 | cmd = "/usr/bin/aptitude search '^python-[a-z]*$' --disable-columns -F '%p\$%v'" | ||
458 | 141 | proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) | ||
459 | 142 | pkg_list = proc.communicate()[0] | ||
460 | 143 | #Convert to a list of packages, filtering to keep those where the Version | ||
461 | 144 | #is "<none>" (i.e. not installed) | ||
462 | 145 | python_uninst_pkgs = [] | ||
463 | 146 | for pkg in pkg_list.split("\n"): | ||
464 | 147 | if len(pkg.strip()) > 0: | ||
465 | 148 | parts = pkg.split("$") | ||
466 | 149 | #print parts | ||
467 | 150 | if parts[1].strip() == "<none>": | ||
468 | 151 | python_uninst_pkgs.append(parts[0]) | ||
469 | 152 | return python_uninst_pkgs | ||
470 | 153 | |||
471 | 154 | #------------------------------------------------------------------------------ | ||
472 | 155 | |||
473 | 156 | def __get_pkg_list_debian(): | ||
474 | 157 | """Returns a list of Python library packages that are not installed yet.""" | ||
475 | 158 | return __get_pkg_list_ubuntu() #Redirect to Ubuntu code - same family | ||
476 | 159 | |||
477 | 160 | #------------------------------------------------------------------------------ | ||
478 | 161 | |||
479 | 162 | def __get_pkg_list_redhat(): | ||
480 | 163 | """Returns a list of Python library packages that are not installed yet.""" | ||
481 | 164 | utils.not_implemented(utils.funcname()) | ||
482 | 165 | return [] | ||
483 | 166 | |||
484 | 167 | #------------------------------------------------------------------------------ | ||
485 | 168 | |||
486 | 169 | def __get_pkg_list_centos(): | ||
487 | 170 | """Returns a list of Python library packages that are not installed yet.""" | ||
488 | 171 | return __get_pkg_list_redhat() #Redirect to RH code - same family | ||
489 | 172 | |||
490 | 173 | #------------------------------------------------------------------------------ | ||
491 | 174 | |||
492 | 175 | def __get_pkg_list_fedora(): | ||
493 | 176 | """Returns a list of Python library packages that are not installed yet.""" | ||
494 | 177 | return __get_pkg_list_redhat() #Redirect to RH code - same family | ||
495 | 178 | |||
496 | 179 | #------------------------------------------------------------------------------ | ||
497 | 180 | |||
498 | 181 | def __get_pkg_list_mandriva(): | ||
499 | 182 | """Returns a list of Python library packages that are not installed yet.""" | ||
500 | 183 | utils.not_implemented(utils.funcname()) | ||
501 | 184 | return [] | ||
502 | 185 | |||
503 | 186 | #------------------------------------------------------------------------------ | ||
504 | 187 | |||
505 | 188 | def __get_pkg_list_suse(): | ||
506 | 189 | """Returns a list of Python library packages that are not installed yet.""" | ||
507 | 190 | utils.not_implemented(utils.funcname()) | ||
508 | 191 | return [] | ||
509 | 192 | |||
510 | 193 | #------------------------------------------------------------------------------ | ||
511 | 194 | |||
512 | 195 | def __get_pkg_list_slackware(): | ||
513 | 196 | """Returns a list of Python library packages that are not installed yet.""" | ||
514 | 197 | utils.not_implemented(utils.funcname()) | ||
515 | 198 | return [] | ||
516 | 199 | |||
517 | 200 | #------------------------------------------------------------------------------ | ||
518 | 201 | |||
519 | 202 | def __get_pkg_list_gentoo(): | ||
520 | 203 | """Returns a list of Python library packages that are not installed yet.""" | ||
521 | 204 | utils.not_implemented(utils.funcname()) | ||
522 | 205 | return [] | ||
523 | 206 | |||
524 | 207 | #------------------------------------------------------------------------------ | ||
525 | 208 | |||
526 | 209 | def __get_pkg_list_yellowdog(): | ||
527 | 210 | """Returns a list of Python library packages that are not installed yet.""" | ||
528 | 211 | utils.not_implemented(utils.funcname()) | ||
529 | 212 | return [] | ||
530 | 213 | |||
531 | 214 | #------------------------------------------------------------------------------ | ||
532 | 215 | |||
533 | 216 | def __get_pkg_list_unitedlinux(): | ||
534 | 217 | """Returns a list of Python library packages that are not installed yet.""" | ||
535 | 218 | utils.not_implemented(utils.funcname()) | ||
536 | 219 | return [] | ||
537 | 220 | |||
538 | 221 | #------------------------------------------------------------------------------ | ||
539 | 222 | |||
540 | 223 | def __get_pkg_list_turbolinux(): | ||
541 | 224 | """Returns a list of Python library packages that are not installed yet.""" | ||
542 | 225 | utils.not_implemented(utils.funcname()) | ||
543 | 226 | return [] | ||
544 | 227 | |||
545 | 228 | #------------------------------------------------------------------------------ | ||
546 | 229 | |||
547 | 230 | def __get_pkg_list_rocks(): | ||
548 | 231 | """Returns a list of Python library packages that are not installed yet.""" | ||
549 | 232 | utils.not_implemented(utils.funcname()) | ||
550 | 233 | return [] | ||
551 | 234 | |||
552 | 235 | #------------------------------------------------------------------------------ | ||
553 | 236 | |||
554 | 237 | |||
555 | 238 | ### Module self-test (limited) | ||
556 | 239 | if __name__ == "__main__": | ||
557 | 240 | for distro in ["fedora", "rocks", "turbolinux", "debian"]: | ||
558 | 241 | dpu = DistroPkgUtils(distro) | ||
559 | 242 | if len(dpu.get_pkg_list()) > 0: | ||
560 | 243 | dpu.install_pkgs(["python-clutter"]) | ||
561 | 0 | \ No newline at end of file | 244 | \ No newline at end of file |
562 | 1 | 245 | ||
563 | === added file 'acire/install_packages.py' | |||
564 | --- acire/install_packages.py 1970-01-01 00:00:00 +0000 | |||
565 | +++ acire/install_packages.py 2010-05-06 10:56:27 +0000 | |||
566 | @@ -0,0 +1,208 @@ | |||
567 | 1 | #! /usr/bin/python | ||
568 | 2 | #coding=utf-8 | ||
569 | 3 | ### BEGIN LICENSE | ||
570 | 4 | # Copyright (C) 2010 Edgar D'Souza <edgar.b.dsouza@gmail.com> | ||
571 | 5 | #This program is free software: you can redistribute it and/or modify it | ||
572 | 6 | #under the terms of the GNU General Public License version 3, as published | ||
573 | 7 | #by the Free Software Foundation. | ||
574 | 8 | # | ||
575 | 9 | #This program is distributed in the hope that it will be useful, but | ||
576 | 10 | #WITHOUT ANY WARRANTY; without even the implied warranties of | ||
577 | 11 | #MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
578 | 12 | #PURPOSE. See the GNU General Public License for more details. | ||
579 | 13 | # | ||
580 | 14 | #You should have received a copy of the GNU General Public License along | ||
581 | 15 | #with this program. If not, see <http://www.gnu.org/licenses/>. | ||
582 | 16 | ### END LICENSE | ||
583 | 17 | |||
584 | 18 | import pygtk | ||
585 | 19 | pygtk.require("2.0") | ||
586 | 20 | import gtk | ||
587 | 21 | import subprocess | ||
588 | 22 | import os | ||
589 | 23 | import sys | ||
590 | 24 | import time | ||
591 | 25 | |||
592 | 26 | # Check if we are working in the source tree or from the installed | ||
593 | 27 | # package and mangle the python path accordingly | ||
594 | 28 | if os.path.dirname(sys.argv[0]) != ".": | ||
595 | 29 | if sys.argv[0][0] == "/": | ||
596 | 30 | fullPath = os.path.dirname(sys.argv[0]) | ||
597 | 31 | else: | ||
598 | 32 | fullPath = os.getcwd() + "/" + os.path.dirname(sys.argv[0]) | ||
599 | 33 | else: | ||
600 | 34 | fullPath = os.getcwd() | ||
601 | 35 | sys.path.insert(0, os.path.dirname(fullPath)) | ||
602 | 36 | import utils | ||
603 | 37 | |||
604 | 38 | #Helper function - writes debug messages to a log file. | ||
605 | 39 | def log(msg): | ||
606 | 40 | filename = '/tmp/install_packages.log' | ||
607 | 41 | dumpstr = "%s\n" % msg | ||
608 | 42 | write_mode = 'a' | ||
609 | 43 | tmpfile = open(filename, write_mode, 0) | ||
610 | 44 | tmpfile.write(dumpstr) | ||
611 | 45 | tmpfile.close() | ||
612 | 46 | |||
613 | 47 | |||
614 | 48 | def __install_pkgs_ubuntu(pkglist): | ||
615 | 49 | """Install the packages passed as the pkglist parameter. | ||
616 | 50 | python-apt must be installed (must be a dependency of the Acire package). | ||
617 | 51 | """ | ||
618 | 52 | try: | ||
619 | 53 | import apt.progress.gtk2 | ||
620 | 54 | |||
621 | 55 | win = gtk.Window() | ||
622 | 56 | win.connect("destroy", gtk.main_quit) | ||
623 | 57 | win.set_size_request(450, 440) | ||
624 | 58 | win.set_position(gtk.WIN_POS_CENTER_ALWAYS) | ||
625 | 59 | win.set_title("Acire Module Installation") | ||
626 | 60 | |||
627 | 61 | vbox = gtk.VBox(False, 3) | ||
628 | 62 | vbox.set_border_width(10) | ||
629 | 63 | |||
630 | 64 | progress = apt.progress.gtk2.GtkAptProgress() | ||
631 | 65 | vbox.pack_start(progress) | ||
632 | 66 | |||
633 | 67 | hbox = gtk.HButtonBox() | ||
634 | 68 | hbox.set_layout(gtk.BUTTONBOX_END) | ||
635 | 69 | close_button = gtk.Button("Close", gtk.STOCK_CLOSE) | ||
636 | 70 | close_button.connect("clicked", gtk.main_quit) | ||
637 | 71 | hbox.add(close_button) | ||
638 | 72 | |||
639 | 73 | vbox.pack_end(hbox, True, True, 0) | ||
640 | 74 | |||
641 | 75 | win.add(vbox) | ||
642 | 76 | |||
643 | 77 | close_button.show() | ||
644 | 78 | progress.show() | ||
645 | 79 | vbox.show() | ||
646 | 80 | win.show() | ||
647 | 81 | cache = apt.cache.Cache(progress.open) | ||
648 | 82 | for pkg in pkglist: | ||
649 | 83 | cache[pkg].markInstall() | ||
650 | 84 | progress.show_terminal(expanded=True) | ||
651 | 85 | cache.commit(progress.fetch, progress.install) | ||
652 | 86 | hbox.show() | ||
653 | 87 | gtk.main() | ||
654 | 88 | time.sleep(1) | ||
655 | 89 | except Exception, e: | ||
656 | 90 | log("%s: Exception: %s" % (utils.funcname(), repr(e))) | ||
657 | 91 | time.sleep(1) | ||
658 | 92 | |||
659 | 93 | #------------------------------------------------------------------------------ | ||
660 | 94 | |||
661 | 95 | def __install_pkgs_debian(pkglist): | ||
662 | 96 | """Installs the packages passed as the pkglist parameter.""" | ||
663 | 97 | __install_pkgs_ubuntu(pkglist) #Redirect to Ubuntu code - same family | ||
664 | 98 | |||
665 | 99 | #------------------------------------------------------------------------------ | ||
666 | 100 | |||
667 | 101 | def __install_pkgs_redhat(pkglist): | ||
668 | 102 | """Installs the packages passed as the pkglist parameter.""" | ||
669 | 103 | utils.not_implemented(utils.funcname(), True) | ||
670 | 104 | |||
671 | 105 | #------------------------------------------------------------------------------ | ||
672 | 106 | |||
673 | 107 | def __install_pkgs_centos(pkglist): | ||
674 | 108 | """Installs the packages passed as the pkglist parameter.""" | ||
675 | 109 | __install_pkgs_redhat(pkglist) #Redirect to RH code - same family | ||
676 | 110 | |||
677 | 111 | #------------------------------------------------------------------------------ | ||
678 | 112 | |||
679 | 113 | def __install_pkgs_fedora(pkglist): | ||
680 | 114 | """Installs the packages passed as the pkglist parameter.""" | ||
681 | 115 | __install_pkgs_redhat(pkglist) #Redirect to RH code - same family | ||
682 | 116 | |||
683 | 117 | #------------------------------------------------------------------------------ | ||
684 | 118 | |||
685 | 119 | def __install_pkgs_mandriva(pkglist): | ||
686 | 120 | """Installs the packages passed as the pkglist parameter.""" | ||
687 | 121 | utils.not_implemented(utils.funcname(), True) | ||
688 | 122 | |||
689 | 123 | #------------------------------------------------------------------------------ | ||
690 | 124 | |||
691 | 125 | def __install_pkgs_suse(pkglist): | ||
692 | 126 | """Installs the packages passed as the pkglist parameter.""" | ||
693 | 127 | utils.not_implemented(utils.funcname(), True) | ||
694 | 128 | |||
695 | 129 | #------------------------------------------------------------------------------ | ||
696 | 130 | |||
697 | 131 | def __install_pkgs_slackware(pkglist): | ||
698 | 132 | """Installs the packages passed as the pkglist parameter.""" | ||
699 | 133 | utils.not_implemented(utils.funcname(), True) | ||
700 | 134 | |||
701 | 135 | #------------------------------------------------------------------------------ | ||
702 | 136 | |||
703 | 137 | def __install_pkgs_gentoo(pkglist): | ||
704 | 138 | """Installs the packages passed as the pkglist parameter.""" | ||
705 | 139 | utils.not_implemented(utils.funcname(), True) | ||
706 | 140 | |||
707 | 141 | #------------------------------------------------------------------------------ | ||
708 | 142 | |||
709 | 143 | def __install_pkgs_yellowdog(pkglist): | ||
710 | 144 | """Installs the packages passed as the pkglist parameter.""" | ||
711 | 145 | utils.not_implemented(utils.funcname(), True) | ||
712 | 146 | |||
713 | 147 | #------------------------------------------------------------------------------ | ||
714 | 148 | |||
715 | 149 | def __install_pkgs_unitedlinux(pkglist): | ||
716 | 150 | """Installs the packages passed as the pkglist parameter.""" | ||
717 | 151 | utils.not_implemented(utils.funcname(), True) | ||
718 | 152 | |||
719 | 153 | #------------------------------------------------------------------------------ | ||
720 | 154 | |||
721 | 155 | def __install_pkgs_turbolinux(pkglist): | ||
722 | 156 | """Installs the packages passed as the pkglist parameter.""" | ||
723 | 157 | utils.not_implemented(utils.funcname(), True) | ||
724 | 158 | |||
725 | 159 | #------------------------------------------------------------------------------ | ||
726 | 160 | |||
727 | 161 | def __install_pkgs_rocks(pkglist): | ||
728 | 162 | """Installs the packages passed as the pkglist parameter.""" | ||
729 | 163 | utils.not_implemented(utils.funcname(), True) | ||
730 | 164 | |||
731 | 165 | #------------------------------------------------------------------------------ | ||
732 | 166 | #------------------------------------------------------------------------------ | ||
733 | 167 | |||
734 | 168 | |||
735 | 169 | import sys | ||
736 | 170 | import optparse | ||
737 | 171 | |||
738 | 172 | if __name__ == "__main__": | ||
739 | 173 | parser = optparse.OptionParser() | ||
740 | 174 | parser.add_option("-i","--install",action="store_true",dest="instaction") | ||
741 | 175 | parser.add_option("-d","--debug",action="store",type="string",dest="debug") | ||
742 | 176 | |||
743 | 177 | (options, args) = parser.parse_args() | ||
744 | 178 | |||
745 | 179 | log("Starting run at: %s" % time.asctime()) | ||
746 | 180 | |||
747 | 181 | # Make sure we have our mandatory argument (at least one package) | ||
748 | 182 | if len(args) == 0: | ||
749 | 183 | print "This file is not for general usage, but meant for use from" | ||
750 | 184 | print "Acire's distropkgutils library. It should be invoked with " | ||
751 | 185 | print "a list of packages to install." | ||
752 | 186 | sys.exit(1) | ||
753 | 187 | |||
754 | 188 | log("Args: ") | ||
755 | 189 | log(str(args)) | ||
756 | 190 | |||
757 | 191 | #Choose distro-specific install function from this module | ||
758 | 192 | distname_lower = utils.distro_name() | ||
759 | 193 | log("Detected distro %s" % distname_lower) | ||
760 | 194 | |||
761 | 195 | thismodule = sys.modules[__name__] | ||
762 | 196 | inst_func_name = "__install_pkgs_%s" % distname_lower | ||
763 | 197 | try: | ||
764 | 198 | inst_func = getattr(thismodule, inst_func_name) | ||
765 | 199 | if callable(inst_func): | ||
766 | 200 | log("Calling install function: %s" % inst_func.__name__) | ||
767 | 201 | inst_func(args) | ||
768 | 202 | time.sleep(0.25) | ||
769 | 203 | except Exception, e: | ||
770 | 204 | log("Exception while trying to access install function for %s in %s" % (distname_lower, __name__)) | ||
771 | 205 | log("Exception was: %s" % str(e)) | ||
772 | 206 | time.sleep(0.25) | ||
773 | 207 | sys.exit(1) | ||
774 | 208 | |||
775 | 0 | \ No newline at end of file | 209 | \ No newline at end of file |
776 | 1 | 210 | ||
777 | === added file 'acire/utils.py' | |||
778 | --- acire/utils.py 1970-01-01 00:00:00 +0000 | |||
779 | +++ acire/utils.py 2010-05-06 10:56:27 +0000 | |||
780 | @@ -0,0 +1,47 @@ | |||
781 | 1 | #! /usr/bin/env python | ||
782 | 2 | #coding=utf-8 | ||
783 | 3 | ### BEGIN LICENSE | ||
784 | 4 | # Copyright (C) 2010 Edgar D'Souza <edgar.b.dsouza@gmail.com> | ||
785 | 5 | #This program is free software: you can redistribute it and/or modify it | ||
786 | 6 | #under the terms of the GNU General Public License version 3, as published | ||
787 | 7 | #by the Free Software Foundation. | ||
788 | 8 | # | ||
789 | 9 | #This program is distributed in the hope that it will be useful, but | ||
790 | 10 | #WITHOUT ANY WARRANTY; without even the implied warranties of | ||
791 | 11 | #MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
792 | 12 | #PURPOSE. See the GNU General Public License for more details. | ||
793 | 13 | # | ||
794 | 14 | #You should have received a copy of the GNU General Public License along | ||
795 | 15 | #with this program. If not, see <http://www.gnu.org/licenses/>. | ||
796 | 16 | ### END LICENSE | ||
797 | 17 | |||
798 | 18 | import pygtk | ||
799 | 19 | pygtk.require("2.0") | ||
800 | 20 | import gtk | ||
801 | 21 | import sys | ||
802 | 22 | import platform | ||
803 | 23 | import string | ||
804 | 24 | |||
805 | 25 | def not_implemented(function_name_string, show_dialog=False): | ||
806 | 26 | """Utility function for outputting info message that the (pkg-mgt) function | ||
807 | 27 | whose name is passed as the sole param is not yet implemented.""" | ||
808 | 28 | |||
809 | 29 | msg = "%s: Not implemented yet, please contribute!" % function_name_string | ||
810 | 30 | |||
811 | 31 | print msg | ||
812 | 32 | |||
813 | 33 | if show_dialog: | ||
814 | 34 | md = gtk.MessageDialog(None, gtk.DIALOG_DESTROY_WITH_PARENT, | ||
815 | 35 | gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE, msg) | ||
816 | 36 | md.run() | ||
817 | 37 | md.destroy() | ||
818 | 38 | |||
819 | 39 | def funcname(): | ||
820 | 40 | """Utility function, returns the name of the function | ||
821 | 41 | that calls this one.""" | ||
822 | 42 | return sys._getframe(1).f_code.co_name | ||
823 | 43 | |||
824 | 44 | def distro_name(): | ||
825 | 45 | p = platform.linux_distribution() | ||
826 | 46 | return string.lower(p[0]) | ||
827 | 47 | |||
828 | 0 | \ No newline at end of file | 48 | \ No newline at end of file |
829 | 1 | 49 | ||
830 | === modified file 'bin/acire' | |||
831 | --- bin/acire 2010-03-26 19:41:43 +0000 | |||
832 | +++ bin/acire 2010-05-06 10:56:27 +0000 | |||
833 | @@ -48,6 +48,7 @@ | |||
834 | 48 | 48 | ||
835 | 49 | from acire import AboutAcireDialog, PreferencesAcireDialog | 49 | from acire import AboutAcireDialog, PreferencesAcireDialog |
836 | 50 | from acire.acireconfig import getdatapath | 50 | from acire.acireconfig import getdatapath |
837 | 51 | from acire import depchecker | ||
838 | 51 | 52 | ||
839 | 52 | # Set up translations | 53 | # Set up translations |
840 | 53 | import gettext | 54 | import gettext |
841 | @@ -103,14 +104,14 @@ | |||
842 | 103 | self.terminal_expander = self.builder.get_object("terminal_expander") | 104 | self.terminal_expander = self.builder.get_object("terminal_expander") |
843 | 104 | self.status_label = self.builder.get_object("status_label") | 105 | self.status_label = self.builder.get_object("status_label") |
844 | 105 | self.docs_box = self.builder.get_object("docs_box") | 106 | self.docs_box = self.builder.get_object("docs_box") |
845 | 107 | self.right_pane_vbox = self.builder.get_object("vbox4") | ||
846 | 106 | 108 | ||
847 | 107 | # set up source view | 109 | # set up source view |
848 | 108 | 110 | ||
849 | 109 | self.editor_buffer = gtksourceview2.Buffer() | 111 | self.editor_buffer = gtksourceview2.Buffer() |
850 | 110 | self.editor_view = gtksourceview2.View(self.editor_buffer) | 112 | self.editor_view = gtksourceview2.View(self.editor_buffer) |
851 | 111 | self.editor_view.set_show_line_numbers(True) | 113 | self.editor_view.set_show_line_numbers(True) |
854 | 112 | 114 | ||
853 | 113 | |||
855 | 114 | # read system's monospace font, fallback to 'monospace 10' | 115 | # read system's monospace font, fallback to 'monospace 10' |
856 | 115 | self.gconf = gconf.client_get_default() | 116 | self.gconf = gconf.client_get_default() |
857 | 116 | gconf_mono_font = self.gconf.get_string("/desktop/gnome/interface/monospace_font_name") | 117 | gconf_mono_font = self.gconf.get_string("/desktop/gnome/interface/monospace_font_name") |
858 | @@ -251,6 +252,15 @@ | |||
859 | 251 | self.location_label.set_text(self.current_filename) | 252 | self.location_label.set_text(self.current_filename) |
860 | 252 | self.description_label.set_text(self.snippetsdata[self.current_filename]["description"]) | 253 | self.description_label.set_text(self.snippetsdata[self.current_filename]["description"]) |
861 | 253 | 254 | ||
862 | 255 | ###Snippet modules dependency checker (depchecker) invocation | ||
863 | 256 | # Remove the eventbox for missing modules - it will be added again if | ||
864 | 257 | # needed for the snippet that is just loaded. | ||
865 | 258 | depchecker.remove_eventbox() | ||
866 | 259 | |||
867 | 260 | # Check the script for missing modules, alert user. | ||
868 | 261 | check_results = depchecker.check_script(self.current_filename, self.right_pane_vbox) | ||
869 | 262 | ###Snippet modules dependency checker (depchecker) invocation -- ENDS | ||
870 | 263 | |||
871 | 254 | # update docs | 264 | # update docs |
872 | 255 | 265 | ||
873 | 256 | ## first delete any existing docs buttons: | 266 | ## first delete any existing docs buttons: |
Sorry for the delay, Ed! I just tested on Maverick and this doesn't work when I tested a snippet with Zeitgeist.