def resolve_object(obj_name: str, gitdir: pathlib.Path) -> tp.List[str]: if 4 > len(obj_name) or len(obj_name) > 40: raise Exception(f"Not a valid object name {obj_name}") objects = repo_find() / "objects" obj_list = [] for file in (objects / obj_name[:2]).glob("*"): cur_obj_name = file.parent.name + file.name if obj_name == cur_obj_name[:len(obj_name)]: obj_list.append(cur_obj_name) if not obj_list: raise Exception(f"Not a valid object name {obj_name}") return obj_list
def hash_object(data: bytes, fmt: str, write: bool = False) -> str: sha = hashlib.sha1((fmt + " " + str(len(data))).encode() + b"\00" + data).hexdigest() if write: obj_dir = repo_find() / "objects" / sha[:2] if not obj_dir.exists(): obj_dir.mkdir() with (obj_dir / sha[2:]).open("wb") as file: file.write( zlib.compress((fmt + " " + str(len(data))).encode() + b"\00" + data)) return sha
def cat_file(obj_name: str, pretty: bool = True) -> None: gitdir = repo_find() fmt, file_content = read_object(obj_name, gitdir) blob_or_commit_tuple = ("blob", "commit") if fmt in blob_or_commit_tuple: print(file_content.decode()) else: for tree in read_tree(file_content): if tree[0] != 40000: print(f"{tree[0]:06}", "blob", tree[2] + "\t" + tree[1]) else: print(f"{tree[0]:06}", "tree", tree[2] + "\t" + tree[1])
def read_index(gitdir: pathlib.Path) -> tp.List[GitIndexEntry]: repo = repo_find() / "index" entries = [] if repo.exists(): with open(repo, "rb") as f: _ = f.read(8) num_entries = struct.unpack("!I", f.read(4))[0] for entry in range(num_entries): indexEntry = {} indexEntry['ctime_s'] = struct.unpack( "!I", f.read(struct.calcsize("I")))[0] indexEntry['ctime_n'] = struct.unpack( "!I", f.read(struct.calcsize("I")))[0] indexEntry['mtime_s'] = struct.unpack( "!I", f.read(struct.calcsize("I")))[0] indexEntry['mtime_n'] = struct.unpack( "!I", f.read(struct.calcsize("I")))[0] indexEntry['dev'] = struct.unpack("!I", f.read( struct.calcsize("I")))[0] indexEntry['ino'] = struct.unpack("!I", f.read( struct.calcsize("I")))[0] indexEntry['mode'] = struct.unpack( "!I", f.read(struct.calcsize("I")))[0] indexEntry['uid'] = struct.unpack("!I", f.read( struct.calcsize("I")))[0] indexEntry['gid'] = struct.unpack("!I", f.read( struct.calcsize("I")))[0] indexEntry['size'] = struct.unpack( "!I", f.read(struct.calcsize("I")))[0] indexEntry['sha1'] = struct.unpack( "!20s", f.read(struct.calcsize("20s")))[0] indexEntry['flags'] = struct.unpack( "!H", f.read(struct.calcsize("H")))[0] namelen = indexEntry['flags'] & 0xFFF indexEntry['name'] = struct.unpack( "!" + str(namelen) + "s", f.read(struct.calcsize("!" + str(namelen) + "s")))[0].decode() entries.append(GitIndexEntry(**indexEntry)) nuls = 3 _ = f.read(nuls) entries.sort(key=lambda x: x.name) return entries
def hash_object(data: bytes, fmt: str, write: bool = False) -> str: # PUT YOUR CODE HERE header = f"{fmt} {len(data)}\0".encode() store = header + data res = hashlib.sha1(store).hexdigest() if write: path = repo_find() / "objects" / res[:2] path.mkdir(exist_ok=True) with (path / res[2:]).open("wb") as f: new_data = (fmt + " " + str(len(data))).encode() new_data = new_data + b"\00" + data f.write(zlib.compress(new_data)) return res
def resolve_object(obj_name: str, gitdir: pathlib.Path) -> tp.List[str]: if len(obj_name) < 4 or len(obj_name) > 40: raise Exception(f"Not a valid object name {obj_name}") result = [] path = repo_find(gitdir) / "objects" / obj_name[:2] for root, dir, files in os.walk(path): for filename in files: if filename.startswith(obj_name[2:]): result.append(obj_name[:2] + filename) else: raise Exception(f"Not a valid object name {obj_name}") return result
def cat_file(obj_name: str, pretty: bool = True) -> None: gitdir = repo_find() obj_type, content = read_object(obj_name, gitdir) if obj_type == "blob": if pretty: result = content.decode("ascii") print(result) else: result = str(content) print(result) elif obj_type == "tree": tree_entries = read_tree(content) result = "" for entry in tree_entries: mode = str(entry[0]) if len(mode) != 6: mode = "0" + mode tree_pointer_type, _ = read_object(entry[1], gitdir) print(f"{mode} {tree_pointer_type} {entry[1]}\t{entry[2]}") else: _, content = read_object(resolve_object(obj_name, repo_find())[0], repo_find()) print(content.decode())
def hash_object(data: bytes, fmt: str, write: bool = False) -> str: # PUT YOUR CODE HERE formatted_data = (fmt + f" {len(data)}\0").encode() + data hash_str = hashlib.sha1(formatted_data).hexdigest() if write: dir_path = repo_find(".") / "objects" try: dir_path /= hash_str[:2] dir_path.mkdir() except FileExistsError: pass with (dir_path / hash_str[2:]).open("wb") as f: f.write(zlib.compress(formatted_data)) return hash_str
def hash_object(data: bytes, fmt: str, write: bool = False) -> str: header = f'{fmt} {len(data)}\0'.encode() store = header + data sha1 = hashlib.sha1(store).hexdigest() if write: gitdir = repo_find() blob_folder = gitdir.joinpath(f'objects/{sha1[:2]}') blob_folder.mkdir(parents=False, exist_ok=True) with open(blob_folder.joinpath(sha1[2:]), 'wb') as blob_file: zipped_store = zlib.compress(store) blob_file.write(zipped_store) return sha1
def hash_object(data: bytes, fmt: str, write: bool = False) -> str: header = f"{fmt} {len(data)}\0".encode() store = header + data obj_hash = hashlib.sha1(store).hexdigest() obj = zlib.compress(store) if write: gitdir = repo_find() obj_dir = pathlib.Path(str(gitdir) + "/objects/" + obj_hash[:2]) if not obj_dir.is_dir(): os.makedirs(obj_dir) obj_name = obj_dir / obj_hash[2:] with open(obj_name, "wb") as obj_file: obj_file.write(obj) return obj_hash
def hash_object(data: bytes, fmt: str, write: bool = False) -> str: # PUT YOUR CODE HERE objects = "objects" sha = hashlib.sha1((fmt + " " + str(len(data))).encode() + b"\00" + data).hexdigest() if write: gitdir = repo_find() if not (gitdir / objects / sha[:2]).exists(): (gitdir / objects / sha[:2]).mkdir() with (gitdir / objects / sha[:2] / sha[2:]).open("wb") as file: file.write( zlib.compress((fmt + " " + str(len(data))).encode() + b"\00" + data)) return sha
def hash_object(data: bytes, fmt: str, write: bool = False) -> str: header = f"{fmt} {len(data)}\0" store = header.encode() + data res = hashlib.sha1(store).hexdigest() if write: obj_dir = repo_find() / "objects" / res[0:2] if not obj_dir.exists(): obj_dir.mkdir() with (obj_dir / res[2:]).open("wb") as file: file.write( zlib.compress((fmt + " " + str(len(data))).encode() + b"\00" + data)) return res
def hash_object(data: bytes, fmt: str, write: bool = False) -> str: header = f"{fmt} {len(data)}\0" store = header.encode() + data result = hashlib.sha1(store).hexdigest() if write: gitdir = repo_find(os.getcwd()) os.makedirs(gitdir / "objects" / result[0:2], exist_ok=True) pathlib.Path(gitdir / "objects" / result[0:2] / result[2:]).touch() cur_file = open(gitdir / "objects" / result[0:2] / result[2:], "wb") level = -1 if fmt == "tree": level = 1 cur_file.write(zlib.compress(store, level)) cur_file.close() return result
def hash_object(data: bytes, fmt: str, write: bool = False) -> str: header = (fmt + f" {len(data)}\0").encode() store = header + data hash_obj = hashlib.sha1(store).hexdigest() if write: repo = repo_find() objects = repo / "objects" / hash_obj[:2] if not objects.exists(): objects.mkdir() with open(objects / hash_obj[2:], "wb") as f: compressed = zlib.compress(store) f.write(compressed) return hash_obj
def hash_object(data: bytes, fmt: str, write: bool = False) -> str: header = f"{fmt} {len(data)}\0".encode() line = header + data sha = hashlib.sha1(line).hexdigest() if write: dir_name = sha[:2] file_name = sha[2:] path = repo_find() / 'objects' / dir_name if not path.exists(): path.mkdir() with open(str(path / file_name), 'wb+') as file: file.write(zlib.compress(line)) return sha
def hash_object(data: bytes, fmt: str, write: bool = False) -> str: header = f"{fmt} {len(data)}\0" store = header.encode() + data hash_name = hashlib.sha1(store).hexdigest() if write: path = repo_find() / "objects" / hash_name[:2] if os.path.exists(path / hash_name[2:]): return hash_name os.mkdir(path) with open(path / hash_name[2:], "wb") as f: f.write(zlib.compress(store)) return hash_name
def resolve_object(obj_name: str, gitdir: pathlib.Path) -> tp.List[str]: objects = "objects" if not 4 < len(obj_name) < 40: raise Exception(f"Not a valid object name {obj_name}") gitdir = repo_find() obj_list = [] for dir in (gitdir / objects).glob("*"): if not dir.is_dir(): continue for file in dir.glob("*"): cur_obj_name = file.parent.name + file.name if obj_name == cur_obj_name[:len(obj_name)]: obj_list.append(cur_obj_name) if not obj_list: raise Exception(f"Not a valid object name {obj_name}") return obj_list
def cat_file(obj_name: str, pretty: bool = True) -> None: gitdir = repo_find() fmt, content = read_object(obj_name, gitdir) if fmt == "blob": print(content.decode("ascii") if pretty else str(content)) elif fmt == "tree": tree = read_tree(content) for i in tree: mode = i[0] mode = str(mode) lenght, value = len(mode), 6 if lenght != value: mode = "0" + mode print(f"{mode} {read_object(i[1], gitdir)[0]} {i[1]}\t{i[2]}") else: obj_name1 = resolve_object(obj_name, gitdir)[0] print(read_object(obj_name1, gitdir)[1].decode())
def resolve_object(obj_name: str, gitdir: pathlib.Path) -> tp.List[str]: if len(obj_name) < 4 or len(obj_name) > 40: raise Exception(f"Not a valid object name {obj_name}") repo = repo_find() obj_path = repo / "objects" / obj_name[:2] objects = [] if obj_path.exists() and obj_path.is_dir(): for child in obj_path.iterdir(): if child.name[:3] == obj_name[2:]: objects.append(obj_name[:2] + child.name) if len(objects) == 0: raise Exception(f"Not a valid object name {obj_name}") return objects
def cat_file(obj_name: str, pretty: bool = True) -> None: repo = repo_find() read_obj = read_object(obj_name, repo) if read_obj[0] == "blob": print(read_object(obj_name, repo)[1].decode()) elif read_obj[0] == "tree": objs = read_tree(read_obj[1]) s = "" for obj in objs: if obj[0] == 40000: s += f"0{obj[0]} tree {obj[2]}\t{obj[1]}\n" else: s += f"{obj[0]} blob {obj[2]}\t{obj[1]}\n" print(s) elif read_obj[0] == "commit": print(read_obj[1].decode())
def hash_object(data: bytes, fmt: str, write: bool = False) -> str: header = f"{fmt} {len(data)}\0" store = header.encode() + data result = hashlib.sha1(store).hexdigest() content = zlib.compress(store) if write: workdir = pathlib.Path(".").absolute() gitdir = repo_find(workdir) if not pathlib.Path.exists(gitdir / "objects" / result[0:2]): (gitdir / "objects" / result[0:2]).mkdir() if not pathlib.Path.exists( gitdir / "objects" / result[0:2] / result[:2]): (gitdir / "objects" / result[0:2] / result[2:]).write_bytes(content) return result
def read_tree(data: bytes) -> tp.List[tp.Tuple[int, str, str]]: tree_entries: tp.List[tp.Tuple[int, str, str]] = [] while len(data): sha = bytes.hex(data[-20:]) data = data[:-21] obj_type, _ = read_object(sha, repo_find()) space_pos = data.rfind(b" ") name = data[space_pos + 1 :].decode("ascii") data = data[:space_pos] if obj_type == "tree": mode = "40000" else: mode = data[-6:].decode("ascii") mode_len = -1 * len(mode) data = data[:mode_len] mode_int = int(mode) tree_entries.insert(0, (mode_int, sha, name)) return tree_entries
def hash_object(data: bytes, fmt: str, write: bool = False) -> str: if fmt == "blob": content = data.decode() header = f"{fmt} {len(content)}\0" store = header + content hash_object = hashlib.sha1(store.encode()) hex_dig = hash_object.hexdigest() if fmt == "tree" or fmt == "commit": header = f"{fmt} {len(data)}\0" store = header.encode() + data hash_object = hashlib.sha1(store) hex_dig = hash_object.hexdigest() if write == True: path = repo_find() paths = pathlib.Path(path, "objects") if fmt == "tree": content = data header = f"{fmt} {len(content)}\0" store = header.encode() + content hash_object = hashlib.sha1(store) else: content = data.decode() header = f"{fmt} {len(content)}\0" store = header + content hash_object = hashlib.sha1(store.encode()) hex_dig = hash_object.hexdigest() start = hex_dig[0:2] continues = hex_dig[2:] if not os.path.exists(pathlib.Path(paths / start)): os.mkdir(pathlib.Path(paths / start)) if not os.path.exists(pathlib.Path(paths / start / continues)): pathlib.Path(paths / start / continues).touch() lib = pathlib.Path(paths / start / continues) with lib.open(mode="wb") as f: if fmt == "blob" or fmt == "commit": a = zlib.compress(store.encode(), -1) if fmt == "tree": a = zlib.compress(store, 1) f.write(a) f.close() return hex_dig
def cat_file(obj_name: str, pretty: bool = True) -> None: """ :version: 0.3.0 + 0.6.0 Вывод файлов, аналог функции cat :param obj_name: :param pretty: :return: """ gitdir = repo_find() fmt, data = read_object(obj_name, gitdir) if fmt in ("blob", "commit"): print(data.decode() if pretty else data) else: for tree in read_tree(data): print( f"{tree[0]:06}", "tree" if tree[0] == 40000 else "blob", tree[2] + "\t" + tree[1] )
def hash_object(data: bytes, fmt: str, write: bool = False) -> str: """ Вычисление хэш-суммы :version: 0.2.0 :param data: :param fmt: :param write: :return: """ store = f"{fmt} {len(data)}\0".encode() + data hash_sum = hashlib.sha1(store).hexdigest() if write: folder_name, file_name = hash_sum[:2], hash_sum[2:] obj_dir = repo_find() / "objects" / folder_name if not obj_dir.exists(): obj_dir.mkdir() with open(obj_dir / file_name, "wb") as f: f.write(zlib.compress(store)) return hash_sum
def cat_file(obj_name: str, pretty: bool = True) -> None: # PUT YOUR CODE HERE data = read_object(obj_name, repo_find(".")) if data[0] in ("blob", "commit"): out = data[1].decode() if pretty: print(out) else: print(data[0], out) elif data[0] == "tree": out1 = read_tree(data[1]) if pretty: print( *[f'{x[0]:06} {"tree" if x[0] == 40000 else "blob"} {x[2]}\t{x[1]}' for x in out1], sep="\n", ) else: print( data[0], "\n".join( f'{x[0]:06} {"tree" if x[0] == 40000 else "blob"} {x[2]}\t{x[1]}' for x in out1 ), )
def read_tree(data: bytes) -> tp.List[tp.Tuple[int, str, str]]: tree = [] while len(data) > 0: border = -21 sha = bytes.hex(data[border+1:]) data = data[:border] gitdir = repo_find() fmt, content = read_object(sha, gitdir) border = data.rfind(b" ") name = data[border+1:].decode("ascii") data = data[:border] border = -6 mode = "40000" if fmt == "tree" else data[border:].decode("ascii") border = len(mode) mode = int(mode) data = data[:-border] tuple = mode, sha, name tree.insert(0, tuple) return tree
def cat_file(obj_name: str, pretty: bool = True) -> None: gitdir = repo_find() shas = resolve_object(obj_name, gitdir) if len(shas) > 1: raise Exception('specify longer name') sha = shas[0] object_type, object_content_bytes = read_object(sha, gitdir) if object_type == 'tree': permissions, shas, names = read_tree(object_content_bytes) resulting_string = '' for i in range(len(shas)): perm = permissions[i] sha = shas[i] name = names[i] type = 'tree' if perm == '040000' else 'blob' resulting_string += f'{perm} {type} {sha}\t{name}\n' if pretty: print(resulting_string) else: object_content_decoded = object_content_bytes.decode('ascii') if pretty: print(object_content_decoded)
def test_repo_not_found(self): with self.assertRaises(Exception) as ctx: _ = repo.repo_find() self.assertEqual("Not a git repository", str(ctx.exception))
def read_object(sha: str, gitdir: pathlib.Path) -> tp.Tuple[str, bytes]: objects = repo_find() / "objects" with (objects / sha[:2] / sha[2:]).open("rb") as f: data = zlib.decompress(f.read()) return (data.split(b"\00")[0].split(b" ")[0].decode(), data.split(b"\00", maxsplit=1)[1])