249 lines
8.7 KiB
Python
249 lines
8.7 KiB
Python
# Copyright (c) 2007-2008 Canonical
|
|
#
|
|
# AUTHOR:
|
|
# Michael Vogt <mvo@ubuntu.com>
|
|
# With contributions by Siegfried-A. Gevatter <rainct@ubuntu.com>
|
|
#
|
|
# This file is part of AptUrl
|
|
#
|
|
# AptUrl 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; either version 2 of the License, or (at
|
|
# your option) any later version.
|
|
#
|
|
# AptUrl 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
|
|
# General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with AptUrl; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
import apt
|
|
import apt_pkg
|
|
|
|
import aptsources.distro
|
|
from . import Parser
|
|
from . import Helpers
|
|
from .Helpers import _
|
|
|
|
from aptsources.sourceslist import SourcesList
|
|
from optparse import OptionParser
|
|
|
|
import os
|
|
import os.path
|
|
|
|
# adding new repositories is currently disabled because some people have
|
|
# security concerns about this feature
|
|
allow_new_repositories = False
|
|
|
|
# channels that we know about
|
|
channelsdir = "/usr/share/app-install/channels"
|
|
|
|
# return codes
|
|
(RESULT_OK,
|
|
RESULT_CANCELT,
|
|
RESULT_ERROR,
|
|
RESULT_BADARGS) = list(range(4))
|
|
|
|
class AptUrlController(object):
|
|
|
|
def __init__(self, ui):
|
|
self.ui = ui
|
|
|
|
def enableSection(self, apturl):
|
|
# parse sources.list
|
|
sourceslist = SourcesList()
|
|
distro = aptsources.distro.get_distro()
|
|
distro.get_sources(sourceslist)
|
|
|
|
# check if we actually need to enable anything
|
|
requested_components = []
|
|
for component in apturl.section:
|
|
if not component in distro.enabled_comps:
|
|
requested_components.append(component)
|
|
# if not, we are fine
|
|
if not requested_components:
|
|
return RESULT_OK
|
|
# otherwise ask the user if the really wants to anble them
|
|
if not self.ui.askEnableSections(apturl.section):
|
|
return RESULT_CANCELT
|
|
if not self.ui.doEnableSection(apturl.section):
|
|
self.ui.error(_("Enabling '%s' failed") %
|
|
", ".join(apturl.section))
|
|
return RESULT_ERROR
|
|
self.ui.doUpdate()
|
|
self.openCache()
|
|
return RESULT_OK
|
|
|
|
def enableChannel(self, apturl):
|
|
# ensure that no funny path tricks can be played
|
|
# by e.g. passing "apt:foo?channel=../../"
|
|
channel = os.path.basename(apturl.channel)
|
|
|
|
channelpath = "%s/%s.list" % (channelsdir,channel)
|
|
channelkey = "%s/%s.key" % (channelsdir,channel)
|
|
channelhtml = "%s/%s.eula" % (channelsdir,channel)
|
|
|
|
# check
|
|
if not os.path.exists(channelpath):
|
|
self.ui.error(_("Unknown channel '%s'") % channel,
|
|
_("The channel '%s' is not known") % channel)
|
|
return RESULT_ERROR
|
|
channel_info_html = ""
|
|
if os.path.exists(channelhtml):
|
|
channel_info_html = open(channelhtml).read()
|
|
if not self.ui.askEnableChannel(apturl.channel, channel_info_html):
|
|
return RESULT_CANCELT
|
|
if not self.ui.doEnableChannel(channelpath, channelkey):
|
|
self.ui.error(_("Enabling channel '%s' failed") % apturl.channel)
|
|
return RESULT_ERROR
|
|
self.ui.doUpdate()
|
|
self.openCache()
|
|
return RESULT_OK
|
|
|
|
def openCache(self):
|
|
try:
|
|
self.cache = apt.Cache()
|
|
except SystemError as strerr:
|
|
if not '/etc/apt/sources.list' in str(strerr):
|
|
raise
|
|
self.ui.error(_("Invalid /etc/apt/sources.list file"), strerr)
|
|
return False
|
|
if self.cache._depcache.broken_count > 0:
|
|
err_header = _("Software index is broken")
|
|
err_body = _("This is a major failure of your software "
|
|
"management system. Please check for broken packages "
|
|
"with synaptic, check the file permissions and "
|
|
"correctness of the file '/etc/apt/sources.list' and "
|
|
"reload the software information with: "
|
|
"'sudo apt-get update' and 'sudo apt-get install -f'."
|
|
)
|
|
self.ui.error(err_header, err_body)
|
|
return False
|
|
return True
|
|
|
|
def parseArgs(self):
|
|
parser = OptionParser()
|
|
parser.add_option("-p", "--http-proxy", dest="http_proxy",
|
|
default=None, help="use http proxy")
|
|
(options, args) = parser.parse_args()
|
|
|
|
# eval and add proxy
|
|
if options.http_proxy is not None:
|
|
proxy = options.http_proxy
|
|
if not ":" in proxy:
|
|
proxy += ":3128"
|
|
os.environ["http_proxy"] = "http://%s" % proxy
|
|
|
|
# parse
|
|
try:
|
|
apturl_list = Parser.parse(args[0])
|
|
except IndexError as e:
|
|
self.ui.error(_("Need a url to continue, exiting"))
|
|
return []
|
|
except Parser.InvalidUrlException as e:
|
|
self.ui.error(_("Invalid url: '%s' given, exiting") % e.url,
|
|
str(e))
|
|
return []
|
|
return (apturl_list)
|
|
|
|
def verifyInstall(self, apturl):
|
|
" verify that the install package actually is installed "
|
|
# check if the package got actually installed
|
|
self.openCache()
|
|
pkg = self.cache[apturl.package]
|
|
if (not pkg.is_installed or
|
|
pkg._pkg.current_state != apt_pkg.CURSTATE_INSTALLED or
|
|
self.cache._depcache.broken_count > 0):
|
|
return False
|
|
return True
|
|
|
|
def main(self):
|
|
# global return code
|
|
ret = RESULT_OK
|
|
ui = self.ui
|
|
|
|
# parse arguments
|
|
apturl_list = self.parseArgs()
|
|
if not apturl_list:
|
|
return RESULT_BADARGS
|
|
|
|
# open cache
|
|
if not self.openCache():
|
|
return RESULT_ERROR
|
|
|
|
# now go over the url list
|
|
for apturl in apturl_list:
|
|
# FIXME: move this code block into a func like
|
|
# evalAptUrl()
|
|
|
|
if not apturl.schema in ("apt", "apt+http"):
|
|
self.ui.error(_("Can not deal with protocol '%s' ")
|
|
% apturl.schema)
|
|
continue
|
|
|
|
if apturl.section:
|
|
if self.enableSection(apturl) != RESULT_OK:
|
|
continue
|
|
elif apturl.channel:
|
|
if self.enableChannel(apturl) != RESULT_OK:
|
|
continue
|
|
elif apturl.refresh is not None:
|
|
ui.doUpdate()
|
|
if not self.openCache():
|
|
return RESULT_ERROR
|
|
|
|
# now check the package
|
|
if apturl.package not in self.cache:
|
|
try:
|
|
package_in_cache = bool(self.cache._cache[apturl.package])
|
|
except KeyError:
|
|
package_in_cache = False
|
|
if package_in_cache:
|
|
ui.error(_("Package '%s' is virtual.") % apturl.package)
|
|
continue
|
|
else:
|
|
ui.error(_("Could not find package '%s'.")
|
|
% apturl.package)
|
|
continue
|
|
|
|
if (self.cache[apturl.package].is_installed and
|
|
apturl.minver is None):
|
|
ui.message(_("Package '%s' is already installed")
|
|
% apturl.package)
|
|
continue
|
|
|
|
# ask the user
|
|
pkg = self.cache[apturl.package]
|
|
(sum, desc, homepage) = Helpers.parse_pkg(pkg)
|
|
if not ui.askInstallPackage(apturl.package, sum, desc, homepage):
|
|
ret = RESULT_CANCELT
|
|
continue
|
|
|
|
# try to install it
|
|
try:
|
|
self.cache[apturl.package].mark_install()
|
|
except SystemError as e:
|
|
ui.error(_("Can not install '%s' (%s) ") % (apturl.package, e))
|
|
continue
|
|
if apturl.minver is not None:
|
|
verStr = self.cache[apturl.package].candidate.version
|
|
if apt_pkg.version_compare(verStr, apturl.minver) < 1:
|
|
ui.error(_(
|
|
"Package '%s' requests minimal version '%s', but "
|
|
"only '%s' is available") % (apturl.package,
|
|
apturl.minver,
|
|
verStr))
|
|
continue
|
|
|
|
# install it
|
|
ui.doInstall(apturl)
|
|
|
|
if not self.verifyInstall(apturl):
|
|
ret = RESULT_ERROR
|
|
|
|
# return values
|
|
return ret
|