Skip to content

Commit 5ea3bf0

Browse files
committed
Initial commit
0 parents  commit 5ea3bf0

18 files changed

+728
-0
lines changed

__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__author__ = 'root'

__init__.pyc

132 Bytes
Binary file not shown.

bin/create_manifest.py

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/usr/local/bin/python
2+
import os
3+
from xfl import DirTree
4+
from os import sys
5+
6+
import argparse
7+
8+
9+
if __name__ == "__main__":
10+
parser = argparse.ArgumentParser()
11+
12+
parser.add_argument("-f", "--file",
13+
dest="filename",
14+
help="Write to specific XML file",
15+
default="{0}_file_digest.xml".format(sys.platform))
16+
parser.add_argument("-p", "--path",
17+
dest="path",
18+
help="Specific path to parse out, defaults to current directory",
19+
default=os.getcwd())
20+
parser.add_argument("--hash",
21+
dest="hash_type",
22+
help="Choose a hashing mode (leave blank for none): MD5 or SHA1",
23+
default=None)
24+
25+
args = parser.parse_args()
26+
27+
hasher = None
28+
if args.hash_type is None:
29+
hasher = None
30+
else:
31+
import hashlib
32+
if args.hash_type.upper() == 'SHA1':
33+
hasher = hashlib.sha1()
34+
if args.hash_type.upper() == 'MD5':
35+
hasher = hashlib.md5()
36+
37+
dt = DirTree()
38+
print "Creating directory list: {0}".format(args.path)
39+
dt.read_disk(args.path, hasher=hasher)
40+
print "Writing to file: %s" % (args.filename)
41+
dt.write_file(args.filename)
42+
print "Done!"
43+
del dt

build/lib/xfl/__init__.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
__author__ = 'root'
2+
3+
from xfl import DirTree, compare_DT, compare_files
4+
5+

build/lib/xfl/xfl.py

