Merge lp:~mvo/software-center/expunge-cache-5.0 into lp:software-center
- expunge-cache-5.0
- Merge into trunk
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 |
Related bugs: |
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.
Commit message
Description of the change
Trivial addition to be more gently on the CPU with os.nice()
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
1 | === modified file 'debian/changelog' | |||
2 | --- debian/changelog 2012-03-01 19:53:28 +0000 | |||
3 | +++ debian/changelog 2012-03-05 18:23:26 +0000 | |||
4 | @@ -1,3 +1,4 @@ | |||
5 | 1 | <<<<<<< TREE | ||
6 | 1 | software-center (5.1.11) precise; urgency=low | 2 | software-center (5.1.11) precise; urgency=low |
7 | 2 | 3 | ||
8 | 3 | [ Michael Vogt ] | 4 | [ Michael Vogt ] |
9 | @@ -553,11 +554,50 @@ | |||
10 | 553 | 554 | ||
11 | 554 | software-center (5.0.3.2) UNRELEASED; urgency=low | 555 | software-center (5.0.3.2) UNRELEASED; urgency=low |
12 | 555 | 556 | ||
13 | 557 | ======= | ||
14 | 558 | software-center (5.0.5) UNRELEASED; urgency=low | ||
15 | 559 | |||
16 | 560 | [ Gary Lasker ] | ||
17 | 561 | * lp:~gary-lasker/software-center/fix-lp913756-for-5.0: | ||
18 | 562 | - do not offer to add an icon to the Unity launcher for packages | ||
19 | 563 | that do not have an Exec entry in their corresponding desktop | ||
20 | 564 | file, e.g. ubuntu-restricted-extras, wine (LP: #913756) | ||
21 | 565 | * lp:~gary-lasker/software-center/staging-certs-2-for-5.0: | ||
22 | 566 | - add SOFTWARE_CENTER_FORCE_DISABLE_CERTS_CHECK to allow QA easier | ||
23 | 567 | testing (LP: #918746) | ||
24 | 568 | |||
25 | 569 | [ Michael Vogt ] | ||
26 | 570 | * lp:~mvo/software-center/fix-server-pagination: | ||
27 | 571 | - reset server side review "page" when switching to a different | ||
28 | 572 | app | ||
29 | 573 | |||
30 | 574 | [ Kiwinote ] | ||
31 | 575 | * grab exhibits for the current series only (LP: #899257) | ||
32 | 576 | |||
33 | 577 | -- Gary Lasker <gary.lasker@canonical.com> Thu, 19 Jan 2012 10:54:47 -0500 | ||
34 | 578 | |||
35 | 579 | software-center (5.0.4) oneiric-proposed; urgency=low | ||
36 | 580 | |||
37 | 581 | [ Gary Lasker ] | ||
38 | 582 | >>>>>>> MERGE-SOURCE | ||
39 | 556 | * lp:~gary-lasker/software-center/fix-lp891499-for-5.0: | 583 | * lp:~gary-lasker/software-center/fix-lp891499-for-5.0: |
40 | 557 | - be more robust about problems reading the cataloged_times file | 584 | - be more robust about problems reading the cataloged_times file |
41 | 558 | as problems here can hang the UI (LP: #891499) | 585 | as problems here can hang the UI (LP: #891499) |
44 | 559 | 586 | ||
45 | 560 | -- Gary Lasker <gary.lasker@canonical.com> Mon, 28 Nov 2011 14:22:24 -0500 | 587 | [ Gabor Kelemen ] |
46 | 588 | * lp:~kelemeng/software-center/bug869935: | ||
47 | 589 | - Update help translations from Launchpad (LP: #869935) | ||
48 | 590 | * lp:~kelemeng/software-center/bug880757: | ||
49 | 591 | - Mark strings containing the “ character as Unicode, to fix | ||
50 | 592 | their translations. LP: #880757 | ||
51 | 593 | |||
52 | 594 | [ Michael Vogt ] | ||
53 | 595 | * fix cache opening to improve startup time | ||
54 | 596 | * lp:~mvo/software-center/icon-data-for-5.0: | ||
55 | 597 | - remove the need for inline icon data from the agent, instead | ||
56 | 598 | download icons directly using the provided URL (LP: #914054) | ||
57 | 599 | |||
58 | 600 | -- Michael Vogt <michael.vogt@ubuntu.com> Tue, 10 Jan 2012 09:52:09 +0100 | ||
59 | 561 | 601 | ||
60 | 562 | software-center (5.0.3.1) oneiric-proposed; urgency=low | 602 | software-center (5.0.3.1) oneiric-proposed; urgency=low |
61 | 563 | 603 | ||
62 | 564 | 604 | ||
63 | === modified file 'setup.py' | |||
64 | === modified file 'softwarecenter/backend/scagent.py' | |||
65 | --- softwarecenter/backend/scagent.py 2012-01-17 15:56:14 +0000 | |||
66 | +++ softwarecenter/backend/scagent.py 2012-03-05 18:23:26 +0000 | |||
67 | @@ -107,6 +107,13 @@ | |||
68 | 107 | self.emit("available-for-me", piston_available_for_me) | 107 | self.emit("available-for-me", piston_available_for_me) |
69 | 108 | 108 | ||
70 | 109 | def query_exhibits(self): | 109 | def query_exhibits(self): |
71 | 110 | <<<<<<< TREE | ||
72 | 111 | ======= | ||
73 | 112 | cmd = self.HELPER_CMD[:] | ||
74 | 113 | cmd.append("exhibits") | ||
75 | 114 | cmd.append(get_language()) | ||
76 | 115 | cmd.append(self.distro.get_codename()) | ||
77 | 116 | >>>>>>> MERGE-SOURCE | ||
78 | 110 | spawner = SpawnHelper() | 117 | spawner = SpawnHelper() |
79 | 111 | spawner.parent_xid = self.xid | 118 | spawner.parent_xid = self.xid |
80 | 112 | spawner.ignore_cache = self.ignore_cache | 119 | spawner.ignore_cache = self.ignore_cache |
81 | 113 | 120 | ||
82 | === modified file 'softwarecenter/db/update.py' | |||
83 | --- softwarecenter/db/update.py 2012-02-28 22:35:19 +0000 | |||
84 | +++ softwarecenter/db/update.py 2012-03-05 18:23:26 +0000 | |||
85 | @@ -672,6 +672,11 @@ | |||
86 | 672 | while context.pending(): | 672 | while context.pending(): |
87 | 673 | context.iteration() | 673 | context.iteration() |
88 | 674 | try: | 674 | try: |
89 | 675 | <<<<<<< TREE | ||
90 | 676 | ======= | ||
91 | 677 | # magic channel | ||
92 | 678 | entry.channel = AVAILABLE_FOR_PURCHASE_MAGIC_CHANNEL_NAME | ||
93 | 679 | >>>>>>> MERGE-SOURCE | ||
94 | 675 | # now the normal parser | 680 | # now the normal parser |
95 | 676 | parser = SCAApplicationParser(entry) | 681 | parser = SCAApplicationParser(entry) |
96 | 677 | index_app_info_from_parser(parser, db, cache) | 682 | index_app_info_from_parser(parser, db, cache) |
97 | @@ -932,8 +937,166 @@ | |||
98 | 932 | seen.add(name) | 937 | seen.add(name) |
99 | 933 | 938 | ||
100 | 934 | index_name(doc, name, term_generator) | 939 | index_name(doc, name, term_generator) |
101 | 940 | <<<<<<< TREE | ||
102 | 935 | 941 | ||
103 | 936 | pkgname = doc.get_value(XapianValues.PKGNAME) | 942 | pkgname = doc.get_value(XapianValues.PKGNAME) |
104 | 943 | ======= | ||
105 | 944 | doc.add_value(XapianValues.APPNAME_UNTRANSLATED, untranslated_name) | ||
106 | 945 | |||
107 | 946 | # check if we should ignore this file | ||
108 | 947 | if parser.has_option_desktop("X-AppInstall-Ignore"): | ||
109 | 948 | ignore = parser.get_desktop("X-AppInstall-Ignore") | ||
110 | 949 | if ignore.strip().lower() == "true": | ||
111 | 950 | LOG.debug("X-AppInstall-Ignore found for '%s'" % parser.desktopf) | ||
112 | 951 | return | ||
113 | 952 | # architecture | ||
114 | 953 | pkgname_extension = '' | ||
115 | 954 | if parser.has_option_desktop("X-AppInstall-Architectures"): | ||
116 | 955 | arches = parser.get_desktop("X-AppInstall-Architectures") | ||
117 | 956 | doc.add_value(XapianValues.ARCHIVE_ARCH, arches) | ||
118 | 957 | native_archs = get_current_arch() in arches.split(',') | ||
119 | 958 | foreign_archs = list(set(arches.split(',')) & set(get_foreign_architectures())) | ||
120 | 959 | if not (native_archs or foreign_archs): return | ||
121 | 960 | if not native_archs and foreign_archs: | ||
122 | 961 | pkgname_extension = ':' + foreign_archs[0] | ||
123 | 962 | # package name | ||
124 | 963 | pkgname = parser.get_desktop("X-AppInstall-Package") + pkgname_extension | ||
125 | 964 | doc.add_term("AP"+pkgname) | ||
126 | 965 | if '-' in pkgname: | ||
127 | 966 | # we need this to work around xapian oddness | ||
128 | 967 | doc.add_term(pkgname.replace('-','_')) | ||
129 | 968 | doc.add_value(XapianValues.PKGNAME, pkgname) | ||
130 | 969 | doc.add_value(XapianValues.DESKTOP_FILE, parser.desktopf) | ||
131 | 970 | # display name | ||
132 | 971 | if "display_name" in axi_values: | ||
133 | 972 | doc.add_value(axi_values["display_name"], name) | ||
134 | 973 | # cataloged_times | ||
135 | 974 | if "catalogedtime" in axi_values: | ||
136 | 975 | if pkgname in cataloged_times: | ||
137 | 976 | doc.add_value(axi_values["catalogedtime"], | ||
138 | 977 | xapian.sortable_serialise(cataloged_times[pkgname])) | ||
139 | 978 | else: | ||
140 | 979 | # also catalog apps not found in axi (e.g. for-purchase apps) | ||
141 | 980 | doc.add_value(axi_values["catalogedtime"], | ||
142 | 981 | xapian.sortable_serialise(time.time())) | ||
143 | 982 | # pocket (main, restricted, ...) | ||
144 | 983 | if parser.has_option_desktop("X-AppInstall-Section"): | ||
145 | 984 | archive_section = parser.get_desktop("X-AppInstall-Section") | ||
146 | 985 | doc.add_term("AS"+archive_section) | ||
147 | 986 | doc.add_value(XapianValues.ARCHIVE_SECTION, archive_section) | ||
148 | 987 | # section (mail, base, ..) | ||
149 | 988 | if pkgname in cache and cache[pkgname].candidate: | ||
150 | 989 | section = cache[pkgname].section | ||
151 | 990 | doc.add_term("AE"+section) | ||
152 | 991 | # channel (third party stuff) | ||
153 | 992 | if parser.has_option_desktop("X-AppInstall-Channel"): | ||
154 | 993 | archive_channel = parser.get_desktop("X-AppInstall-Channel") | ||
155 | 994 | doc.add_term("AH"+archive_channel) | ||
156 | 995 | doc.add_value(XapianValues.ARCHIVE_CHANNEL, archive_channel) | ||
157 | 996 | # signing key (third party) | ||
158 | 997 | if parser.has_option_desktop("X-AppInstall-Signing-Key-Id"): | ||
159 | 998 | keyid = parser.get_desktop("X-AppInstall-Signing-Key-Id") | ||
160 | 999 | doc.add_value(XapianValues.ARCHIVE_SIGNING_KEY_ID, keyid) | ||
161 | 1000 | # license (third party) | ||
162 | 1001 | if parser.has_option_desktop("X-AppInstall-License"): | ||
163 | 1002 | license = parser.get_desktop("X-AppInstall-License") | ||
164 | 1003 | doc.add_value(XapianValues.LICENSE, license) | ||
165 | 1004 | # purchased date | ||
166 | 1005 | if parser.has_option_desktop("X-AppInstall-Purchased-Date"): | ||
167 | 1006 | date = parser.get_desktop("X-AppInstall-Purchased-Date") | ||
168 | 1007 | # strip the subseconds from the end of the date string | ||
169 | 1008 | doc.add_value(XapianValues.PURCHASED_DATE, str(date).split(".")[0]) | ||
170 | 1009 | # deb-line (third party) | ||
171 | 1010 | if parser.has_option_desktop("X-AppInstall-Deb-Line"): | ||
172 | 1011 | debline = parser.get_desktop("X-AppInstall-Deb-Line") | ||
173 | 1012 | doc.add_value(XapianValues.ARCHIVE_DEB_LINE, debline) | ||
174 | 1013 | # license key (third party) | ||
175 | 1014 | if parser.has_option_desktop("X-AppInstall-License-Key"): | ||
176 | 1015 | key = parser.get_desktop("X-AppInstall-License-Key") | ||
177 | 1016 | doc.add_value(XapianValues.LICENSE_KEY, key) | ||
178 | 1017 | # license keypath (third party) | ||
179 | 1018 | if parser.has_option_desktop("X-AppInstall-License-Key-Path"): | ||
180 | 1019 | path = parser.get_desktop("X-AppInstall-License-Key-Path") | ||
181 | 1020 | doc.add_value(XapianValues.LICENSE_KEY_PATH, path) | ||
182 | 1021 | # PPA (third party stuff) | ||
183 | 1022 | if parser.has_option_desktop("X-AppInstall-PPA"): | ||
184 | 1023 | archive_ppa = parser.get_desktop("X-AppInstall-PPA") | ||
185 | 1024 | doc.add_value(XapianValues.ARCHIVE_PPA, archive_ppa) | ||
186 | 1025 | # add archive origin data here so that its available even if | ||
187 | 1026 | # the PPA is not (yet) enabled | ||
188 | 1027 | doc.add_term("XOO"+"lp-ppa-%s" % archive_ppa.replace("/", "-")) | ||
189 | 1028 | # screenshot (for third party) | ||
190 | 1029 | if parser.has_option_desktop("X-AppInstall-Screenshot-Url"): | ||
191 | 1030 | url = parser.get_desktop("X-AppInstall-Screenshot-Url") | ||
192 | 1031 | doc.add_value(XapianValues.SCREENSHOT_URL, url) | ||
193 | 1032 | # thumbnail (for third party) | ||
194 | 1033 | if parser.has_option_desktop("X-AppInstall-Thumbnail-Url"): | ||
195 | 1034 | url = parser.get_desktop("X-AppInstall-Thumbnail-Url") | ||
196 | 1035 | doc.add_value(XapianValues.THUMBNAIL_URL, url) | ||
197 | 1036 | # icon (for third party) | ||
198 | 1037 | if parser.has_option_desktop("X-AppInstall-Icon-Url"): | ||
199 | 1038 | url = parser.get_desktop("X-AppInstall-Icon-Url") | ||
200 | 1039 | doc.add_value(XapianValues.ICON_URL, url) | ||
201 | 1040 | if not parser.has_option_desktop("X-AppInstall-Icon"): | ||
202 | 1041 | # prefix pkgname to avoid name clashes | ||
203 | 1042 | doc.add_value(XapianValues.ICON, "%s-icon-%s" % ( | ||
204 | 1043 | pkgname, os.path.basename(url))) | ||
205 | 1044 | |||
206 | 1045 | # price (pay stuff) | ||
207 | 1046 | if parser.has_option_desktop("X-AppInstall-Price"): | ||
208 | 1047 | price = parser.get_desktop("X-AppInstall-Price") | ||
209 | 1048 | doc.add_value(XapianValues.PRICE, price) | ||
210 | 1049 | # since this is a commercial app, indicate it in the component value | ||
211 | 1050 | doc.add_value(XapianValues.ARCHIVE_SECTION, "commercial") | ||
212 | 1051 | # icon | ||
213 | 1052 | if parser.has_option_desktop("Icon"): | ||
214 | 1053 | icon = parser.get_desktop("Icon") | ||
215 | 1054 | doc.add_value(XapianValues.ICON, icon) | ||
216 | 1055 | # write out categories | ||
217 | 1056 | for cat in parser.get_desktop_categories(): | ||
218 | 1057 | doc.add_term("AC"+cat.lower()) | ||
219 | 1058 | categories_string = ";".join(parser.get_desktop_categories()) | ||
220 | 1059 | doc.add_value(XapianValues.CATEGORIES, categories_string) | ||
221 | 1060 | for mime in parser.get_desktop_mimetypes(): | ||
222 | 1061 | doc.add_term("AM"+mime.lower()) | ||
223 | 1062 | # get type (to distinguish between apps and packages | ||
224 | 1063 | if parser.has_option_desktop("Type"): | ||
225 | 1064 | type = parser.get_desktop("Type") | ||
226 | 1065 | doc.add_term("AT"+type.lower()) | ||
227 | 1066 | # check gettext domain | ||
228 | 1067 | if parser.has_option_desktop("X-Ubuntu-Gettext-Domain"): | ||
229 | 1068 | domain = parser.get_desktop("X-Ubuntu-Gettext-Domain") | ||
230 | 1069 | doc.add_value(XapianValues.GETTEXT_DOMAIN, domain) | ||
231 | 1070 | # Description (software-center extension) | ||
232 | 1071 | if parser.has_option_desktop("X-AppInstall-Description"): | ||
233 | 1072 | descr = parser.get_desktop("X-AppInstall-Description") | ||
234 | 1073 | doc.add_value(XapianValues.SC_DESCRIPTION, descr) | ||
235 | 1074 | # popcon | ||
236 | 1075 | # FIXME: popularity not only based on popcon but also | ||
237 | 1076 | # on archive section, third party app etc | ||
238 | 1077 | if parser.has_option_desktop("X-AppInstall-Popcon"): | ||
239 | 1078 | popcon = float(parser.get_desktop("X-AppInstall-Popcon")) | ||
240 | 1079 | # sort_by_value uses string compare, so we need to pad here | ||
241 | 1080 | doc.add_value(XapianValues.POPCON, | ||
242 | 1081 | xapian.sortable_serialise(popcon)) | ||
243 | 1082 | global popcon_max | ||
244 | 1083 | popcon_max = max(popcon_max, popcon) | ||
245 | 1084 | |||
246 | 1085 | # comment goes into the summary data if there is one, | ||
247 | 1086 | # other wise we try GenericName and if nothing else, | ||
248 | 1087 | # the summary of the package | ||
249 | 1088 | if parser.has_option_desktop("Comment"): | ||
250 | 1089 | s = parser.get_desktop("Comment") | ||
251 | 1090 | doc.add_value(XapianValues.SUMMARY, s) | ||
252 | 1091 | elif parser.has_option_desktop("GenericName"): | ||
253 | 1092 | s = parser.get_desktop("GenericName") | ||
254 | 1093 | if s != name: | ||
255 | 1094 | doc.add_value(XapianValues.SUMMARY, s) | ||
256 | 1095 | elif pkgname in cache and cache[pkgname].candidate: | ||
257 | 1096 | s = cache[pkgname].candidate.summary | ||
258 | 1097 | doc.add_value(XapianValues.SUMMARY, s) | ||
259 | 1098 | |||
260 | 1099 | >>>>>>> MERGE-SOURCE | ||
261 | 937 | # add packagename as meta-data too | 1100 | # add packagename as meta-data too |
262 | 938 | term_generator.index_text_without_positions(pkgname, WEIGHT_APT_PKGNAME) | 1101 | term_generator.index_text_without_positions(pkgname, WEIGHT_APT_PKGNAME) |
263 | 939 | 1102 | ||
264 | 940 | 1103 | ||
265 | === modified file 'softwarecenter/ui/gtk3/app.py' | |||
266 | --- softwarecenter/ui/gtk3/app.py 2012-02-29 17:23:24 +0000 | |||
267 | +++ softwarecenter/ui/gtk3/app.py 2012-03-05 18:23:26 +0000 | |||
268 | @@ -387,6 +387,7 @@ | |||
269 | 387 | if not (options.enable_lp or och): | 387 | if not (options.enable_lp or och): |
270 | 388 | file_menu.remove(self.builder.get_object("separator_login")) | 388 | file_menu.remove(self.builder.get_object("separator_login")) |
271 | 389 | else: | 389 | else: |
272 | 390 | <<<<<<< TREE | ||
273 | 390 | # running the agent will trigger a db reload so we do it later | 391 | # running the agent will trigger a db reload so we do it later |
274 | 391 | GObject.timeout_add_seconds(30, self._run_software_center_agent) | 392 | GObject.timeout_add_seconds(30, self._run_software_center_agent) |
275 | 392 | 393 | ||
276 | @@ -394,6 +395,22 @@ | |||
277 | 394 | # keep the cache clean | 395 | # keep the cache clean |
278 | 395 | GObject.timeout_add_seconds(15, self._run_expunge_cache_helper) | 396 | GObject.timeout_add_seconds(15, self._run_expunge_cache_helper) |
279 | 396 | 397 | ||
280 | 398 | ======= | ||
281 | 399 | sc_agent_update = os.path.join( | ||
282 | 400 | self.datadir, "update-software-center-agent") | ||
283 | 401 | (pid, stdin, stdout, stderr) = GObject.spawn_async( | ||
284 | 402 | [sc_agent_update, "--datadir", datadir], | ||
285 | 403 | flags=GObject.SPAWN_DO_NOT_REAP_CHILD) | ||
286 | 404 | GObject.child_watch_add( | ||
287 | 405 | pid, self._on_update_software_center_agent_finished) | ||
288 | 406 | |||
289 | 407 | if options.disable_buy and not options.enable_lp: | ||
290 | 408 | file_menu.remove(self.builder.get_object("separator_login")) | ||
291 | 409 | |||
292 | 410 | # keep the cache clean | ||
293 | 411 | GObject.timeout_add_seconds(45, self._run_expunge_cache_helper) | ||
294 | 412 | |||
295 | 413 | >>>>>>> MERGE-SOURCE | ||
296 | 397 | # TODO: Remove the following two lines once we have remove repository | 414 | # TODO: Remove the following two lines once we have remove repository |
297 | 398 | # support in aptdaemon (see LP: #723911) | 415 | # support in aptdaemon (see LP: #723911) |
298 | 399 | file_menu = self.builder.get_object("menu1") | 416 | file_menu = self.builder.get_object("menu1") |
299 | @@ -413,6 +430,7 @@ | |||
300 | 413 | 430 | ||
301 | 414 | 431 | ||
302 | 415 | # helper | 432 | # helper |
303 | 433 | <<<<<<< TREE | ||
304 | 416 | def _run_software_center_agent(self): | 434 | def _run_software_center_agent(self): |
305 | 417 | """ helper that triggers the update-software-center-agent helper """ | 435 | """ helper that triggers the update-software-center-agent helper """ |
306 | 418 | sc_agent_update = os.path.join( | 436 | sc_agent_update = os.path.join( |
307 | @@ -433,6 +451,18 @@ | |||
308 | 433 | softwarecenter.paths.SOFTWARE_CENTER_CACHE_DIR, | 451 | softwarecenter.paths.SOFTWARE_CENTER_CACHE_DIR, |
309 | 434 | ]) | 452 | ]) |
310 | 435 | 453 | ||
311 | 454 | ======= | ||
312 | 455 | def _run_expunge_cache_helper(self): | ||
313 | 456 | """ helper that expires the piston-mini-client cache """ | ||
314 | 457 | sc_expunge_cache = os.path.join( | ||
315 | 458 | self.datadir, "expunge-cache.py") | ||
316 | 459 | (pid, stdin, stdout, stderr) = GObject.spawn_async( | ||
317 | 460 | [sc_expunge_cache, | ||
318 | 461 | "--by-unsuccessful-http-states", | ||
319 | 462 | softwarecenter.paths.SOFTWARE_CENTER_CACHE_DIR, | ||
320 | 463 | ]) | ||
321 | 464 | |||
322 | 465 | >>>>>>> MERGE-SOURCE | ||
323 | 436 | def _rebuild_and_reopen_local_db(self, pathname): | 466 | def _rebuild_and_reopen_local_db(self, pathname): |
324 | 437 | """ helper that rebuilds a db and reopens it """ | 467 | """ helper that rebuilds a db and reopens it """ |
325 | 438 | from softwarecenter.db.update import rebuild_database | 468 | from softwarecenter.db.update import rebuild_database |
326 | 439 | 469 | ||
327 | === modified file 'softwarecenter/ui/gtk3/models/appstore2.py' | |||
328 | === modified file 'softwarecenter/ui/gtk3/panes/availablepane.py' | |||
329 | --- softwarecenter/ui/gtk3/panes/availablepane.py 2012-02-28 13:14:06 +0000 | |||
330 | +++ softwarecenter/ui/gtk3/panes/availablepane.py 2012-03-05 18:23:26 +0000 | |||
331 | @@ -134,9 +134,18 @@ | |||
332 | 134 | #~ self.app_view._append_appcount(appcount) | 134 | #~ self.app_view._append_appcount(appcount) |
333 | 135 | #~ liststore.connect('appcount-changed', on_appcount_changed) | 135 | #~ liststore.connect('appcount-changed', on_appcount_changed) |
334 | 136 | self.app_view.set_model(liststore) | 136 | self.app_view.set_model(liststore) |
338 | 137 | liststore.connect( | 137 | <<<<<<< TREE |
339 | 138 | "needs-refresh", lambda helper, pkgname: self.app_view.queue_draw()) | 138 | liststore.connect( |
340 | 139 | 139 | "needs-refresh", lambda helper, pkgname: self.app_view.queue_draw()) | |
341 | 140 | |||
342 | 141 | ======= | ||
343 | 142 | # setup purchase stuff | ||
344 | 143 | self.app_details_view.connect("purchase-requested", | ||
345 | 144 | self.on_purchase_requested) | ||
346 | 145 | liststore.connect( | ||
347 | 146 | "needs-refresh", lambda helper, pkgname: self.app_view.queue_draw()) | ||
348 | 147 | |||
349 | 148 | >>>>>>> MERGE-SOURCE | ||
350 | 140 | # purchase view | 149 | # purchase view |
351 | 141 | self.purchase_view = PurchaseView() | 150 | self.purchase_view = PurchaseView() |
352 | 142 | app_manager = get_appmanager() | 151 | app_manager = get_appmanager() |
353 | 143 | 152 | ||
354 | === modified file 'softwarecenter/ui/gtk3/panes/installedpane.py' | |||
355 | --- softwarecenter/ui/gtk3/panes/installedpane.py 2012-02-28 13:51:20 +0000 | |||
356 | +++ softwarecenter/ui/gtk3/panes/installedpane.py 2012-03-05 18:23:26 +0000 | |||
357 | @@ -156,9 +156,14 @@ | |||
358 | 156 | oneconftoolbar.set_orientation(Gtk.Orientation.HORIZONTAL) | 156 | oneconftoolbar.set_orientation(Gtk.Orientation.HORIZONTAL) |
359 | 157 | oneconfpropertymenu = Gtk.Menu() | 157 | oneconfpropertymenu = Gtk.Menu() |
360 | 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)) |
361 | 159 | <<<<<<< TREE | ||
362 | 159 | self.stopsync_label = _(u"Stop Syncing “%s”") | 160 | self.stopsync_label = _(u"Stop Syncing “%s”") |
363 | 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()) |
364 | 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) |
365 | 163 | ======= | ||
366 | 164 | stop_oneconf_share_menuitem = Gtk.MenuItem(label=_(u"Stop Syncing “%s”") % platform.node()) | ||
367 | 165 | stop_oneconf_share_menuitem.connect("activate", self._on_stop_showing_oneconf_clicked) | ||
368 | 166 | >>>>>>> MERGE-SOURCE | ||
369 | 162 | stop_oneconf_share_menuitem.show() | 167 | stop_oneconf_share_menuitem.show() |
370 | 163 | oneconfpropertymenu.append(stop_oneconf_share_menuitem) | 168 | oneconfpropertymenu.append(stop_oneconf_share_menuitem) |
371 | 164 | self.oneconfcontrol.pack_start(oneconftoolbar, False, False, 1) | 169 | self.oneconfcontrol.pack_start(oneconftoolbar, False, False, 1) |
372 | @@ -433,9 +438,15 @@ | |||
373 | 433 | L = len(enq.matches) | 438 | L = len(enq.matches) |
374 | 434 | 439 | ||
375 | 435 | if L: | 440 | if L: |
376 | 441 | <<<<<<< TREE | ||
377 | 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', |
378 | 437 | u'%(amount)s items on “%(machine)s” not on this computer', | 443 | u'%(amount)s items on “%(machine)s” not on this computer', |
379 | 438 | L)) % { 'amount' : L, 'machine': utf8(self.current_hostname)} | 444 | L)) % { 'amount' : L, 'machine': utf8(self.current_hostname)} |
380 | 445 | ======= | ||
381 | 446 | cat_title = ngettext(u'%(amount)s item on “%(machine)s” not on this computer', | ||
382 | 447 | u'%(amount)s items on “%(machine)s” not on this computer', | ||
383 | 448 | L) % { 'amount' : L, 'machine': self.current_hostname} | ||
384 | 449 | >>>>>>> MERGE-SOURCE | ||
385 | 439 | i += L | 450 | i += L |
386 | 440 | docs = enq.get_documents() | 451 | docs = enq.get_documents() |
387 | 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]) |
388 | @@ -455,9 +466,15 @@ | |||
389 | 455 | 466 | ||
390 | 456 | L = len(enq.matches) | 467 | L = len(enq.matches) |
391 | 457 | if L: | 468 | if L: |
392 | 469 | <<<<<<< TREE | ||
393 | 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”', |
394 | 459 | '%(amount)s items on this computer not on “%(machine)s”', | 471 | '%(amount)s items on this computer not on “%(machine)s”', |
395 | 460 | L)) % { 'amount' : L, 'machine': utf8(self.current_hostname)} | 472 | L)) % { 'amount' : L, 'machine': utf8(self.current_hostname)} |
396 | 473 | ======= | ||
397 | 474 | cat_title = ngettext(u'%(amount)s item on this computer not on “%(machine)s”', | ||
398 | 475 | u'%(amount)s items on this computer not on “%(machine)s”', | ||
399 | 476 | L) % { 'amount' : L, 'machine': self.current_hostname} | ||
400 | 477 | >>>>>>> MERGE-SOURCE | ||
401 | 461 | i += L | 478 | i += L |
402 | 462 | docs = enq.get_documents() | 479 | docs = enq.get_documents() |
403 | 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]) |
404 | 464 | 481 | ||
405 | === modified file 'softwarecenter/ui/gtk3/panes/softwarepane.py' | |||
406 | --- softwarecenter/ui/gtk3/panes/softwarepane.py 2012-02-28 13:51:20 +0000 | |||
407 | +++ softwarecenter/ui/gtk3/panes/softwarepane.py 2012-03-05 18:23:26 +0000 | |||
408 | @@ -34,7 +34,8 @@ | |||
409 | 34 | 34 | ||
410 | 35 | from softwarecenter.utils import (ExecutionTime, | 35 | from softwarecenter.utils import (ExecutionTime, |
411 | 36 | wait_for_apt_cache_ready, | 36 | wait_for_apt_cache_ready, |
413 | 37 | utf8 | 37 | utf8, |
414 | 38 | get_exec_line_from_desktop | ||
415 | 38 | ) | 39 | ) |
416 | 39 | 40 | ||
417 | 40 | from softwarecenter.ui.gtk3.session.viewmanager import get_viewmanager | 41 | from softwarecenter.ui.gtk3.session.viewmanager import get_viewmanager |
418 | @@ -43,8 +44,15 @@ | |||
419 | 43 | from softwarecenter.ui.gtk3.widgets.searchaid import SearchAid | 44 | from softwarecenter.ui.gtk3.widgets.searchaid import SearchAid |
420 | 44 | 45 | ||
421 | 45 | from softwarecenter.ui.gtk3.views.appview import AppView | 46 | from softwarecenter.ui.gtk3.views.appview import AppView |
422 | 47 | <<<<<<< TREE | ||
423 | 46 | from softwarecenter.ui.gtk3.views.appdetailsview import AppDetailsView | 48 | from softwarecenter.ui.gtk3.views.appdetailsview import AppDetailsView |
424 | 47 | 49 | ||
425 | 50 | ======= | ||
426 | 51 | from softwarecenter.ui.gtk3.views.appdetailsview_gtk import ( | ||
427 | 52 | AppDetailsViewGtk as | ||
428 | 53 | AppDetailsView) | ||
429 | 54 | |||
430 | 55 | >>>>>>> MERGE-SOURCE | ||
431 | 48 | from basepane import BasePane | 56 | from basepane import BasePane |
432 | 49 | 57 | ||
433 | 50 | LOG = logging.getLogger(__name__) | 58 | LOG = logging.getLogger(__name__) |
434 | @@ -283,6 +291,87 @@ | |||
435 | 283 | vm = get_viewmanager() | 291 | vm = get_viewmanager() |
436 | 284 | vm.nav_forward() | 292 | vm.nav_forward() |
437 | 285 | 293 | ||
438 | 294 | <<<<<<< TREE | ||
439 | 295 | ======= | ||
440 | 296 | def on_transaction_started(self, backend, pkgname, appname, trans_id, | ||
441 | 297 | trans_type): | ||
442 | 298 | self._register_unity_launcher_transaction_started( | ||
443 | 299 | backend, pkgname, appname, trans_id, trans_type) | ||
444 | 300 | |||
445 | 301 | |||
446 | 302 | def _get_onscreen_icon_details_for_launcher_service(self, app): | ||
447 | 303 | if self.is_app_details_view_showing(): | ||
448 | 304 | return self.app_details_view.get_app_icon_details() | ||
449 | 305 | else: | ||
450 | 306 | # TODO: implement the app list view case once it has been specified | ||
451 | 307 | return (0, 0, 0) | ||
452 | 308 | |||
453 | 309 | def _register_unity_launcher_transaction_started(self, backend, pkgname, | ||
454 | 310 | appname, trans_id, | ||
455 | 311 | trans_type): | ||
456 | 312 | # mvo: use use softwarecenter.utils explictely so that we can monkey | ||
457 | 313 | # patch it in the test | ||
458 | 314 | if not softwarecenter.utils.is_unity_running(): | ||
459 | 315 | return | ||
460 | 316 | # add to launcher only applies in the details view currently | ||
461 | 317 | if not self.is_app_details_view_showing(): | ||
462 | 318 | return | ||
463 | 319 | # we only care about getting the launcher information on an install | ||
464 | 320 | if not trans_type == TransactionTypes.INSTALL: | ||
465 | 321 | if pkgname in self.unity_launcher_items: | ||
466 | 322 | self.unity_launcher_items.pop(pkgname) | ||
467 | 323 | self.action_bar.clear() | ||
468 | 324 | return | ||
469 | 325 | # gather details for this transaction and create the launcher_info object | ||
470 | 326 | app = Application(pkgname=pkgname, appname=appname) | ||
471 | 327 | appdetails = app.get_details(self.db) | ||
472 | 328 | (icon_size, icon_x, icon_y) = self._get_onscreen_icon_details_for_launcher_service(app) | ||
473 | 329 | launcher_info = UnityLauncherInfo(app.name, | ||
474 | 330 | appdetails.icon, | ||
475 | 331 | "", # we set the icon_file_path value *after* install | ||
476 | 332 | icon_x, | ||
477 | 333 | icon_y, | ||
478 | 334 | icon_size, | ||
479 | 335 | appdetails.desktop_file, | ||
480 | 336 | "", # we set the installed_desktop_file_path *after* install | ||
481 | 337 | trans_id) | ||
482 | 338 | self.unity_launcher_items[app.pkgname] = launcher_info | ||
483 | 339 | self.show_add_to_launcher_panel(backend, pkgname, appname, app, appdetails, trans_id, trans_type) | ||
484 | 340 | |||
485 | 341 | def show_add_to_launcher_panel(self, backend, pkgname, appname, app, appdetails, trans_id, trans_type): | ||
486 | 342 | """ | ||
487 | 343 | if Unity is currently running, display a panel to allow the user | ||
488 | 344 | the choose whether to add a newly-installed application to the | ||
489 | 345 | launcher | ||
490 | 346 | """ | ||
491 | 347 | # TODO: handle local deb install case | ||
492 | 348 | # TODO: implement the list view case (once it is specified) | ||
493 | 349 | # only show the panel if unity is running and this is a package install | ||
494 | 350 | # | ||
495 | 351 | # we only show the prompt for apps with a desktop file | ||
496 | 352 | if not appdetails.desktop_file: | ||
497 | 353 | return | ||
498 | 354 | # do not add apps that have no Exec entry in their desktop file | ||
499 | 355 | # (e.g. wine, see LP: #848437 or ubuntu-restricted-extras, | ||
500 | 356 | # see LP: #913756) | ||
501 | 357 | if (os.path.exists(appdetails.desktop_file) and | ||
502 | 358 | not get_exec_line_from_desktop(appdetails.desktop_file)): | ||
503 | 359 | return | ||
504 | 360 | |||
505 | 361 | self.action_bar.add_button(ActionButtons.CANCEL_ADD_TO_LAUNCHER, | ||
506 | 362 | _("Not Now"), | ||
507 | 363 | self.on_cancel_add_to_launcher, | ||
508 | 364 | pkgname) | ||
509 | 365 | self.action_bar.add_button(ActionButtons.ADD_TO_LAUNCHER, | ||
510 | 366 | _("Add to Launcher"), | ||
511 | 367 | self.on_add_to_launcher, | ||
512 | 368 | pkgname, | ||
513 | 369 | app, | ||
514 | 370 | appdetails, | ||
515 | 371 | trans_id) | ||
516 | 372 | self.action_bar.set_label(utf8(_("Add %s to the launcher?")) % utf8(app.name)) | ||
517 | 373 | |||
518 | 374 | >>>>>>> MERGE-SOURCE | ||
519 | 286 | def on_query_complete(self, enquirer): | 375 | def on_query_complete(self, enquirer): |
520 | 287 | self.emit("app-list-changed", len(enquirer.matches)) | 376 | self.emit("app-list-changed", len(enquirer.matches)) |
521 | 288 | self.app_view.display_matches(enquirer.matches, | 377 | self.app_view.display_matches(enquirer.matches, |
522 | 289 | 378 | ||
523 | === modified file 'softwarecenter/ui/gtk3/views/appdetailsview.py' | |||
524 | === modified file 'softwarecenter/ui/gtk3/views/purchaseview.py' | |||
525 | --- softwarecenter/ui/gtk3/views/purchaseview.py 2012-02-09 10:34:40 +0000 | |||
526 | +++ softwarecenter/ui/gtk3/views/purchaseview.py 2012-03-05 18:23:26 +0000 | |||
527 | @@ -20,14 +20,21 @@ | |||
528 | 20 | from gi.repository import GObject | 20 | from gi.repository import GObject |
529 | 21 | from gi.repository import Gtk | 21 | from gi.repository import Gtk |
530 | 22 | from gi.repository import Gdk | 22 | from gi.repository import Gdk |
531 | 23 | <<<<<<< TREE | ||
532 | 23 | from gi.repository import Pango | 24 | from gi.repository import Pango |
533 | 25 | ======= | ||
534 | 26 | from gi.repository import WebKit as webkit | ||
535 | 27 | >>>>>>> MERGE-SOURCE | ||
536 | 24 | import logging | 28 | import logging |
537 | 25 | import os | 29 | import os |
538 | 26 | import json | 30 | import json |
539 | 27 | import sys | 31 | import sys |
540 | 28 | import urllib | 32 | import urllib |
541 | 33 | <<<<<<< TREE | ||
542 | 29 | import urlparse | 34 | import urlparse |
543 | 30 | from gi.repository import WebKit as webkit | 35 | from gi.repository import WebKit as webkit |
544 | 36 | ======= | ||
545 | 37 | >>>>>>> MERGE-SOURCE | ||
546 | 31 | 38 | ||
547 | 32 | from gettext import gettext as _ | 39 | from gettext import gettext as _ |
548 | 33 | 40 | ||
549 | @@ -36,6 +43,16 @@ | |||
550 | 36 | 43 | ||
551 | 37 | LOG = logging.getLogger(__name__) | 44 | LOG = logging.getLogger(__name__) |
552 | 38 | 45 | ||
553 | 46 | # enable certificates validation in webkit views unless specified otherwise | ||
554 | 47 | if not "SOFTWARE_CENTER_FORCE_DISABLE_CERTS_CHECK" in os.environ: | ||
555 | 48 | session = webkit.get_default_session() | ||
556 | 49 | session.set_property("ssl-ca-file", "/etc/ssl/certs/ca-certificates.crt") | ||
557 | 50 | else: | ||
558 | 51 | # WARN the user!! Do not remove this | ||
559 | 52 | LOG.warning("SOFTWARE_CENTER_FORCE_DISABLE_CERTS_CHECK " + | ||
560 | 53 | "has been specified, all purchase transactions " + | ||
561 | 54 | "are now INSECURE and UNENCRYPTED!!") | ||
562 | 55 | |||
563 | 39 | class LocaleAwareWebView(webkit.WebView): | 56 | class LocaleAwareWebView(webkit.WebView): |
564 | 40 | 57 | ||
565 | 41 | def __init__(self): | 58 | def __init__(self): |
566 | 42 | 59 | ||
567 | === modified file 'softwarecenter/ui/gtk3/widgets/buttons.py' | |||
568 | --- softwarecenter/ui/gtk3/widgets/buttons.py 2012-02-20 15:59:17 +0000 | |||
569 | +++ softwarecenter/ui/gtk3/widgets/buttons.py 2012-03-05 18:23:26 +0000 | |||
570 | @@ -186,8 +186,13 @@ | |||
571 | 186 | label = helper.get_appname(doc) | 186 | label = helper.get_appname(doc) |
572 | 187 | icon = helper.get_icon_at_size(doc, icon_size, icon_size) | 187 | icon = helper.get_icon_at_size(doc, icon_size, icon_size) |
573 | 188 | stats = helper.get_review_stats(doc) | 188 | stats = helper.get_review_stats(doc) |
574 | 189 | <<<<<<< TREE | ||
575 | 189 | helper.update_availability(doc) | 190 | helper.update_availability(doc) |
576 | 190 | helper.connect("needs-refresh", self._on_needs_refresh, doc, icon_size) | 191 | helper.connect("needs-refresh", self._on_needs_refresh, doc, icon_size) |
577 | 192 | ======= | ||
578 | 193 | doc.installed = doc.available = None | ||
579 | 194 | helper.connect("needs-refresh", self._on_needs_refresh, doc, icon_size) | ||
580 | 195 | >>>>>>> MERGE-SOURCE | ||
581 | 191 | self.is_installed = helper.is_installed(doc) | 196 | self.is_installed = helper.is_installed(doc) |
582 | 192 | self._overlay = helper.icons.load_icon(Icons.INSTALLED_OVERLAY, | 197 | self._overlay = helper.icons.load_icon(Icons.INSTALLED_OVERLAY, |
583 | 193 | self.INSTALLED_OVERLAY_SIZE, | 198 | self.INSTALLED_OVERLAY_SIZE, |
584 | 194 | 199 | ||
585 | === modified file 'test/test_database.py' | |||
586 | --- test/test_database.py 2012-02-28 22:35:19 +0000 | |||
587 | +++ test/test_database.py 2012-03-05 18:23:26 +0000 | |||
588 | @@ -150,12 +150,16 @@ | |||
589 | 150 | ppa.count("/") == 1, | 150 | ppa.count("/") == 1, |
590 | 151 | "ARCHIVE_PPA value incorrect, got '%s'" % ppa) | 151 | "ARCHIVE_PPA value incorrect, got '%s'" % ppa) |
591 | 152 | self.assertTrue( | 152 | self.assertTrue( |
592 | 153 | <<<<<<< TREE | ||
593 | 153 | "-icon-" in doc.get_value(XapianValues.ICON)) | 154 | "-icon-" in doc.get_value(XapianValues.ICON)) |
594 | 154 | # check support url in the DB | 155 | # check support url in the DB |
595 | 155 | url=doc.get_value(XapianValues.SUPPORT_SITE_URL) | 156 | url=doc.get_value(XapianValues.SUPPORT_SITE_URL) |
596 | 156 | if url: | 157 | if url: |
597 | 157 | self.assertTrue(url.startswith("http") or | 158 | self.assertTrue(url.startswith("http") or |
598 | 158 | url.startswith("mailto:")) | 159 | url.startswith("mailto:")) |
599 | 160 | ======= | ||
600 | 161 | "-icon-" in doc.get_value(XapianValues.ICON)) | ||
601 | 162 | >>>>>>> MERGE-SOURCE | ||
602 | 159 | 163 | ||
603 | 160 | def test_license_string_data_from_software_center_agent(self): | 164 | def test_license_string_data_from_software_center_agent(self): |
604 | 161 | #os.environ["SOFTWARE_CENTER_DEBUG_HTTP"] = "1" | 165 | #os.environ["SOFTWARE_CENTER_DEBUG_HTTP"] = "1" |
605 | 162 | 166 | ||
606 | === modified file 'test/test_utils.py' | |||
607 | --- test/test_utils.py 2012-03-01 11:32:37 +0000 | |||
608 | +++ test/test_utils.py 2012-03-05 18:23:26 +0000 | |||
609 | @@ -161,6 +161,45 @@ | |||
610 | 161 | self.assertTrue(os.path.exists(os.path.join(dirname, "foo-random"))) | 161 | self.assertTrue(os.path.exists(os.path.join(dirname, "foo-random"))) |
611 | 162 | 162 | ||
612 | 163 | 163 | ||
613 | 164 | class TestExpungeCache(unittest.TestCase): | ||
614 | 165 | |||
615 | 166 | def test_expunge_cache(self): | ||
616 | 167 | import subprocess | ||
617 | 168 | import tempfile | ||
618 | 169 | dirname = tempfile.mkdtemp('s-c-testsuite') | ||
619 | 170 | for name, content in [ ("foo-301", "status: 301"), | ||
620 | 171 | ("foo-200", "status: 200"), | ||
621 | 172 | ("foo-random", "random"), | ||
622 | 173 | ]: | ||
623 | 174 | fullpath = os.path.join(dirname, name) | ||
624 | 175 | open(fullpath, "w").write(content) | ||
625 | 176 | # set to 1970+1s time to ensure the cleaner finds it | ||
626 | 177 | os.utime(fullpath, (1,1)) | ||
627 | 178 | res = subprocess.call(["../utils/expunge-cache.py", dirname]) | ||
628 | 179 | # no arguments | ||
629 | 180 | self.assertEqual(res, 1) | ||
630 | 181 | # by status | ||
631 | 182 | res = subprocess.call(["../utils/expunge-cache.py", | ||
632 | 183 | "--debug", | ||
633 | 184 | "--by-unsuccessful-http-states", | ||
634 | 185 | dirname]) | ||
635 | 186 | self.assertFalse(os.path.exists(os.path.join(dirname, "foo-301"))) | ||
636 | 187 | self.assertTrue(os.path.exists(os.path.join(dirname, "foo-200"))) | ||
637 | 188 | self.assertTrue(os.path.exists(os.path.join(dirname, "foo-random"))) | ||
638 | 189 | |||
639 | 190 | # by time | ||
640 | 191 | res = subprocess.call(["../utils/expunge-cache.py", | ||
641 | 192 | "--debug", | ||
642 | 193 | "--by-days", "1", | ||
643 | 194 | dirname]) | ||
644 | 195 | # now we expect the old file to be gone but the unknown one not to | ||
645 | 196 | # be touched | ||
646 | 197 | self.assertFalse(os.path.exists(os.path.join(dirname, "foo-200"))) | ||
647 | 198 | self.assertTrue(os.path.exists(os.path.join(dirname, "foo-random"))) | ||
648 | 199 | |||
649 | 200 | |||
650 | 201 | |||
651 | 202 | |||
652 | 164 | if __name__ == "__main__": | 203 | if __name__ == "__main__": |
653 | 165 | import logging | 204 | import logging |
654 | 166 | logging.basicConfig(level=logging.DEBUG) | 205 | logging.basicConfig(level=logging.DEBUG) |
655 | 167 | 206 | ||
656 | === modified file 'utils/expunge-cache.py' | |||
657 | --- utils/expunge-cache.py 2012-02-29 17:14:43 +0000 | |||
658 | +++ utils/expunge-cache.py 2012-03-05 18:23:26 +0000 | |||
659 | @@ -1,80 +1,166 @@ | |||
740 | 1 | #!/usr/bin/python | 1 | <<<<<<< TREE |
741 | 2 | 2 | #!/usr/bin/python | |
742 | 3 | """ | 3 | |
743 | 4 | Expunge httplib2 caches | 4 | """ |
744 | 5 | """ | 5 | Expunge httplib2 caches |
745 | 6 | 6 | """ | |
746 | 7 | import argparse | 7 | |
747 | 8 | import logging | 8 | import argparse |
748 | 9 | import os | 9 | import logging |
749 | 10 | import time | 10 | import os |
750 | 11 | import sys | 11 | import time |
751 | 12 | 12 | import sys | |
752 | 13 | class ExpungeCache(object): | 13 | |
753 | 14 | def __init__(self, dirs, args): | 14 | class ExpungeCache(object): |
754 | 15 | self.dirs = dirs | 15 | def __init__(self, dirs, args): |
755 | 16 | # days to keep data in the cache (0 == disabled) | 16 | self.dirs = dirs |
756 | 17 | self.keep_time = 60*60*24* args.by_days | 17 | # days to keep data in the cache (0 == disabled) |
757 | 18 | self.keep_only_http200 = args.by_unsuccessful_http_states | 18 | self.keep_time = 60*60*24* args.by_days |
758 | 19 | self.dry_run = args.dry_run | 19 | self.keep_only_http200 = args.by_unsuccessful_http_states |
759 | 20 | 20 | self.dry_run = args.dry_run | |
760 | 21 | def _rm(self, f): | 21 | |
761 | 22 | if self.dry_run: | 22 | def _rm(self, f): |
762 | 23 | print "Would delete: %s" % f | 23 | if self.dry_run: |
763 | 24 | else: | 24 | print "Would delete: %s" % f |
764 | 25 | logging.debug("Deleting: %s" % f) | 25 | else: |
765 | 26 | os.unlink(f) | 26 | logging.debug("Deleting: %s" % f) |
766 | 27 | 27 | os.unlink(f) | |
767 | 28 | def clean(self): | 28 | |
768 | 29 | # go over the directories | 29 | def clean(self): |
769 | 30 | now = time.time() | 30 | # go over the directories |
770 | 31 | for d in self.dirs: | 31 | now = time.time() |
771 | 32 | for root, dirs, files in os.walk(d): | 32 | for d in self.dirs: |
772 | 33 | for f in files: | 33 | for root, dirs, files in os.walk(d): |
773 | 34 | fullpath = os.path.join(root, f) | 34 | for f in files: |
774 | 35 | header = open(fullpath).readline().strip() | 35 | fullpath = os.path.join(root, f) |
775 | 36 | if not header.startswith("status:"): | 36 | header = open(fullpath).readline().strip() |
776 | 37 | logging.debug( | 37 | if not header.startswith("status:"): |
777 | 38 | "Skipping files with unknown header: '%s'" % f) | 38 | logging.debug( |
778 | 39 | continue | 39 | "Skipping files with unknown header: '%s'" % f) |
779 | 40 | if self.keep_only_http200 and header != "status: 200": | 40 | continue |
780 | 41 | self._rm(fullpath) | 41 | if self.keep_only_http200 and header != "status: 200": |
781 | 42 | if self.keep_time: | 42 | self._rm(fullpath) |
782 | 43 | mtime = os.path.getmtime(fullpath) | 43 | if self.keep_time: |
783 | 44 | logging.debug("mtime of '%s': '%s" % (f, mtime)) | 44 | mtime = os.path.getmtime(fullpath) |
784 | 45 | if (mtime + self.keep_time) < now: | 45 | logging.debug("mtime of '%s': '%s" % (f, mtime)) |
785 | 46 | self._rm(fullpath) | 46 | if (mtime + self.keep_time) < now: |
786 | 47 | 47 | self._rm(fullpath) | |
787 | 48 | if __name__ == "__main__": | 48 | |
788 | 49 | parser = argparse.ArgumentParser( | 49 | if __name__ == "__main__": |
789 | 50 | description='clean software-center httplib2 cache') | 50 | parser = argparse.ArgumentParser( |
790 | 51 | parser.add_argument( | 51 | description='clean software-center httplib2 cache') |
791 | 52 | '--debug', action="store_true", | 52 | parser.add_argument( |
792 | 53 | help='show debug output') | 53 | '--debug', action="store_true", |
793 | 54 | parser.add_argument( | 54 | help='show debug output') |
794 | 55 | '--dry-run', action="store_true", | 55 | parser.add_argument( |
795 | 56 | help='do not act, just show what would be done') | 56 | '--dry-run', action="store_true", |
796 | 57 | parser.add_argument( | 57 | help='do not act, just show what would be done') |
797 | 58 | 'directories', metavar='directory', nargs='+', type=str, | 58 | parser.add_argument( |
798 | 59 | help='directories to be checked') | 59 | 'directories', metavar='directory', nargs='+', type=str, |
799 | 60 | parser.add_argument( | 60 | help='directories to be checked') |
800 | 61 | '--by-days', type=int, default=0, | 61 | parser.add_argument( |
801 | 62 | help='expire everything older than N days') | 62 | '--by-days', type=int, default=0, |
802 | 63 | parser.add_argument( | 63 | help='expire everything older than N days') |
803 | 64 | '--by-unsuccessful-http-states', action="store_true", | 64 | parser.add_argument( |
804 | 65 | help='expire any non 200 status responses') | 65 | '--by-unsuccessful-http-states', action="store_true", |
805 | 66 | args = parser.parse_args() | 66 | help='expire any non 200 status responses') |
806 | 67 | 67 | args = parser.parse_args() | |
807 | 68 | if args.debug: | 68 | |
808 | 69 | logging.basicConfig(level=logging.DEBUG) | 69 | if args.debug: |
809 | 70 | else: | 70 | logging.basicConfig(level=logging.DEBUG) |
810 | 71 | logging.basicConfig(level=logging.INFO) | 71 | else: |
811 | 72 | 72 | logging.basicConfig(level=logging.INFO) | |
812 | 73 | # sanity checking | 73 | |
813 | 74 | if args.by_days == 0 and not args.by_unsuccessful_http_states: | 74 | # sanity checking |
814 | 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: |
815 | 76 | sys.exit(1) | 76 | print "Need either --by-days or --by-unsuccessful-http-states argument" |
816 | 77 | 77 | sys.exit(1) | |
817 | 78 | # do it | 78 | |
818 | 79 | cleaner = ExpungeCache(args.directories, args) | 79 | # do it |
819 | 80 | cleaner.clean() | 80 | cleaner = ExpungeCache(args.directories, args) |
820 | 81 | cleaner.clean() | ||
821 | 82 | ======= | ||
822 | 83 | #!/usr/bin/python | ||
823 | 84 | |||
824 | 85 | """ | ||
825 | 86 | Expunge httplib2 caches | ||
826 | 87 | """ | ||
827 | 88 | |||
828 | 89 | import argparse | ||
829 | 90 | import logging | ||
830 | 91 | import os | ||
831 | 92 | import time | ||
832 | 93 | import sys | ||
833 | 94 | |||
834 | 95 | class ExpungeCache(object): | ||
835 | 96 | def __init__(self, dirs, args): | ||
836 | 97 | self.dirs = dirs | ||
837 | 98 | # days to keep data in the cache (0 == disabled) | ||
838 | 99 | self.keep_time = 60*60*24* args.by_days | ||
839 | 100 | self.keep_only_http200 = args.by_unsuccessful_http_states | ||
840 | 101 | self.dry_run = args.dry_run | ||
841 | 102 | |||
842 | 103 | def _rm(self, f): | ||
843 | 104 | if self.dry_run: | ||
844 | 105 | print "Would delete: %s" % f | ||
845 | 106 | else: | ||
846 | 107 | logging.debug("Deleting: %s" % f) | ||
847 | 108 | os.unlink(f) | ||
848 | 109 | |||
849 | 110 | def clean(self): | ||
850 | 111 | # go over the directories | ||
851 | 112 | now = time.time() | ||
852 | 113 | for d in self.dirs: | ||
853 | 114 | for root, dirs, files in os.walk(d): | ||
854 | 115 | for f in files: | ||
855 | 116 | fullpath = os.path.join(root, f) | ||
856 | 117 | header = open(fullpath).readline().strip() | ||
857 | 118 | if not header.startswith("status:"): | ||
858 | 119 | logging.debug( | ||
859 | 120 | "Skipping files with unknown header: '%s'" % f) | ||
860 | 121 | continue | ||
861 | 122 | if self.keep_only_http200 and header != "status: 200": | ||
862 | 123 | self._rm(fullpath) | ||
863 | 124 | if self.keep_time: | ||
864 | 125 | mtime = os.path.getmtime(fullpath) | ||
865 | 126 | logging.debug("mtime of '%s': '%s" % (f, mtime)) | ||
866 | 127 | if (mtime + self.keep_time) < now: | ||
867 | 128 | self._rm(fullpath) | ||
868 | 129 | |||
869 | 130 | if __name__ == "__main__": | ||
870 | 131 | parser = argparse.ArgumentParser( | ||
871 | 132 | description='clean software-center httplib2 cache') | ||
872 | 133 | parser.add_argument( | ||
873 | 134 | '--debug', action="store_true", | ||
874 | 135 | help='show debug output') | ||
875 | 136 | parser.add_argument( | ||
876 | 137 | '--dry-run', action="store_true", | ||
877 | 138 | help='do not act, just show what would be done') | ||
878 | 139 | parser.add_argument( | ||
879 | 140 | 'directories', metavar='directory', nargs='+', type=str, | ||
880 | 141 | help='directories to be checked') | ||
881 | 142 | parser.add_argument( | ||
882 | 143 | '--by-days', type=int, default=0, | ||
883 | 144 | help='expire everything older than N days') | ||
884 | 145 | parser.add_argument( | ||
885 | 146 | '--by-unsuccessful-http-states', action="store_true", | ||
886 | 147 | help='expire any non 200 status responses') | ||
887 | 148 | args = parser.parse_args() | ||
888 | 149 | |||
889 | 150 | if args.debug: | ||
890 | 151 | logging.basicConfig(level=logging.DEBUG) | ||
891 | 152 | else: | ||
892 | 153 | logging.basicConfig(level=logging.INFO) | ||
893 | 154 | |||
894 | 155 | # sanity checking | ||
895 | 156 | if args.by_days == 0 and not args.by_unsuccessful_http_states: | ||
896 | 157 | print "Need either --by-days or --by-unsuccessful-http-states argument" | ||
897 | 158 | sys.exit(1) | ||
898 | 159 | |||
899 | 160 | # be nice | ||
900 | 161 | os.nice(19) | ||
901 | 162 | |||
902 | 163 | # do it | ||
903 | 164 | cleaner = ExpungeCache(args.directories, args) | ||
904 | 165 | cleaner.clean() | ||
905 | 166 | >>>>>>> MERGE-SOURCE | ||
906 | 81 | 167 | ||
907 | === added file 'utils/piston-helpers/piston_get_scagent_available_apps.py.OTHER' | |||
908 | --- utils/piston-helpers/piston_get_scagent_available_apps.py.OTHER 1970-01-01 00:00:00 +0000 | |||
909 | +++ utils/piston-helpers/piston_get_scagent_available_apps.py.OTHER 2012-03-05 18:23:26 +0000 | |||
910 | @@ -0,0 +1,194 @@ | |||
911 | 1 | #!/usr/bin/python | ||
912 | 2 | |||
913 | 3 | from gi.repository import GObject | ||
914 | 4 | |||
915 | 5 | import argparse | ||
916 | 6 | import logging | ||
917 | 7 | import os | ||
918 | 8 | import pickle | ||
919 | 9 | import sys | ||
920 | 10 | |||
921 | 11 | import piston_mini_client.auth | ||
922 | 12 | |||
923 | 13 | from softwarecenter.enums import (SOFTWARE_CENTER_NAME_KEYRING, | ||
924 | 14 | SOFTWARE_CENTER_SSO_DESCRIPTION, | ||
925 | 15 | ) | ||
926 | 16 | from softwarecenter.paths import SOFTWARE_CENTER_CACHE_DIR | ||
927 | 17 | from softwarecenter.backend.piston.scaclient import SoftwareCenterAgentAPI | ||
928 | 18 | from softwarecenter.backend.login_sso import get_sso_backend | ||
929 | 19 | from softwarecenter.backend.restfulclient import UbuntuSSOAPI | ||
930 | 20 | from softwarecenter.utils import clear_token_from_ubuntu_sso | ||
931 | 21 | |||
932 | 22 | from gettext import gettext as _ | ||
933 | 23 | |||
934 | 24 | LOG = logging.getLogger(__name__) | ||
935 | 25 | |||
936 | 26 | class SSOLoginHelper(object): | ||
937 | 27 | def __init__(self, xid=0): | ||
938 | 28 | self.oauth = None | ||
939 | 29 | self.xid = xid | ||
940 | 30 | self.loop = GObject.MainLoop(GObject.main_context_default()) | ||
941 | 31 | |||
942 | 32 | def _login_successful(self, sso_backend, oauth_result): | ||
943 | 33 | self.oauth = oauth_result | ||
944 | 34 | # FIXME: actually verify the token against ubuntu SSO | ||
945 | 35 | self.loop.quit() | ||
946 | 36 | |||
947 | 37 | def verify_token(self, token): | ||
948 | 38 | def _whoami_done(sso, me): | ||
949 | 39 | self._whoami = me | ||
950 | 40 | self.loop.quit() | ||
951 | 41 | self._whoami = None | ||
952 | 42 | sso = UbuntuSSOAPI(token) | ||
953 | 43 | sso.connect("whoami", _whoami_done) | ||
954 | 44 | sso.connect("error", lambda sso, err: self.loop.quit()) | ||
955 | 45 | sso.whoami() | ||
956 | 46 | self.loop.run() | ||
957 | 47 | # check if the token is valid | ||
958 | 48 | if self._whoami is None: | ||
959 | 49 | return False | ||
960 | 50 | else: | ||
961 | 51 | return True | ||
962 | 52 | |||
963 | 53 | def clear_token(self): | ||
964 | 54 | clear_token_from_ubuntu_sso(SOFTWARE_CENTER_NAME_KEYRING) | ||
965 | 55 | |||
966 | 56 | def get_oauth_token_sync(self): | ||
967 | 57 | self.oauth = None | ||
968 | 58 | sso = get_sso_backend( | ||
969 | 59 | self.xid, | ||
970 | 60 | SOFTWARE_CENTER_NAME_KEYRING, | ||
971 | 61 | _(SOFTWARE_CENTER_SSO_DESCRIPTION)) | ||
972 | 62 | sso.connect("login-successful", self._login_successful) | ||
973 | 63 | sso.connect("login-failed", lambda s: self.loop.quit()) | ||
974 | 64 | sso.connect("login-canceled", lambda s: self.loop.quit()) | ||
975 | 65 | sso.login_or_register() | ||
976 | 66 | self.loop.run() | ||
977 | 67 | return self.oauth | ||
978 | 68 | |||
979 | 69 | if __name__ == "__main__": | ||
980 | 70 | logging.basicConfig() | ||
981 | 71 | |||
982 | 72 | # command line parser | ||
983 | 73 | parser = argparse.ArgumentParser(description="Helper for software-center-agent") | ||
984 | 74 | parser.add_argument("--debug", action="store_true", default=False, | ||
985 | 75 | help="enable debug output") | ||
986 | 76 | parser.add_argument("--ignore-cache", action="store_true", default=False, | ||
987 | 77 | help="force ignore cache") | ||
988 | 78 | parser.add_argument("--parent-xid", default=0, | ||
989 | 79 | help="xid of the parent window") | ||
990 | 80 | |||
991 | 81 | subparser = parser.add_subparsers(title="Commands") | ||
992 | 82 | # available_apps | ||
993 | 83 | command = subparser.add_parser("available_apps") | ||
994 | 84 | command.add_argument("lang") | ||
995 | 85 | command.add_argument("series") | ||
996 | 86 | command.add_argument("arch") | ||
997 | 87 | command.set_defaults(command="available_apps") | ||
998 | 88 | |||
999 | 89 | # available_apps_qa | ||
1000 | 90 | command = subparser.add_parser("available_apps_qa") | ||
1001 | 91 | command.add_argument("lang") | ||
1002 | 92 | command.add_argument("series") | ||
1003 | 93 | command.add_argument("arch") | ||
1004 | 94 | command.set_defaults(command="available_apps_qa") | ||
1005 | 95 | # subscriptions | ||
1006 | 96 | command = subparser.add_parser("subscriptions_for_me") | ||
1007 | 97 | command.set_defaults(command="subscriptions_for_me") | ||
1008 | 98 | # exhibits | ||
1009 | 99 | command = subparser.add_parser("exhibits") | ||
1010 | 100 | command.add_argument("lang") | ||
1011 | 101 | command.add_argument("series") | ||
1012 | 102 | command.set_defaults(command="exhibits") | ||
1013 | 103 | |||
1014 | 104 | args = parser.parse_args() | ||
1015 | 105 | |||
1016 | 106 | if args.debug: | ||
1017 | 107 | LOG.setLevel(logging.DEBUG) | ||
1018 | 108 | |||
1019 | 109 | if args.ignore_cache: | ||
1020 | 110 | cachedir = None | ||
1021 | 111 | else: | ||
1022 | 112 | cachedir = os.path.join(SOFTWARE_CENTER_CACHE_DIR, "scaclient") | ||
1023 | 113 | |||
1024 | 114 | |||
1025 | 115 | # check if auth is required | ||
1026 | 116 | if args.command in ("available_apps_qa", "subscriptions_for_me"): | ||
1027 | 117 | helper = SSOLoginHelper(args.parent_xid) | ||
1028 | 118 | token = helper.get_oauth_token_sync() | ||
1029 | 119 | # check if the token is valid and reset it if it is not | ||
1030 | 120 | if token and not helper.verify_token(token): | ||
1031 | 121 | helper.clear_token() | ||
1032 | 122 | # re-trigger login | ||
1033 | 123 | token = helper.get_oauth_token_sync() | ||
1034 | 124 | # if we don't have a token, error here | ||
1035 | 125 | if not token: | ||
1036 | 126 | sys.stderr.write("ERROR: can not obtain a oauth token\n") | ||
1037 | 127 | sys.exit(1) | ||
1038 | 128 | |||
1039 | 129 | auth = piston_mini_client.auth.OAuthAuthorizer(token["token"], | ||
1040 | 130 | token["token_secret"], | ||
1041 | 131 | token["consumer_key"], | ||
1042 | 132 | token["consumer_secret"]) | ||
1043 | 133 | scaclient = SoftwareCenterAgentAPI(cachedir=cachedir, auth=auth) | ||
1044 | 134 | else: | ||
1045 | 135 | scaclient = SoftwareCenterAgentAPI(cachedir=cachedir) | ||
1046 | 136 | |||
1047 | 137 | piston_reply = None | ||
1048 | 138 | |||
1049 | 139 | # common kwargs | ||
1050 | 140 | if args.command in ("available_apps", "available_apps_qa"): | ||
1051 | 141 | kwargs = {"lang": args.lang, | ||
1052 | 142 | "series": args.series, | ||
1053 | 143 | "arch": args.arch | ||
1054 | 144 | } | ||
1055 | 145 | |||
1056 | 146 | # handle the args | ||
1057 | 147 | if args.command == "available_apps": | ||
1058 | 148 | try: | ||
1059 | 149 | piston_reply = scaclient.available_apps(**kwargs) | ||
1060 | 150 | except: | ||
1061 | 151 | LOG.exception("available_apps") | ||
1062 | 152 | sys.exit(1) | ||
1063 | 153 | |||
1064 | 154 | elif args.command == "available_apps_qa": | ||
1065 | 155 | try: | ||
1066 | 156 | piston_reply = scaclient.available_apps_qa(**kwargs) | ||
1067 | 157 | except: | ||
1068 | 158 | LOG.exception("available_apps_qa") | ||
1069 | 159 | sys.exit(1) | ||
1070 | 160 | elif args.command == "subscriptions_for_me": | ||
1071 | 161 | try: | ||
1072 | 162 | piston_reply = scaclient.subscriptions_for_me(complete_only=True) | ||
1073 | 163 | # the new piston API send the data in a nasty format, most | ||
1074 | 164 | # interessting stuff is in the "application" dict, move it | ||
1075 | 165 | # back int othe main object here so that the parser understands it | ||
1076 | 166 | for item in piston_reply: | ||
1077 | 167 | for k, v in item.application.iteritems(): | ||
1078 | 168 | setattr(item, k, v) | ||
1079 | 169 | except: | ||
1080 | 170 | LOG.exception("subscriptions_for_me") | ||
1081 | 171 | sys.exit(1) | ||
1082 | 172 | if args.command == "exhibits": | ||
1083 | 173 | try: | ||
1084 | 174 | piston_reply = scaclient.exhibits(lang=args.lang, series=args.series) | ||
1085 | 175 | except: | ||
1086 | 176 | LOG.exception("exhibits") | ||
1087 | 177 | sys.exit(1) | ||
1088 | 178 | |||
1089 | 179 | if args.debug: | ||
1090 | 180 | LOG.debug("reply: %s" % piston_reply) | ||
1091 | 181 | for item in piston_reply: | ||
1092 | 182 | for var in vars(item): | ||
1093 | 183 | print "%s: %s" % (var, getattr(item, var)) | ||
1094 | 184 | print "\n\n" | ||
1095 | 185 | |||
1096 | 186 | |||
1097 | 187 | # print to stdout where its consumed by the parent | ||
1098 | 188 | if piston_reply is not None: | ||
1099 | 189 | try: | ||
1100 | 190 | print pickle.dumps(piston_reply) | ||
1101 | 191 | except IOError: | ||
1102 | 192 | # this can happen if the parent gets killed, no need to trigger | ||
1103 | 193 | # apport for this | ||
1104 | 194 | pass |
Just a note that I merged the lp:~mvo/software-center/expunge-cache branch, which is the one targeting trunk. Thanks!