Clarified copyrights.
[zeroinstall.git] / zeroinstall / zerostore / cli.py
blobb748cd768015f1dc93f837848d6f6612d54a8153
1 # Copyright (C) 2006, Thomas Leonard
2 # See the README file for details, or visit http://0install.net.
4 import sys, os, sha
5 from zeroinstall.zerostore.manifest import generate_manifest
6 from zeroinstall import zerostore, SafeException
8 stores = None
10 def init_stores():
11 global stores
12 assert stores is None
13 if stores is None:
14 stores = zerostore.Stores()
16 class UsageError(SafeException): pass
18 def do_manifest(args):
19 """manifest DIRECTORY"""
20 if len(args) != 1: raise UsageError("Wrong number of arguments")
21 import sha
22 digest = sha.new()
23 for line in generate_manifest(args[0]):
24 print line
25 digest.update(line + '\n')
26 print "sha1=" + digest.hexdigest()
27 sys.exit(0)
29 def do_find(args):
30 """find DIGEST"""
31 if len(args) != 1: raise UsageError("Wrong number of arguments")
32 try:
33 print stores.lookup(args[0])
34 sys.exit(0)
35 except zerostore.BadDigest, ex:
36 print >>sys.stderr, ex
37 except zerostore.NotStored, ex:
38 print >>sys.stderr, ex
39 sys.exit(1)
41 def do_add(args):
42 """add DIGEST (DIRECTORY | (ARCHIVE [EXTRACT])"""
43 if len(args) < 2: raise UsageError("Missing arguments")
44 digest = args[0]
45 if os.path.isdir(args[1]):
46 if len(args) > 2: raise UsageError("Too many arguments")
47 stores.add_dir_to_cache(digest, args[1])
48 elif os.path.isfile(args[1]):
49 if len(args) > 3: raise UsageError("Too many arguments")
50 if len(args) > 2:
51 extract = args[2]
52 else:
53 extract = None
54 stores.add_archive_to_cache(digest, file(args[1]), args[1], extract)
55 else:
56 raise UsageError("No such file or directory '%s'" % args[1])
58 def do_verify(args):
59 """verify (DIGEST | DIRECTORY)"""
60 if len(args) != 1: raise UsageError("Missing DIGEST or DIRECTORY")
61 root = get_stored(args[0])
63 print "Verifying", root
65 required_digest = os.path.basename(args[0])
66 if not required_digest.startswith('sha1='):
67 raise zerostore.BadDigest("Directory name '%s' does not start with 'sha1='" %
68 required_digest)
70 digest = sha.new()
71 lines = []
72 for line in generate_manifest(root):
73 line += '\n'
74 digest.update(line)
75 lines.append(line)
76 actual_digest = 'sha1=' + digest.hexdigest()
78 manifest_file = os.path.join(root, '.manifest')
79 if os.path.isfile(manifest_file):
80 digest = sha.new()
81 digest.update(file(manifest_file).read())
82 manifest_digest = 'sha1=' + digest.hexdigest()
83 else:
84 manifest_digest = None
86 print
87 if required_digest == actual_digest == manifest_digest:
88 print "OK"
89 return
91 print "Cached item does NOT verify:\n" + \
92 " Expected digest: " + required_digest + "\n" + \
93 " Actual digest: " + actual_digest + "\n" + \
94 ".manifest digest: " + (manifest_digest or 'No .manifest file')
96 print
97 if manifest_digest is None:
98 print "No .manifest, so no further details available."
99 elif manifest_digest == actual_digest:
100 print "The .manifest file matches the actual contents."
101 print "Very strange!"
102 elif manifest_digest == required_digest:
103 print "The .manifest file matches directory name. The "
104 print "contents of the directory have changed:"
105 show_changes(lines, file(manifest_file).readlines())
106 elif required_digest == actual_digest:
107 print "The directory contents are correct, but the .manifest file is "
108 print "wrong!"
109 else:
110 print "The .manifest file matches neither of the other digests."
111 print "Odd."
112 sys.exit(1)
114 def show_changes(actual, saved):
115 import difflib
116 for line in difflib.unified_diff(saved, actual, 'Recorded', 'Actual'):
117 print line,
119 def do_list(args):
120 """list"""
121 if args: raise UsageError("List takes no arguments")
122 print "User store (writable) : " + stores.stores[0].dir
123 for s in stores.stores[1:]:
124 print "System store : " + s.dir
125 if len(stores.stores) < 2:
126 print "No system stores."
128 def get_stored(dir_or_digest):
129 if os.path.isdir(dir_or_digest):
130 return dir_or_digest
131 else:
132 try:
133 return stores.lookup(dir_or_digest)
134 except zerostore.NotStored, ex:
135 print >>sys.stderr, ex
136 sys.exit(1)
138 commands = [do_add, do_find, do_list, do_manifest, do_verify]