https://wiki.archlinux.org/api.php?action=feedcontributions&user=Uthark&feedformat=atomArchWiki - User contributions [en]2024-03-29T09:11:06ZUser contributionsMediaWiki 1.41.0https://wiki.archlinux.org/index.php?title=CacheClean&diff=119552CacheClean2010-10-21T05:26:45Z<p>Uthark: updated to work with python 3</p>
<hr />
<div>[[Category:Scripts (English)]]<br />
[[Category:Package management (English)]]<br />
<br />
This script has been included in the AUR at [[http://aur.archlinux.org/packages.php?ID=37572 this page]].<br />
<br />
It was originally written by "alterkacker" - see his forum thread: [[http://bbs.archlinux.org/viewtopic.php?id=9104||A utility for cleaning /var/cache/pacman/pkg]]<br />
<br />
<br />
<br />
<pre><br />
#!/usr/bin/env python<br />
"""cache_clean - a simple python script to clean up the /var/cache/pacman/pkg directory.<br />
More versatile than 'pacman -Sc' in that you can select how many old versions<br />
to keep.<br />
Usage: cache_clean {-p} {-v} <# of copies to keep><br />
# of copies to keep - (required) how many generations of each package to keep<br />
-p - (optional) preview what would be deleted; forces verbose (-v) mode.<br />
-v - (optional) show deleted packages."""<br />
# Note that the determination of package age is done by simply looking at the date-time<br />
# modified stamp on the file. There is just enough variation in the way package version<br />
# is done that I thought this would be simpler & just as good.<br />
# Also note that you must be root to run this script.<br />
<br />
import getopt<br />
import os<br />
import re<br />
import sys<br />
<br />
# helper function to get tuple of (file dtm, file name, file sz) <br />
def fn_stats(fn):<br />
s = os.stat(fn)<br />
return (s[8], fn, s[6])<br />
<br />
# cleanup does the actual pkg file deletion<br />
def cleanup(run_list):<br />
# strictly speaking only the first two of these globals need to be listed.<br />
global n_deleted, bytes_deleted, opt_verbose, opt_preview, n_to_keep<br />
# return if the run_list is too short<br />
#print run_list<br />
#return<br />
if len(run_list) <= n_to_keep: return<br />
# Build list of tuples (date-time file modified, file name, file size)<br />
dtm_list = [fn_stats(tfn) for tfn in run_list]<br />
# Sort the list by date-time<br />
dtm_list.sort()<br />
# Build list of the filenames to delete (all but last n_to_keep).<br />
# <showing_off><br />
#kill_list = [tfn[1] for tfn in dtm_list[:-n_to_keep]]<br />
#bytes_deleted = sum(x[2] for x in dtm_list[:-n_to_keep])<br />
# </showing_off><br />
kill_list = []<br />
for x in dtm_list[:-n_to_keep]:<br />
kill_list.append(x[1])<br />
bytes_deleted += x[2]<br />
if opt_verbose: print (kill_list)<br />
n_deleted += len(kill_list)<br />
# and finally delete (if not in preview mode)<br />
if not opt_preview:<br />
for dfn in kill_list:<br />
os.unlink(dfn)<br />
<br />
######################################################################<br />
# mainline processing<br />
<br />
# process command line options<br />
try:<br />
opts, pargs = getopt.getopt(sys.argv[1:], 'vp')<br />
opt_dict = dict(opts)<br />
opt_preview = '-p' in opt_dict<br />
opt_verbose = '-v' in opt_dict<br />
if opt_preview: opt_verbose = True<br />
if len(pargs) == 1:<br />
n_to_keep = pargs[0]<br />
else:<br />
raise getopt.GetoptError("missing required argument.")<br />
try:<br />
n_to_keep = int(n_to_keep)<br />
if n_to_keep <= 0: raise ValueError<br />
except ValueError as e:<br />
raise getopt.GetoptError("# of copies to keep must be numeric > 0!")<br />
except getopt.GetoptError as msg:<br />
print ("Error:",msg,"\n",__doc__)<br />
sys.exit(1)<br />
<br />
# change to the pkg directory & get a sorted list of its contents<br />
os.chdir('/var/cache/pacman/pkg')<br />
pkg_fns = os.listdir('.')<br />
pkg_fns.sort()<br />
<br />
# Pattern to use to extract the package name from the tar file name:<br />
# for pkg e.g. 'gnome-common-2.8.0-1-i686.pkg.tar.gz' group(1) is 'gnome-common'.<br />
bpat = re.compile(r'^(.+)-\d[^-]+-.+?(-i686|-x86_64|-any)?\.pkg\.tar\.(gz|bz2|xz)(\.aria2)?$')<br />
<br />
n_deleted = 0<br />
bytes_deleted = 0<br />
pkg_base_nm = ''<br />
# now look for "runs" of the same package name differing only in version info.<br />
for run_end in range(len(pkg_fns)):<br />
fn = pkg_fns[run_end]<br />
<br />
# make sure we skip directories<br />
if os.path.isdir(fn) == False:<br />
mo = bpat.match(fn) # test for a match of the package name pattern<br />
if mo:<br />
#print >>sys.stdout, "Processing file '" + fn + "'", mo.lastindex<br />
tbase = mo.group(1) # gets the 'base' package name<br />
# include the architecture in the name if it's present<br />
if mo.lastindex > 1:<br />
if mo.group(2) is not None:<br />
tbase += mo.group(2)<br />
#print 'tbase: ',tbase,' ',mo.lastindex<br />
# is it a new base name, i.e. the start of a new run?<br />
if tbase != pkg_base_nm: # if so then process the prior run<br />
if pkg_base_nm != '':<br />
cleanup(pkg_fns[run_start:run_end])<br />
pkg_base_nm = tbase # & setup for the new run<br />
run_start = run_end<br />
else:<br />
print ("File '"+fn+"' doesn't match package pattern!", file=sys.stderr)<br />
else:<br />
print >>sys.stdout, "skipping directory '"+fn+"'!"<br />
<br />
# catch the final run of the list<br />
run_end += 1<br />
cleanup(pkg_fns[run_start:run_end])<br />
<br />
if opt_verbose:<br />
if opt_preview:<br />
print ("Preview mode (no files deleted):"),<br />
print (n_deleted,"files deleted,",bytes_deleted/1000,"kbytes.")<br />
</pre></div>Uthark