Пример #1
0
 def run(self, args):
     location = File(args.location)
     if args.plain:
         repository_folder = location
     else:
         location.mkdirs()
         repository_folder = location.child(".filer")
     init_repository(repository_folder)
     if not args.plain:
         repository = Repository(repository_folder)
         working = WorkingCopy(repository, location)
         working.create()
     print "Repository created at %r." % repository_folder.path
Пример #2
0
class Repository(object):
    def __init__(self, folder, debug=None):
        if debug is None:
            debug = global_debug
        self.debug = debug
        self.folder = File(folder)
        # Sanity check to make sure we're not using the parent folder
        if self.folder.child(".filer").exists:
            raise Exception("You should specify the .filer directory as the "
                    "repository to work with, not the folder that contains it")
        self.store_folder = self.folder.child("store")
        self.store_folder.mkdirs(True)
        self.store_folder.child("type").write("direct")
        self.store = DirectStore(self.store_folder.child("direct"))
        self.numbers = self.folder.child("numbers")
        self.numbers.mkdirs(True)
        self.numbersbyrev = self.folder.child("numbersbyrev")
        self.numbersbyrev.mkdirs(True)
    
    def get_revision(self, id):
        """
        Gets the revision with the specified revision id, which can either be a
        hex string representing the full sha1 hash or the revision's numeric id.
        An exceptions.NoSuchObject will be thrown if no such revision exists.
        
        The return value is a BEC object corresponding to the revision.
        
        Note that short revision numbers must still be given as strings. Bad
        things (exceptions mainly) will happen if ints are passed in instead.
        """
        if self.numbers.child(id).exists:
            id = self.numbers.child(id).read()
        return self.store.get(id)
    
    def create_revision(self, data):
        """
        Creates a new revision with the specified data, which should be a BEC
        object (not a string). The new revision's hash will be returned.
        
        Entries in changeparents, changechildren, dirparents, and dirchildren
        will be created for this new revision. (Update: those have been
        disabled for now, and will probably be replaced with some sort of graph
        database soon.)
        """
        if not isinstance(data, dict):
            raise Exception("Invalid revision data value: %r (must be a dict)"
                    % data)
        hash = self.store.store(data)
        if self.debug:
            print "Wrote revision %s" % hash
        # TODO: Implement a better algorithm for searching for the next number;
        # perhaps start at 0 and double until an unused number N is hit, then
        # do a binary search from 0 to N for the lowest unused number
        number = 1
        while self.numbers.child(str(number)).exists:
            number += 1
        # Add an entry into numbers for this number
        self.numbers.child(str(number)).write(hash)
        # Add a reverse entry into numbersbyrev
        self.numbersbyrev.child(hash).write(str(number))
        return hash
    
    def revision_iterator(self):
        """
        A generator that returns a (number, hash, data_str, data) tuple for all
        of the revisions in this repository. number will be a string.
        """
        current_number = 1
        while self.numbers.child(str(current_number)).exists:
            # We've still got a revision, so yield it
            hash = self.numbers.child(str(current_number)).read()
            print >>sys.stderr, current_number, hash
            data = self.store.get(hash)
            yield str(current_number), hash, data
            current_number += 1
    
    def number_for_rev(self, hash):
        """
        Returns the short number (as a string) of the specified revision hash.
        """
        return self.numbersbyrev.child(hash).read()
    
    def rev_for_number(self, number):
        if self.numbers.child(number).exists:
            return self.numbers.child(number).read()
        # Assume it's a hash instead of a number and just return it
        return number
        
    def has_revision(self, hash):
        """
        Returns True if the specified revision is present in this repository.
        """
        return self.store.has(hash)
    
    def is_ancestor(self, descendant, ancestor):
        descendant, ancestor = self.rev_for_number(descendant), self.rev_for_number(ancestor)
        if descendant == ancestor:
            return True
        current = set(self.get_revision(descendant)["parents"])
        while current:
            rev = current.pop()
            if rev == ancestor:
                return True
            current |= set(self.get_revision(rev)["parents"])
        return False