Commits

Shu Zong Chen committed bf88f14

Initial version

Comments (0)

Files changed (12)

+# use glob syntax.
+syntax: glob
+
+*.swp
+*.pyc
+#!/usr/bin/env python
+
+import masquerade
+import sys
+
+def main():
+	fn, options = masquerade.parse_args(sys.argv[1:])
+	m = masquerade.Masquerade(fn, options)
+	m.go()
+
+if __name__ == "__main__":
+	main()
+

masquerade/__init__.py

+from masq import Masquerade
+
+import os
+
+def parse_args(args):
+	options = {
+		'as':None,
+		'into':'json',
+		'with':None,
+	}
+	if len(args):
+		fn = args[0]
+	else:
+		raise Exception("No filename")
+	rest = iter(args[1:])
+	for a, b in zip(rest, rest):
+		if a not in options:
+			raise Exception("Invalid option")
+		options[a] = b
+	if options['with'] is None:
+		options['with'] = os.environ.get('EDITOR') or os.environ.get('VISUAL')
+	if options['with'] is None:
+		raise Exception("No EDITOR or VISUAL defined, set that or use 'with FOO'")
+
+	return fn, options

masquerade/formatters/__init__.py

Empty file added.

masquerade/formatters/generic.py

+
+
+class MasqueradeFormatter(object):
+	file_object = True
+	editable = False
+
+	@staticmethod
+	def read(fh):
+		raise NotImplementedError("Read is not defined")
+
+	@staticmethod
+	def write(data):
+		raise NotImplementedError("Write is not defined")

masquerade/formatters/jsonformat.py

+from generic import MasqueradeFormatter
+import json
+
+class JSONFormatter(MasqueradeFormatter):
+	editable = True
+
+	@staticmethod
+	def read(fh):
+		return json.load(fh)
+
+	@staticmethod
+	def write(data):
+		return json.dumps(data, ensure_ascii = False, allow_nan = True, sort_keys = True, indent=4)
+
+	@staticmethod
+	def commit(data, fn):
+		with open(fn, 'w') as fh:
+			fh.write(JSONFormatter.write(data))
+
+export = JSONFormatter

masquerade/formatters/reprformat.py

+from generic import MasqueradeFormatter
+
+class REPRFormatter(MasqueradeFormatter):
+
+	@staticmethod
+	def read(fh):
+		return eval(fh.read())
+
+	@staticmethod
+	def write(data):
+		return repr(data)
+
+export = REPRFormatter

masquerade/formatters/sqliteformat.py

+import sqlite3
+import tempfile
+import os
+
+from generic import MasqueradeFormatter
+from collections import namedtuple
+
+SqliteEntity = namedtuple('SqliteEntity', [
+	'type',
+	'name',
+	'tbl_name',
+	'rootpage',
+	'sql',
+])
+
+class SqliteFormatter(MasqueradeFormatter):
+	file_object = False
+
+	@staticmethod
+	def read(fh):
+		conn = sqlite3.connect(fh)
+		cur = conn.execute("SELECT * FROM sqlite_master;")
+
+		items = cur.fetchall()
+		ret = {
+			"tables":{},
+			"indexes":[],
+		}
+		
+		for item in items:
+			se = SqliteEntity(*item)
+			if se.type == 'table':
+				ret['tables'][se.name] = {}
+				ret['tables'][se.name]['schema'] = se.sql
+				ret['tables'][se.name]['items'] = []
+
+		for tbl_name in ret['tables']:
+			# I assume this is safe because tbl_name came from the db
+			cur = conn.execute("SELECT * FROM {0}".format(tbl_name))
+			items = cur.fetchall()
+			for item in items:
+				ret['tables'][tbl_name]['items'].append(item)
+		return ret
+
+	@staticmethod
+	def commit(data, fn):
+		_, tmp_file = tempfile.mkstemp()
+		os.close(_)
+
+		conn = sqlite3.connect(tmp_file)
+
+		for tbl_name, table in data['tables'].iteritems():
+			conn.execute(table['schema'])
+			for item in table['items']:
+				sql = "INSERT INTO {0} VALUES ({1})".format(
+					tbl_name,
+					",".join(['?'] * len(item))
+				)
+				conn.execute(sql, item)
+		conn.commit()
+		conn.close()
+
+		with open(fn, 'wb') as fh:
+			with open(tmp_file, 'rb') as fhb:
+				fh.write(fhb.read())
+
+		os.unlink(tmp_file)
+
+export = SqliteFormatter

masquerade/masq.py

+import tempfile
+import os
+import subprocess
+import pkgutil
+
+class Masquerade(object):
+	def __init__(self, fn, options):
+		self._available_formats = None
+		self.fn = fn
+		self.editor = options['with']
+		self.source = self.get_formatter(options['as'])
+		self.target = self.get_formatter(options['into'])
+
+	def go(self):
+		data = Masquerade.read_from_source(self.source, self.fn)
+		masked = self.target.write(data)
+
+		tmp_dir, fn = self.mkfile(masked)
+
+		while 1:
+			subprocess.call([self.editor, fn])
+
+			try:
+				unmasked = Masquerade.read_from_source(self.target, fn)
+			except Exception as e:
+				print e
+				print e.message
+				s = raw_input("Please fix this")
+				continue
+
+			try:
+				self.source.commit(unmasked, self.fn)
+			except Exception as e:
+				raise e
+			break
+
+		self.rmfile(tmp_dir)
+
+	def get_formatter(self, format):
+		if format == 'sqlite':
+			import masquerade.formatters.sqliteformat as _fmtr
+		elif format == 'json':
+			import masquerade.formatters.jsonformat as _fmtr
+		elif format == 'repr':
+			import masquerade.formatters.reprformat as _fmtr
+		else:
+			formats = self.get_formats()
+			if format in formats:
+				_fmtr = __import__(formats[format], globals(), locals(), [], -1)
+			else:
+				raise Exception("No such format")
+		return _fmtr.export
+
+	def get_formats(self):
+		if self._available_formats is None:
+			prefix = "masquerade_"
+			af = {}
+			for pkg in pkgutil.iter_modules():
+				if pkg[1].startswith(prefix):
+					af[pkg[1][len(prefix):]] = pkg[1]
+			self._available_formats = af
+		return self._available_formats
+
+	def mkfile(self, data):
+		tmp_dir = tempfile.mkdtemp()
+		fn = os.path.join(tmp_dir, self.fn)
+		with open(fn, 'w') as fh:
+			fh.write(data)
+		return tmp_dir, fn
+
+	def rmfile(self, dn):
+		os.unlink(os.path.join(dn, self.fn))
+		os.rmdir(dn)
+
+	@staticmethod
+	def read_from_source(src, v):
+		if src.file_object == True:
+			with open(v) as fh:
+				return src.read(fh)
+		return src.read(v)
+

tests/files/test.json

+{
+    "indexes": [], 
+    "tables": {
+        "t": {
+            "items": [
+                [
+                    1, 
+                    1, 
+                    5
+                ], 
+                [
+                    2, 
+                    2, 
+                    3
+                ], 
+                [
+                    3, 
+                    4, 
+                    5
+                ]
+            ], 
+            "schema": "CREATE TABLE t(x INTEGER PRIMARY KEY ASC, y, z)"
+        }
+    }
+}

tests/files/test.test.sqlite3

Binary file added.

tests/files/test.yaml

+indexes: []
+tables:
+  t:
+    items:
+    - [1, 1, 5]
+    - [2, 2, 3]
+    - [3, 4, 5]
+    schema: CREATE TABLE t(x INTEGER PRIMARY KEY ASC, y, z)