summaryrefslogtreecommitdiff
path: root/obnamlib/plugins/show_plugin.py
diff options
context:
space:
mode:
authorIan Campbell <ijc@hellion.org.uk>2014-11-16 11:24:11 +0000
committerLars Wirzenius <liw@liw.fi>2014-12-06 19:02:39 +0200
commitda263719bc13e65b8f5948e657a4b2555523d509 (patch)
tree39f2ac63d12cb15ca9a7b18110a31f98d15649c5 /obnamlib/plugins/show_plugin.py
parentce0e45fece3dcec7faace976b30d99314f2d4c15 (diff)
downloadobnam-da263719bc13e65b8f5948e657a4b2555523d509.tar.gz
Implement support for listing a generation in kdirstat.cache format
This implements an ls variant whose output format is compatible with the kdirstat cache format. The best reference I can find for this is from an old fork: https://github.com/thomas-joiner/k4dirstat/blob/master/kdirstat/cache-file-format.txt Recent versions of k4dirstat appear to be able to read the files produced just fine, although this document is not present in their source AFAICT. I find k4dirstat to be an excellent way to visualise what is included in a backup, e.g. for the purposes of excluding file types or marking directories with a CACHEDIR.TAG. My previous solution involved post-processing the output of ls which require a ssh to the machine with the files (for stat() purposes). This approach pulls all of the data out of the obnam repo, so is much faster, less hacky and gets the status of the actual generation and not the current files etc.
Diffstat (limited to 'obnamlib/plugins/show_plugin.py')
-rw-r--r--obnamlib/plugins/show_plugin.py69
1 files changed, 57 insertions, 12 deletions
diff --git a/obnamlib/plugins/show_plugin.py b/obnamlib/plugins/show_plugin.py
index 7c933cfb..949b2143 100644
--- a/obnamlib/plugins/show_plugin.py
+++ b/obnamlib/plugins/show_plugin.py
@@ -55,6 +55,7 @@ class ShowPlugin(obnamlib.ObnamPlugin):
self.app.add_subcommand('generations', self.generations)
self.app.add_subcommand('genids', self.genids)
self.app.add_subcommand('ls', self.ls, arg_synopsis='[FILE]...')
+ self.app.add_subcommand('kdirstat', self.kdirstat, arg_synopsis='[FILE]...')
self.app.add_subcommand('diff', self.diff,
arg_synopsis='[GENERATION1] GENERATION2')
self.app.add_subcommand('nagios-last-backup-age',
@@ -179,8 +180,8 @@ class ShowPlugin(obnamlib.ObnamPlugin):
sys.stdout.write('%s\n' % self.repo.make_generation_spec(gen_id))
self.repo.close()
- def ls(self, args):
- '''List contents of a generation.'''
+ def traverse(self, hdr, cb, args):
+ '''Traverse a generation calling callback.'''
self.open_repository()
@@ -196,12 +197,11 @@ class ShowPlugin(obnamlib.ObnamPlugin):
gen_id, obnamlib.REPO_GENERATION_ENDED)
started = self.format_time(started)
ended = self.format_time(ended)
- self.app.output.write(
- 'Generation %s (%s - %s)\n' %
+ hdr('Generation %s (%s - %s)\n' %
(self.repo.make_generation_spec(gen_id), started, ended))
- for ls_file in args:
- ls_file = self.remove_trailing_slashes(ls_file)
- self.show_objects(gen_id, ls_file)
+ for file in args:
+ file = self.remove_trailing_slashes(file)
+ self.show_objects(cb, gen_id, file)
self.repo.close()
@@ -218,19 +218,26 @@ class ShowPlugin(obnamlib.ObnamPlugin):
gen_id, filename, obnamlib.REPO_FILE_MODE)
return stat.S_ISDIR(mode)
- def show_objects(self, gen_id, dirname):
- self.show_item(gen_id, dirname)
+ def show_objects(self, cb, gen_id, dirname):
+ cb(gen_id, dirname)
subdirs = []
for filename in sorted(self.repo.get_file_children(gen_id, dirname)):
if self.isdir(gen_id, filename):
subdirs.append(filename)
else:
- self.show_item(gen_id, filename)
+ cb(gen_id, filename)
for subdir in subdirs:
- self.show_objects(gen_id, subdir)
+ self.show_objects(cb, gen_id, subdir)
+
+ def ls(self, args):
+ '''List contents of a generation.'''
+ self.traverse(self.show_hdr_ls, self.show_item_ls, args)
- def show_item(self, gen_id, filename):
+ def show_hdr_ls(self, comment):
+ self.app.output.write(comment)
+
+ def show_item_ls(self, gen_id, filename):
fields = self.fields(gen_id, filename)
widths = [
1, # mode
@@ -251,6 +258,44 @@ class ShowPlugin(obnamlib.ObnamPlugin):
result.append(fmt % (abs(widths[i]), fields[i]))
self.app.output.write('%s\n' % ' '.join(result))
+ def kdirstat(self, args):
+ '''List contents of a generation in kdirstat cache format.'''
+ self.traverse(self.show_hdr_kdirstat, self.show_item_kdirstat, args)
+
+ def show_hdr_kdirstat(self, comment):
+ self.app.output.write('''
+[kdirstat 4.0 cache file]
+# Generated by obnam %s
+# Do not edit!
+#
+# Type path size mtime <optional fields>
+
+''' % comment)
+
+ def show_item_kdirstat(self, gen_id, filename):
+ mode = self.repo.get_file_key(
+ gen_id, filename, obnamlib.REPO_FILE_MODE)
+ size = self.repo.get_file_key(
+ gen_id, filename, obnamlib.REPO_FILE_SIZE)
+ mtime_sec = self.repo.get_file_key(
+ gen_id, filename, obnamlib.REPO_FILE_MTIME_SEC)
+
+ if stat.S_ISREG(mode): mode_str = "F\t"
+ elif stat.S_ISDIR(mode): mode_str = "D "
+ elif stat.S_ISLNK(mode): mode_str = "L\t"
+ elif stat.S_ISBLK(mode): mode_str = "BlockDev\t"
+ elif stat.S_ISCHR(mode): mode_str = "CharDev\t"
+ elif stat.S_ISSOCK(mode): mode_str = "Socket\t"
+
+ enc_filename = filename.replace("%", "%25")
+ enc_filename = enc_filename.replace(" ", "%20")
+ enc_filename = enc_filename.replace("\t", "%09")
+
+ if (filename == "/"): return
+
+ self.app.output.write("%s%s\t%d\t%#x\n" %
+ (mode_str, enc_filename, size, mtime_sec))
+
def show_diff_for_file(self, gen_id, fullname, change_char):
'''Show what has changed for a single file.