Merge lp:~mac9416/keryx/keryx-1.0 into lp:keryx/unstable

Proposed by mac9416
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
Reviewer Review Type Date Requested Status
Senthil Kumar_Webrsk (community) Approve
Keryx Admins Pending
Review via email: mp+36507@code.launchpad.net

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.

To post a comment you must log in.
Revision history for this message
mac9416 (mac9416) 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. :-)

Revision history for this message
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 ?

Revision history for this message
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.

Revision history for this message
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

review: Needs Information
Revision history for this message
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.

Revision history for this message
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.

Revision history for this message
Senthil Kumar_Webrsk (webrsk-ideas) wrote :

Ya we can proceed merging :)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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/'

Subscribers

People subscribed via source and target branches

to all changes: