Merge lp:~mac9416/keryx/keryx-1.0 into lp:keryx/unstable
- keryx-1.0
- Merge into unstable
Status: | Merged |
---|---|
Merged at revision: | 36 |
Proposed branch: | lp:~mac9416/keryx/keryx-1.0 |
Merge into: | lp:keryx/unstable |
Diff against target: |
494 lines (+133/-148) 4 files modified
.bzrignore (+5/-5) bin/keryx (+119/-69) data/ui/KeryxWindow.ui (+5/-70) keryx/keryxconfig.py (+4/-4) |
To merge this branch: | bzr merge lp:~mac9416/keryx/keryx-1.0 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Senthil Kumar_Webrsk (community) | Approve | ||
Keryx Admins | Pending | ||
Review via email: mp+36507@code.launchpad.net |
Commit message
Description of the change
"Code‽ I don't have time to code! There's hay to be bailed and cows to be milked and..."
Anyway, I made some time to code. I managed to implement the Download button and the Installed Version text. That required an additional function in Unwrapt, mind you, (merge request for that coming soon) so be sure to update both branches before testing.
I'm adding RSK as a reviewer.
mac9416 (mac9416) wrote : | # |
Senthil Kumar_Webrsk (webrsk-ideas) wrote : | # |
> Bah, looks like I forgot to push the last batch of code into unstable. RSK,
> you'll just have to skim over old stuff. :-)
So do i have to take 63 revision of lp:~mac9416/keryx/unwrapt ?
mac9416 (mac9416) wrote : | # |
> So do i have to take 63 revision of lp:~mac9416/keryx/unwrapt ?
Yes, for this revision of Keryx, you'll have to have the latest Unwrapt revision from my branch as well.
To make Keryx able to import Unwrapt, you'll have to create a link at keryx/unwrapt to the unwrapt directory in your local Unwrapt branch. If keryx/unwrapt already exists, replace it with your new link.
Senthil Kumar_Webrsk (webrsk-ideas) wrote : | # |
When i try to manage the computer it fails to download the index files. As per the code it should proceed further but it raises more error.
Reading packing lists... 46%Traceback
IOError:Not a gzipped file
mac9416 (mac9416) wrote : | # |
I've encountered that error too. By adding a print statement to the index file reading code in Unwrapt, I was able to see that it was a Medibuntu index file that threw the error. Opening the file with an archive app worked perfectly fine.
Even more befuddling is that the error occurs on my 64-bit Studio desktop, but not my 32-bit Lubuntu laptop. I'll test on another 32-bit machine and see what happens.
At any rate, you can disable whatever repos are causing the error and continue testing. I'll send a message to the mailing list that this needs looking into.
mac9416 (mac9416) wrote : | # |
Hey, RSK, I'm going to go on and merge this in. If there are any serious issues, we'll iron them out later.
Senthil Kumar_Webrsk (webrsk-ideas) wrote : | # |
Ya we can proceed merging :)
Preview Diff
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2010-08-07 03:19:39 +0000 |
3 | +++ .bzrignore 2010-09-23 21:27:41 +0000 |
4 | @@ -12,9 +12,9 @@ |
5 | .git/objects |
6 | .git/refs |
7 | .git |
8 | -data/projects/amanda |
9 | -data/projects/amandasd |
10 | -data/downloads |
11 | -data/downloads |
12 | data/keryx.conf |
13 | -data/projects |
14 | +data/projects/* |
15 | +data/downloads/* |
16 | +downloads/* |
17 | +data/profiles |
18 | +keryx/unwrapt |
19 | |
20 | === modified file 'bin/keryx' |
21 | --- bin/keryx 2010-08-17 00:09:50 +0000 |
22 | +++ bin/keryx 2010-09-23 21:27:41 +0000 |
23 | @@ -27,30 +27,59 @@ |
24 | from gettext import gettext as _ |
25 | gettext.textdomain('keryx') |
26 | |
27 | -# optional Launchpad integration |
28 | -# this shouldn't crash if not found as it is simply used for bug reporting |
29 | + |
30 | +### Optional Launchpad integration ### |
31 | +# This shouldn't crash if not found as it is simply used for bug reporting. |
32 | try: |
33 | import LaunchpadIntegration |
34 | launchpad_available = True |
35 | except: |
36 | launchpad_available = False |
37 | |
38 | -# Add project root directory (enable symlink, and trunk execution). |
39 | -PROJECT_ROOT_DIRECTORY = os.path.abspath( |
40 | + |
41 | +### Add profile root directory (enable symlink, and trunk execution). ### |
42 | +PROFILE_ROOT_DIRECTORY = os.path.abspath( |
43 | os.path.dirname(os.path.dirname(os.path.realpath(sys.argv[0])))) |
44 | |
45 | -if (os.path.exists(os.path.join(PROJECT_ROOT_DIRECTORY, 'keryx')) |
46 | - and PROJECT_ROOT_DIRECTORY not in sys.path): |
47 | - sys.path.insert(0, PROJECT_ROOT_DIRECTORY) |
48 | - os.putenv('PYTHONPATH', PROJECT_ROOT_DIRECTORY) # for subprocesses |
49 | - |
50 | -from keryx import ( |
51 | - AboutKeryxDialog, keryxconfig) |
52 | +if (os.path.exists(os.path.join(PROFILE_ROOT_DIRECTORY, 'keryx')) |
53 | + and PROFILE_ROOT_DIRECTORY not in sys.path): |
54 | + sys.path.insert(0, PROFILE_ROOT_DIRECTORY) |
55 | + os.putenv('PYTHONPATH', PROFILE_ROOT_DIRECTORY) # for subprocesses |
56 | + |
57 | + |
58 | +### Start bringing in some Keryx grooviness. ### |
59 | +from keryx import AboutKeryxDialog, keryxconfig |
60 | from keryx.MessageDialogs import (error_dialog, info_dialog, question_dialog, |
61 | warning_dialog) |
62 | from keryx.helpers import create_tab, create_closeable_tab, get_builder |
63 | |
64 | |
65 | +class UnsupportedOSException(Exception): |
66 | + pass |
67 | + |
68 | + |
69 | +class ProfileExistsException(Exception): |
70 | + pass |
71 | + |
72 | + |
73 | +def is_supported_os(): |
74 | + """If the current OS is supported, return True; else, False.""" |
75 | + return platform.system() == "Linux" and \ |
76 | + os.path.exists("/var/lib/dpkg/status") |
77 | + |
78 | + |
79 | +def get_architecture(): |
80 | + """Get the architecture of the current machine, converting to an APT- |
81 | + friendly form. |
82 | + """ |
83 | + arch = platform.machine() |
84 | + if arch == "x86_64": |
85 | + arch = "amd64" |
86 | + elif arch =="i686": |
87 | + arch = "i386" |
88 | + return arch |
89 | + |
90 | + |
91 | class KeryxWindow(gtk.Window): |
92 | __gtype_name__ = "KeryxWindow" |
93 | |
94 | @@ -102,12 +131,12 @@ |
95 | else: |
96 | launchpad_available = False |
97 | |
98 | - # Uncomment the following code to read in preferences at start up. |
99 | + # Load in the preferences. |
100 | self.config = keryxconfig.Config() |
101 | |
102 | # Code for other initialization actions should be added here. |
103 | self.notebook = self._get("notebook") |
104 | - |
105 | + |
106 | name = self._get("add_computer_name_entry") |
107 | name.set_text(platform.node()) |
108 | |
109 | @@ -136,12 +165,12 @@ |
110 | |
111 | |
112 | def load_config(self): |
113 | - # Create and set the projects folder |
114 | - projects_chooser = self._get("projects_filechooserbutton") |
115 | - path = os.path.abspath(self.config.get("projects")) |
116 | + # Create and set the profiles folder |
117 | + profiles_chooser = self._get("profiles_filechooserbutton") |
118 | + path = os.path.abspath(self.config.get("profiles")) |
119 | if not os.path.exists(path): |
120 | os.makedirs(path) |
121 | - projects_chooser.set_current_folder(path) |
122 | + profiles_chooser.set_current_folder(path) |
123 | |
124 | # Create and set the downloads folder |
125 | downloads_chooser = self._get("downloads_filechooserbutton") |
126 | @@ -160,7 +189,7 @@ |
127 | self._get("proxy_username_entry").set_text(self.config.get("proxy_username")) |
128 | self._get("proxy_password_entry").set_text(self.config.get("proxy_password")) |
129 | |
130 | - for root, dirs, files in os.walk(self.config.get("projects")): |
131 | + for root, dirs, files in os.walk(self.config.get("profiles")): |
132 | for computer in [filename for filename in files if filename.endswith(".keryx")]: |
133 | self.computers_list.append([computer[:-6], root]) |
134 | |
135 | @@ -200,11 +229,11 @@ |
136 | "Path": path, |
137 | "Client": client} |
138 | |
139 | - f = open(os.path.join(path, "apt.conf"), "rb") |
140 | + f = open(os.path.join(path, "profile.conf"), "rb") |
141 | lines = f.readlines() |
142 | f.close() |
143 | |
144 | - # Read apt.conf |
145 | + # Read profile.conf |
146 | hostname = lines[0].strip() |
147 | dist, version, codename = [line.strip() for line in lines[1].split()] |
148 | arch = lines[2].strip() |
149 | @@ -216,14 +245,13 @@ |
150 | client.set_status(os.path.join(path, "status")) |
151 | |
152 | # Set repositories |
153 | + #TODO: Don't forget sources.list.d files. |
154 | f = open(os.path.join(path, "sources.list"), "rb") |
155 | repos = f.readlines() |
156 | f.close() |
157 | |
158 | def valid_line(line): |
159 | - """ |
160 | - Verify a sources line |
161 | - """ |
162 | + """Take an APT source line and only return it if it's valid.""" |
163 | line = line.strip() |
164 | |
165 | # Line must not be empty |
166 | @@ -234,13 +262,17 @@ |
167 | |
168 | return line |
169 | |
170 | - |
171 | |
172 | # Parse for valid repos |
173 | repos = [valid_line(line) for line in repos if valid_line(line)] |
174 | |
175 | client.set_repositories(repos) |
176 | - client.update() #TODO: reporthook |
177 | + try: |
178 | + client.update() #TODO: reporthook |
179 | + except IOError: |
180 | + logging.error(_("Downloading index files failed. Loading profile " \ |
181 | + "without downloading index files.")) |
182 | + client.update(download=False) |
183 | |
184 | |
185 | for item in client.get_available_package_names(): |
186 | @@ -259,53 +291,52 @@ |
187 | textbuf = self._get("package_textbuffer") |
188 | textbuf.set_text(package["Long"]) |
189 | |
190 | - #self.computer["Client"].get_package_status( |
191 | - #self._get("installed_label").set_text( |
192 | - |
193 | - |
194 | - #TODO: Move errors to their own function to be called easily |
195 | + version = self.computer["Client"].get_package_version(name) |
196 | + if not version: |
197 | + version = _("None") |
198 | + self._get("installed_label").set_text(version) |
199 | + |
200 | + |
201 | def on_add_button_clicked(self, widget, data=None): |
202 | - status_file = "/var/lib/dpkg/status" |
203 | - sources_file = "/etc/apt/sources.list" |
204 | - |
205 | - if not platform.system() == "Linux" or \ |
206 | - not os.path.exists(status_file) or \ |
207 | - not os.path.exists(sources_file): # FIXME: Not everyone has a main sources_file. |
208 | - error_dialog(self, |
209 | - "Sorry, you can only add Debian based Linux " \ |
210 | - "distros.\nPlease use Keryx on your offline " \ |
211 | - "machine.", |
212 | - "Error adding computer") |
213 | - return |
214 | - |
215 | name = self._get("add_computer_name_entry").get_text() |
216 | - |
217 | - path = os.path.join(self.config.get("projects"), name) |
218 | + path = os.path.join(self.config.get("profiles"), name) |
219 | + |
220 | + try: |
221 | + self.create_profile(name, path) |
222 | + except UnsupportedOSException: |
223 | + self.wrong_os_dialog() |
224 | + return |
225 | + except ProfileExistsException: |
226 | + self.already_managed_dialog() |
227 | + logging.error("Computer already managed: %s" % path) |
228 | + return |
229 | + |
230 | + self.computers_list.append([name, path]) |
231 | + info_dialog(self, |
232 | + "Computer added successfully!\n\nTo get started, take " \ |
233 | + "Keryx to a computer with internet access or\nyou can " \ |
234 | + "click Manage now to mark packages to download later.", |
235 | + "Everything Went Better Than Expected") |
236 | + |
237 | + def create_profile(self, name, path): |
238 | + if not is_supported_os(): |
239 | + raise UnsupportedOSException |
240 | + |
241 | + # Create the new profile's directory. |
242 | if os.path.exists(path): |
243 | - error_dialog(self, |
244 | - "The computer appears to have already been added.\n" \ |
245 | - "\nMake sure you to use a different name for each " \ |
246 | - "computer.", |
247 | - "Error Adding Computer") |
248 | - logging.error("Computer already managed: %s" % path) |
249 | - return |
250 | - |
251 | + raise ProfileExistsException |
252 | os.makedirs(path) |
253 | + |
254 | + # Create the .keryx config file. |
255 | filename = "%s.keryx" % name |
256 | f = open(os.path.join(path, filename), "wb") |
257 | f.write("%s\napt" % name) |
258 | f.close() |
259 | |
260 | - self.computers_list.append([name, path]) |
261 | - |
262 | - arch = platform.machine() |
263 | - if arch == "x86_64": |
264 | - arch = "amd64" |
265 | - |
266 | - f = open(os.path.join(path, "apt.conf"), "wb") |
267 | - f.write("%s\n%s\n%s\n%s" % (platform.uname()[1], |
268 | + f = open(os.path.join(path, "profile.conf"), "wb") |
269 | + f.write("%s\n%s\n%s\n%s" % (platform.uname()[1], |
270 | " ".join(platform.linux_distribution()), |
271 | - arch, |
272 | + get_architecture(), |
273 | platform.release())) |
274 | f.close() |
275 | |
276 | @@ -318,12 +349,6 @@ |
277 | |
278 | shutil.copy("/var/lib/dpkg/status", os.path.join(path, "status")) |
279 | |
280 | - info_dialog(self, |
281 | - "Computer added successfully!\n\nTo get started, take " \ |
282 | - "Keryx to a computer with internet access or\nyou can " \ |
283 | - "click Manage now to mark packages to download later.", |
284 | - "Everything Went Better Than Expected") |
285 | - |
286 | def about(self, widget, data=None): |
287 | """Display the about box for keryx.""" |
288 | about = AboutKeryxDialog.AboutKeryxDialog() |
289 | @@ -360,7 +385,7 @@ |
290 | self._get(item).set_sensitive(s) |
291 | |
292 | def on_preferences_changed(self, widget, data=None): |
293 | - self.config.set("projects", self._get("projects_filechooserbutton").get_current_folder()) |
294 | + self.config.set("profiles", self._get("profiles_filechooserbutton").get_current_folder()) |
295 | self.config.set("downloads", self._get("downloads_filechooserbutton").get_current_folder()) |
296 | |
297 | self.config.set("proxy", self._get("proxy_manual_radiobutton").get_active()) |
298 | @@ -379,10 +404,35 @@ |
299 | |
300 | def on_switch_tab(self, notebook, page, page_num, data=None): |
301 | self._get("preferences_label").set_text("Click Save to apply changes") |
302 | + |
303 | + def on_download(self, widget, data=None): |
304 | + # Get the name of the package selected (overcomplicated process). |
305 | + liststore, treeiter = self._get("packages_treeview").get_selection().get_selected() |
306 | + name = liststore.get_value(treeiter, 0) |
307 | + |
308 | + # Download the package. |
309 | + client = self.computer["Client"] |
310 | + package = client.get_latest_binary(name) |
311 | + client.mark_package(package) |
312 | + client.apply_changes() |
313 | |
314 | def _get(self, name): |
315 | return self.builder.get_object(name) |
316 | |
317 | + ### Error dialogs ### |
318 | + |
319 | + def wrong_os_dialog(self): |
320 | + error_dialog(self, |
321 | + "Sorry, you can only add Debian based Linux distros.\n" \ |
322 | + "Please use Keryx on your offline computer.", |
323 | + "Error Adding Computer") |
324 | + |
325 | + def already_managed_dialog(self): |
326 | + error_dialog(self, |
327 | + "The computer appears to have already been added.\n\n" \ |
328 | + "Make sure you to use a different name for each computer.", |
329 | + "Error Adding Computer") |
330 | + |
331 | if __name__ == "__main__": |
332 | # Support for command line options. |
333 | import optparse |
334 | |
335 | === modified file 'data/ui/KeryxWindow.ui' |
336 | --- data/ui/KeryxWindow.ui 2010-08-17 00:09:50 +0000 |
337 | +++ data/ui/KeryxWindow.ui 2010-09-23 21:27:41 +0000 |
338 | @@ -70,24 +70,6 @@ |
339 | </object> |
340 | </child> |
341 | <child> |
342 | - <object class="GtkImageMenuItem" id="imagemenuitem3"> |
343 | - <property name="label">gtk-save</property> |
344 | - <property name="visible">True</property> |
345 | - <property name="use_underline">True</property> |
346 | - <property name="use_stock">True</property> |
347 | - <accelerator key="s" signal="activate" modifiers="GDK_CONTROL_MASK"/> |
348 | - </object> |
349 | - </child> |
350 | - <child> |
351 | - <object class="GtkImageMenuItem" id="imagemenuitem4"> |
352 | - <property name="label">gtk-save-as</property> |
353 | - <property name="visible">True</property> |
354 | - <property name="use_underline">True</property> |
355 | - <property name="use_stock">True</property> |
356 | - <accelerator key="s" signal="activate" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK"/> |
357 | - </object> |
358 | - </child> |
359 | - <child> |
360 | <object class="GtkSeparatorMenuItem" id="separatormenuitem1"> |
361 | <property name="visible">True</property> |
362 | </object> |
363 | @@ -115,47 +97,6 @@ |
364 | <object class="GtkMenu" id="menu2"> |
365 | <property name="visible">True</property> |
366 | <child> |
367 | - <object class="GtkImageMenuItem" id="imagemenuitem6"> |
368 | - <property name="label">gtk-cut</property> |
369 | - <property name="visible">True</property> |
370 | - <property name="use_underline">True</property> |
371 | - <property name="use_stock">True</property> |
372 | - <accelerator key="x" signal="activate" modifiers="GDK_CONTROL_MASK"/> |
373 | - </object> |
374 | - </child> |
375 | - <child> |
376 | - <object class="GtkImageMenuItem" id="imagemenuitem7"> |
377 | - <property name="label">gtk-copy</property> |
378 | - <property name="visible">True</property> |
379 | - <property name="use_underline">True</property> |
380 | - <property name="use_stock">True</property> |
381 | - <accelerator key="c" signal="activate" modifiers="GDK_CONTROL_MASK"/> |
382 | - </object> |
383 | - </child> |
384 | - <child> |
385 | - <object class="GtkImageMenuItem" id="imagemenuitem8"> |
386 | - <property name="label">gtk-paste</property> |
387 | - <property name="visible">True</property> |
388 | - <property name="use_underline">True</property> |
389 | - <property name="use_stock">True</property> |
390 | - <accelerator key="v" signal="activate" modifiers="GDK_CONTROL_MASK"/> |
391 | - </object> |
392 | - </child> |
393 | - <child> |
394 | - <object class="GtkImageMenuItem" id="imagemenuitem9"> |
395 | - <property name="label">gtk-delete</property> |
396 | - <property name="visible">True</property> |
397 | - <property name="use_underline">True</property> |
398 | - <property name="use_stock">True</property> |
399 | - <accelerator key="Delete" signal="activate"/> |
400 | - </object> |
401 | - </child> |
402 | - <child> |
403 | - <object class="GtkSeparatorMenuItem" id="separatormenuitem2"> |
404 | - <property name="visible">True</property> |
405 | - </object> |
406 | - </child> |
407 | - <child> |
408 | <object class="GtkImageMenuItem" id="imagemenuitem11"> |
409 | <property name="label">gtk-preferences</property> |
410 | <property name="visible">True</property> |
411 | @@ -169,13 +110,6 @@ |
412 | </object> |
413 | </child> |
414 | <child> |
415 | - <object class="GtkMenuItem" id="menuitem3"> |
416 | - <property name="visible">True</property> |
417 | - <property name="label" translatable="yes">_View</property> |
418 | - <property name="use_underline">True</property> |
419 | - </object> |
420 | - </child> |
421 | - <child> |
422 | <object class="GtkMenuItem" id="menuitem4"> |
423 | <property name="visible">True</property> |
424 | <property name="label" translatable="yes">_Help</property> |
425 | @@ -675,6 +609,7 @@ |
426 | <property name="visible">True</property> |
427 | <property name="can_focus">True</property> |
428 | <property name="receives_default">True</property> |
429 | + <signal name="clicked" handler="on_download"/> |
430 | <child> |
431 | <object class="GtkHBox" id="hbox3"> |
432 | <property name="visible">True</property> |
433 | @@ -765,7 +700,7 @@ |
434 | <object class="GtkLabel" id="label20"> |
435 | <property name="visible">True</property> |
436 | <property name="xalign">0</property> |
437 | - <property name="label" translatable="yes">Projects:</property> |
438 | + <property name="label" translatable="yes">Profiles:</property> |
439 | <property name="width_chars">10</property> |
440 | </object> |
441 | <packing> |
442 | @@ -775,10 +710,10 @@ |
443 | </packing> |
444 | </child> |
445 | <child> |
446 | - <object class="GtkFileChooserButton" id="projects_filechooserbutton"> |
447 | + <object class="GtkFileChooserButton" id="profiles_filechooserbutton"> |
448 | <property name="visible">True</property> |
449 | + <property name="show_hidden">True</property> |
450 | <property name="action">select-folder</property> |
451 | - <property name="show_hidden">True</property> |
452 | </object> |
453 | <packing> |
454 | <property name="expand">False</property> |
455 | @@ -810,8 +745,8 @@ |
456 | <child> |
457 | <object class="GtkFileChooserButton" id="downloads_filechooserbutton"> |
458 | <property name="visible">True</property> |
459 | + <property name="show_hidden">True</property> |
460 | <property name="action">select-folder</property> |
461 | - <property name="show_hidden">True</property> |
462 | </object> |
463 | <packing> |
464 | <property name="expand">False</property> |
465 | |
466 | === modified file 'keryx/keryxconfig.py' |
467 | --- keryx/keryxconfig.py 2010-08-05 18:55:48 +0000 |
468 | +++ keryx/keryxconfig.py 2010-09-23 21:27:41 +0000 |
469 | @@ -73,7 +73,7 @@ |
470 | class Config: |
471 | section = "keryx" |
472 | defaults = [("data", get_data_path()), |
473 | - ("projects", os.path.join(get_data_path(), "projects")), |
474 | + ("profiles", os.path.join(get_data_path(), "profiles")), |
475 | ("downloads", os.path.join(get_data_path(), "downloads")), |
476 | ("proxy", "False"), |
477 | ("proxy_url", "http://localhost"), |
478 | @@ -92,10 +92,10 @@ |
479 | self._set_defaults() |
480 | self.config_file = config_path |
481 | |
482 | - projects_path = os.path.join(get_data_path(), "projects") |
483 | + profiles_path = os.path.join(get_data_path(), "profiles") |
484 | |
485 | - if not os.path.exists(projects_path): |
486 | - os.mkdir(projects_path) |
487 | + if not os.path.exists(profiles_path): |
488 | + os.mkdir(profiles_path) |
489 | |
490 | def get_filename(self): |
491 | return self.config_file |
492 | |
493 | === removed symlink 'keryx/unwrapt' |
494 | === target was u'/home/chris/projects/unwrapt/unwrapt/' |
Bah, looks like I forgot to push the last batch of code into unstable. RSK, you'll just have to skim over old stuff. :-)