git » abk » commit 46a9c7a

Initial import

author
2005-03-02 04:44:00 UTC
committer
2005-03-02 04:44:00 UTC

Initial import

abk +257 -0

diff --git a/abk b/abk
new file mode 100644
index 0000000..29b164f
--- /dev/null
+++ b/abk
@@ -0,0 +1,257 @@
+#!/usr/bin/python
+
+import sys
+import os
+import bz2
+import time
+import sha
+import mmap
+import cPickle
+from stat import *
+
+
+#
+# constants
+#
+
+PSIZE = 4 * 1024
+
+
+#
+# classes
+#
+
+class file_info:
+	"Represents a file"
+	def __init__(self, name):
+		self.name = name
+		self.mtime = 0
+		self.mode = 0
+		self.uid = 0
+		self.gid = 0
+		self.mtime = 0
+		self.type = ''
+		self.linkto = None
+		self.rdev = None
+		self.hash = None
+		self.stat = None
+
+	def __repr__(self):
+		return self.name
+
+	def load(self):
+		"Loads data from the file."
+		s = os.lstat(self.name)
+		self.stat = s
+		if S_ISREG(s.st_mode):
+			self.type = 'r'
+		elif S_ISLNK(s.st_mode):
+			self.type = 'l'
+		elif S_ISCHR(s.st_mode):
+			self.type = 'c'
+			self.rdev = s.st_rdev
+		elif S_ISBLK(s.st_mode):
+			self.type = 'b'
+			self.rdev = s.st_rdev
+		elif S_ISFIFO(s.st_mode):
+			self.type = 'f'
+			self.linkto = os.readlink(self.name)
+		elif S_ISDIR(s.st_mode):
+			self.type = 'd'
+		else:
+			self.type = 'u'
+
+		self.mtime = s.st_mtime
+		self.mode = s.st_mode
+		self.uid = s.st_uid
+		self.gid = s.st_gid
+		
+		# FIXME: hacer opcional para Damian
+		if self.type == 'r':
+			self.hash = self.hash_file()
+
+	def __eq__(self, other):
+		"Compares to other file_info object."
+		if self.name != other.name: return 0
+		if self.mtime != other.mtime: return 0
+		if self.type != other.type: return 0
+		if self.size != other.size: return 0
+		if self.mode != other.mode: return 0
+		if self.uid != other.uid: return 0
+		if self.gid != other.gid: return 0
+		if self.hash != other.hash: return 0
+
+		if self.mode == 'b' or self.mode == 'c':
+			if self.rdev != other.rdev:
+				return 0
+		if self.mode == 'l':
+			if self.linkto != other.linkto:
+				return 0
+
+		return 1
+
+	def __ne__(self, other):
+		return not (self == other)
+
+	def copy_file_reg(self, dst):
+		"Copy a regular file."
+		sfile = open(self.name, 'r')
+		dfile = open(dst, 'w')
+
+		# the data
+		data = sfile.read(PSIZE)
+		while data:
+			dfile.write(data)
+			data = sfile.read(PSIZE)
+
+		sfile.close()
+		dfile.close()
+
+		os.chmod(dst, self.mode & 07777)	# FIXME: is this linux-only?
+		os.chown(dst, self.uid, self.gid)
+
+
+	def copy_file_link(self, dst):
+		"Copy a symbolic link."
+		linkto = os.readlink(self.name)
+		os.symlink(linkto, dst)
+		os.chown(dst, self.uid, self.gid)
+		# note that we don't chmod, because it will change the
+		# destination owner instead of the link's.
+
+
+	def copy_file_dev(self, dst):
+		"Copy a device file."
+		major = os.major(self.rdev)
+		minor = os.minor(self.rdev)
+		dev = os.makedev(major, minor)
+		os.mknod(dst, self.mode, dev)
+		os.chmod(dst, self.mode & 07777)
+		os.chown(dst, self.uid, self.gid)
+
+
+	def copy_file(self, dst):
+		"Copies a file, along with its permissions and ownership."
+		if self.type == 'r':
+			self.copy_file_reg(dst)
+		elif self.type == 'l':
+			self.copy_file_link(dst)
+		elif self.type == 'b' or self.type == 'c':
+			self.copy_file_dev(dst)
+		elif self.type == 'f':
+			# we just create fifos
+			os.mkfifo(dst, self.type & 07777)
+		elif self.type == 'd':
+			# we just create directories
+			#os.mkdir(dst, self.type & 07777)
+			os.makedirs(dst, self.type & 07777)
+		else:
+			raise 'Unk type: 0x%x %d' % (self.mode, self.name)
+
+
+	def hash_file(self):
+		"Returns the sha1sum of a file."
+		hash = sha.new()
+		f = open(self.name)
+		data = f.read(PSIZE)
+		while data:
+			hash.update(data)
+			data = f.read(PSIZE)
+		f.close()
+		return hash.hexdigest()
+
+
+
+class index_file:
+	"Represents the index file."
+	def __init__(self, name):
+		self.name = name
+		self.db = {}
+
+	def load(self):
+		"Loads data from the file."
+		try:
+			f = open(self.name)
+		except IOError:
+			# probably file doesn't exist, ignore
+			return
+		self.db = cPickle.load(f)
+		f.close()
+
+	def save(self):
+		"Saves the index to the disk."
+		f = open(self.name, 'w')
+		cPickle.dump(self.db, f, cPickle.HIGHEST_PROTOCOL)
+		f.close()
+
+	def put_file(self, filename):
+		"Incorporates a file into the index."
+		self.db[filename] = file_info(filename)
+		self.db[filename].load()
+
+	def get_file(self, filename):
+		"Get the file_info object for the given filename."
+		return self.db[filename]
+	
+	def del_file(self, filename):
+		"Remove a file from the index."
+		del(self.db[filename])
+
+	def populate(self, root):
+		"Populate the index from a root path."
+		self.put_file(root)
+		tree = os.walk(root)
+		for path, childs, files in tree:
+			for f in files:
+				name = os.path.join(path, f)
+				self.put_file(name)
+			for c in childs:
+				name = os.path.join(path, c)
+				self.put_file(name)
+
+
+def bz2_file(src, dst = None):
+	"Compress a file using bz2."
+	if not dst:
+		dst = src + '.bz2'
+
+	sfile = open(src)
+	dfile = open(dst, 'w')
+
+	bcomp = bz2.BZ2Compressor()
+	data = sfile.read(PSIZE)
+	while data:
+		dfile.write(bcomp.compress(data))
+		data = sfile.read(PSIZE)
+	dfile.write(bcomp.flush())
+	sfile.close()
+	dfile.close()
+
+
+
+
+#
+# main
+#
+src_path = sys.argv[1]
+srcidx_path = sys.argv[2]
+dst_path = sys.argv[3]
+dstidx_path = sys.argv[4]
+
+# load destination index
+dstidx = index_file(dstidx_path)
+dstidx.load()
+
+# create source index
+srcidx = index_file(srcidx_path)
+srcidx.populate(src_path)
+srcidx.save()
+
+# compare them
+dkeys = dstidx.db.keys()
+for f in srcidx.db.keys():
+	if f not in dkeys:
+		dst = os.path.join(dst_path, f)
+		print 'copy', f, dst
+		srcidx.db[f].copy_file(dst)
+