+296
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
#!/usr/bin/python
2+
# -*- coding: latin-1 -*-
3+
"""
4+
XFL - XML File List v0.06 2008-02-06 - Philippe Lagadec
5+
6+
A module to store directory trees and file information in XML
7+
files, and to track changes in files and directories.
8+
9+
Project website: http://www.decalage.info/python/xfl
10+
11+
License: CeCILL v2, open-source (GPL compatible)
12+
see http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
13+
"""
14+
15+
#------------------------------------------------------------------------------
16+
# CHANGELOG:
17+
# 2006-08-04 v0.01 PL: - 1st version
18+
# 2006-06-08 v0.03 PL
19+
# 2007-08-15 v0.04 PL: - improved dir callback
20+
# 2007-08-15 v0.05 PL: - added file callback, added element to callbacks
21+
# 2008-02-06 v0.06 PL: - first public release
22+
23+
#------------------------------------------------------------------------------
24+
# TODO:
25+
# + store timestamps with XML-Schema dateTime format
26+
# - options to store owner
27+
# + add simple methods like isfile, isdir, which take a path as arg
28+
# + handle exceptions file-by-file and store them in the XML
29+
# ? replace callback functions by DirTree methods which may be overloaded ?
30+
# - allow callback functions for dirs and files (path + object)
31+
# - DirTree options to handle owner, hash, ...
32+
33+
#--- IMPORTS ------------------------------------------------------------------
34+
import sys
35+
import hashlib
36+
37+
# path module to easily handle files and dirs:
38+
try:
39+
from path import path
40+
except:
41+
raise ImportError, "the path module is not installed: " \
42+
+ "see http://www.jorendorff.com/articles/python/path/"
43+
44+
### import LXML for pythonic XML:
45+
##try:
46+
## import lxml.etree as ET
47+
##except:
48+
## raise ImportError, "You must install lxml: http://codespeak.net/lxml"
49+
50+
# ElementTree for pythonic XML:
51+
try:
52+
if sys.hexversion >= 0x02050000:
53+
# ElementTree is included in the standard library since Python 2.5
54+
import xml.etree.ElementTree as ET
55+
else:
56+
# external ElemenTree for Python <=2.4
57+
import elementtree.ElementTree as ET
58+
except:
59+
raise ImportError, "the ElementTree module is not installed: " \
60+
+ "see http://effbot.org/zone/element-index.htm"
61+
62+
#--- CONSTANTS ----------------------------------------------------------------
63+
64+
# XML tags
65+
TAG_DIRTREE = "dirtree"
66+
TAG_DIR = "dir"
67+
TAG_FILE = "file"
68+
69+
# XML attributes
70+
ATTR_NAME = "name"
71+
ATTR_TIME = "time"
72+
ATTR_MTIME = "mtime"
73+
ATTR_SIZE = "size"
74+
ATTR_OWNER = "owner"
75+
ATTR_HASH = 'hash'
76+
77+
#Hash consts
78+
BLOCKSIZE = 65536
79+
80+
#--- CLASSES ------------------------------------------------------------------
81+
82+
83+
class DirTree:
84+
"""
85+
class representing a tree of directories and files,
86+
that can be written or read from an XML file.
87+
"""
88+
89+
def __init__(self, rootpath=""):
90+
"""
91+
DirTree constructor.
92+
"""
93+
self.rootpath = path(rootpath)
94+
95+
def read_disk(self, rootpath=None, callback_dir=None, callback_file=None, hasher=None):
96+
"""
97+
to read the DirTree from the disk.
98+
"""
99+
# creation of the root ElementTree:
100+
self.et = ET.Element(TAG_DIRTREE)
101+
if rootpath:
102+
self.rootpath = path(rootpath)
103+
# name attribute = rootpath
104+
self.et.set(ATTR_NAME, self.rootpath)
105+
# time attribute = time of scan
106+
#self.et.set(ATTR_TIME, str(time.time()))
107+
self._scan_dir(self.rootpath, self.et, callback_dir, callback_file, hasher)
108+
109+
def _scan_dir(self, directory, parent, callback_dir=None, callback_file=None, hasher=None):
110+
"""
111+
to scan a directory on the disk (recursive scan).
112+
(this is a private method)
113+
"""
114+
if callback_dir:
115+
callback_dir(directory, parent)
116+
for f in directory.files():
117+
e = ET.SubElement(parent, TAG_FILE)
118+
e.set(ATTR_NAME, f.name)
119+
e.set(ATTR_SIZE, str(f.getsize()))
120+
121+
if hasher is not None:
122+
e.set(ATTR_HASH, self._get_file_hash(f, hasher))
123+
124+
try:
125+
e.set(ATTR_OWNER, f.get_owner())
126+
except:
127+
pass
128+
if callback_file:
129+
callback_file(f, e)
130+
for d in directory.dirs():
131+
#print d
132+
e = ET.SubElement(parent, TAG_DIR)
133+
e.set(ATTR_NAME, d.name)
134+
self._scan_dir(d, e, callback_dir, callback_file, hasher)
135+
136+
def write_file(self, filename, encoding="utf-8"):
137+
"""
138+
to write the DirTree in an XML file.
139+
"""
140+
tree = ET.ElementTree(self.et)
141+
tree.write(filename, encoding)
142+
143+
def read_file(self, filename):
144+
"""
145+
to read the DirTree from an XML file.
146+
"""
147+
tree = ET.parse(filename)
148+
self.et = tree.getroot()
149+
self.rootpath = self.et.get(ATTR_NAME)
150+
151+
def pathdict(self):
152+
"""
153+
to create a dictionary which indexex all objects by their paths.
154+
"""
155+
self.dict = {}
156+
self._pathdict_dir(path(""), self.et)
157+
158+
def _pathdict_dir(self, base, et):
159+
"""
160+
(private method)
161+
"""
162+
dirs = et.findall(TAG_DIR)
163+
for d in dirs:
164+
dpath = base / d.get(ATTR_NAME)
165+
self.dict[dpath] = d
166+
self._pathdict_dir(dpath, d)
167+
files = et.findall(TAG_FILE)
168+
for f in files:
169+
fpath = base / f.get(ATTR_NAME)
170+
self.dict[fpath] = f
171+
172+
173+
def _get_file_hash(self, file_name, hasher):
174+
"""
175+
176+
:param file_name:
177+
:param hasher:
178+
:return:
179+
"""
180+
with open(file_name, 'rb') as current_file:
181+
buf = current_file.read(BLOCKSIZE)
182+
while len(buf) > 0:
183+
hasher.update(buf)
184+
buf = current_file.read(BLOCKSIZE)
185+
186+
return hasher.hexdigest()
187+
188+
189+
190+
#--- FUNCTIONS ----------------------------------------------------------------
191+
192+
def compare_files(et1, et2):
193+
"""
194+
to compare two files or dirs.
195+
returns True if files/dirs information are identical,
196+
False otherwise.
197+
"""
198+
if et1.tag != et2.tag:
199+
return False
200+
if et1.tag == TAG_DIR:
201+
if et1.get(ATTR_NAME) != et2.get(ATTR_NAME):
202+
return False
203+
else:
204+
return True
205+
elif et1.tag == TAG_FILE:
206+
if et1.get(ATTR_NAME) != et2.get(ATTR_NAME):
207+
#Compare names
208+
return False
209+
if et1.get(ATTR_SIZE) != et2.get(ATTR_SIZE):
210+
#Compare sizes
211+
return False
212+
if et1.get(ATTR_HASH) != et2.get(ATTR_HASH):
213+
#Compare file hash (if the one has a hash and the other does not, it'll return false)
214+
return False
215+
else:
216+
return True
217+
else:
218+
raise TypeError
219+
220+
221+
def compare_DT(dirTree1, dirTree2):
222+
"""
223+
to compare two DirTrees, and report which files have changed.
224+
returns a tuple of 4 lists of paths: same files, different files,
225+
files only in dt1, files only in dt2.
226+
"""
227+
same = []
228+
different = []
229+
only1 = []
230+
only2 = []
231+
dirTree1.pathdict()
232+
dirTree2.pathdict()
233+
paths1 = dirTree1.dict.keys()
234+
paths2 = dirTree2.dict.keys()
235+
for p in paths1:
236+
if p in paths2:
237+
# path is in the 2 DT, we have to compare file info
238+
f1 = dirTree1.dict[p]
239+
f2 = dirTree2.dict[p]
240+
if compare_files(f1, f2):
241+
# files/dirs are the same
242+
same.append(p)
243+
else:
244+
different.append(p)
245+
paths2.remove(p)
246+
else:
247+
only1.append(p)
248+
# now paths2 should contain only files and dirs that weren't in paths1
249+
only2 = paths2
250+
return same, different, only1, only2
251+
252+
253+
def callback_dir_print(dir, element):
254+
"""
255+
sample callback function to print dir path.
256+
"""
257+
print dir
258+
259+
260+
def callback_file_print(file, element):
261+
"""
262+
sample callback function to print file path.
263+
"""
264+
print " - " + file
265+
266+
267+
#--- MAIN ---------------------------------------------------------------------
268+
269+
if __name__ == "__main__":
270+
271+
if len(sys.argv) < 3:
272+
print __doc__
273+
print "usage: python %s <root path> <xml file> [previous xml file]" % path(sys.argv[0]).name
274+
sys.exit(1)
275+
d = DirTree()
276+
d.read_disk(sys.argv[1], callback_dir_print, callback_file_print)
277+
d.write_file(sys.argv[2])
278+
if len(sys.argv) > 3:
279+
d2 = DirTree()
280+
d2.read_file(sys.argv[3])
281+
same, different, only1, only2 = compare_DT(d, d2)
282+
## print "\nSAME:"
283+
## for f in sorted(same):
284+
## print " "+f
285+
print "\nDIFFERENT:"
286+
for f in sorted(different):
287+
print " " + f
288+
print "\nNEW:"
289+
for f in sorted(only1):
290+
print " " + f
291+
print "\nDELETED:"
292+
for f in sorted(only2):
293+
print " " + f
294+
295+
296+

