mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-10 18:02:57 +00:00
133 lines
4.9 KiB
Python
133 lines
4.9 KiB
Python
#!/usr/bin/env python3
|
|
import os
|
|
import pygit2
|
|
from . import dmm
|
|
from .mapmerge import merge_map
|
|
|
|
|
|
STATUS_INDEX = (pygit2.GIT_STATUS_INDEX_NEW
|
|
| pygit2.GIT_STATUS_INDEX_MODIFIED
|
|
| pygit2.GIT_STATUS_INDEX_DELETED
|
|
| pygit2.GIT_STATUS_INDEX_RENAMED
|
|
| pygit2.GIT_STATUS_INDEX_TYPECHANGE
|
|
)
|
|
STATUS_WT = (pygit2.GIT_STATUS_WT_NEW
|
|
| pygit2.GIT_STATUS_WT_MODIFIED
|
|
| pygit2.GIT_STATUS_WT_DELETED
|
|
| pygit2.GIT_STATUS_WT_RENAMED
|
|
| pygit2.GIT_STATUS_WT_TYPECHANGE
|
|
)
|
|
ABBREV_LEN = 12
|
|
TGM_HEADER = dmm.TGM_HEADER.encode(dmm.ENCODING)
|
|
|
|
|
|
def walk_tree(tree, *, _prefix=''):
|
|
for child in tree:
|
|
if isinstance(child, pygit2.Tree):
|
|
yield from walk_tree(child, _prefix=f'{_prefix}{child.name}/')
|
|
else:
|
|
yield f'{_prefix}{child.name}', child
|
|
|
|
|
|
def insert_into_tree(repo, tree_builder, path, blob_oid):
|
|
try:
|
|
first, rest = path.split('/', 1)
|
|
except ValueError:
|
|
tree_builder.insert(path, blob_oid, pygit2.GIT_FILEMODE_BLOB)
|
|
else:
|
|
inner = repo.TreeBuilder(tree_builder.get(first))
|
|
insert_into_tree(repo, inner, rest, blob_oid)
|
|
tree_builder.insert(first, inner.write(), pygit2.GIT_FILEMODE_TREE)
|
|
|
|
|
|
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() - converted.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
|
|
|
|
|
|
if __name__ == '__main__':
|
|
exit(main(pygit2.Repository(pygit2.discover_repository(os.getcwd()))))
|