def rename(self, new_path, force=False): """Rename self to a new path :param new_path: Either a simple name or a full path, i.e. new_name or features/new_name. The prefix refs/ is implied for references and will be set as needed. In case this is a symbolic ref, there is no implied prefix :param force: If True, the rename will succeed even if a head with the target name already exists. It will be overwritten in that case :return: self :raise OSError: In case a file at path but a different contents already exists """ new_path = self.to_full_path(new_path) if self.path == new_path: return self new_abs_path = join(self.repo.git_dir, new_path) cur_abs_path = join(self.repo.git_dir, self.path) if isfile(new_abs_path): if not force: # if they point to the same file, its not an error if open(new_abs_path, 'rb').read().strip() != open( cur_abs_path, 'rb').read().strip(): raise OSError("File at path %r already exists" % new_abs_path) # else: we could remove ourselves and use the otherone, but # but clarity we just continue as usual # END not force handling os.remove(new_abs_path) # END handle existing target file dname = dirname(new_abs_path) if not isdir(dname): os.makedirs(dname) # END create directory rename(cur_abs_path, new_abs_path) self.path = new_path return self
def _set_alternates(self, alts): """Sets the alternates :parm alts: is the array of string paths representing the alternates at which git should look for objects, i.e. /home/user/repo/.git/objects :raise NoSuchPathError: :note: The method does not check for the existance of the paths in alts as the caller is responsible.""" alternates_path = self._alternates_path() if not alts: if isfile(alternates_path): os.remove(alternates_path) else: try: f = open(alternates_path, 'w') f.write("\n".join(alts)) finally: f.close()
def rename(self, new_path, force=False): """Rename self to a new path :param new_path: Either a simple name or a full path, i.e. new_name or features/new_name. The prefix refs/ is implied for references and will be set as needed. In case this is a symbolic ref, there is no implied prefix :param force: If True, the rename will succeed even if a head with the target name already exists. It will be overwritten in that case :return: self :raise OSError: In case a file at path but a different contents already exists """ new_path = self.to_full_path(new_path) if self.path == new_path: return self new_abs_path = join(self.repo.git_dir, new_path) cur_abs_path = join(self.repo.git_dir, self.path) if isfile(new_abs_path): if not force: # if they point to the same file, its not an error if open(new_abs_path, 'rb').read().strip() != open(cur_abs_path, 'rb').read().strip(): raise OSError("File at path %r already exists" % new_abs_path) # else: we could remove ourselves and use the otherone, but # but clarity we just continue as usual # END not force handling os.remove(new_abs_path) # END handle existing target file dname = dirname(new_abs_path) if not isdir(dname): os.makedirs(dname) # END create directory rename(cur_abs_path, new_abs_path) self.path = new_path return self
def _create(cls, repo, path, resolve, reference, force, logmsg=None): """internal method used to create a new symbolic reference. If resolve is False, the reference will be taken as is, creating a proper symbolic reference. Otherwise it will be resolved to the corresponding object and a detached symbolic reference will be created instead""" full_ref_path = cls.to_full_path(path) abs_ref_path = join(repo.git_dir, full_ref_path) # figure out target data target = reference if resolve: # could just use the resolve method, but it could be expensive # so we handle most common cases ourselves if isinstance(reference, cls.ObjectCls): target = reference.hexsha elif isinstance(reference, SymbolicReference): target = reference.object.hexsha else: target = repo.resolve_object(str(reference)) #END handle resoltion #END need resolution if not force and isfile(abs_ref_path): target_data = str(target) if isinstance(target, SymbolicReference): target_data = target.path if not resolve: target_data = "ref: " + target_data existing_data = open(abs_ref_path, 'rb').read().strip() if existing_data != target_data: raise OSError( "Reference at %r does already exist, pointing to %r, requested was %r" % (full_ref_path, existing_data, target_data)) # END no force handling ref = cls(repo, full_ref_path) ref.set_reference(target, logmsg) return ref
def _create(cls, repo, path, resolve, reference, force, logmsg=None): """internal method used to create a new symbolic reference. If resolve is False, the reference will be taken as is, creating a proper symbolic reference. Otherwise it will be resolved to the corresponding object and a detached symbolic reference will be created instead""" full_ref_path = cls.to_full_path(path) abs_ref_path = join(repo.git_dir, full_ref_path) # figure out target data target = reference if resolve: # could just use the resolve method, but it could be expensive # so we handle most common cases ourselves if isinstance(reference, cls.ObjectCls): target = reference.hexsha elif isinstance(reference, SymbolicReference): target = reference.object.hexsha else: target = repo.resolve_object(str(reference)) # END handle resoltion # END need resolution if not force and isfile(abs_ref_path): target_data = str(target) if isinstance(target, SymbolicReference): target_data = target.path if not resolve: target_data = "ref: " + target_data existing_data = open(abs_ref_path, 'rb').read().strip() if existing_data != target_data: raise OSError("Reference at %r does already exist, pointing to %r, requested was %r" % (full_ref_path, existing_data, target_data)) # END no force handling ref = cls(repo, full_ref_path) ref.set_reference(target, logmsg) return ref
def is_dirty(self, index=True, working_tree=True, untracked_files=False): if self._bare: # Bare repositories with no associated working directory are # always consired to be clean. return False # start from the one which is fastest to evaluate default_args = ('--abbrev=40', '--full-index', '--raw') if index: # diff index against HEAD if isfile(self.index.path) and self.head.is_valid() and \ len(self.git.diff('HEAD', '--cached', *default_args)): return True # END index handling if working_tree: # diff index against working tree if len(self.git.diff(*default_args)): return True # END working tree handling if untracked_files: if len(self.untracked_files): return True # END untracked files return False
def store(self, istream): """note: The sha we produce will be hex by nature""" tmp_path = None writer = self.ostream() if writer is None: # open a tmp file to write the data to fd, tmp_path = tempfile.mkstemp(prefix="obj", dir=self._root_path) if istream.binsha is None: writer = FDCompressedSha1Writer(fd) else: writer = FDStream(fd) # END handle direct stream copies # END handle custom writer try: try: if istream.binsha is not None: # copy as much as possible, the actual uncompressed item size might # be smaller than the compressed version stream_copy(istream.read, writer.write, sys.maxint, self.stream_chunk_size) else: # write object with header, we have to make a new one write_object( istream.type, istream.size, istream.read, writer.write, chunk_size=self.stream_chunk_size ) # END handle direct stream copies finally: if tmp_path: writer.close() # END assure target stream is closed except: if tmp_path: os.remove(tmp_path) raise # END assure tmpfile removal on error hexsha = None if istream.binsha: hexsha = istream.hexsha else: hexsha = writer.sha(as_hex=True) # END handle sha if tmp_path: obj_path = self.db_path(self.object_path(hexsha)) obj_dir = dirname(obj_path) if not isdir(obj_dir): mkdir(obj_dir) # END handle destination directory # rename onto existing doesn't work on windows if os.name == "nt" and isfile(obj_path): remove(obj_path) # END handle win322 rename(tmp_path, obj_path) # make sure its readable for all ! It started out as rw-- tmp file # but needs to be rwrr chmod(obj_path, self.new_objects_mode) # END handle dry_run istream.binsha = hex_to_bin(hexsha) return istream
def store(self, istream): """note: The sha we produce will be hex by nature""" tmp_path = None writer = self.ostream() if writer is None: # open a tmp file to write the data to fd, tmp_path = tempfile.mkstemp(prefix='obj', dir=self._root_path) if istream.binsha is None: writer = FDCompressedSha1Writer(fd) else: writer = FDStream(fd) # END handle direct stream copies # END handle custom writer try: try: if istream.binsha is not None: # copy as much as possible, the actual uncompressed item size might # be smaller than the compressed version stream_copy(istream.read, writer.write, sys.maxint, self.stream_chunk_size) else: # write object with header, we have to make a new one write_object(istream.type, istream.size, istream.read, writer.write, chunk_size=self.stream_chunk_size) # END handle direct stream copies finally: if tmp_path: writer.close() # END assure target stream is closed except: if tmp_path: os.remove(tmp_path) raise # END assure tmpfile removal on error hexsha = None if istream.binsha: hexsha = istream.hexsha else: hexsha = writer.sha(as_hex=True) # END handle sha if tmp_path: obj_path = self.db_path(self.object_path(hexsha)) obj_dir = dirname(obj_path) if not isdir(obj_dir): mkdir(obj_dir) # END handle destination directory # rename onto existing doesn't work on windows if os.name == 'nt' and isfile(obj_path): remove(obj_path) # END handle win322 rename(tmp_path, obj_path) # make sure its readable for all ! It started out as rw-- tmp file # but needs to be rwrr chmod(obj_path, self.new_objects_mode) # END handle dry_run istream.binsha = hex_to_bin(hexsha) return istream