Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Basic repo, commit, branch implementation

  • Loading branch information...
commit e4f1ea1ac144457a160e5000c0e84f9b8a169031 0 parents
Daniel Reverri authored June 07, 2009
0  __init__.py
No changes.
198  evolve.py
... ...
@@ -0,0 +1,198 @@
  1
+import copy, hashlib
  2
+
  3
+try:
  4
+	import json
  5
+except ImportError:
  6
+	import simplejson as json
  7
+
  8
+class BranchNotFound(Exception):
  9
+	pass
  10
+	
  11
+class CommitNotFound(Exception):
  12
+	pass
  13
+	
  14
+class InvalidChange(Exception):
  15
+	pass
  16
+
  17
+class Repository:
  18
+	def __init__(self):
  19
+		self.commits = {'root':{'changelog':[],'msg':'root'}}
  20
+		self.branches = {}
  21
+		self.checkouts = {}
  22
+		
  23
+	def branch(self,branch_name,parent_branch_name=None):
  24
+		if parent_branch_name:
  25
+			try:
  26
+				self.branches[branch_name] = self.branches[parent_branch_name]
  27
+			except KeyError:
  28
+				raise BranchNotFound("Could not find the %s branch" % parent_branch_name)
  29
+		else:
  30
+			self.branches[branch_name] = 'root'
  31
+		return self.checkout(branch_name)
  32
+		
  33
+	def checkout(self,branch_name):
  34
+		try:
  35
+			commit_id = self.branches[branch_name]
  36
+		except KeyError:
  37
+			raise BranchNotFound("Could not find the %s branch" % branch_name)
  38
+		
  39
+		try:
  40
+			commit = self.checkouts[commit_id]
  41
+		except KeyError:
  42
+			commit = Commit(self)
  43
+			commit.checkout(commit_id)
  44
+			self.checkouts[commit_id] = commit
  45
+			
  46
+		branch = Branch(self,branch_name,commit)
  47
+		return branch
  48
+		
  49
+	def rollback(self,commit):
  50
+		pass
  51
+		
  52
+	def find_common_parent(self,start_commit,end_commit):
  53
+		pass
  54
+
  55
+class Schema:
  56
+	def __init__(self):
  57
+		self.tables = {}
  58
+		
  59
+	def verify(self,change):
  60
+		"""Verify change against the working schema"""
  61
+		tables = self.tables
  62
+		action = change['change']
  63
+		schema = change['schema']
  64
+		table = schema['id']
  65
+		fields = schema['properties']
  66
+	
  67
+		if action == 'create':
  68
+			return table not in tables
  69
+		
  70
+		if action == 'drop':
  71
+			return table in tables
  72
+		
  73
+		if action == 'alter.add' or action == 'alter.rename':
  74
+			if table not in tables:
  75
+				return False
  76
+			for field in fields:
  77
+				if field in tables[table]['properties']:
  78
+					return False
  79
+			return True
  80
+		
  81
+		if action == 'alter.modify':
  82
+			if table not in tables:
  83
+				return False
  84
+			for field in fields:
  85
+				if field not in tables[table]['properties']:
  86
+					return False
  87
+			return True
  88
+
  89
+	def add(self,change):
  90
+		"""Add change to the working changelog, indexed per table, and working schema"""
  91
+		tables = self.tables
  92
+		action = change['change']
  93
+		schema = change['schema']
  94
+		table = change['schema']['id']
  95
+		fields = change['schema']['properties']
  96
+
  97
+		if action == 'create':
  98
+			tables[table] = schema
  99
+
  100
+		if action == 'drop':
  101
+			del tables[table]
  102
+
  103
+		if action == 'alter.add' or action == 'alter.modify':
  104
+			for field in fields:
  105
+				tables[table]['properties'][field] = fields[field]
  106
+
  107
+		if action == 'alter.rename':
  108
+			for field in fields:
  109
+				newname = fields[field]
  110
+				tables[table]['properties'][newname] = tables[table]['properties'][field]
  111
+				del tables[table]['properties'][field]
  112
+
  113
+		if action == 'alter.drop':
  114
+			for field in fields:
  115
+				del tables[table]['properties'][field]
  116
+		
  117
+class Commit:
  118
+	def __init__(self,repository):
  119
+		self.repository = repository
  120
+		self.parent = None
  121
+		self.changelog = None
  122
+		self.schema = None
  123
+		self.commit_id = None
  124
+		self.msg = None
  125
+		self.checkedout = False
  126
+		
  127
+	def checkout(self,commit_id):
  128
+		if self.checkedout:
  129
+			return
  130
+		
  131
+		try:
  132
+			commit_dict = self.repository.commits[commit_id]
  133
+		except KeyError:
  134
