예제 #1
0
    def add_file(self, filename):
        binstore_filename = self.get_binstore_filename(filename)

        # TODO: make hash algorithm configurable

        # relative link is needed, here, so it points from the file directly to
        # the .git directory
        relative_link = os.path.relpath(binstore_filename,
                                        os.path.dirname(filename))
        #  create only a link if file already exists in binstore
        if os.path.exists(binstore_filename):
            print('WARNING: File with that hash already exists in binstore.')
            if filecmp.cmp(filename, binstore_filename):
                print('         Creating a link to existing file')
                commands = cmd.CompoundCommand(
                    cmd.SafeRemoveCommand(filename),
                    cmd.LinkToFileCommand(filename, relative_link),
                    cmd.GitAddCommand(self.gitrepo, filename),
                )
            else:
                raise ValueError('hash collision found between %s and %s',
                                 filename, binstore_filename)
        else:
            commands = cmd.CompoundCommand(
                cmd.SafeMoveFileCommand(filename, binstore_filename),
                cmd.LinkToFileCommand(filename, relative_link),
                cmd.ChmodCommand(stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH,
                                 binstore_filename),
                cmd.GitAddCommand(self.gitrepo, filename),
            )

        commands.execute()
예제 #2
0
    def checkout(self, filenames):
        """ Revert local modifications to a list of files """
        printv("GitBin.checkout(%s)" % filenames)
        for filename in filenames:

            # if the filename is a directory, recurse into it.
            # TODO: maybe make recursive directory crawls optional/configurable
            if os.path.isdir(filename):
                printv("\trecursing into %s" % filename)
                for root, dirs, files in os.walk(filename):
                    # first checkout_dashdash all directories recursively
                    len(dirs) and self.checkout(
                        [os.path.join(root, dn) for dn in dirs])
                    # now checkout_dashdash all the files
                    len(files) and self.checkout(
                        [os.path.join(root, fn) for fn in files])
                continue

            status = self.gitrepo.status(filename)
            if (status & git.STATUS_STAGED_MASK) == git.STATUS_STAGED:
                # staged, skip it.
                print "you probably meant to do: git bin reset %s" % filename
                continue

            if not (status & git.STATUS_CHANGED_MASK):
                # the file hasn't changed, skip it.
                continue

            # The first two cases can just be passed through to regular git
            # checkout --.
            # {1} (GBAdded[MSs] -> Reset[MS])
            # {2} (GBEdit[TF])
            # In the third case, there is some local modification that we should
            # save 'just in case' first.
            # {3} (GBEdit[TF] -> Modified[TF]) (*)

            if (status & git.STATUS_TYPECHANGED
                ) and not self.binstore.has(filename):
                justincase_filename = os.path.join(
                    "/tmp",
                    "%s.%s.justincase" % (filename, utils.md5_file(filename)))
                commands = cmd.CompoundCommand(
                    cmd.CopyFileCommand(
                        self.binstore.get_binstore_filename(filename),
                        filename, justincase_filename), )
                commands.execute()

            self.gitrepo.restore(filename)
예제 #3
0
    def edit_file(self, filename):
        printv("edit_file(%s)" % filename)
        printv("binstore_filename: %s" % self.get_binstore_filename(filename))
        temp_filename = os.path.join(os.path.dirname(filename),
                                     ".tmp_%s" % os.path.basename(filename))
        printv("temp_filename: %s" % temp_filename)
        commands = cmd.CompoundCommand(
            cmd.CopyFileCommand(self.get_binstore_filename(filename),
                                temp_filename),
            cmd.SafeMoveFileCommand(temp_filename, filename, noprogress=True),
            cmd.ChmodCommand(
                stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP
                | stat.S_IROTH | stat.S_IWOTH, filename),
        )

        commands.execute()
예제 #4
0
    def reset(self, filenames):
        """ Unstage a list of files """
        printv("GitBin.reset(%s)" % filenames)
        for filename in filenames:

            # if the filename is a directory, recurse into it.
            # TODO: maybe make recursive directory crawls optional/configurable
            if os.path.isdir(filename):
                printv("\trecursing into %s" % filename)
                for root, dirs, files in os.walk(filename):
                    # first reset all directories recursively
                    len(dirs) and self.reset(
                        [os.path.join(root, dn) for dn in dirs])
                    # now reset all the files
                    len(files) and self.reset(
                        [os.path.join(root, fn) for fn in files])
                continue

            status = self.gitrepo.status(filename)
            if not status & git.STATUS_STAGED_MASK == git.STATUS_STAGED:
                # not staged, skip it.
                print "you probably meant to do: git bin checkout -- %s" % filename
                continue

            # unstage the file:
            self.gitrepo.unstage(filename)

            # key: F=real file; S=symlink; T=typechange; M=modified; s=staged
            # {1} ([F] -> GBAdded[Ss]) -> Untracked[S]
            # {2} ([S] -> GBEdit[TF] -> Modified[TF] -> GBAdded[MSs])
            #      -> Modified[MS]
            new_status = self.gitrepo.status(filename)

            if self.binstore.has(filename) and (
                    new_status & git.STATUS_UNTRACKED
                    or new_status & git.STATUS_MODIFIED):

                # TODO: in case {1} it's possible that we might be leaving an
                # orphan unreferenced file in the binstore. We might want to
                # deal with this.
                commands = cmd.CompoundCommand(
                    cmd.CopyFileCommand(
                        self.binstore.get_binstore_filename(filename),
                        filename), )
                commands.execute()
예제 #5
0
    def init(self, binstore_base):
        self.localpath = os.path.join(self.gitrepo.path, ".git", "binstore")
        self.path = os.path.join(binstore_base, self.gitrepo.reponame)

        if not os.path.exists(binstore_base):
            raise BinstoreException((
                "The binstore base (%s) is inaccessible. Did you forget to mount"
                + " something?") % binstore_base)
        if not os.path.exists(self.localpath):
            print "creating"
            commands = cmd.CompoundCommand(
                cmd.MakeDirectoryCommand(self.path),
                cmd.LinkToFileCommand(self.localpath, self.path),
            )
            commands.execute()

            # self.gitrepo.config.set("binstore", "path", self.path)
        if not os.path.exists(self.path):
            raise BinstoreException(
                "A binstore.path is set (%s), but it doesn't exist. Weird." %
                self.path)