2 # Copyright (c) 2001 Bizar Software Pty Ltd (http://www.bizarsoftware.com.au/)
3 # This module is free software, and you may redistribute it and/or modify
4 # under the same terms as Python, so long as this copyright message and
5 # disclaimer are retained in their original form.
7 # IN NO EVENT SHALL BIZAR SOFTWARE PTY LTD BE LIABLE TO ANY PARTY FOR
8 # DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING
9 # OUT OF THE USE OF THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE
10 # POSSIBILITY OF SUCH DAMAGE.
12 # BIZAR SOFTWARE PTY LTD SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
14 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS"
15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
18 # $Id: install_util.py,v 1.11 2006-01-25 03:11:43 richard Exp $
20 """Support module to generate and check fingerprints of installed files.
22 __docformat__
= 'restructuredtext'
25 from roundup
.anypy
.hashlib_
import sha1
27 sgml_file_types
= [".xml", ".ent", ".html"]
28 hash_file_types
= [".py", ".sh", ".conf", ".cgi"]
29 slast_file_types
= [".css"]
31 digested_file_types
= sgml_file_types
+ hash_file_types
+ slast_file_types
33 def extractFingerprint(lines
):
34 # get fingerprint from last line
35 if lines
[-1].startswith("#SHA: "):
36 # handle .py/.sh comment
37 return lines
[-1][6:].strip()
38 elif lines
[-1].startswith("<!-- SHA: "):
39 # handle xml/html files
40 fingerprint
= lines
[-1][10:]
41 fingerprint
= fingerprint
.replace('-->', '')
42 return fingerprint
.strip()
43 elif lines
[-1].startswith("/* SHA: "):
45 fingerprint
= lines
[-1][8:]
46 fingerprint
= fingerprint
.replace('*/', '')
47 return fingerprint
.strip()
50 def checkDigest(filename
):
51 """Read file, check for valid fingerprint, return TRUE if ok"""
53 inp
= open(filename
, "r")
54 lines
= inp
.readlines()
57 fingerprint
= extractFingerprint(lines
)
58 if fingerprint
is None:
62 # calculate current digest
67 # compare current to stored digest
68 return fingerprint
== digest
.hexdigest()
72 """ A class that you can use like open() and that calculates
73 and writes a SHA digest to the target file.
76 def __init__(self
, filename
):
77 self
.filename
= filename
79 self
.file = open(self
.filename
, "w")
81 def write(self
, data
):
82 lines
= data
.splitlines()
83 # if the file is coming from an installed tracker being used as a
84 # template, then we will want to re-calculate the SHA
85 fingerprint
= extractFingerprint(lines
)
86 if fingerprint
is not None:
87 data
= '\n'.join(lines
[:-1]) + '\n'
89 self
.digest
.update(data
)
92 file, ext
= os
.path
.splitext(self
.filename
)
94 if ext
in sgml_file_types
:
95 self
.file.write("<!-- SHA: %s -->\n" % (self
.digest
.hexdigest(),))
96 elif ext
in hash_file_types
:
97 self
.file.write("#SHA: %s\n" % (self
.digest
.hexdigest(),))
98 elif ext
in slast_file_types
:
99 self
.file.write("/* SHA: %s */\n" % (self
.digest
.hexdigest(),))
104 def copyDigestedFile(src
, dst
, copystat
=1):
105 """ Copy data from `src` to `dst`, adding a fingerprint to `dst`.
106 If `copystat` is true, the file status is copied, too
109 if os
.path
.isdir(dst
):
110 dst
= os
.path
.join(dst
, os
.path
.basename(src
))
112 dummy
, ext
= os
.path
.splitext(src
)
113 if ext
not in digested_file_types
:
115 return shutil
.copy2(src
, dst
)
117 return shutil
.copyfile(src
, dst
)
122 fsrc
= open(src
, 'r')
123 fdst
= DigestFile(dst
)
124 shutil
.copyfileobj(fsrc
, fdst
)
126 if fdst
: fdst
.close()
127 if fsrc
: fsrc
.close()
129 if copystat
: shutil
.copystat(src
, dst
)
135 testdata
= open(sys
.argv
[0], 'r').read()
137 for ext
in digested_file_types
:
138 testfile
= "__digest_test" + ext
140 out
= DigestFile(testfile
)
144 assert checkDigest(testfile
), "digest ok w/o modification"
146 mod
= open(testfile
, 'r+')
148 mod
.write('# changed!')
151 assert not checkDigest(testfile
), "digest fails after modification"
156 if __name__
== '__main__':
159 # vim: set filetype=python ts=4 sw=4 et si