+			raise CommitNotFound("Could not find the commit %s" % commit_id)
  135
+		
  136
+		self.commit_id = commit_id
  137
+		self.msg = commit_dict['msg']
  138
+		
  139
+		if 'parent' in commit_dict:
  140
+			self.parent = Commit(self.repository)
  141
+			self.parent.checkout(commit_dict['parent'])
  142
+			self.schema = copy.deepcopy(self.parent.schema)
  143
+		else:
  144
+			self.parent = None
  145
+			self.schema = Schema()
  146
+		
  147
+		self.changelog = commit_dict['changelog']
  148
+			
  149
+		for change in self.changelog:
  150
+			self.schema.add(change)
  151
+			
  152
+		self.checkedout = True
  153
+		
  154
+	def toDict(self):
  155
+		d = {
  156
+			'changelog':self.changelog,
  157
+			'msg':self.msg
  158
+		}
  159
+		
  160
+		if self.parent:
  161
+			d['parent'] = self.parent.commit_id
  162
+			
  163
+		return d
  164
+			
  165
+class Branch:
  166
+	def __init__(self,repository,name,parent):
  167
+		self.repository = repository
  168
+		self.name = name
  169
+		self.parent = parent
  170
+		self.reset()
  171
+		
  172
+	def verify(self,change):
  173
+		return self.schema.verify(change)
  174
+
  175
+	def add(self,change):
  176
+		if self.verify(change):
  177
+			self.changelog.append(change)
  178
+			self.schema.add(change)
  179
+		else:
  180
+			raise InvalidChange
  181
+
  182
+	def commit(self,msg):
  183
+		commit = Commit(self.repository)
  184
+		commit.parent = self.parent
  185
+		commit.changelog = self.changelog
  186
+		commit.schema = self.schema
  187
+		commit.msg = msg
  188
+		commit.commit_id = hashlib.sha1(json.dumps(commit.toDict()))
  189
+		commit.checkedout = True
  190
+		self.repository.commits[commit.commit_id] = commit.toDict()
  191
+		self.repository.checkouts[commit.commit_id] = commit
  192
+		self.repository.branches[self.name] = commit.commit_id
  193
+		self.parent = commit
  194
+		self.reset()
  195
+		
  196
+	def reset(self):
  197
+		self.schema = copy.deepcopy(self.parent.schema)
  198
+		self.changelog = []
BIN  evolve.pyc
Binary file not shown
66  test_evolve.py
... ...
@@ -0,0 +1,66 @@
  1
+import unittest
  2
+import evolve
  3
+
  4
+class TestEvolve(unittest.TestCase):
  5
+	def setUp(self):
  6
+		self.repo = evolve.Repository()
  7
+		
  8
+	def test_branch(self):
  9
+		branch = self.repo.branch('master')
  10
+		self.assertEqual(branch.name,'master')
  11
+		self.assertEqual(branch.parent.commit_id,'root')
  12
+		
  13
+	def test_branch_from_branch(self):
  14
+		master = self.repo.branch('master')
  15
+		exp = self.repo.branch('exp','master')
  16
+		self.assertEqual(exp.name,'exp')
  17
+		self.assertEqual(exp.parent.commit_id,'root')
  18
+		
  19
+	def test_verify(self):
  20
+		change = {
  21
+			"change":"create",
  22
+			"schema":{
  23
+				"id":"person",
  24
+				"type":"object",
  25
+				"properties":{
  26
+					"id":{"type":"string"}
  27
+				}
  28
+			}
  29
+		}
  30
+		branch = self.repo.branch('master')
  31
+		branch.verify(change)
  32
+		
  33
+	def test_add(self):
  34
+		change = {
  35
+			"change":"create",
  36
+			"schema":{
  37
+				"id":"person",
  38
+				"type":"object",
  39
+				"properties":{
  40
+					"id":{"type":"string"}
  41
+				}
  42
+			}
  43
+		}
  44
+		branch = self.repo.branch('master')
  45
+		branch.add(change)
  46
+		self.assertTrue('person' in branch.schema.tables)
  47
+		
  48
+	def test_commit(self):
  49
+		change = {
  50
+			"change":"create",
  51
+			"schema":{
  52
+				"id":"person",
  53
+				"type":"object",
  54
+				"properties":{
  55
+					"id":{"type":"string"}
  56
+				}
  57
+			}
  58
+		}
  59
+		branch = self.repo.branch('master')
  60
+		branch.add(change)
  61
+		branch.commit('test commit')
  62
+		self.assertTrue(branch.parent.commit_id is not 'root')
  63
+		
  64
+		
  65
+if __name__ == '__main__':
  66
+    unittest.main()

0 notes on commit e4f1ea1

Please sign in to comment.
Something went wrong with that request. Please try again.