build/scripts-2.7/create_manifest.py

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/root/.pyenv/versions/2.7.5/bin/python
2+
import os
3+
from xfl import DirTree
4+
from os import sys
5+
6+
import argparse
7+
8+
9+
if __name__ == "__main__":
10+
parser = argparse.ArgumentParser()
11+
12+
parser.add_argument("-f", "--file",
13+
dest="filename",
14+
help="Write to specific XML file",
15+
default="{0}_file_digest.xml".format(sys.platform))
16+
parser.add_argument("-p", "--path",
17+
dest="path",
18+
help="Specific path to parse out, defaults to current directory",
19+
default=os.getcwd())
20+
parser.add_argument("--hash",
21+
dest="hash_type",
22+
help="Choose a hashing mode (leave blank for none): MD5 or SHA1",
23+
default=None)
24+
25+
args = parser.parse_args()
26+
27+
hasher = None
28+
if args.hash_type is None:
29+
hasher = None
30+
else:
31+
import hashlib
32+
if args.hash_type.upper() == 'SHA1':
33+
hasher = hashlib.sha1()
34+
if args.hash_type.upper() == 'MD5':
35+
hasher = hashlib.md5()
36+
37+
dt = DirTree()
38+
print "Creating directory list: {0}".format(args.path)
39+
dt.read_disk(args.path, hasher=hasher)
40+
print "Writing to file: %s" % (args.filename)
41+
dt.write_file(args.filename)
42+
print "Done!"
43+
del dt

dist/xfl-.06-py2.7.egg

8.18 KB
Binary file not shown.

0 commit comments

Comments
 (0)