|
Server : Apache/2.2.17 (Unix) mod_ssl/2.2.17 OpenSSL/0.9.8e-fips-rhel5 DAV/2 PHP/5.2.17 System : Linux localhost 2.6.18-419.el5 #1 SMP Fri Feb 24 22:47:42 UTC 2017 x86_64 User : nobody ( 99) PHP Version : 5.2.17 Disable Function : NONE Directory : /proc/21573/root/usr/lib/python2.4/site-packages/pirut/ |
Upload File : |
# 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
if r.repofile is None:
d = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR,
gtk.BUTTONS_OK, _("This repository could not be edited."))
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()