Viewing file: RepoSelector.py (15.85 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
# Copyright 2007 Red Hat, Inc. # # Jeremy Katz <katzj@redhat.com> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 only # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
import os import logging # # Python gettext: # import gettext import string import sys import urlparse import urllib
import gtk import gtk.glade import gtk.gdk as gdk import gobject
import iniparse
import yum import yum.Errors try: import repomd.mdErrors as mdErrors except ImportError: # yum 2.9.x mdErrors = yum.Errors from yum.constants import *
from constants import *
from rhpl.translate import _, N_
GLADE_FILE = "RepositoryManager.glade"
def _getgladefile(fn): if os.path.exists(fn): return fn elif os.path.exists("data/%s" %(fn,)): return "data/%s" %(fn,) else: return "/usr/share/pirut/ui/%s" %(fn,)
REPO_COLUMN = 0 REPO_ENABLED_COLUMN = 1 REPO_TEXT_COLUMN = 2
# # Python gettext: # t = gettext.translation(I18N_DOMAIN, "/usr/share/locale", fallback = True) # _ = t.lgettext
def quote(url): """Takes a url in string form, breaks it up, urlquotes it, and puts it back together to return as a string. ick.""" (s, n, u, p, q, f) = urlparse.urlparse(url) u = urllib.quote(u) return urlparse.urlunparse((s, n, u, p, q, f))
def unquote(url): (s, n, u, p, q, f) = urlparse.urlparse(url) u = urllib.unquote(u) return urlparse.urlunparse((s, n, u, p, q, f))
class RepoEditor: def __init__(self, parent, ayum, repo = None, getgladefunc = None): if getgladefunc: xmlfn = getgladefunc(GLADE_FILE) else: xmlfn = _getgladefile(GLADE_FILE) self.xml = gtk.glade.XML(xmlfn, domain=I18N_DOMAIN, root="addRepoDialog") self.dialog = self.xml.get_widget("addRepoDialog") self.dialog.set_transient_for(parent) self.parent = parent self.ayum = ayum self.repo = repo self._setSizeGroup()
e = self.xml.get_widget("advancedRepoDetailsExpander") e.set_expanded(False)
sigs = {"on_gpgCheckButton_toggled": self._gpgToggled, "on_baseurlRadio_toggled": self._baseurlToggled, "on_mirrorRadio_toggled": self._mirrorToggled} self.xml.signal_autoconnect(sigs)
if repo: self.xml.get_widget("nameEntry").set_text(repo.id) self.xml.get_widget("nameEntryLabel").set_text(repo.id) self.xml.get_widget("nameEntry").hide() self.xml.get_widget("nameEntryLabel").show() self.xml.get_widget("descriptionEntry").set_text(repo.name)
urls = string.join(map(lambda x: unquote(x), repo.baseurl), ", ") self.xml.get_widget("baseurlEntry").set_text(urls)
self.xml.get_widget("gpgCheckButton").set_active(repo.gpgcheck)
if repo.mirrorlist: ml = unquote(repo.mirrorlist) self.xml.get_widget("mirrorEntry").set_text(ml) self.xml.get_widget("mirrorRadio").set_active(True) else: self.xml.get_widget("baseurlRadio").set_active(True)
if repo.gpgkey: g = string.join(map(lambda x: unquote(x), repo.gpgkey), ", ") self.xml.get_widget("gpgEntry").set_text(g) e.set_expanded(True) def _setSizeGroup(self): # too bad we can't do this in the glade file sg = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) for w in ("nameLabel", "descriptionLabel", "baseurlRadio", "mirrorRadio", "advancedLabel"): sg.add_widget(self.xml.get_widget(w))
sg = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) for w in ("nameEntry", "descriptionEntry", "baseurlEntry", "mirrorEntry", "nameEntryLabel"): sg.add_widget(self.xml.get_widget(w))
def _gpgToggled(self, *args): cb = self.xml.get_widget("gpgCheckButton") entry = self.xml.get_widget("gpgEntry") entry.set_sensitive(cb.get_active())
def _baseurlToggled(self, rb): self.xml.get_widget("baseurlEntry").set_sensitive(rb.get_active()) def _mirrorToggled(self, rb): self.xml.get_widget("mirrorEntry").set_sensitive(rb.get_active())
def _setRepoAttr(self, attr, value): # this is kind of a hack; really, it should probably be done # within the YumRepository object self.repo.__setattr__(attr, value) if type(value) == list: value = string.join(value, ",") elif type(value) == bool: value = "%d" %(value,) self.repo.cfg.set(self.repo.id, attr, value) def run(self): while True: rc = self.dialog.run() if rc == gtk.RESPONSE_CANCEL: rc = None break
name = self.xml.get_widget("nameEntry").get_text().strip() if len(name) == 0: d = gtk.MessageDialog(self.parent, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Must provide a name for the repository.")) d.run() d.destroy() continue
desc = self.xml.get_widget("descriptionEntry").get_text().strip() if len(desc) == 0: d = gtk.MessageDialog(self.parent, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Must provide a description for the repository.")) d.run() d.destroy() continue
baseurl = self.xml.get_widget("baseurlEntry").get_text().strip().split(",") baseurl = map(lambda x: quote(x.strip()), baseurl) if self.xml.get_widget("baseurlRadio").get_active() and \ len(baseurl) == 0: d = gtk.MessageDialog(self.parent, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Must provide either a location or a " "mirror list for the repository.")) d.run() d.destroy() continue
mirror = quote(self.xml.get_widget("mirrorEntry").get_text().strip()) if self.xml.get_widget("mirrorRadio").get_active() and \ len(mirror) == 0: d = gtk.MessageDialog(self.parent, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Must provide either a location or a " "mirror list for the repository.")) d.run() d.destroy() continue
gpgkey = self.xml.get_widget("gpgEntry").get_text().strip().split(",") gpgkey = map(lambda x: quote(x.strip()), gpgkey)
# determine if there are any urls given which aren't urls bad = filter(lambda x: len(x) > 0 and \ urlparse.urlparse(x)[0] not in ("http", "https", "file", "ftp"), gpgkey + baseurl + [mirror]) if len(bad) > 0: d = gtk.MessageDialog(self.parent, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Invalid URL")) d.format_secondary_text(_("Invalid URL given. URLs must be " "begin with http://, https://, " "ftp://, or file://")) d.run() d.destroy() continue
# FIXME: we need to sanity check the values of all of our inputs # * name/description constraints? if self.repo is None: try: if self.ayum and self.ayum.repos.getRepo(name): d = gtk.MessageDialog(self.parent, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Repository named %s already " "exists.") %(name,)) d.run() d.destroy() continue except (KeyError, yum.Errors.RepoError): pass self.repo = yum.yumRepo.YumRepository(name) self.repo.cfg = iniparse.compat.ConfigParser() self.repo.cfg.add_section(name) f = "/etc/yum.repos.d/%s.repo" %(name,) while os.path.exists(f): f = "%s-1.repo" %(f[:-5],) self.repo.repofile = f self._setRepoAttr('enabled', True) self._setRepoAttr('name', desc) if len(baseurl) > 0 and self.xml.get_widget("baseurlRadio").get_active(): self._setRepoAttr('baseurl', baseurl) if len(mirror) > 0 and self.xml.get_widget("mirrorRadio").get_active(): self._setRepoAttr('mirrorlist', mirror) if self.xml.get_widget("gpgCheckButton").get_active(): self._setRepoAttr('gpgcheck', True) if len(gpgkey) > 0: self._setRepoAttr('gpgkey', gpgkey) else: self._setRepoAttr('gpgcheck', False) rc = self.repo break self.destroy() return rc
def destroy(self): return self.dialog.destroy()
class RepoSelector: def __init__(self, yumobj, getgladefunc = None): self.ayum = yumobj self._changed = False
if getgladefunc: xmlfn = getgladefunc(GLADE_FILE) else: xmlfn = _getgladefile(GLADE_FILE)
self.xml = gtk.glade.XML(xmlfn, domain=I18N_DOMAIN, root ="repoDialog") self.dialog = self.xml.get_widget("repoDialog")
sigs = {"on_repoAddButton_clicked": self._add, "on_repoEditButton_clicked": self._edit, "on_repoRemoveButton_clicked": self._remove} self.xml.signal_autoconnect(sigs)
self._createRepoStore(self.xml.get_widget("repoView"))
def __getSelectedRepo(self): selection = self.xml.get_widget("repoView").get_selection() (model, i) = selection.get_selected() if not i: return None return model.get_value(i, REPO_COLUMN)
def _add(self, *args): return self._repoEditor(None)
def _edit(self, *args): r = self.__getSelectedRepo() if r is None: d = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("No repository selected")) d.run() d.destroy() return
path = os.path.normpath(r.repofile) if len(self.ayum.rpmdb.searchFiles(path)) > 0: d = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_OK_CANCEL, _("The %s repository is included in the " "%s package. Editing of this repository " "may result in your system not " "functioning properly. Are you sure " "you want to continue?") %(r.id , self.ayum.rpmdb.searchFiles(path)[0])) rc = d.run() d.destroy() if rc == gtk.RESPONSE_CANCEL: return
return self._repoEditor(r)
def _repoEditor(self, r): d = RepoEditor(self.dialog, self.ayum, r) repo = d.run() if repo is not None: del repo.urls repo.cfg.write(file(repo.repofile, 'w')) self._changed = True if r is None: self.ayum.repos.add(repo) self._populate() def _remove(self, *args): repo = self.__getSelectedRepo() if repo is None: d = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("No repository selected")) d.run() d.destroy() return
path = os.path.normpath(repo.repofile) if len(self.ayum.rpmdb.searchFiles(path)) > 0: d = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_OK_CANCEL, _("The %s repository is included in the " "%s package. Removal of this repository " "may result in your system not " "functioning properly. Are you sure " "you want to continue?") %(repo.id , self.ayum.rpmdb.searchFiles(path)[0])) rc = d.run() d.destroy() if rc == gtk.RESPONSE_CANCEL: return
repo.cfg.remove_section(repo.id) repo.cfg.write(file(repo.repofile, 'w')) if len(repo.cfg.sections()) == 0: try: os.unlink(repo.repofile) except OSError, e: print >> sys.stderr, "Error removing repo file %s: %s" %(repo.repofile, e) self.ayum.repos.delete(repo.id) self._changed = True self._populate()
def _createRepoStore(self, tree): self.repoStore = gtk.ListStore(gobject.TYPE_PYOBJECT, gobject.TYPE_BOOLEAN, gobject.TYPE_STRING)
col = gtk.TreeViewColumn(None, None) cbr = gtk.CellRendererToggle() col.pack_start(cbr, False) col.add_attribute(cbr, 'active', REPO_ENABLED_COLUMN) cbr.connect("toggled", self._repoToggled) tree.append_column(col)
col = gtk.TreeViewColumn(None, None) txt = gtk.CellRendererText() col.pack_start(txt, False) col.add_attribute(txt, 'markup', REPO_TEXT_COLUMN) tree.append_column(col)
tree.set_model(self.repoStore)
def _repoToggled(self, widget, path): i = self.repoStore.get_iter(path) repo = self.repoStore.get_value(i, REPO_COLUMN) cb = self.repoStore.get_value(i, REPO_ENABLED_COLUMN) if repo.enabled: self.repoStore.set_value(i, REPO_ENABLED_COLUMN, False) repo.disablePersistent() else: self.repoStore.set_value(i, REPO_ENABLED_COLUMN, True) repo.enablePersistent() self._changed = True
def _populate(self): self.repoStore.clear() for repo in self.ayum.repos.sort(): self.repoStore.append([repo, repo.enabled, "<b>%s</b>\n<i>%s</i>" %(repo.id, repo.name)])
def run(self): self._populate() self.dialog.run() return self._changed
def set_transient_for(self, parent): self.dialog.set_transient_for(parent)
def destroy(self): return self.dialog.destroy()
def main(): my = yum.YumBase() my.doGenericSetup()
r = RepoSelector(my) rc = r.run() print rc r.destroy()
if __name__ == "__main__": main()
|