<s> import collections <EOL> import datetime <EOL> import dulwich . objects <EOL> import dulwich . repo <EOL> import email . utils <EOL> import fnmatch <EOL> import os <EOL> import stat <EOL> import time <EOL> from subprocess import Popen , PIPE <EOL> from threading import Lock <EOL> class BaseObject ( object ) : <EOL> def __init__ ( self , odb , obj ) : <EOL> self . _odb = odb <EOL> self . _obj = obj <EOL> self . sha = obj . sha ( ) . hexdigest ( ) <EOL> self . parent = None <EOL> self . name = None <EOL> self . _commit_sha = None <EOL> @ property <EOL> def abs_name ( self ) : <EOL> paths = [ self . name ] <EOL> parent = self . parent <EOL> while parent is not None : <EOL> paths . insert ( <NUM_LIT:0> , parent . name ) <EOL> parent = parent . parent <EOL> return os . path . join ( * paths ) <EOL> @ property <EOL> def root_path ( self ) : <EOL> return self . abs_name . lstrip ( '<STR_LIT:/>' ) <EOL> @ property <EOL> def author_name ( self ) : <EOL> return self . last_modified_commit . author_name <EOL> @ property <EOL> def created ( self ) : <EOL> created = None <EOL> visited = set ( ) <EOL> pendings = [ self . commit ] <EOL> abs_name = self . abs_name <EOL> while pendings : <EOL> commit = pendings . pop ( <NUM_LIT:0> ) <EOL> visited . add ( commit . sha ) <EOL> for parent_commit in commit . parents : <EOL> if parent_commit in visited : <EOL> continue <EOL> if abs_name in parent_commit . tree : <EOL> pendings . append ( parent_commit ) <EOL> else : <EOL> commit_time = parent_commit . commit_time <EOL> if created is None or commit_time < created : <EOL> created = commit_time <EOL> else : <EOL> created = commit . commit_time <EOL> return created <EOL> @ property <EOL> def last_modified ( self ) : <EOL> return self . last_modified_commit . commit_time <EOL> @ property <EOL> def last_modified_commit ( self ) : <EOL> visited = set ( ) <EOL> pendings = [ self . commit ] <EOL> abs_name = self . abs_name <EOL> while pendings : <EOL> commit = pendings . pop ( <NUM_LIT:0> ) <EOL> visited . add ( commit . sha ) <EOL> for parent_commit in commit . parents : <EOL> if parent_commit in visited : <EOL> continue <EOL> try : <EOL> obj_sha = parent_commit . tree [ abs_name ] . sha <EOL> except KeyError : <EOL> obj_sha = None <EOL> if self . sha == obj_sha : <EOL> pendings . append ( parent_commit ) <EOL> break <EOL> else : <EOL> return commit <EOL> return commit <EOL> @ property <EOL> def commit ( self ) : <EOL> if self . _commit_sha is None : <EOL> return self . _odb . index <EOL> else : <EOL> return self . _odb . get_commit ( self . _commit_sha ) <EOL> def set_commit ( self , commit_obj ) : <EOL> if isinstance ( commit_obj , CommitObject ) : <EOL> self . _commit_sha = commit_obj . sha <EOL> elif isinstance ( commit_obj , basestring ) : <EOL> self . _commit_sha = commit_obj <EOL> elif commit_obj is None : <EOL> self . _commit_sha = None <EOL> else : <EOL> raise ObjectTypeMismatch <EOL> def __eq__ ( self , other ) : <EOL> if hasattr ( other , '<STR_LIT>' ) : <EOL> return self . sha == other . sha <EOL> else : <EOL> return False <EOL> def __ne__ ( self , other ) : <EOL> return not self == other <EOL> def __hash__ ( self ) : <EOL> return hash ( self . sha ) <EOL> class BlobObject ( BaseObject ) : <EOL> _size = None <EOL> @ property <EOL> def data ( self ) : <EOL> return self . _obj . data <EOL> @ property <EOL> def size ( self ) : <EOL> if self . _size is None : <EOL> self . _size = len ( self . data ) <EOL> return self . _size <EOL> class LinkObject ( BaseObject ) : <EOL> size = <NUM_LIT:0> <EOL> @ property <EOL> def target ( self ) : <EOL> target_path = self . _obj . data <EOL> try : <EOL> if target_path . startswith ( '<STR_LIT:/>' ) : <EOL> return self . commit . tree [ target_path ] <EOL> else : <EOL> return self . parent [ target_path ] <EOL> except KeyError : <EOL> return None <EOL> class TreeObject ( BaseObject ) : <EOL> @ property <EOL> def root_path ( self ) : <EOL> if self . parent is None : <EOL> return '<STR_LIT>' <EOL> else : <EOL> return self . abs_name . lstrip ( '<STR_LIT:/>' ) + '<STR_LIT:/>' <EOL> def iteritems ( self ) : <EOL> for name , _ , _ in self . _obj . iteritems ( ) : <EOL> yield ( name , self [ name ] ) <EOL> def itervalues ( self ) : <EOL> for _ , f in self . iteritems ( ) : <EOL> yield f <EOL> def __iter__ ( self ) : <EOL> return iter ( self . _obj ) <EOL> def __contains__ ( self , name ) : <EOL> if '<STR_LIT:/>' in name : <EOL> try : <EOL> self [ name ] <EOL> return True <EOL> except KeyError : <EOL> return False <EOL> else : <EOL> return name in self . _obj <EOL> def __getitem__ ( self , name ) : <EOL> if '<STR_LIT:/>' in name : <EOL> return self . _get_path ( name ) <EOL> if name == '<STR_LIT:.>' : <EOL> return self <EOL> elif name == '<STR_LIT:..>' : <EOL> if self . parent : <EOL> return self . parent <EOL> else : <EOL> return self <EOL> mode , hash = self . _obj [ name ] <EOL> if mode & stat . S_IFDIR : <EOL> obj = self . _odb . get_tree ( hash ) <EOL> elif ( mode & stat . S_IFLNK ) == stat . S_IFLNK : <EOL> obj = self . _odb . get_link ( hash ) <EOL> else : <EOL> obj = self . _odb . get_blob ( hash ) <EOL> obj . parent = self <EOL> obj . name = name <EOL> obj . set_commit ( self . _commit_sha ) <EOL> return obj <EOL> def _get_path ( self , path ) : <EOL> path = path . strip ( '<STR_LIT:/>' ) <EOL> if path == '<STR_LIT>' : <EOL> return self <EOL> if '<STR_LIT:/>' in path : <EOL> dirname , subpath = path . split ( '<STR_LIT:/>' , <NUM_LIT:1> ) <EOL> subdir = self [ dirname ] <EOL> if not isinstance ( subdir , TreeObject ) : <EOL> raise KeyError <EOL> return subdir [ subpath ] <EOL> else : <EOL> return self [ path ] <EOL> def walk ( self , topdown = True ) : <EOL> roots = collections . deque ( [ self ] ) <EOL> while roots : <EOL> root = roots . popleft ( ) <EOL> dirs = [ ] <EOL> files = [ ] <EOL> for f in root . itervalues ( ) : <EOL> if isinstance ( f , BlobObject ) : <EOL> files . append ( f ) <EOL> elif isinstance ( f , TreeObject ) : <EOL> dirs . append ( f ) <EOL> else : <EOL> pass <EOL> yield root , dirs , files <EOL> if topdown : <EOL> roots . extendleft ( reversed ( dirs ) ) <EOL> else : <EOL> roots . extend ( dirs ) <EOL> def diff ( self , other ) : <EOL> '''<STR_LIT>''' <EOL> added = [ ] <EOL> removed = [ ] <EOL> modified = [ ] <EOL> my_contents = dict ( self . iteritems ( ) ) <EOL> for k , v in other . iteritems ( ) : <EOL> if k in my_contents : <EOL> my_v = my_contents [ k ] <EOL> if my_v != v : <EOL> if isinstance ( my_v , TreeObject ) : <EOL> a , r , m = my_v . diff ( v ) <EOL> added . extend ( a ) <EOL> removed . extend ( r ) <EOL> modified . extend ( m ) <EOL> else : <EOL> modified . append ( my_v ) <EOL> del my_contents [ k ] <EOL> added . extend ( my_contents . values ( ) ) <EOL> return ( added , removed , modified ) <EOL> def find ( self , name = None , type_ = BaseObject , max_depth = None , reverse = False ) : <EOL> if max_depth is not None : <EOL> if max_depth == <NUM_LIT:0> : <EOL> return <EOL> max_depth -= <NUM_LIT:1> <EOL> for obj_name , obj in sorted ( self . iteritems ( ) , reverse = reverse ) : <EOL> if ( isinstance ( obj , type_ ) ) and ( name is None or fnmatch . fnmatch ( obj_name , name ) ) : <EOL> yield obj <EOL> if isinstance ( obj , TreeObject ) : <EOL> for obj_ in obj . find ( name , type_ , max_depth ) : <EOL> yield obj_ <EOL> class CommitObject ( BaseObject ) : <EOL> def __init__ ( self , repo , obj ) : <EOL> super ( CommitObject , self ) . __init__ ( repo , obj ) <EOL> self . _tree = None <EOL> self . _parents = None <EOL> if self . sha == self . _odb . _repo . head ( ) : <EOL> self . name = '<STR_LIT>' <EOL> else : <EOL> self . name = self . sha <EOL> @ property <EOL> def author ( self ) : <EOL> return self . _obj . author <EOL> @ property <EOL> def author_name ( self ) : <EOL> name , _ = email . utils . parseaddr ( self . author ) <EOL> return name <EOL> @ property <EOL> def author_email ( self ) : <EOL> _ , addr = email . utils . parseaddr ( self . author ) <EOL> return addr <EOL> @ property <EOL> def tree ( self ) : <EOL> if self . _tree is None : <EOL> self . _tree = self . _odb . get_tree ( self . _obj . tree ) <EOL> self . _tree . name = '<STR_LIT:/>' <EOL> self . _tree . set_commit ( self ) <EOL> return self . _tree <EOL> @ property <EOL> def parents ( self ) : <EOL> if self . _parents is None : <EOL> self . _parents = [ self . _odb . get_commit ( hash ) <EOL> for hash in self . _obj . parents ] <EOL> return list ( self . _parents ) <EOL> @ property <EOL> def commit_time ( self ) : <EOL> return datetime . datetime . fromtimestamp ( self . _obj . commit_time , <EOL> _TO ( self . _obj . commit_timezone ) ) <EOL> def diff ( self , other = None ) : <EOL> '''<STR_LIT>''' <EOL> if other is None : <EOL> other = self . parents [ <NUM_LIT:0> ] <EOL> if not isinstance ( other , CommitObject ) : <EOL> raise ObjectTypeMismatch ( '<STR_LIT>' % <EOL> ( self . __class__ . __name__ , repr ( other ) ) ) <EOL> return self . tree . diff ( other . tree ) <EOL> class _TO ( datetime . tzinfo ) : <EOL> zero = datetime . timedelta ( <NUM_LIT:0> ) <EOL> def __init__ ( self , sec_offset ) : <EOL> self . _offset = datetime . timedelta ( seconds = sec_offset ) <EOL> def utcoffset ( self , dt ) : <EOL> return self . _offset <EOL> def tzname ( self , dt ) : <EOL> return None <EOL> def dst ( self , dt ) : <EOL> return self . zero <EOL> def __getinitargs__ ( self ) : <EOL> return ( self . _offset . seconds , ) <EOL> class IndexObject ( CommitObject ) : <EOL> def __init__ ( self , odb , index ) : <EOL> self . _index = index <EOL> self . _odb = odb <EOL> self . _obj = None <EOL> self . sha = None <EOL> self . parent = None <EOL> self . name = '<STR_LIT:index>' <EOL> self . _tree = None <EOL> self . _parents = None <EOL> @ property <EOL> def tree ( self ) : <EOL> if self . _tree is None : <EOL> tree_sha = self . _index . commit ( self . _odb . object_store ) <EOL> self . _tree = self . _odb . get_tree ( tree_sha ) <EOL> self . _tree . name = '<STR_LIT:/>' <EOL> self . _tree . set_commit ( self ) <EOL> return self . _tree <EOL> @ property <EOL> def parents ( self ) : <EOL> return [ self . _odb . head ] <EOL> @ property <EOL> def author_name ( self ) : <EOL> return '<STR_LIT:index>' <EOL> @ property <EOL> def commit_time ( self ) : <EOL> return datetime . datetime . now ( _TO ( - time . timezone ) ) <EOL> class ObjectTypeMismatch ( Exception ) : <EOL> pass <EOL> class ObjectDatabase ( object ) : <EOL> def __init__ ( self , repo ) : <EOL> if not isinstance ( repo , dulwich . repo . BaseRepo ) : <EOL> repo = dulwich . repo . Repo ( repo ) <EOL> self . _repo = repo <EOL> self . _cache = Cache ( ) <EOL> def __contains__ ( self , key ) : <EOL> return self . _repo . __contains__ ( key ) <EOL> def __getitem__ ( self , key ) : <EOL> if key not in self . _repo : <EOL> raise KeyError <EOL> raw_obj = self . _cache . get ( key ) <EOL> if obj is None : <EOL> raw_obj = self . _repo [ key ] <EOL> self . _cache . set ( key , raw_obj ) <EOL> for expected_class , return_class in [ ( dulwich . objects . Blob , BlobObject ) , <EOL> ( dulwich . objects . Commit , CommitObject ) , <EOL> ( dulwich . objects . Tree , TreeObject ) ] : <EOL> if isinstance ( raw_obj , expected_class ) : <EOL> return return_class ( self , raw_obj ) <EOL> raise ObjectTypeMismatch ( '<STR_LIT>' % repr ( raw_obj ) ) <EOL> def _make_get ( expected_class , return_class ) : <EOL> def _get_object ( self , hash ) : <EOL> obj = self . _cache . get ( hash ) <EOL> if obj is None : <EOL> obj = self . _repo . get_object ( hash ) <EOL> self . _cache . set ( hash , obj ) <EOL> if not isinstance ( obj , expected_class ) : <EOL> raise ObjectTypeMismatch ( '<STR_LIT>' % <EOL> ( expected_class . __name__ , repr ( obj ) ) ) <EOL> return return_class ( self , obj ) <EOL> return _get_object <EOL> get_blob = _make_get ( dulwich . objects . Blob , BlobObject ) <EOL> get_link = _make_get ( dulwich . objects . Blob , LinkObject ) <EOL> get_tree = _make_get ( dulwich . objects . Tree , TreeObject ) <EOL> get_commit = _make_get ( dulwich . objects . Commit , CommitObject ) <EOL> @ property <EOL> def name ( self ) : <EOL> path = os . path . abspath ( self . _repo . path ) <EOL> name = os . path . basename ( path ) <EOL> if name . endswith ( '<STR_LIT>' ) : <EOL> name = name [ : - <NUM_LIT:4> ] <EOL> return name <EOL> @ property <EOL> def description ( self ) : <EOL> return self . _repo . get_named_file ( '<STR_LIT:description>' ) . read ( ) . decode ( '<STR_LIT:utf-8>' ) <EOL> @ property <EOL> def controldir ( self ) : <EOL> return self . _repo . controldir ( ) <EOL> @ property <EOL> def head ( self ) : <EOL> return self . get_commit ( self . _repo . head ( ) ) <EOL> @ property <EOL> def index ( self ) : <EOL> if self . _repo . has_index ( ) and self . is_writable ( ) : <EOL> return IndexObject ( self , self . _repo . open_index ( ) ) <EOL> else : <EOL> return None <EOL> def is_writable ( self ) : <EOL> return os . access ( self . _repo . object_store . path , os . R_OK | os . W_OK | os . X_OK ) <EOL> @ property <EOL> def object_store ( self ) : <EOL> return self . _repo . object_store <EOL> @ property <EOL> def histories ( self ) : <EOL> commit = self . head <EOL> known_hashes = set ( commit . sha ) <EOL> pending = [ commit ] <EOL> while pending : <EOL> commit = pending . pop ( <NUM_LIT:0> ) <EOL> if commit . sha in known_hashes : <EOL> continue <EOL> known_hashes . add ( commit . sha ) <EOL> yield commit <EOL> pending . extend ( commit . parents ) <EOL> def git ( self , * args , ** kwargs ) : <EOL> '''<STR_LIT>''' <EOL> cmdargs = [ '<STR_LIT>' ] <EOL> cmdargs . extend ( args ) <EOL> cmdargs . extend ( '<STR_LIT>' % kv for kv in kwargs . iteritems ( ) ) <EOL> try : <EOL> p = Popen ( cmdargs , stdout = PIPE , cwd = self . _repo . path ) <EOL> for line in p . stdout : <EOL> yield line . rstrip ( '<STR_LIT:\r\n>' ) <EOL> except GeneratorExit : <EOL> p . stdout . close ( ) <EOL> p . wait ( ) <EOL> class Cache ( object ) : <EOL> def __init__ ( self , maxlen = <NUM_LIT:1000> ) : <EOL> self . _maxlen = maxlen <EOL> self . _cache = { } <EOL> self . _lock = Lock ( ) <EOL> def set ( self , key , value ) : <EOL> self . _set ( key , value ) <EOL> self . _prune ( ) <EOL> def get ( self , key ) : <EOL> try : <EOL> _ , value = self . _cache [ key ] <EOL> self . _set ( key , value ) <EOL> return value <EOL> except KeyError : <EOL> return None <EOL> def _set ( self , key , value ) : <EOL> self . _cache [ key ] = ( time . time ( ) , value ) <EOL> def _prune ( self ) : <EOL> with self . _lock : <EOL> if len ( self . _cache ) > self . _maxlen : <EOL> L = [ ( t , k ) for k , ( t , _ ) in self . _cache . items ( ) ] <EOL> L . sort ( ) <EOL> for _ , k in L [ : self . _maxlen / <NUM_LIT:2> ] : <EOL> del self . _cache [ k ] </s>
