Merge lp:~mvo/software-center/expunge-cache-5.0 into lp:software-center

Proposed by Michael Vogt
Status: Superseded
Proposed branch: lp:~mvo/software-center/expunge-cache-5.0
Merge into: lp:software-center
Diff against target: 1104 lines (+786/-86) (has conflicts)
13 files modified
debian/changelog (+42/-2)
softwarecenter/backend/scagent.py (+7/-0)
softwarecenter/db/update.py (+163/-0)
softwarecenter/ui/gtk3/app.py (+30/-0)
softwarecenter/ui/gtk3/panes/availablepane.py (+12/-3)
softwarecenter/ui/gtk3/panes/installedpane.py (+17/-0)
softwarecenter/ui/gtk3/panes/softwarepane.py (+90/-1)
softwarecenter/ui/gtk3/views/purchaseview.py (+17/-0)
softwarecenter/ui/gtk3/widgets/buttons.py (+5/-0)
test/test_database.py (+4/-0)
test/test_utils.py (+39/-0)
utils/expunge-cache.py (+166/-80)
utils/piston-helpers/piston_get_scagent_available_apps.py.OTHER (+194/-0)
Text conflict in debian/changelog
Text conflict in softwarecenter/backend/scagent.py
Text conflict in softwarecenter/db/update.py
Text conflict in softwarecenter/ui/gtk3/app.py
Text conflict in softwarecenter/ui/gtk3/panes/availablepane.py
Text conflict in softwarecenter/ui/gtk3/panes/installedpane.py
Text conflict in softwarecenter/ui/gtk3/panes/softwarepane.py
Text conflict in softwarecenter/ui/gtk3/views/purchaseview.py
Text conflict in softwarecenter/ui/gtk3/widgets/buttons.py
Text conflict in test/test_database.py
Text conflict in utils/expunge-cache.py
Contents conflict in utils/piston-helpers/piston_get_scagent_available_apps.py
To merge this branch: bzr merge lp:~mvo/software-center/expunge-cache-5.0
Reviewer Review Type Date Requested Status
Gary Lasker (community) Approve
Review via email: mp+95966@code.launchpad.net

This proposal has been superseded by a proposal from 2012-03-06.

Description of the change

Trivial addition to be more gently on the CPU with os.nice()

To post a comment you must log in.
Revision history for this message
Gary Lasker (gary-lasker) wrote :

Just a note that I merged the lp:~mvo/software-center/expunge-cache branch, which is the one targeting trunk. Thanks!

review: Approve

Unmerged revisions

2491. By Michael Vogt

add os.nice()

2490. By Michael Vogt

merged expunge-cache branch for 5.0

