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

Proposed by Michael Vogt
Status: Merged
Merged at revision: 2796
Proposed branch: lp:~mvo/software-center/expunge-cache
Merge into: lp:software-center
Diff against target: 178 lines (+132/-0)
4 files modified
setup.py (+2/-0)
softwarecenter/ui/gtk3/app.py (+14/-0)
test/test_utils.py (+36/-0)
utils/expunge-cache.py (+80/-0)
To merge this branch: bzr merge lp:~mvo/software-center/expunge-cache
Reviewer Review Type Date Requested Status
Gary Lasker (community) Approve
Review via email: mp+95219@code.launchpad.net

Description of the change

This adds a helper that keeps the cache clean from cached 301/404 etc responses.
It also offers cleanup by mtime but that is currently not used (only tested)

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

Nice work, thanks mvo!!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added symlink 'data/expunge-cache.py'
2=== target is u'../utils/expunge-cache.py'
3=== modified file 'setup.py'
4--- setup.py 2012-01-27 10:47:16 +0000
5+++ setup.py 2012-02-29 17:32:19 +0000
6@@ -94,6 +94,8 @@
7 "utils/update-software-center",
8 "utils/update-software-center-channels",
9 "utils/update-software-center-agent",
10+ # generic helpers
11+ "utils/expunge-cache.py",
12 ] + glob.glob("utils/piston-helpers/*.py"),
13 packages=['softwarecenter',
14 'softwarecenter.backend',
15
16=== modified file 'softwarecenter/ui/gtk3/app.py'
17--- softwarecenter/ui/gtk3/app.py 2012-02-29 07:15:46 +0000
18+++ softwarecenter/ui/gtk3/app.py 2012-02-29 17:32:19 +0000
19@@ -390,6 +390,10 @@
20 # running the agent will trigger a db reload so we do it later
21 GObject.timeout_add_seconds(30, self._run_software_center_agent)
22
23+
24+ # keep the cache clean
25+ GObject.timeout_add_seconds(15, self._run_expunge_cache_helper)
26+
27 # TODO: Remove the following two lines once we have remove repository
28 # support in aptdaemon (see LP: #723911)
29 file_menu = self.builder.get_object("menu1")
30@@ -419,6 +423,16 @@
31 GObject.child_watch_add(
32 pid, self._on_update_software_center_agent_finished)
33
34+ def _run_expunge_cache_helper(self):
35+ """ helper that expires the piston-mini-client cache """
36+ sc_expunge_cache = os.path.join(
37+ self.datadir, "expunge-cache.py")
38+ (pid, stdin, stdout, stderr) = GObject.spawn_async(
39+ [sc_expunge_cache,
40+ "--by-unsuccessful-http-states",
41+ softwarecenter.paths.SOFTWARE_CENTER_CACHE_DIR,
42+ ])
43+
44 def _rebuild_and_reopen_local_db(self, pathname):
45 """ helper that rebuilds a db and reopens it """
46 from softwarecenter.db.update import rebuild_database
47
48=== modified file 'test/test_utils.py'
49--- test/test_utils.py 2012-02-12 20:03:56 +0000
50+++ test/test_utils.py 2012-02-29 17:32:19 +0000
51@@ -124,6 +124,42 @@
52 uuid = get_uuid()
53 self.assertTrue(uuid and len(uuid) > 0)
54
55+class TestExpungeCache(unittest.TestCase):
56+
57+ def test_expunge_cache(self):
58+ import subprocess
59+ import tempfile
60+ dirname = tempfile.mkdtemp('s-c-testsuite')
61+ for name, content in [ ("foo-301", "status: 301"),
62+ ("foo-200", "status: 200"),
63+ ("foo-random", "random"),
64+ ]:
65+ fullpath = os.path.join(dirname, name)
66+ open(fullpath, "w").write(content)
67+ # set to 1970+1s time to ensure the cleaner finds it
68+ os.utime(fullpath, (1,1))
69+ res = subprocess.call(["../utils/expunge-cache.py", dirname])
70+ # no arguments
71+ self.assertEqual(res, 1)
72+ # by status
73+ res = subprocess.call(["../utils/expunge-cache.py",
74+ "--debug",
75+ "--by-unsuccessful-http-states",
76+ dirname])
77+ self.assertFalse(os.path.exists(os.path.join(dirname, "foo-301")))
78+ self.assertTrue(os.path.exists(os.path.join(dirname, "foo-200")))
79+ self.assertTrue(os.path.exists(os.path.join(dirname, "foo-random")))
80+
81+ # by time
82+ res = subprocess.call(["../utils/expunge-cache.py",
83+ "--debug",
84+ "--by-days", "1",
85+ dirname])
86+ # now we expect the old file to be gone but the unknown one not to
87+ # be touched
88+ self.assertFalse(os.path.exists(os.path.join(dirname, "foo-200")))
89+ self.assertTrue(os.path.exists(os.path.join(dirname, "foo-random")))
90+
91
92 if __name__ == "__main__":
93 import logging
94
95=== added file 'utils/expunge-cache.py'
96--- utils/expunge-cache.py 1970-01-01 00:00:00 +0000
97+++ utils/expunge-cache.py 2012-02-29 17:32:19 +0000
98@@ -0,0 +1,80 @@
99+#!/usr/bin/python
100+
101+"""
102+Expunge httplib2 caches
103+"""
104+
105+import argparse
106+import logging
107+import os
108+import time
109+import sys
110+
111+class ExpungeCache(object):
112+ def __init__(self, dirs, args):
113+ self.dirs = dirs
114+ # days to keep data in the cache (0 == disabled)
115+ self.keep_time = 60*60*24* args.by_days
116+ self.keep_only_http200 = args.by_unsuccessful_http_states
117+ self.dry_run = args.dry_run
118+
119+ def _rm(self, f):
120+ if self.dry_run:
121+ print "Would delete: %s" % f
122+ else:
123+ logging.debug("Deleting: %s" % f)
124+ os.unlink(f)
125+
126+ def clean(self):
127+ # go over the directories
128+ now = time.time()
129+ for d in self.dirs:
130+ for root, dirs, files in os.walk(d):
131+ for f in files:
132+ fullpath = os.path.join(root, f)
133+ header = open(fullpath).readline().strip()
134+ if not header.startswith("status:"):
135+ logging.debug(
136+ "Skipping files with unknown header: '%s'" % f)
137+ continue
138+ if self.keep_only_http200 and header != "status: 200":
139+ self._rm(fullpath)
140+ if self.keep_time:
141+ mtime = os.path.getmtime(fullpath)
142+ logging.debug("mtime of '%s': '%s" % (f, mtime))
143+ if (mtime + self.keep_time) < now:
144+ self._rm(fullpath)
145+
146+if __name__ == "__main__":
147+ parser = argparse.ArgumentParser(
148+ description='clean software-center httplib2 cache')
149+ parser.add_argument(
150+ '--debug', action="store_true",
151+ help='show debug output')
152+ parser.add_argument(
153+ '--dry-run', action="store_true",
154+ help='do not act, just show what would be done')
155+ parser.add_argument(
156+ 'directories', metavar='directory', nargs='+', type=str,
157+ help='directories to be checked')
158+ parser.add_argument(
159+ '--by-days', type=int, default=0,
160+ help='expire everything older than N days')
161+ parser.add_argument(
162+ '--by-unsuccessful-http-states', action="store_true",
163+ help='expire any non 200 status responses')
164+ args = parser.parse_args()
165+
166+ if args.debug:
167+ logging.basicConfig(level=logging.DEBUG)
168+ else:
169+ logging.basicConfig(level=logging.INFO)
170+
171+ # sanity checking
172+ if args.by_days == 0 and not args.by_unsuccessful_http_states:
173+ print "Need either --by-days or --by-unsuccessful-http-states argument"
174+ sys.exit(1)
175+
176+ # do it
177+ cleaner = ExpungeCache(args.directories, args)
178+ cleaner.clean()

Subscribers

People subscribed via source and target branches