# # Copyright 2009-2013 Canonical Ltd. # # 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 3. # # 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 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import datetime import locale import logging import os import re from apt.utils import (get_release_filename_for_pkg, get_release_date_from_release_file, get_maintenance_end_date) from gettext import gettext as _ from softwarecenter.distro.debian import Debian from softwarecenter.enums import BUY_SOMETHING_HOST from softwarecenter.utils import utf8 LOG = logging.getLogger(__name__) class Ubuntu(Debian): # metapackages IMPORTANT_METAPACKAGES = ( "ubuntu-standard", "ubuntu-minimal", "ubuntu-desktop", "kubuntu-desktop") # screenshot handling SCREENSHOT_THUMB_URL = ("http://screenshots.ubuntu.com/" "thumbnail-with-version/%(pkgname)s/%(version)s") SCREENSHOT_LARGE_URL = ("http://screenshots.ubuntu.com/" "screenshot-with-version/%(pkgname)s/%(version)s") # the json description of the available screenshots SCREENSHOT_JSON_URL = "http://screenshots.ubuntu.com/json/package/%s" # purchase subscription PURCHASE_APP_URL = (BUY_SOMETHING_HOST + "/subscriptions/%s/ubuntu/%s/" "+new/?%s") # reviews REVIEWS_SERVER = (os.environ.get("SOFTWARE_CENTER_REVIEWS_HOST") or "http://reviews.ubuntu.com/reviews/api/1.0") REVIEWS_URL = (REVIEWS_SERVER + "/reviews/filter/%(language)s/%(origin)s/" "%(distroseries)s/%(version)s/%(pkgname)s%(appname)s/") #REVIEW_STATS_URL = (REVIEWS_SERVER + "/reviews/api/1.0/%(language)s/" # "%(origin)s/%(distroseries)s/review-stats/") # FIXME: does that make sense?!? REVIEW_STATS_URL = REVIEWS_SERVER + "/review-stats" # Starting point for Ubuntu app developers DEVELOPER_URL = "http://developer.ubuntu.com/" def get_app_name(self): return _("Ubuntu Software Center") def get_app_id(self): return "ubuntu-software-center" def get_app_description(self): return _("Lets you choose from thousands of applications available " "for Ubuntu.") def get_distro_channel_name(self): """ The name in the Release file """ return "Ubuntu" def get_distro_channel_description(self): """ The description of the main distro channel """ return _("Provided by Ubuntu") def get_removal_warning_text(self, cache, pkg, appname, depends): primary = _("To remove %s, these items must be removed " "as well:") % utf8(appname) button_text = _("Remove All") # alter it if an important meta-package is affected for m in self.IMPORTANT_METAPACKAGES: if m in depends: primary = _("%s is a core item in Ubuntu. " "Removing it may cause future upgrades " "to be incomplete. Are you sure you want to " "continue?") % appname button_text = _("Remove Anyway") depends = [] break # alter it if a meta-package is affected for m in depends: if cache[m].section == "metapackages": primary = _("If you uninstall %s, future updates will not " "include new items in %s set. " "Are you sure you want to continue?") % ( appname, cache[m].installed.summary) button_text = _("Remove Anyway") depends = [] break return (primary, button_text) def get_license_text(self, component): if component in ("main", "universe", "independent"): return _("Open source") elif component == "restricted": return _("Proprietary") else: # commercial apps provide license info via the # software-center-agent, but if a given commercial app does not # provide this for some reason, default to a license type of # "Unknown" return _("Unknown") def is_supported(self, cache, doc, pkgname): # the doc does not by definition contain correct data regarding the # section. Looking up in the cache seems just as fast/slow. if pkgname in cache and cache[pkgname].candidate: for origin in cache[pkgname].candidate.origins: if (origin.origin == "Ubuntu" and origin.trusted and (origin.component == "main" or origin.component == "restricted")): return True return False def get_supported_query(self): import xapian query1 = xapian.Query("XOL" + "Ubuntu") query2a = xapian.Query("XOC" + "main") query2b = xapian.Query("XOC" + "restricted") query2 = xapian.Query(xapian.Query.OP_OR, query2a, query2b) return xapian.Query(xapian.Query.OP_AND, query1, query2) def get_supported_filter_name(self): return _("Canonical-Maintained Software") def get_maintenance_status(self, cache, appname, pkgname, component, channelname): # try to figure out the support dates of the release and make # sure to look only for stuff in "Ubuntu" and "distro_codename" # (to exclude stuff in ubuntu-updates for the support time # calculation because the "Release" file time for that gets # updated regularly) if not hasattr(cache, '_cache') or not pkgname: return releasef = get_release_filename_for_pkg(cache._cache, pkgname, "Ubuntu", self.get_codename()) time_t = get_release_date_from_release_file(releasef) # check the release date and show support information # based on this if time_t: release_date = datetime.datetime.fromtimestamp(time_t) #print "release_date: ", release_date now = datetime.datetime.now() #release_age = (now - release_date).days #print "release age: ", release_age # init with the default time support_month = 18 # see if we have a "Supported" entry in the pkg record if (pkgname in cache and cache[pkgname].candidate): support_time = cache._cache[pkgname].candidate.record.get( "Supported") if support_time: if support_time.endswith("y"): support_month = 12 * int(support_time.strip("y")) elif support_time.endswith("m"): support_month = int(support_time.strip("m")) else: LOG.warning("unsupported 'Supported' string '%s'" % support_time) # mvo: we do not define the end date very precisely # currently this is why it will just display a end # range # print release_date, support_month (support_end_year, support_end_month) = get_maintenance_end_date( release_date, support_month) support_end_month_str = locale.nl_langinfo( getattr(locale, "MON_%d" % support_end_month)) # check if the support has ended support_ended = (now.year >= support_end_year and now.month > support_end_month) if component == "main": if support_ended: return _("Canonical does no longer provide " "updates for %s in Ubuntu %s. " "Updates may be available in a newer version of " "Ubuntu.") % (appname, self.get_distro_release()) else: d = {'appname': appname, 'support_end_month_str': support_end_month_str, 'support_end_year': support_end_year} return _("Canonical provides critical updates for " "%(appname)s until %(support_end_month_str)s " "%(support_end_year)s.") % d elif component == "restricted": if support_ended: return _("Canonical does no longer provide " "updates for %s in Ubuntu %s. " "Updates may be available in a newer version of " "Ubuntu.") % (appname, self.get_distro_release()) else: d = {'appname': appname, 'support_end_month_str': support_end_month_str, 'support_end_year': support_end_year, } return _("Canonical provides critical updates supplied " "by the developers of %(appname)s until " "%(support_end_month_str)s " "%(support_end_year)s.") % d # if we couldn't determine a support date, use a generic maintenance # string without the date if (channelname or component in ("partner", "independent", "commercial")): return _("Provided by the vendor.") elif component == "main": return _("Canonical provides critical updates for %s.") % appname elif component == "restricted": return _("Canonical provides critical updates supplied by the " "developers of %s.") % appname elif component == "universe" or component == "multiverse": return _("Canonical does not provide updates for %s. " "Some updates may be provided by the " "Ubuntu community.") % appname #return (_("Application %s has an unknown maintenance status.") % # appname) def get_downloadable_icon_url(self, full_archive_url, icon_filename): """ generates the url for a downloadable icon based on the download uri and the icon filename itself """ split_at_pool = full_archive_url.split("pool")[0] # support ppas and extras.ubuntu.com if split_at_pool.endswith("/ppa/ubuntu/"): # it's a ppa, generate the icon_url for a ppa split_at_ppa = split_at_pool.split("/ppa/")[0] downloadable_icon_url = [] downloadable_icon_url.append(split_at_ppa) downloadable_icon_url.append("/meta/ppa/") downloadable_icon_url.append(icon_filename) return "".join(downloadable_icon_url) elif re.match("http://(.*)extras.ubuntu.com/", split_at_pool): # it's from extras.ubuntu.com, generate the icon_url for a ppa split_at_ubuntu = split_at_pool.split("/ubuntu/")[0] downloadable_icon_url = [] downloadable_icon_url.append(split_at_ubuntu) downloadable_icon_url.append("/meta/") downloadable_icon_url.append(icon_filename) return "".join(downloadable_icon_url) else: #raise ValueError("we currently support downloadable icons in " # "ppa's only") LOG.warning("downloadable icon is not supported for archive: '%s'" % full_archive_url) return '' if __name__ == "__main__": import apt cache = apt.Cache() print cache.get_maintenance_status(cache, "synaptic app", "synaptic", "main", None) print cache.get_maintenance_status(cache, "3dchess app", "3dchess", "universe", None)