def add_from_other_repo(self, other_repo, committish, src="", dest="", exclude=()): """Copies files from another repository over to this one.""" def _copy_blob(blob_id): # Copy object over to this repo local_id = self.repo.create_blob(other_repo[blob_id].read_raw()) # Two blobs with same content MUST have the same id in both repos assert local_id == blob_id commit = resolve_committish(other_repo, committish) node = commit.tree src = posixpath.normpath(src) dest = posixpath.normpath(dest) # Traverse down to the proper subtree or blob if src != ".": for part in src.split(os.sep): if not isinstance(node, pygit2.Tree): # We reached a leaf and hence can't descend further raise KeyError(part) node /= part if isinstance(node, pygit2.Blob): # Copy only a single file if dest == ".": # When nothing is specified as destination, keep the file's name dest = posixpath.split(src)[1] _copy_blob(node.id) self.index.add(pygit2.IndexEntry(dest, node.id, node.filemode)) return assert isinstance(node, pygit2.Tree) # Read tree into in-memory index and then copy the entries over index = pygit2.Index() index.read_tree(node) for entry in index: # Check if file (or the directory the file is in) is in exclude list for path in exclude: if entry.path == path or entry.path.startswith(f"{path}/"): break else: _copy_blob(entry.id) self.index.add( pygit2.IndexEntry( posixpath.normpath(posixpath.join(dest, entry.path)), entry.id, entry.mode, ))
def test_entry_eq(testrepo): index = testrepo.index hello_entry = index['hello.txt'] entry = pygit2.IndexEntry(hello_entry.path, hello_entry.id, hello_entry.mode) assert hello_entry == entry entry = pygit2.IndexEntry("README.md", hello_entry.id, hello_entry.mode) assert hello_entry != entry oid = Oid(hex='0907563af06c7464d62a70cdd135a6ba7d2b41d8') entry = pygit2.IndexEntry(hello_entry.path, oid, hello_entry.mode) assert hello_entry != entry entry = pygit2.IndexEntry(hello_entry.path, hello_entry.id, pygit2.GIT_FILEMODE_BLOB_EXECUTABLE) assert hello_entry != entry
def _posthoc_main(driver: MergeDriver, args: typing.List[str]): """ Apply merge driver logic to a repository which is already in a conflicted state, running the driver on any conflicted files. """ repo_dir = pygit2.discover_repository(os.getcwd()) repo = pygit2.Repository(repo_dir) conflicts = repo.index.conflicts if not conflicts: print("There are no unresolved conflicts.") return 0 all_success = True index_changed = False any_attempted = False for base, left, right in list(conflicts): if not base or not left or not right: # (not left) or (not right): deleted in one branch, modified in the other. # (not base): added differently in both branches. # In either case, there's nothing we can do for now. continue path = left.path if not _applies_to(repo, driver, path): # Skip the file if it's not the right extension. continue any_attempted = True driver.pre_announce(path) io_base = io.BytesIO(repo[base.id].data) io_left = io.BytesIO(repo[left.id].data) io_right = io.BytesIO(repo[right.id].data) success, merge_result = driver.merge(io_base, io_left, io_right) if merge_result: # If we got anything, write it to the working directory. with open(os.path.join(repo.workdir, path), 'wb') as io_output: driver.to_file(io_output, merge_result) if success: # If we were successful, mark the conflict as resolved. with open(os.path.join(repo.workdir, path), 'rb') as io_readback: contents = io_readback.read() merged_id = repo.create_blob(contents) repo.index.add(pygit2.IndexEntry(path, merged_id, left.mode)) del conflicts[path] index_changed = True if not success: all_success = False driver.post_announce(success, merge_result) if index_changed: repo.index.write() if not any_attempted: print("There are no unresolved", driver.driver_id, "conflicts.") if not all_success: # Not usually observed, but indicate the failure just in case. return 1
def add(self, key, value): """Add a value for a key to the working tree, staging it for commit. >>> repo.add('added', 'but not committed!') >>> repo.index('added') u'but not committed!' >>> repo.show('added') KeyError: 'There is no key at added' :param key: The key to add :type key: string :param value: The value to insert :type value: anything that runs through :func:`json.dumps` :raises: :class:`NotJsonError <jsongit.NotJsonError>` :class:`InvalidKeyError <jsongit.InvalidKeyError>` """ self._key2ref(key) # throw InvalidKeyError try: blob_id = self._repo.write(pygit2.GIT_OBJ_BLOB, self._dumps(value)) except ValueError as e: raise NotJsonError(e) except TypeError as e: raise NotJsonError(e) if key in self._repo.index: self._repo.index.remove(key) self._repo.index.add( pygit2.IndexEntry(key, blob_id, pygit2.GIT_FILEMODE_BLOB)) self._repo.index.write()
def test_create_entry_aspath(testrepo): index = testrepo.index hello_entry = index[Path('hello.txt')] entry = pygit2.IndexEntry(Path('README.md'), hello_entry.id, hello_entry.mode) index.add(entry) index.write_tree()
def createCommits(repo, commitsData, destHead, branchName): index = pygit2.Index() destCommit = destHead index.read_tree(destCommit.tree) for commitData in commitsData: srcCommit = commitData.commit tree = commitData.commit.tree for file in commitData.files: try: fileObject = tree[file] index.add( pygit2.IndexEntry(file, fileObject.id, pygit2.GIT_FILEMODE_BLOB)) except KeyError: removeFileFromTree(index, file) destTree = index.write_tree(repo) diff = repo[destTree].diff_to_tree(destCommit.tree) if len(diff): destCommitId = repo.create_commit('refs/heads/' + branchName, srcCommit.author, srcCommit.committer, srcCommit.message, destTree, [destCommit.id]) destCommit = repo[destCommitId] print srcCommit.id
def _write(self, path: Path, value: str) -> None: blob = self.repo.create_blob(value) # Check if the blob is identical, then just return. previous_blob: Optional[pygit2.Object] = None if self._current_session_branch is not None: # Try in session index. previous_blob = self._read_blob( f"refs/heads/{self._current_session_branch}", path) else: # Try in namespace branch. previous_blob = self._read_blob( f"refs/heads/{self.namespace_branch}", path) if previous_blob is not None: if blob == previous_blob.oid: return if self._current_session_index is None: raise Exception("There should be a index setup") new_entry = pygit2.IndexEntry(str(path), blob, pygit2.GIT_FILEMODE_BLOB) self._current_session_index.add(new_entry)
def apply_changes(repo, version, contents, path): # Apply the requested change to the git repository branch_name = BRANCHES[version.channel] git_repo = repo.git_repository blob_id = git_repo.create_blob(contents) # Initialize the index from the tree structure of the most # recent commit in `branch` tree = git_repo.revparse_single(branch_name).tree index = git_repo.index index.read_tree(tree) # Add / update the index path = os.path.join(EXTRACTED_PREFIX, path) entry = pygit2.IndexEntry(path, blob_id, pygit2.GIT_FILEMODE_BLOB) index.add(entry) tree = index.write_tree() # Now apply a new commit author = pygit2.Signature('test', '*****@*****.**') committer = pygit2.Signature('test', '*****@*****.**') branch = git_repo.branches.get(branch_name) # Create commit and properly update branch and reflog oid = git_repo.create_commit(None, author, committer, '...', tree, [branch.target]) commit = git_repo.get(oid) branch.set_target(commit.hex) # To make sure the serializer makes use of the new commit we'll have # to update the `git_hash` values on the version object. version.update(git_hash=commit.hex)
def __setitem__(self, key, value): _check_key(key) if self._dumper: value = self._dumper(value) blob_id = self._repo.create_blob(value) self._index.add( pygit2.IndexEntry(key, blob_id, pygit2.GIT_FILEMODE_BLOB))
def write(self, path): """ Serialise this MergeIndex to the given path. Regular entries, conflicts, and resolves are each serialised separately, so that they can be roundtripped accurately. """ index = pygit2.Index(str(path)) index.clear() for e in self.entries.values(): index.add(pygit2.IndexEntry(e.path, e.id, e.mode)) for e in self._serialise_conflicts(): index.add(pygit2.IndexEntry(e.path, e.id, e.mode)) for e in self._serialise_resolves(): index.add(pygit2.IndexEntry(e.path, e.id, e.mode)) index.write()
def test_create_entry(testrepo): index = testrepo.index hello_entry = index['hello.txt'] entry = pygit2.IndexEntry('README.md', hello_entry.id, hello_entry.mode) index.add(entry) tree_id = index.write_tree() assert '60e769e57ae1d6a2ab75d8d253139e6260e1f912' == str(tree_id)
def add_tree(self, tree): # type: (Dict[Text, bytes]) -> None self.has_changes = True for path, data in iteritems(tree): blob = self.pygit2_repo.create_blob(data) index_entry = pygit2.IndexEntry(path, blob, pygit2.GIT_FILEMODE_BLOB) self.index.add(index_entry)
def main(repo, *, use_workdir=False): if repo.index.conflicts: print("You need to resolve merge conflicts first.") return 1 try: repo.lookup_reference('MERGE_HEAD') print("Not running mapmerge for merge commit.") return 0 except KeyError: pass target_statuses = pygit2.GIT_STATUS_INDEX_MODIFIED | pygit2.GIT_STATUS_INDEX_NEW skip_to_file_statuses = pygit2.GIT_STATUS_WT_DELETED | pygit2.GIT_STATUS_WT_MODIFIED if use_workdir: target_statuses |= pygit2.GIT_STATUS_WT_MODIFIED | pygit2.GIT_STATUS_WT_NEW skip_to_file_statuses &= ~pygit2.GIT_STATUS_WT_MODIFIED changed = 0 for path, status in repo.status().items(): if path.endswith(".dmm") and (status & target_statuses): # read the index index_entry = repo.index[path] if use_workdir: index_map = dmm.DMM.from_file(os.path.join(repo.workdir, path)) else: index_map = dmm.DMM.from_bytes(repo[index_entry.id].read_raw()) try: head_blob = repo[repo[repo.head.target].tree[path].id] except KeyError: # New map, no entry in HEAD print(f"Converting new map: {path}", flush=True) assert (status & pygit2.GIT_STATUS_INDEX_NEW) merged_map = index_map else: # Entry in HEAD, merge the index over it print(f"Converting map: {path}", flush=True) assert not (status & pygit2.GIT_STATUS_INDEX_NEW) head_map = dmm.DMM.from_bytes(head_blob.read_raw()) merged_map = merge_map(index_map, head_map) # write to the index blob_id = repo.create_blob(merged_map.to_bytes()) repo.index.add(pygit2.IndexEntry(path, blob_id, index_entry.mode)) changed += 1 # write to the working directory if that's clean if status & skip_to_file_statuses: print( f"Warning: {path} has unindexed changes, not overwriting them" ) else: merged_map.to_file(os.path.join(repo.workdir, path)) if changed: repo.index.write() return 0
def test_create_entry(self): index = self.repo.index hello_entry = index['hello.txt'] entry = pygit2.IndexEntry('README.md', hello_entry.oid, hello_entry.mode) index.add(entry) tree_id = index.write_tree() self.assertEqual('60e769e57ae1d6a2ab75d8d253139e6260e1f912', str(tree_id))
def _write_feature(): feature = next(feature_iter) dest_path, dest_data = dataset.encode_feature( feature, **kwargs) blob_id = repo.create_blob(dest_data) entry = pygit2.IndexEntry(f"{dataset.path}/{dest_path}", blob_id, pygit2.GIT_FILEMODE_BLOB) index.add(entry)
def write_feature_to_dataset_entry(feature, dataset, repo): """ Adds the given feature to the given dataset by writing a blob to the sno repo. Returns the IndexEntry that refers to that blob - this IndexEntry still needs to be written to the repo to complete the write. """ feature_path, feature_data = dataset.encode_feature(feature) blob_id = repo.create_blob(feature_data) return pygit2.IndexEntry(feature_path, blob_id, pygit2.GIT_FILEMODE_BLOB)
def write_resolved_tree(self, repo): """ Write all the merged entries and the resolved conflicts to a tree in the given repo. Resolved conflicts will be written the same as merged entries in the resulting tree. Only works when all conflicts are resolved. """ assert not self.unresolved_conflicts index = pygit2.Index() # Entries that were merged automatically by libgit2, often trivially: for e in self.entries.values(): index.add(pygit2.IndexEntry(e.path, e.id, e.mode)) # libgit2 leaves entries in the main part of the index, even if they are conflicts. # We make sure this index only contains merged entries and resolved conflicts. index.remove_all(list(self._conflicts_paths())) # Entries that have been explicitly selected to resolve conflicts: for e in self._resolves_entries(): index.add(pygit2.IndexEntry(e.path, e.id, e.mode)) return index.write_tree(repo)
def unstage(self, path): self._logger.info("Unstage {}".format(path)) index = self.index index.remove(path) head_tree = self.head.tree if path in head_tree: # Restore index to HEAD tree_entry = head_tree[path] index_entry = git.IndexEntry(path, tree_entry.oid, tree_entry.filemode) self._logger.info("Reset index to HEAD for {}".format(path)) index.add(index_entry) index.write()
def add_from_fs(self, dir_to_add, prefix=""): """Add all files under dir_to_add to index recursively.""" for root, dirnames, filenames in os.walk(dir_to_add): if filenames: rel_root = os.path.relpath(root, dir_to_add) for filename in filenames: disk_path = os.path.join(root, filename) repo_path = posixpath.normpath( posixpath.join(prefix, rel_root, filename)) self.index.add( pygit2.IndexEntry( repo_path, self.repo.create_blob_fromdisk(disk_path), os.stat(disk_path).st_mode, ))
def add_other_files(app, myRepo, myIndex, overrides): logging.info("Agregando otros archivos, overrides: " + repr(overrides.keys())) file_name = get_filepath(app.package_name, app.md5) zipfile = ZipFile(file_name, 'r') for filename in zipfile.namelist(): if filename in overrides: logging.info("Storing " + filename + " from overrides\n") myBytes = overrides[filename] else: myBytes = zipfile.read(filename) logging.info("Storing " + filename + "from zip") contents = myRepo.create_blob(myBytes) myIndex.add( pygit2.IndexEntry(filename, contents, pygit2.GIT_FILEMODE_BLOB)) zipfile.close()
def main(repo): if repo.index.conflicts: print("You need to resolve merge conflicts first.") return 1 changed = 0 for path, status in repo.status().items(): if path.endswith(".dmm") and ( status & (pygit2.GIT_STATUS_INDEX_MODIFIED | pygit2.GIT_STATUS_INDEX_NEW)): # read the index index_entry = repo.index[path] index_map = dmm.DMM.from_bytes(repo[index_entry.id].read_raw()) try: head_blob = repo[repo[repo.head.target].tree[path].id] except KeyError: # New map, no entry in HEAD print("Converting new map: {}".format(path)) assert (status & pygit2.GIT_STATUS_INDEX_NEW) merged_map = index_map else: # Entry in HEAD, merge the index over it print("Merging map: {}".format(path)) assert not (status & pygit2.GIT_STATUS_INDEX_NEW) head_map = dmm.DMM.from_bytes(head_blob.read_raw()) merged_map = merge_map(index_map, head_map) # write to the index blob_id = repo.create_blob(merged_map.to_bytes()) repo.index.add(pygit2.IndexEntry(path, blob_id, index_entry.mode)) changed += 1 # write to the working directory if that's clean if status & (pygit2.GIT_STATUS_WT_DELETED | pygit2.GIT_STATUS_WT_MODIFIED): print( "Warning: {} has unindexed changes, not overwriting them". format(path)) else: merged_map.to_file(os.path.join(repo.workdir, path)) if changed: repo.index.write() print("Merged {} maps.".format(changed)) return 0
def setUp(self): self.maxDiff = None tests.reset_emulator() # TODO(ochang): Refactor out into common test utilities. self.original_clone = pygit2.clone_repository self.clone_repository_patcher = mock.patch('pygit2.clone_repository') mock_clone = self.clone_repository_patcher.start() mock_clone.side_effect = self.mock_clone patcher = mock.patch('osv.types.utcnow') mock_utcnow = patcher.start() mock_utcnow.return_value = datetime.datetime(2021, 1, 1) self.addCleanup(patcher.stop) # Initialise fake source_repo. self.tmp_dir = tempfile.TemporaryDirectory() self.remote_source_repo_path = os.path.join(self.tmp_dir.name, 'source_repo') repo = pygit2.init_repository(self.remote_source_repo_path, True) tree = repo.TreeBuilder().write() author = pygit2.Signature('OSV', '*****@*****.**') repo.create_commit('HEAD', author, author, 'Initial commit', tree, []) # Add a source. oid = repo.write( pygit2.GIT_OBJ_BLOB, self._load_test_data(os.path.join(TEST_DATA_DIR, 'BLAH-123.yaml'))) repo.index.add( pygit2.IndexEntry('BLAH-123.yaml', oid, pygit2.GIT_FILEMODE_BLOB)) repo.index.write() tree = repo.index.write_tree() repo.create_commit('HEAD', author, author, 'Changes', tree, [repo.head.peel().oid]) osv.SourceRepository(id='source', name='source', repo_url='file://' + self.remote_source_repo_path, repo_username='').put() osv.Bug(id='BLAH-123', project='blah.com/package', ecosystem='golang').put()
def fetch(self, uni_id, robot_id): print("fetch({}, {})".format(uni_id, robot_id)) # Clone student repository if self.clone_repository(uni_id): # Get output.txt if self.sftp_file("9" + robot_id, "output.txt", "get"): # Remove log directory from repository path = os.getcwd() + "/student/logs" try: shutil.rmtree(path) except: pass os.mkdir("student/logs") # Rename based on timestamp filename = str(int(time.time())) + ".txt" relpath = "student/logs/" + filename os.rename("output.txt", relpath) # Add log to git commit s = pygit2.Signature('Roboproge Logmaster', '*****@*****.**') file_contents = "" with open(relpath) as f: for line in f.readlines(): file_contents += line contents = self.repository.create_blob(file_contents) self.repository.index.add( pygit2.IndexEntry("logs/" + filename, contents, pygit2.GIT_FILEMODE_BLOB)) self.repository.index.write() tree = self.repository.index.write_tree() master = self.repository.lookup_branch("master") self.repository.create_commit('refs/heads/master', s, s, 'Log upload', tree, [master.target]) # Push commit self.repository.remotes["origin"].push( ["refs/heads/master"], callbacks=self.callbacks) # Remove repository self.remove_student_repository() else: print("Unable to download output file!") else: print("Unable to clone repository!")
def _save(self, name, content): """Save the File content under the given path name. @param name: file path, relative to the repository root @param content: File content (temporary or in-memory file object) @return: the name under which the content was saved """ path = self._git_path(name) if hasattr(content, 'temporary_file_path'): blob_id = self.repository.create_blob_fromdisk(content.temporary_file_path()) content.close() else: # TODO Yes, we're loading a potentially big file in memory # Use create_blob_fromiobase when available blob_id = self.repository.create_blob(content.read()) # The index is a flatten representation of the repository tree index = self.repository.index index.add(pygit2.IndexEntry(path, blob_id, pygit2.GIT_FILEMODE_BLOB)) tree_id = index.write_tree() self._commit(app_config.SAVE_MESSAGE, tree_id) return name
def stage_apk(app, overrides): myRepo = pygit2.Repository(repo_name(app.package_name)) master = myRepo.lookup_branch("master") # if master == None: #myTreeGen = myRepo.TreeBuilder() # else: # lastcommit = myRepo.get(master.target) # lastTree = lastcommit.tree.oid #myTreeGen = myRepo.TreeBuilder(lastTree) myIndex = myRepo.index for sourcefile in app.sourcefile_set.all(): logging.info("Storing " + sourcefile.file_name + "\n") src = (sourcefile.file_contents).encode('ascii', 'replace').replace( "\\n", "\n") contents = myRepo.create_blob(src) myIndex.add( pygit2.IndexEntry(sourcefile.file_name + ".java", contents, pygit2.GIT_FILEMODE_BLOB)) logging.info("Listo el codigo fuente") add_other_files(app, myRepo, myIndex, overrides) #myTreeGen.insert(sourcefile.file_name, contents, pygit2.GIT_FILEMODE_BLOB) #myTree = myTreeGen.write() myTree = myIndex.write_tree() version = app.version author = pygit2.Signature("Alice Author", "*****@*****.**") committer = pygit2.Signature("Alice Author", "*****@*****.**") if master == None: myRepo.create_commit('refs/heads/master', author, committer, version, myTree, []) else: myRepo.create_commit('refs/heads/master', author, committer, version, myTree, [master.target]) myRepo.create_branch(version, myRepo.head.get_object()) myRemote = myRepo.remotes[0] #myRemote.credentials = pygit2.UserPass("marvin",marvin_git_passwd) credentials = pygit2.UserPass("marvin", marvin_git_passwd) callbacks = pygit2.RemoteCallbacks(credentials=credentials) myRemote.push(["refs/heads/master"], callbacks=callbacks) myRemote.push(["refs/heads/" + version], callbacks=callbacks)
def setUp(self): self.maxDiff = None # pylint: disable=invalid-name self.tmp_dir = tempfile.mkdtemp() self.remote_source_repo_path = os.path.join(self.tmp_dir, 'source_repo') patcher = mock.patch('osv.types.utcnow') mock_utcnow = patcher.start() mock_utcnow.return_value = datetime.datetime(2021, 1, 1) self.addCleanup(patcher.stop) # Initialise fake source_repo. repo = pygit2.init_repository(self.remote_source_repo_path, True) tree = repo.TreeBuilder().write() author = pygit2.Signature('OSV', '*****@*****.**') repo.create_commit('HEAD', author, author, 'Initial commit', tree, []) # Add a fake user change. with open(os.path.join(self.remote_source_repo_path, '2021-111.yaml'), 'w') as f: f.write('') oid = repo.write(pygit2.GIT_OBJ_BLOB, '') repo.index.add( pygit2.IndexEntry('2021-111.yaml', oid, pygit2.GIT_FILEMODE_BLOB)) repo.index.write() tree = repo.index.write_tree() author = pygit2.Signature('User', 'user@email') repo.create_commit('HEAD', author, author, 'Changes', tree, [repo.head.peel().oid]) osv.SourceRepository(id='oss-fuzz', name='oss-fuzz', repo_url='file://' + self.remote_source_repo_path, repo_username='').put() osv.Bug( id='2017-134', affected=['FILE5_29', 'FILE5_30'], affected_fuzzy=['5-29', '5-30'], confidence=100, details=( 'OSS-Fuzz report: ' 'https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=1064\n\n' 'Crash type: Heap-buffer-overflow READ 1\n' 'Crash state:\ncdf_file_property_info\ncdf_file_summary_info\n' 'cdf_check_summary_info\n'), ecosystem='', fixed='19ccebafb7663c422c714e0c67fa4775abf91c43', has_affected=True, issue_id='1064', project='file', public=True, reference_urls=[ 'https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=1064' ], regressed='17ee4cf670c363de8d2ea4a4897d7a699837873f', repo_url='https://github.com/file/file.git', search_indices=['file', '2017-134', '2017', '134'], severity='MEDIUM', sort_key='2017-0000134', source_id='oss-fuzz:5417710252982272', status=1, summary='Heap-buffer-overflow in cdf_file_property_info', timestamp=datetime.datetime(2021, 1, 15, 0, 0, 24, 559102)).put()
def add_update_to_repo(sess, repo, filename, data): blob_id = repo.create_blob(data) entry = pygit2.IndexEntry(filename, blob_id, pygit2.GIT_FILEMODE_BLOB) repo.index.add(entry) repo.index.write()
def add_file(self, path, contents): """Adds a file.""" oid = self._repo.write(pygit2.GIT_OBJ_BLOB, contents) self._repo.index.add(pygit2.IndexEntry(path, oid, pygit2.GIT_FILEMODE_BLOB)) self._repo.index.write()
def main(repo): if repo.index.conflicts: print("You need to resolve merge conflicts first.") return 1 # Ensure the index is clean. for path, status in repo.status().items(): if status & pygit2.GIT_STATUS_IGNORED: continue if status & STATUS_INDEX: print("You have changes staged for commit. Commit them or unstage them first.") print("If you are about to commit maps for the first time, run `Run Before Committing.bat`.") return 1 if path.endswith(".dmm") and (status & STATUS_WT): print("You have modified maps. Commit them first.") print("If you are about to commit maps for the first time, run `Run Before Committing.bat`.") return 1 # Read the HEAD commit. head_commit = repo[repo.head.target] head_files = {} for path, blob in walk_tree(head_commit.tree): if path.endswith(".dmm"): data = blob.read_raw() if not data.startswith(TGM_HEADER): head_files[path] = dmm.DMM.from_bytes(data) if not head_files: print("All committed maps appear to be in the correct format.") print("If you are about to commit maps for the first time, run `Run Before Committing.bat`.") return 1 # Work backwards to find a base for each map, converting as found. converted = {} if len(head_commit.parents) != 1: print("Unable to automatically fix anything because HEAD is a merge commit.") return 1 commit_message_lines = [] working_commit = head_commit.parents[0] while len(converted) < len(head_files): for path in head_files.keys() - converted.keys(): try: blob = working_commit.tree[path] except KeyError: commit_message_lines.append(f"{'new':{ABBREV_LEN}}: {path}") print(f"Converting new map: {path}") converted[path] = head_files[path] else: data = blob.read_raw() if data.startswith(TGM_HEADER): str_id = str(working_commit.id)[:ABBREV_LEN] commit_message_lines.append(f"{str_id}: {path}") print(f"Converting map: {path}") converted[path] = merge_map(head_files[path], dmm.DMM.from_bytes(data)) if len(working_commit.parents) != 1: print("A merge commit was encountered before good versions of these maps were found:") print("\n".join(f" {x}" for x in head_files.keys() - base_files.keys())) return 1 working_commit = working_commit.parents[0] # Okay, do the actual work. tree_builder = repo.TreeBuilder(head_commit.tree) for path, merged_map in converted.items(): blob_oid = repo.create_blob(merged_map.to_bytes()) insert_into_tree(repo, tree_builder, path, blob_oid) repo.index.add(pygit2.IndexEntry(path, blob_oid, repo.index[path].mode)) merged_map.to_file(os.path.join(repo.workdir, path)) # Save the index. repo.index.write() # Commit the index to the current branch. signature = pygit2.Signature(repo.config['user.name'], repo.config['user.email']) joined = "\n".join(commit_message_lines) repo.create_commit( repo.head.name, signature, # author signature, # committer f'Convert maps to TGM\n\n{joined}\n\nAutomatically commited by: {os.path.relpath(__file__, repo.workdir)}', tree_builder.write(), [head_commit.id], ) # Success. print("Successfully committed a fixup. Push as needed.") return 0
def do_merge(self, synced_branch: pygit2.IndexEntry, theirs_branch: pygit2.IndexEntry) -> None: theirs_commit = self.repo[theirs_branch.target] # synced_branch = self.repo.branches[synced_branch.name] merge_result, _ = self.repo.merge_analysis(theirs_branch.target, synced_branch.name) if merge_result & pygit2.GIT_MERGE_ANALYSIS_UP_TO_DATE: return merged_index = self.repo.merge_commits(synced_branch, theirs_commit) if merged_index.conflicts: for (base_index, ours_index, theirs_index) in list(merged_index.conflicts): path = None base = None if base_index is not None: base = sakdb_loads( self.repo[base_index.oid].data.decode("utf-8")) path = Path(base_index.path) ours = None if ours_index is not None: ours = sakdb_loads( self.repo[ours_index.oid].data.decode("utf-8")) path = Path(ours_index.path) theirs = None if theirs_index is not None: theirs = sakdb_loads( self.repo[theirs_index.oid].data.decode("utf-8")) path = Path(theirs_index.path) merged = merge(base, ours, theirs) if merged is None: raise Exception( "There was some unresolved merge conflict here.") merged_str = sakdb_dumps(merged) blob = self.repo.create_blob(merged_str) new_entry = pygit2.IndexEntry(str(path), blob, pygit2.GIT_FILEMODE_BLOB) merged_index.add(new_entry) del merged_index.conflicts[str(path)] user = self.repo.default_signature tree = merged_index.write_tree() message = f"Merge {theirs_branch.name}" # Move the namespace branch to the synced branch. self.repo.create_commit( synced_branch.name, user, user, message, tree, [synced_branch.target, theirs_branch.target], )