2489. By Gary Lasker

    testing (LP: #918746)

2488. By Michael Vogt

* lp:~gary-lasker/software-center/staging-certs-2-for-5.0:
  - add SOFTWARE_CENTER_FORCE_DISABLE_CERTS_CHECK to allow QA easier
    testing

2487. By Michael Vogt

grab exhibits for the current series only (LP: #899257)

2486. By Michael Vogt

* lp:~mvo/software-center/fix-server-pagination:
  - reset server side review "page" when switching to a different
    app

2485. By Michael Vogt

* lp:~gary-lasker/software-center/fix-lp913756-for-5.0:
  - do not offer to add an icon to the Unity launcher for packages
    that do not have an Exec entry in their corresponding desktop
    file, e.g. ubuntu-restricted-extras, wine (LP: #913756)

2484. By Michael Vogt

releasing version 5.0.4

2483. By Gary Lasker

    download icons directly using the provided URL (LP: #914054)

2482. By Michael Vogt

test fixes

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/changelog'
--- debian/changelog 2012-03-01 19:53:28 +0000
+++ debian/changelog 2012-03-05 18:23:26 +0000
@@ -1,3 +1,4 @@
1<<<<<<< TREE
1software-center (5.1.11) precise; urgency=low2software-center (5.1.11) precise; urgency=low
23
3 [ Michael Vogt ]4 [ Michael Vogt ]
@@ -553,11 +554,50 @@
553554
554software-center (5.0.3.2) UNRELEASED; urgency=low555software-center (5.0.3.2) UNRELEASED; urgency=low
555556
557=======
558software-center (5.0.5) UNRELEASED; urgency=low
559
560 [ Gary Lasker ]
561 * lp:~gary-lasker/software-center/fix-lp913756-for-5.0:
562 - do not offer to add an icon to the Unity launcher for packages
563 that do not have an Exec entry in their corresponding desktop
564 file, e.g. ubuntu-restricted-extras, wine (LP: #913756)
565 * lp:~gary-lasker/software-center/staging-certs-2-for-5.0:
566 - add SOFTWARE_CENTER_FORCE_DISABLE_CERTS_CHECK to allow QA easier
567 testing (LP: #918746)
568
569 [ Michael Vogt ]
570 * lp:~mvo/software-center/fix-server-pagination:
571 - reset server side review "page" when switching to a different
572 app
573
574 [ Kiwinote ]
575 * grab exhibits for the current series only (LP: #899257)
576
577 -- Gary Lasker <gary.lasker@canonical.com> Thu, 19 Jan 2012 10:54:47 -0500
578
579software-center (5.0.4) oneiric-proposed; urgency=low
580
581 [ Gary Lasker ]
582>>>>>>> MERGE-SOURCE
556 * lp:~gary-lasker/software-center/fix-lp891499-for-5.0:583 * lp:~gary-lasker/software-center/fix-lp891499-for-5.0:
557 - be more robust about problems reading the cataloged_times file 584 - be more robust about problems reading the cataloged_times file
558 as problems here can hang the UI (LP: #891499)585 as problems here can hang the UI (LP: #891499)
559586
560 -- Gary Lasker <gary.lasker@canonical.com> Mon, 28 Nov 2011 14:22:24 -0500587 [ Gabor Kelemen ]
588 * lp:~kelemeng/software-center/bug869935:
589 - Update help translations from Launchpad (LP: #869935)
590 * lp:~kelemeng/software-center/bug880757:
591 - Mark strings containing the “ character as Unicode, to fix
592 their translations. LP: #880757
593
594 [ Michael Vogt ]
595 * fix cache opening to improve startup time
596 * lp:~mvo/software-center/icon-data-for-5.0:
597 - remove the need for inline icon data from the agent, instead
598 download icons directly using the provided URL (LP: #914054)
599
600 -- Michael Vogt <michael.vogt@ubuntu.com> Tue, 10 Jan 2012 09:52:09 +0100
561601
562software-center (5.0.3.1) oneiric-proposed; urgency=low602software-center (5.0.3.1) oneiric-proposed; urgency=low
563603
564604
=== modified file 'setup.py'
=== modified file 'softwarecenter/backend/scagent.py'
--- softwarecenter/backend/scagent.py 2012-01-17 15:56:14 +0000
+++ softwarecenter/backend/scagent.py 2012-03-05 18:23:26 +0000
@@ -107,6 +107,13 @@
107 self.emit("available-for-me", piston_available_for_me)107 self.emit("available-for-me", piston_available_for_me)
108108
109 def query_exhibits(self):109 def query_exhibits(self):
110<<<<<<< TREE
111=======
112 cmd = self.HELPER_CMD[:]
113 cmd.append("exhibits")
114 cmd.append(get_language())
115 cmd.append(self.distro.get_codename())
116>>>>>>> MERGE-SOURCE
110 spawner = SpawnHelper()117 spawner = SpawnHelper()
111 spawner.parent_xid = self.xid118 spawner.parent_xid = self.xid
112 spawner.ignore_cache = self.ignore_cache119 spawner.ignore_cache = self.ignore_cache
113120
=== modified file 'softwarecenter/db/update.py'
--- softwarecenter/db/update.py 2012-02-28 22:35:19 +0000
+++ softwarecenter/db/update.py 2012-03-05 18:23:26 +0000
@@ -672,6 +672,11 @@
672 while context.pending():672 while context.pending():
673 context.iteration()673 context.iteration()
674 try:674 try:
675<<<<<<< TREE
676=======
677 # magic channel
678 entry.channel = AVAILABLE_FOR_PURCHASE_MAGIC_CHANNEL_NAME
679>>>>>>> MERGE-SOURCE
675 # now the normal parser680 # now the normal parser
676 parser = SCAApplicationParser(entry)681 parser = SCAApplicationParser(entry)
677 index_app_info_from_parser(parser, db, cache)682 index_app_info_from_parser(parser, db, cache)
@@ -932,8 +937,166 @@
932 seen.add(name)937 seen.add(name)
933938
934 index_name(doc, name, term_generator)939 index_name(doc, name, term_generator)
940<<<<<<< TREE
935941
936 pkgname = doc.get_value(XapianValues.PKGNAME)942 pkgname = doc.get_value(XapianValues.PKGNAME)
943=======
944 doc.add_value(XapianValues.APPNAME_UNTRANSLATED, untranslated_name)
945
946 # check if we should ignore this file
947 if parser.has_option_desktop("X-AppInstall-Ignore"):
948 ignore = parser.get_desktop("X-AppInstall-Ignore")
949 if ignore.strip().lower() == "true":
950 LOG.debug("X-AppInstall-Ignore found for '%s'" % parser.desktopf)
951 return
952 # architecture
953 pkgname_extension = ''
954 if parser.has_option_desktop("X-AppInstall-Architectures"):
955 arches = parser.get_desktop("X-AppInstall-Architectures")
956 doc.add_value(XapianValues.ARCHIVE_ARCH, arches)
957 native_archs = get_current_arch() in arches.split(',')
958 foreign_archs = list(set(arches.split(',')) & set(get_foreign_architectures()))
959 if not (native_archs or foreign_archs): return
960 if not native_archs and foreign_archs:
961 pkgname_extension = ':' + foreign_archs[0]
962 # package name
963 pkgname = parser.get_desktop("X-AppInstall-Package") + pkgname_extension
964 doc.add_term("AP"+pkgname)
965 if '-' in pkgname:
966 # we need this to work around xapian oddness
967 doc.add_term(pkgname.replace('-','_'))
968 doc.add_value(XapianValues.PKGNAME, pkgname)
969 doc.add_value(XapianValues.DESKTOP_FILE, parser.desktopf)
970 # display name
971 if "display_name" in axi_values:
972 doc.add_value(axi_values["display_name"], name)
973 # cataloged_times
974 if "catalogedtime" in axi_values:
975 if pkgname in cataloged_times:
976 doc.add_value(axi_values["catalogedtime"],
977 xapian.sortable_serialise(cataloged_times[pkgname]))
978 else:
979 # also catalog apps not found in axi (e.g. for-purchase apps)
980 doc.add_value(axi_values["catalogedtime"],
981 xapian.sortable_serialise(time.time()))
982 # pocket (main, restricted, ...)
983 if parser.has_option_desktop("X-AppInstall-Section"):
984 archive_section = parser.get_desktop("X-AppInstall-Section")
985 doc.add_term("AS"+archive_section)
986 doc.add_value(XapianValues.ARCHIVE_SECTION, archive_section)
987 # section (mail, base, ..)
988 if pkgname in cache and cache[pkgname].candidate:
989 section = cache[pkgname].section
990 doc.add_term("AE"+section)
991 # channel (third party stuff)
992 if parser.has_option_desktop("X-AppInstall-Channel"):
993 archive_channel = parser.get_desktop("X-AppInstall-Channel")
994 doc.add_term("AH"+archive_channel)
995 doc.add_value(XapianValues.ARCHIVE_CHANNEL, archive_channel)
996 # signing key (third party)
997 if parser.has_option_desktop("X-AppInstall-Signing-Key-Id"):
998 keyid = parser.get_desktop("X-AppInstall-Signing-Key-Id")
999 doc.add_value(XapianValues.ARCHIVE_SIGNING_KEY_ID, keyid)
1000 # license (third party)
1001 if parser.has_option_desktop("X-AppInstall-License"):
1002 license = parser.get_desktop("X-AppInstall-License")
1003 doc.add_value(XapianValues.LICENSE, license)
1004 # purchased date
1005 if parser.has_option_desktop("X-AppInstall-Purchased-Date"):
1006 date = parser.get_desktop("X-AppInstall-Purchased-Date")
1007 # strip the subseconds from the end of the date string
1008 doc.add_value(XapianValues.PURCHASED_DATE, str(date).split(".")[0])
1009 # deb-line (third party)
1010 if parser.has_option_desktop("X-AppInstall-Deb-Line"):
1011 debline = parser.get_desktop("X-AppInstall-Deb-Line")
1012 doc.add_value(XapianValues.ARCHIVE_DEB_LINE, debline)
1013 # license key (third party)
1014 if parser.has_option_desktop("X-AppInstall-License-Key"):
1015 key = parser.get_desktop("X-AppInstall-License-Key")
1016 doc.add_value(XapianValues.LICENSE_KEY, key)
1017 # license keypath (third party)
1018 if parser.has_option_desktop("X-AppInstall-License-Key-Path"):
1019 path = parser.get_desktop("X-AppInstall-License-Key-Path")
1020 doc.add_value(XapianValues.LICENSE_KEY_PATH, path)
1021 # PPA (third party stuff)
1022 if parser.has_option_desktop("X-AppInstall-PPA"):
1023 archive_ppa = parser.get_desktop("X-AppInstall-PPA")
1024 doc.add_value(XapianValues.ARCHIVE_PPA, archive_ppa)
1025 # add archive origin data here so that its available even if
1026 # the PPA is not (yet) enabled
1027 doc.add_term("XOO"+"lp-ppa-%s" % archive_ppa.replace("/", "-"))
1028 # screenshot (for third party)
1029 if parser.has_option_desktop("X-AppInstall-Screenshot-Url"):
1030 url = parser.get_desktop("X-AppInstall-Screenshot-Url")
1031 doc.add_value(XapianValues.SCREENSHOT_URL, url)
1032 # thumbnail (for third party)
1033 if parser.has_option_desktop("X-AppInstall-Thumbnail-Url"):
1034 url = parser.get_desktop("X-AppInstall-Thumbnail-Url")
1035 doc.add_value(XapianValues.THUMBNAIL_URL, url)
1036 # icon (for third party)
1037 if parser.has_option_desktop("X-AppInstall-Icon-Url"):
1038 url = parser.get_desktop("X-AppInstall-Icon-Url")
1039 doc.add_value(XapianValues.ICON_URL, url)
1040 if not parser.has_option_desktop("X-AppInstall-Icon"):
1041 # prefix pkgname to avoid name clashes
1042 doc.add_value(XapianValues.ICON, "%s-icon-%s" % (
1043 pkgname, os.path.basename(url)))
1044
1045 # price (pay stuff)
1046 if parser.has_option_desktop("X-AppInstall-Price"):
1047 price = parser.get_desktop("X-AppInstall-Price")
1048 doc.add_value(XapianValues.PRICE, price)
1049 # since this is a commercial app, indicate it in the component value
1050 doc.add_value(XapianValues.ARCHIVE_SECTION, "commercial")
1051 # icon
1052 if parser.has_option_desktop("Icon"):
1053 icon = parser.get_desktop("Icon")
1054 doc.add_value(XapianValues.ICON, icon)
1055 # write out categories
1056 for cat in parser.get_desktop_categories():
1057 doc.add_term("AC"+cat.lower())
1058 categories_string = ";".join(parser.get_desktop_categories())
1059 doc.add_value(XapianValues.CATEGORIES, categories_string)
1060 for mime in parser.get_desktop_mimetypes():
1061 doc.add_term("AM"+mime.lower())
1062 # get type (to distinguish between apps and packages
1063 if parser.has_option_desktop("Type"):
1064 type = parser.get_desktop("Type")
1065 doc.add_term("AT"+type.lower())
1066 # check gettext domain
1067 if parser.has_option_desktop("X-Ubuntu-Gettext-Domain"):
1068 domain = parser.get_desktop("X-Ubuntu-Gettext-Domain")
1069 doc.add_value(XapianValues.GETTEXT_DOMAIN, domain)
1070 # Description (software-center extension)
1071 if parser.has_option_desktop("X-AppInstall-Description"):
1072 descr = parser.get_desktop("X-AppInstall-Description")
1073 doc.add_value(XapianValues.SC_DESCRIPTION, descr)
1074 # popcon
1075 # FIXME: popularity not only based on popcon but also
1076 # on archive section, third party app etc
1077 if parser.has_option_desktop("X-AppInstall-Popcon"):
1078 popcon = float(parser.get_desktop("X-AppInstall-Popcon"))
1079 # sort_by_value uses string compare, so we need to pad here
1080 doc.add_value(XapianValues.POPCON,
1081 xapian.sortable_serialise(popcon))
1082 global popcon_max
1083 popcon_max = max(popcon_max, popcon)
1084
1085 # comment goes into the summary data if there is one,
1086 # other wise we try GenericName and if nothing else,
1087 # the summary of the package
1088 if parser.has_option_desktop("Comment"):
1089 s = parser.get_desktop("Comment")
1090 doc.add_value(XapianValues.SUMMARY, s)
1091 elif parser.has_option_desktop("GenericName"):
1092 s = parser.get_desktop("GenericName")
1093 if s != name:
1094 doc.add_value(XapianValues.SUMMARY, s)
1095 elif pkgname in cache and cache[pkgname].candidate:
1096 s = cache[pkgname].candidate.summary
1097 doc.add_value(XapianValues.SUMMARY, s)
1098
1099>>>>>>> MERGE-SOURCE
937 # add packagename as meta-data too1100 # add packagename as meta-data too
938 term_generator.index_text_without_positions(pkgname, WEIGHT_APT_PKGNAME)1101 term_generator.index_text_without_positions(pkgname, WEIGHT_APT_PKGNAME)
9391102
9401103
=== modified file 'softwarecenter/ui/gtk3/app.py'
--- softwarecenter/ui/gtk3/app.py 2012-02-29 17:23:24 +0000
+++ softwarecenter/ui/gtk3/app.py 2012-03-05 18:23:26 +0000
@@ -387,6 +387,7 @@
387 if not (options.enable_lp or och):387 if not (options.enable_lp or och):
388 file_menu.remove(self.builder.get_object("separator_login"))388 file_menu.remove(self.builder.get_object("separator_login"))
389 else:389 else:
390<<<<<<< TREE
390 # running the agent will trigger a db reload so we do it later391 # running the agent will trigger a db reload so we do it later
391 GObject.timeout_add_seconds(30, self._run_software_center_agent)392 GObject.timeout_add_seconds(30, self._run_software_center_agent)
392393
@@ -394,6 +395,22 @@
394 # keep the cache clean395 # keep the cache clean
395 GObject.timeout_add_seconds(15, self._run_expunge_cache_helper)396 GObject.timeout_add_seconds(15, self._run_expunge_cache_helper)
396397
398=======
399 sc_agent_update = os.path.join(
400 self.datadir, "update-software-center-agent")
401 (pid, stdin, stdout, stderr) = GObject.spawn_async(
402 [sc_agent_update, "--datadir", datadir],
403 flags=GObject.SPAWN_DO_NOT_REAP_CHILD)
404 GObject.child_watch_add(
405 pid, self._on_update_software_center_agent_finished)
406
407 if options.disable_buy and not options.enable_lp:
408 file_menu.remove(self.builder.get_object("separator_login"))
409
410 # keep the cache clean
411 GObject.timeout_add_seconds(45, self._run_expunge_cache_helper)
412
413>>>>>>> MERGE-SOURCE
397 # TODO: Remove the following two lines once we have remove repository414 # TODO: Remove the following two lines once we have remove repository
398 # support in aptdaemon (see LP: #723911)415 # support in aptdaemon (see LP: #723911)
399 file_menu = self.builder.get_object("menu1")416 file_menu = self.builder.get_object("menu1")
@@ -413,6 +430,7 @@
413430
414431
415 # helper432 # helper
433<<<<<<< TREE
416 def _run_software_center_agent(self):434 def _run_software_center_agent(self):
417 """ helper that triggers the update-software-center-agent helper """435 """ helper that triggers the update-software-center-agent helper """
418 sc_agent_update = os.path.join(436 sc_agent_update = os.path.join(
@@ -433,6 +451,18 @@
433 softwarecenter.paths.SOFTWARE_CENTER_CACHE_DIR,451 softwarecenter.paths.SOFTWARE_CENTER_CACHE_DIR,
434 ])452 ])
435453
454=======
455 def _run_expunge_cache_helper(self):
456 """ helper that expires the piston-mini-client cache """
457 sc_expunge_cache = os.path.join(
458 self.datadir, "expunge-cache.py")
459 (pid, stdin, stdout, stderr) = GObject.spawn_async(
460 [sc_expunge_cache,
461 "--by-unsuccessful-http-states",
462 softwarecenter.paths.SOFTWARE_CENTER_CACHE_DIR,
463 ])
464
465>>>>>>> MERGE-SOURCE
436 def _rebuild_and_reopen_local_db(self, pathname):466 def _rebuild_and_reopen_local_db(self, pathname):
437 """ helper that rebuilds a db and reopens it """467 """ helper that rebuilds a db and reopens it """
438 from softwarecenter.db.update import rebuild_database468 from softwarecenter.db.update import rebuild_database
439469
=== modified file 'softwarecenter/ui/gtk3/models/appstore2.py'
=== modified file 'softwarecenter/ui/gtk3/panes/availablepane.py'
--- softwarecenter/ui/gtk3/panes/availablepane.py 2012-02-28 13:14:06 +0000
+++ softwarecenter/ui/gtk3/panes/availablepane.py 2012-03-05 18:23:26 +0000
@@ -134,9 +134,18 @@
134 #~ self.app_view._append_appcount(appcount)134 #~ self.app_view._append_appcount(appcount)
135 #~ liststore.connect('appcount-changed', on_appcount_changed)135 #~ liststore.connect('appcount-changed', on_appcount_changed)
136 self.app_view.set_model(liststore)136 self.app_view.set_model(liststore)
137 liststore.connect(137<<<<<<< TREE
138 "needs-refresh", lambda helper, pkgname: self.app_view.queue_draw())138 liststore.connect(
139139 "needs-refresh", lambda helper, pkgname: self.app_view.queue_draw())
140
141=======
142 # setup purchase stuff
143 self.app_details_view.connect("purchase-requested",
144 self.on_purchase_requested)
145 liststore.connect(
146 "needs-refresh", lambda helper, pkgname: self.app_view.queue_draw())
147
148>>>>>>> MERGE-SOURCE
140 # purchase view149 # purchase view
141 self.purchase_view = PurchaseView()150 self.purchase_view = PurchaseView()
142 app_manager = get_appmanager()151 app_manager = get_appmanager()
143152
=== modified file 'softwarecenter/ui/gtk3/panes/installedpane.py'
--- softwarecenter/ui/gtk3/panes/installedpane.py 2012-02-28 13:51:20 +0000
+++ softwarecenter/ui/gtk3/panes/installedpane.py 2012-03-05 18:23:26 +0000
@@ -156,9 +156,14 @@
156 oneconftoolbar.set_orientation(Gtk.Orientation.HORIZONTAL)156 oneconftoolbar.set_orientation(Gtk.Orientation.HORIZONTAL)
157 oneconfpropertymenu = Gtk.Menu()157 oneconfpropertymenu = Gtk.Menu()
158 self.oneconfproperty = MenuButton(oneconfpropertymenu, Gtk.Image.new_from_stock(Gtk.STOCK_PROPERTIES, Gtk.IconSize.BUTTON))158 self.oneconfproperty = MenuButton(oneconfpropertymenu, Gtk.Image.new_from_stock(Gtk.STOCK_PROPERTIES, Gtk.IconSize.BUTTON))
159<<<<<<< TREE
159 self.stopsync_label = _(u"Stop Syncing “%s”")160 self.stopsync_label = _(u"Stop Syncing “%s”")
160 stop_oneconf_share_menuitem = Gtk.MenuItem(label=self.stopsync_label % platform.node())161 stop_oneconf_share_menuitem = Gtk.MenuItem(label=self.stopsync_label % platform.node())
161 stop_oneconf_share_menuitem.connect("activate", self._on_stop_oneconf_hostshare_clicked)162 stop_oneconf_share_menuitem.connect("activate", self._on_stop_oneconf_hostshare_clicked)
163=======
164 stop_oneconf_share_menuitem = Gtk.MenuItem(label=_(u"Stop Syncing “%s”") % platform.node())
165 stop_oneconf_share_menuitem.connect("activate", self._on_stop_showing_oneconf_clicked)
166>>>>>>> MERGE-SOURCE
162 stop_oneconf_share_menuitem.show()167 stop_oneconf_share_menuitem.show()
163 oneconfpropertymenu.append(stop_oneconf_share_menuitem)168 oneconfpropertymenu.append(stop_oneconf_share_menuitem)
164 self.oneconfcontrol.pack_start(oneconftoolbar, False, False, 1)169 self.oneconfcontrol.pack_start(oneconftoolbar, False, False, 1)
@@ -433,9 +438,15 @@
433 L = len(enq.matches)438 L = len(enq.matches)
434439
435 if L:440 if L:
441<<<<<<< TREE
436 cat_title = utf8(ngettext(u'%(amount)s item on “%(machine)s” not on this computer',442 cat_title = utf8(ngettext(u'%(amount)s item on “%(machine)s” not on this computer',
437 u'%(amount)s items on “%(machine)s” not on this computer',443 u'%(amount)s items on “%(machine)s” not on this computer',
438 L)) % { 'amount' : L, 'machine': utf8(self.current_hostname)}444 L)) % { 'amount' : L, 'machine': utf8(self.current_hostname)}
445=======
446 cat_title = ngettext(u'%(amount)s item on “%(machine)s” not on this computer',
447 u'%(amount)s items on “%(machine)s” not on this computer',
448 L) % { 'amount' : L, 'machine': self.current_hostname}
449>>>>>>> MERGE-SOURCE
439 i += L450 i += L
440 docs = enq.get_documents()451 docs = enq.get_documents()
441 self.cat_docid_map["missingpkg"] = set([doc.get_docid() for doc in docs])452 self.cat_docid_map["missingpkg"] = set([doc.get_docid() for doc in docs])
@@ -455,9 +466,15 @@
455466
456 L = len(enq.matches)467 L = len(enq.matches)
457 if L:468 if L:
469<<<<<<< TREE
458 cat_title = utf8(ngettext(u'%(amount)s item on this computer not on “%(machine)s”',470 cat_title = utf8(ngettext(u'%(amount)s item on this computer not on “%(machine)s”',
459 '%(amount)s items on this computer not on “%(machine)s”',471 '%(amount)s items on this computer not on “%(machine)s”',
460 L)) % { 'amount' : L, 'machine': utf8(self.current_hostname)}472 L)) % { 'amount' : L, 'machine': utf8(self.current_hostname)}
473=======
474 cat_title = ngettext(u'%(amount)s item on this computer not on “%(machine)s”',
475 u'%(amount)s items on this computer not on “%(machine)s”',
476 L) % { 'amount' : L, 'machine': self.current_hostname}
477>>>>>>> MERGE-SOURCE
461 i += L478 i += L
462 docs = enq.get_documents()479 docs = enq.get_documents()
463 self.cat_docid_map["additionalpkg"] = set([doc.get_docid() for doc in docs])480 self.cat_docid_map["additionalpkg"] = set([doc.get_docid() for doc in docs])
464481
=== modified file 'softwarecenter/ui/gtk3/panes/softwarepane.py'
--- softwarecenter/ui/gtk3/panes/softwarepane.py 2012-02-28 13:51:20 +0000
+++ softwarecenter/ui/gtk3/panes/softwarepane.py 2012-03-05 18:23:26 +0000
@@ -34,7 +34,8 @@
3434
35from softwarecenter.utils import (ExecutionTime,35from softwarecenter.utils import (ExecutionTime,
36 wait_for_apt_cache_ready,36 wait_for_apt_cache_ready,
37 utf837 utf8,
38 get_exec_line_from_desktop
38 )39 )
3940
40from softwarecenter.ui.gtk3.session.viewmanager import get_viewmanager41from softwarecenter.ui.gtk3.session.viewmanager import get_viewmanager
@@ -43,8 +44,15 @@
43from softwarecenter.ui.gtk3.widgets.searchaid import SearchAid44from softwarecenter.ui.gtk3.widgets.searchaid import SearchAid
4445
45from softwarecenter.ui.gtk3.views.appview import AppView46from softwarecenter.ui.gtk3.views.appview import AppView
47<<<<<<< TREE
46from softwarecenter.ui.gtk3.views.appdetailsview import AppDetailsView48from softwarecenter.ui.gtk3.views.appdetailsview import AppDetailsView
4749
50=======
51from softwarecenter.ui.gtk3.views.appdetailsview_gtk import (
52 AppDetailsViewGtk as
53 AppDetailsView)
54
55>>>>>>> MERGE-SOURCE
48from basepane import BasePane56from basepane import BasePane
4957
50LOG = logging.getLogger(__name__)58LOG = logging.getLogger(__name__)
@@ -283,6 +291,87 @@
283 vm = get_viewmanager()291 vm = get_viewmanager()
284 vm.nav_forward()292 vm.nav_forward()
285293
294<<<<<<< TREE
295=======
296 def on_transaction_started(self, backend, pkgname, appname, trans_id,
297 trans_type):
298 self._register_unity_launcher_transaction_started(
299 backend, pkgname, appname, trans_id, trans_type)
300
301
302 def _get_onscreen_icon_details_for_launcher_service(self, app):
303 if self.is_app_details_view_showing():
304 return self.app_details_view.get_app_icon_details()
305 else:
306 # TODO: implement the app list view case once it has been specified
307 return (0, 0, 0)
308
309 def _register_unity_launcher_transaction_started(self, backend, pkgname,
310 appname, trans_id,
311 trans_type):
312 # mvo: use use softwarecenter.utils explictely so that we can monkey
313 # patch it in the test
314 if not softwarecenter.utils.is_unity_running():
315 return
316 # add to launcher only applies in the details view currently
317 if not self.is_app_details_view_showing():
318 return
319 # we only care about getting the launcher information on an install
320 if not trans_type == TransactionTypes.INSTALL:
321 if pkgname in self.unity_launcher_items:
322 self.unity_launcher_items.pop(pkgname)
323 self.action_bar.clear()
324 return
325 # gather details for this transaction and create the launcher_info object
326 app = Application(pkgname=pkgname, appname=appname)
327 appdetails = app.get_details(self.db)
328 (icon_size, icon_x, icon_y) = self._get_onscreen_icon_details_for_launcher_service(app)
329 launcher_info = UnityLauncherInfo(app.name,
330 appdetails.icon,
331 "", # we set the icon_file_path value *after* install
332 icon_x,
333 icon_y,
334 icon_size,
335 appdetails.desktop_file,
336 "", # we set the installed_desktop_file_path *after* install
337 trans_id)
338 self.unity_launcher_items[app.pkgname] = launcher_info
339 self.show_add_to_launcher_panel(backend, pkgname, appname, app, appdetails, trans_id, trans_type)
340
341 def show_add_to_launcher_panel(self, backend, pkgname, appname, app, appdetails, trans_id, trans_type):
342 """
343 if Unity is currently running, display a panel to allow the user
344 the choose whether to add a newly-installed application to the
345 launcher
346 """
347 # TODO: handle local deb install case
348 # TODO: implement the list view case (once it is specified)
349 # only show the panel if unity is running and this is a package install
350 #
351 # we only show the prompt for apps with a desktop file
352 if not appdetails.desktop_file:
353 return
354 # do not add apps that have no Exec entry in their desktop file
355 # (e.g. wine, see LP: #848437 or ubuntu-restricted-extras,
356 # see LP: #913756)
357 if (os.path.exists(appdetails.desktop_file) and
358 not get_exec_line_from_desktop(appdetails.desktop_file)):
359 return
360
361 self.action_bar.add_button(ActionButtons.CANCEL_ADD_TO_LAUNCHER,
362 _("Not Now"),
363 self.on_cancel_add_to_launcher,
364 pkgname)
365 self.action_bar.add_button(ActionButtons.ADD_TO_LAUNCHER,
366 _("Add to Launcher"),
367 self.on_add_to_launcher,
368 pkgname,
369 app,
370 appdetails,
371 trans_id)
372 self.action_bar.set_label(utf8(_("Add %s to the launcher?")) % utf8(app.name))
373
374>>>>>>> MERGE-SOURCE
286 def on_query_complete(self, enquirer):375 def on_query_complete(self, enquirer):
287 self.emit("app-list-changed", len(enquirer.matches))376 self.emit("app-list-changed", len(enquirer.matches))
288 self.app_view.display_matches(enquirer.matches,377 self.app_view.display_matches(enquirer.matches,
289378
=== modified file 'softwarecenter/ui/gtk3/views/appdetailsview.py'
=== modified file 'softwarecenter/ui/gtk3/views/purchaseview.py'
--- softwarecenter/ui/gtk3/views/purchaseview.py 2012-02-09 10:34:40 +0000
+++ softwarecenter/ui/gtk3/views/purchaseview.py 2012-03-05 18:23:26 +0000
@@ -20,14 +20,21 @@
20from gi.repository import GObject20from gi.repository import GObject
21from gi.repository import Gtk21from gi.repository import Gtk
22from gi.repository import Gdk22from gi.repository import Gdk
23<<<<<<< TREE
23from gi.repository import Pango24from gi.repository import Pango
25=======
26from gi.repository import WebKit as webkit
27>>>>>>> MERGE-SOURCE
24import logging28import logging
25import os29import os
26import json30import json
27import sys31import sys
28import urllib32import urllib
33<<<<<<< TREE
29import urlparse34import urlparse
30from gi.repository import WebKit as webkit35from gi.repository import WebKit as webkit
36=======
37>>>>>>> MERGE-SOURCE
3138
32from gettext import gettext as _39from gettext import gettext as _
3340
@@ -36,6 +43,16 @@
3643
37LOG = logging.getLogger(__name__)44LOG = logging.getLogger(__name__)
3845
46# enable certificates validation in webkit views unless specified otherwise
47if not "SOFTWARE_CENTER_FORCE_DISABLE_CERTS_CHECK" in os.environ:
48 session = webkit.get_default_session()
49 session.set_property("ssl-ca-file", "/etc/ssl/certs/ca-certificates.crt")
50else:
51 # WARN the user!! Do not remove this
52 LOG.warning("SOFTWARE_CENTER_FORCE_DISABLE_CERTS_CHECK " +
53 "has been specified, all purchase transactions " +
54 "are now INSECURE and UNENCRYPTED!!")
55
39class LocaleAwareWebView(webkit.WebView):56class LocaleAwareWebView(webkit.WebView):
40 57
41 def __init__(self):58 def __init__(self):
4259
=== modified file 'softwarecenter/ui/gtk3/widgets/buttons.py'
--- softwarecenter/ui/gtk3/widgets/buttons.py 2012-02-20 15:59:17 +0000
+++ softwarecenter/ui/gtk3/widgets/buttons.py 2012-03-05 18:23:26 +0000
@@ -186,8 +186,13 @@
186 label = helper.get_appname(doc)186 label = helper.get_appname(doc)
187 icon = helper.get_icon_at_size(doc, icon_size, icon_size)187 icon = helper.get_icon_at_size(doc, icon_size, icon_size)
188 stats = helper.get_review_stats(doc)188 stats = helper.get_review_stats(doc)
189<<<<<<< TREE
189 helper.update_availability(doc)190 helper.update_availability(doc)
190 helper.connect("needs-refresh", self._on_needs_refresh, doc, icon_size)191 helper.connect("needs-refresh", self._on_needs_refresh, doc, icon_size)
192=======
193 doc.installed = doc.available = None
194 helper.connect("needs-refresh", self._on_needs_refresh, doc, icon_size)
195>>>>>>> MERGE-SOURCE
191 self.is_installed = helper.is_installed(doc)196 self.is_installed = helper.is_installed(doc)
192 self._overlay = helper.icons.load_icon(Icons.INSTALLED_OVERLAY,197 self._overlay = helper.icons.load_icon(Icons.INSTALLED_OVERLAY,
193 self.INSTALLED_OVERLAY_SIZE,198 self.INSTALLED_OVERLAY_SIZE,
194199
=== modified file 'test/test_database.py'
--- test/test_database.py 2012-02-28 22:35:19 +0000
+++ test/test_database.py 2012-03-05 18:23:26 +0000
@@ -150,12 +150,16 @@
150 ppa.count("/") == 1,150 ppa.count("/") == 1,
151 "ARCHIVE_PPA value incorrect, got '%s'" % ppa)151 "ARCHIVE_PPA value incorrect, got '%s'" % ppa)
152 self.assertTrue(152 self.assertTrue(
153<<<<<<< TREE
153 "-icon-" in doc.get_value(XapianValues.ICON))154 "-icon-" in doc.get_value(XapianValues.ICON))
154 # check support url in the DB155 # check support url in the DB
155 url=doc.get_value(XapianValues.SUPPORT_SITE_URL)156 url=doc.get_value(XapianValues.SUPPORT_SITE_URL)
156 if url:157 if url:
157 self.assertTrue(url.startswith("http") or158 self.assertTrue(url.startswith("http") or
158 url.startswith("mailto:"))159 url.startswith("mailto:"))
160=======
161 "-icon-" in doc.get_value(XapianValues.ICON))
162>>>>>>> MERGE-SOURCE
159163
160 def test_license_string_data_from_software_center_agent(self):164 def test_license_string_data_from_software_center_agent(self):
161 #os.environ["SOFTWARE_CENTER_DEBUG_HTTP"] = "1"165 #os.environ["SOFTWARE_CENTER_DEBUG_HTTP"] = "1"
162166
=== modified file 'test/test_utils.py'
--- test/test_utils.py 2012-03-01 11:32:37 +0000
+++ test/test_utils.py 2012-03-05 18:23:26 +0000
@@ -161,6 +161,45 @@
161 self.assertTrue(os.path.exists(os.path.join(dirname, "foo-random")))161 self.assertTrue(os.path.exists(os.path.join(dirname, "foo-random")))
162162
163163
164class TestExpungeCache(unittest.TestCase):
165
166 def test_expunge_cache(self):
167 import subprocess
168 import tempfile
169 dirname = tempfile.mkdtemp('s-c-testsuite')
170 for name, content in [ ("foo-301", "status: 301"),
171 ("foo-200", "status: 200"),
172 ("foo-random", "random"),
173 ]:
174 fullpath = os.path.join(dirname, name)
175 open(fullpath, "w").write(content)
176 # set to 1970+1s time to ensure the cleaner finds it
177 os.utime(fullpath, (1,1))
178 res = subprocess.call(["../utils/expunge-cache.py", dirname])
179 # no arguments
180 self.assertEqual(res, 1)
181 # by status
182 res = subprocess.call(["../utils/expunge-cache.py",
183 "--debug",
184 "--by-unsuccessful-http-states",
185 dirname])
186 self.assertFalse(os.path.exists(os.path.join(dirname, "foo-301")))
187 self.assertTrue(os.path.exists(os.path.join(dirname, "foo-200")))
188 self.assertTrue(os.path.exists(os.path.join(dirname, "foo-random")))
189
190 # by time
191 res = subprocess.call(["../utils/expunge-cache.py",
192 "--debug",
193 "--by-days", "1",
194 dirname])
195 # now we expect the old file to be gone but the unknown one not to
196 # be touched
197 self.assertFalse(os.path.exists(os.path.join(dirname, "foo-200")))
198 self.assertTrue(os.path.exists(os.path.join(dirname, "foo-random")))
199
200
201
202
164if __name__ == "__main__":203if __name__ == "__main__":
165 import logging204 import logging
166 logging.basicConfig(level=logging.DEBUG)205 logging.basicConfig(level=logging.DEBUG)
167206
=== modified file 'utils/expunge-cache.py'
--- utils/expunge-cache.py 2012-02-29 17:14:43 +0000
+++ utils/expunge-cache.py 2012-03-05 18:23:26 +0000
@@ -1,80 +1,166 @@
1#!/usr/bin/python1<<<<<<< TREE
22#!/usr/bin/python
3"""3
4Expunge httplib2 caches4"""
5"""5Expunge httplib2 caches
66"""
7import argparse7
8import logging8import argparse
9import os9import logging
10import time10import os
11import sys11import time
1212import sys
13class ExpungeCache(object):13
14 def __init__(self, dirs, args):14class ExpungeCache(object):
15 self.dirs = dirs15 def __init__(self, dirs, args):
16 # days to keep data in the cache (0 == disabled)16 self.dirs = dirs
17 self.keep_time = 60*60*24* args.by_days17 # days to keep data in the cache (0 == disabled)
18 self.keep_only_http200 = args.by_unsuccessful_http_states18 self.keep_time = 60*60*24* args.by_days
19 self.dry_run = args.dry_run19 self.keep_only_http200 = args.by_unsuccessful_http_states
2020 self.dry_run = args.dry_run
21 def _rm(self, f):21
22 if self.dry_run:22 def _rm(self, f):
23 print "Would delete: %s" % f23 if self.dry_run:
24 else:24 print "Would delete: %s" % f
25 logging.debug("Deleting: %s" % f)25 else:
26 os.unlink(f)26 logging.debug("Deleting: %s" % f)
2727 os.unlink(f)
28 def clean(self):28
29 # go over the directories29 def clean(self):
30 now = time.time()30 # go over the directories
31 for d in self.dirs:31 now = time.time()
32 for root, dirs, files in os.walk(d):32 for d in self.dirs:
33 for f in files:33 for root, dirs, files in os.walk(d):
34 fullpath = os.path.join(root, f)34 for f in files:
35 header = open(fullpath).readline().strip()35 fullpath = os.path.join(root, f)
36 if not header.startswith("status:"):36 header = open(fullpath).readline().strip()
37 logging.debug(37 if not header.startswith("status:"):
38 "Skipping files with unknown header: '%s'" % f)38 logging.debug(
39 continue39 "Skipping files with unknown header: '%s'" % f)
40 if self.keep_only_http200 and header != "status: 200":40 continue
41 self._rm(fullpath)41 if self.keep_only_http200 and header != "status: 200":
42 if self.keep_time:42 self._rm(fullpath)
43 mtime = os.path.getmtime(fullpath)43 if self.keep_time:
44 logging.debug("mtime of '%s': '%s" % (f, mtime))44 mtime = os.path.getmtime(fullpath)
45 if (mtime + self.keep_time) < now:45 logging.debug("mtime of '%s': '%s" % (f, mtime))
46 self._rm(fullpath)46 if (mtime + self.keep_time) < now:
4747 self._rm(fullpath)
48if __name__ == "__main__":48
49 parser = argparse.ArgumentParser(49if __name__ == "__main__":
50 description='clean software-center httplib2 cache')50 parser = argparse.ArgumentParser(
51 parser.add_argument(51 description='clean software-center httplib2 cache')
52 '--debug', action="store_true",52 parser.add_argument(
53 help='show debug output')53 '--debug', action="store_true",
54 parser.add_argument(54 help='show debug output')
55 '--dry-run', action="store_true",55 parser.add_argument(
56 help='do not act, just show what would be done')56 '--dry-run', action="store_true",
57 parser.add_argument(57 help='do not act, just show what would be done')
58 'directories', metavar='directory', nargs='+', type=str,58 parser.add_argument(
59 help='directories to be checked')59 'directories', metavar='directory', nargs='+', type=str,
60 parser.add_argument(60 help='directories to be checked')
61 '--by-days', type=int, default=0,61 parser.add_argument(
62 help='expire everything older than N days')62 '--by-days', type=int, default=0,
63 parser.add_argument(63 help='expire everything older than N days')
64 '--by-unsuccessful-http-states', action="store_true",64 parser.add_argument(
65 help='expire any non 200 status responses')65 '--by-unsuccessful-http-states', action="store_true",
66 args = parser.parse_args()66 help='expire any non 200 status responses')
6767 args = parser.parse_args()
68 if args.debug:68
69 logging.basicConfig(level=logging.DEBUG)69 if args.debug:
70 else:70 logging.basicConfig(level=logging.DEBUG)
71 logging.basicConfig(level=logging.INFO)71 else:
7272 logging.basicConfig(level=logging.INFO)
73 # sanity checking73
74 if args.by_days == 0 and not args.by_unsuccessful_http_states:74 # sanity checking
75 print "Need either --by-days or --by-unsuccessful-http-states argument"75 if args.by_days == 0 and not args.by_unsuccessful_http_states:
76 sys.exit(1)76 print "Need either --by-days or --by-unsuccessful-http-states argument"
7777 sys.exit(1)
78 # do it78
79 cleaner = ExpungeCache(args.directories, args)79 # do it
80 cleaner.clean()80 cleaner = ExpungeCache(args.directories, args)
81 cleaner.clean()
82=======
83#!/usr/bin/python
84
85"""
86Expunge httplib2 caches
87"""
88
89import argparse
90import logging
91import os
92import time
93import sys
94
95class ExpungeCache(object):
96 def __init__(self, dirs, args):
97 self.dirs = dirs
98 # days to keep data in the cache (0 == disabled)
99 self.keep_time = 60*60*24* args.by_days
100 self.keep_only_http200 = args.by_unsuccessful_http_states
101 self.dry_run = args.dry_run
102
103 def _rm(self, f):
104 if self.dry_run:
105 print "Would delete: %s" % f
106 else:
107 logging.debug("Deleting: %s" % f)
108 os.unlink(f)
109
110 def clean(self):
111 # go over the directories
112 now = time.time()
113 for d in self.dirs:
114 for root, dirs, files in os.walk(d):
115 for f in files:
116 fullpath = os.path.join(root, f)
117 header = open(fullpath).readline().strip()
118 if not header.startswith("status:"):
119 logging.debug(
120 "Skipping files with unknown header: '%s'" % f)
121 continue
122 if self.keep_only_http200 and header != "status: 200":
123 self._rm(fullpath)
124 if self.keep_time:
125 mtime = os.path.getmtime(fullpath)
126 logging.debug("mtime of '%s': '%s" % (f, mtime))
127 if (mtime + self.keep_time) < now:
128 self._rm(fullpath)
129
130if __name__ == "__main__":
131 parser = argparse.ArgumentParser(
132 description='clean software-center httplib2 cache')
133 parser.add_argument(
134 '--debug', action="store_true",
135 help='show debug output')
136 parser.add_argument(
137 '--dry-run', action="store_true",
138 help='do not act, just show what would be done')
139 parser.add_argument(
140 'directories', metavar='directory', nargs='+', type=str,
141 help='directories to be checked')
142 parser.add_argument(
143 '--by-days', type=int, default=0,
144 help='expire everything older than N days')
145 parser.add_argument(
146 '--by-unsuccessful-http-states', action="store_true",
147 help='expire any non 200 status responses')
148 args = parser.parse_args()
149
150 if args.debug:
151 logging.basicConfig(level=logging.DEBUG)
152 else:
153 logging.basicConfig(level=logging.INFO)
154
155 # sanity checking
156 if args.by_days == 0 and not args.by_unsuccessful_http_states:
157 print "Need either --by-days or --by-unsuccessful-http-states argument"
158 sys.exit(1)
159
160 # be nice
161 os.nice(19)
162
163 # do it
164 cleaner = ExpungeCache(args.directories, args)
165 cleaner.clean()
166>>>>>>> MERGE-SOURCE
81167
=== added file 'utils/piston-helpers/piston_get_scagent_available_apps.py.OTHER'
--- utils/piston-helpers/piston_get_scagent_available_apps.py.OTHER 1970-01-01 00:00:00 +0000
+++ utils/piston-helpers/piston_get_scagent_available_apps.py.OTHER 2012-03-05 18:23:26 +0000
@@ -0,0 +1,194 @@
1#!/usr/bin/python
2
3from gi.repository import GObject
4
5import argparse
6import logging
7import os
8import pickle
9import sys
10
11import piston_mini_client.auth
12
13from softwarecenter.enums import (SOFTWARE_CENTER_NAME_KEYRING,
14 SOFTWARE_CENTER_SSO_DESCRIPTION,
15 )
16from softwarecenter.paths import SOFTWARE_CENTER_CACHE_DIR
17from softwarecenter.backend.piston.scaclient import SoftwareCenterAgentAPI
18from softwarecenter.backend.login_sso import get_sso_backend
19from softwarecenter.backend.restfulclient import UbuntuSSOAPI
20from softwarecenter.utils import clear_token_from_ubuntu_sso
21
22from gettext import gettext as _
23
24LOG = logging.getLogger(__name__)
25
26class SSOLoginHelper(object):
27 def __init__(self, xid=0):
28 self.oauth = None
29 self.xid = xid
30 self.loop = GObject.MainLoop(GObject.main_context_default())
31
32 def _login_successful(self, sso_backend, oauth_result):
33 self.oauth = oauth_result
34 # FIXME: actually verify the token against ubuntu SSO
35 self.loop.quit()
36
37 def verify_token(self, token):
38 def _whoami_done(sso, me):
39 self._whoami = me
40 self.loop.quit()
41 self._whoami = None
42 sso = UbuntuSSOAPI(token)
43 sso.connect("whoami", _whoami_done)
44 sso.connect("error", lambda sso, err: self.loop.quit())
45 sso.whoami()
46 self.loop.run()
47 # check if the token is valid
48 if self._whoami is None:
49 return False
50 else:
51 return True
52
53 def clear_token(self):
54 clear_token_from_ubuntu_sso(SOFTWARE_CENTER_NAME_KEYRING)
55
56 def get_oauth_token_sync(self):
57 self.oauth = None
58 sso = get_sso_backend(
59 self.xid,
60 SOFTWARE_CENTER_NAME_KEYRING,
61 _(SOFTWARE_CENTER_SSO_DESCRIPTION))
62 sso.connect("login-successful", self._login_successful)
63 sso.connect("login-failed", lambda s: self.loop.quit())
64 sso.connect("login-canceled", lambda s: self.loop.quit())
65 sso.login_or_register()
66 self.loop.run()
67 return self.oauth
68
69if __name__ == "__main__":
70 logging.basicConfig()
71
72 # command line parser
73 parser = argparse.ArgumentParser(description="Helper for software-center-agent")
74 parser.add_argument("--debug", action="store_true", default=False,
75 help="enable debug output")
76 parser.add_argument("--ignore-cache", action="store_true", default=False,
77 help="force ignore cache")
78 parser.add_argument("--parent-xid", default=0,
79 help="xid of the parent window")
80
81 subparser = parser.add_subparsers(title="Commands")
82 # available_apps
83 command = subparser.add_parser("available_apps")
84 command.add_argument("lang")
85 command.add_argument("series")
86 command.add_argument("arch")
87 command.set_defaults(command="available_apps")
88
89 # available_apps_qa
90 command = subparser.add_parser("available_apps_qa")
91 command.add_argument("lang")
92 command.add_argument("series")
93 command.add_argument("arch")
94 command.set_defaults(command="available_apps_qa")
95 # subscriptions
96 command = subparser.add_parser("subscriptions_for_me")
97 command.set_defaults(command="subscriptions_for_me")
98 # exhibits
99 command = subparser.add_parser("exhibits")
100 command.add_argument("lang")
101 command.add_argument("series")
102 command.set_defaults(command="exhibits")
103
104 args = parser.parse_args()
105
106 if args.debug:
107 LOG.setLevel(logging.DEBUG)
108
109 if args.ignore_cache:
110 cachedir = None
111 else:
112 cachedir = os.path.join(SOFTWARE_CENTER_CACHE_DIR, "scaclient")
113
114
115 # check if auth is required
116 if args.command in ("available_apps_qa", "subscriptions_for_me"):
117 helper = SSOLoginHelper(args.parent_xid)
118 token = helper.get_oauth_token_sync()
119 # check if the token is valid and reset it if it is not
120 if token and not helper.verify_token(token):
121 helper.clear_token()
122 # re-trigger login
123 token = helper.get_oauth_token_sync()
124 # if we don't have a token, error here
125 if not token:
126 sys.stderr.write("ERROR: can not obtain a oauth token\n")
127 sys.exit(1)
128
129 auth = piston_mini_client.auth.OAuthAuthorizer(token["token"],
130 token["token_secret"],
131 token["consumer_key"],
132 token["consumer_secret"])
133 scaclient = SoftwareCenterAgentAPI(cachedir=cachedir, auth=auth)
134 else:
135 scaclient = SoftwareCenterAgentAPI(cachedir=cachedir)
136
137 piston_reply = None
138
139 # common kwargs
140 if args.command in ("available_apps", "available_apps_qa"):
141 kwargs = {"lang": args.lang,
142 "series": args.series,
143 "arch": args.arch
144 }
145
146 # handle the args
147 if args.command == "available_apps":
148 try:
149 piston_reply = scaclient.available_apps(**kwargs)
150 except:
151 LOG.exception("available_apps")
152 sys.exit(1)
153
154 elif args.command == "available_apps_qa":
155 try:
156 piston_reply = scaclient.available_apps_qa(**kwargs)
157 except:
158 LOG.exception("available_apps_qa")
159 sys.exit(1)
160 elif args.command == "subscriptions_for_me":
161 try:
162 piston_reply = scaclient.subscriptions_for_me(complete_only=True)
163 # the new piston API send the data in a nasty format, most
164 # interessting stuff is in the "application" dict, move it
165 # back int othe main object here so that the parser understands it
166 for item in piston_reply:
167 for k, v in item.application.iteritems():
168 setattr(item, k, v)
169 except:
170 LOG.exception("subscriptions_for_me")
171 sys.exit(1)
172 if args.command == "exhibits":
173 try:
174 piston_reply = scaclient.exhibits(lang=args.lang, series=args.series)
175 except:
176 LOG.exception("exhibits")
177 sys.exit(1)
178
179 if args.debug:
180 LOG.debug("reply: %s" % piston_reply)
181 for item in piston_reply:
182 for var in vars(item):
183 print "%s: %s" % (var, getattr(item, var))
184 print "\n\n"
185
186
187 # print to stdout where its consumed by the parent
188 if piston_reply is not None:
189 try:
190 print pickle.dumps(piston_reply)
191 except IOError:
192 # this can happen if the parent gets killed, no need to trigger
193 # apport for this
194 pass

Subscribers

People subscribed via source and target branches