summaryrefslogtreecommitdiff
path: root/lib/git/odb/db.py
blob: fd1b640a2e1d6e58362f107a4c53aec284a39220 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
"""Contains implementations of database retrieveing objects"""
import os
from git.errors import InvalidDBRoot


class iObjectDBR(object):
	"""Defines an interface for object database lookup.
	Objects are identified either by hex-sha (40 bytes) or 
	by sha (20 bytes)"""
	__slots__ = tuple()
	
	#{ Query Interface 
	def has_obj_hex(self, hexsha):
		""":return: True if the object identified by the given 40 byte hexsha is 
		contained in the database"""
		raise NotImplementedError("To be implemented in subclass")
		
	def has_obj_bin(self, sha):
		""":return: as ``has_obj_hex``, but takes a 20 byte binary sha"""
		raise NotImplementedError("To be implemented in subclass")
		
	def obj_hex(self, hexsha):
		""":return: tuple(type_string, size_in_bytes, stream) a tuple with object
		information including its type, its size as well as a stream from which its
		contents can be read"""
		raise NotImplementedError("To be implemented in subclass")
		
	def obj_bin(self, sha):
		""":return: as in ``obj_hex``, but takes a binary sha"""
		raise NotImplementedError("To be implemented in subclass")
		
	def obj_info_hex(self, hexsha):
		""":return: tuple(type_string, size_in_bytes) tuple with the object's type 
			string as well as its size in bytes"""
		raise NotImplementedError("To be implemented in subclass")
			
	#} END query interface
	
class iObjectDBW(object):
	"""Defines an interface to create objects in the database"""
	__slots__ = tuple()
	
	#{ Edit Interface
	
	def to_obj(self, type, size, stream, dry_run=False, sha_as_hex=True):
		"""Create a new object in the database
		:return: the sha identifying the object in the database
		:param type: type string identifying the object
		:param size: size of the data to read from stream
		:param stream: stream providing the data
		:param dry_run: if True, the object database will not actually be changed
		:param sha_as_hex: if True, the returned sha identifying the object will be 
			hex encoded, not binary"""
		raise NotImplementedError("To be implemented in subclass")
	
	def to_objs(self, iter_info, dry_run=False, sha_as_hex=True, max_threads=0):
		"""Create multiple new objects in the database
		:return: sequence of shas identifying the created objects in the order in which 
			they where given.
		:param iter_info: iterable yielding tuples containing the type_string
			size_in_bytes and the steam with the content data.
		:param dry_run: see ``to_obj``
		:param sha_as_hex: see ``to_obj``
		:param max_threads: if < 1, any number of threads may be started while processing
			the request, otherwise the given number of threads will be started."""
		# a trivial implementation, ignoring the threads for now
		# TODO: add configuration to the class to determine whether we may 
		# actually use multiple threads, default False of course. If the add
		shas = list()
		for args in iter_info:
			shas.append(self.to_obj(*args, dry_run=dry_run, sha_as_hex=sha_as_hex))
		return shas
		
	#} END edit interface
	

class FileDBBase(object):
	"""Provides basic facilities to retrieve files of interest, including 
	caching facilities to help mapping hexsha's to objects"""
	__slots__ = ('_root_path', )
	
	def __init__(self, root_path):
		"""Initialize this instance to look for its files at the given root path
		All subsequent operations will be relative to this path
		:raise InvalidDBRoot: 
		:note: The base will perform basic checking for accessability, but the subclass
			is required to verify that the root_path contains the database structure it needs"""
		if not os.path.isdir(root_path):
			raise InvalidDBRoot(root_path)
		self._root_path = root_path
		
		
	#{ Interface 
	def root_path(self):
		""":return: path at which this db operates"""
		return self._root_path
	
	#} END interface
		
	#{ Utiltities
	def _root_rela_path(self, rela_path):
		""":return: the given relative path relative to our database root"""
		return os.path.join(self._root_path, rela_path)
		
	#} END utilities
	
	
class LooseObjectDB(FileDBBase, iObjectDBR, iObjectDBW):
	"""A database which operates on loose object files"""
	
	
class PackedDB(FileDBBase, iObjectDBR):
	"""A database operating on a set of object packs"""
	
	
class CompoundDB(iObjectDBR):
	"""A database which delegates calls to sub-databases"""
	

class ReferenceDB(CompoundDB):
	"""A database consisting of database referred to in a file"""
	
	
class GitObjectDB(CompoundDB, iObjectDBW):
	"""A database representing the default git object store, which includes loose 
	objects, pack files and an alternates file
	
	It will create objects only in the loose object database."""