Add 'commit' command
This commit is contained in:
parent
ff78648324
commit
3f49d9f7db
116
libwyag.py
116
libwyag.py
@ -1342,3 +1342,119 @@ def add(repo, paths, delete=True, skip_missing=False):
|
|||||||
index.entries.append(entry)
|
index.entries.append(entry)
|
||||||
|
|
||||||
index_write(repo, index)
|
index_write(repo, index)
|
||||||
|
|
||||||
|
argsp = argsubparsers.add_parser("commit", help="Record changes to the repository.")
|
||||||
|
|
||||||
|
argsp.add_argument("-m",
|
||||||
|
metavar="mesaage",
|
||||||
|
dest="message",
|
||||||
|
help="Message to associate with this commit.")
|
||||||
|
|
||||||
|
def gitconfig_read():
|
||||||
|
xdg_config_home = os.environ["XDG_CONFIG_HOME"] if "XDG_CONFIG_HOME" in os.environ else "~/.config"
|
||||||
|
config_files = [
|
||||||
|
os.path.expanduser(join_path(xdg_config_home, "git/config")).replace("\\", "/"),
|
||||||
|
#os.path.expanduser("~/.gitconfig").replace("\\", "/")
|
||||||
|
]
|
||||||
|
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
config.read(config_files)
|
||||||
|
return config
|
||||||
|
|
||||||
|
def gitconfig_user_get(config):
|
||||||
|
if "user" in config:
|
||||||
|
if "name" in config["user"] and "email" in config["user"]:
|
||||||
|
return f"{config['user']['name']} <{config['user']['email']}>"
|
||||||
|
return None
|
||||||
|
|
||||||
|
def tree_from_index(repo, index):
|
||||||
|
contents = dict()
|
||||||
|
contents[""] = list()
|
||||||
|
|
||||||
|
# Convert entries to dictionary where keys are directories, and values are
|
||||||
|
# lists of directory contents.
|
||||||
|
for entry in index.entries:
|
||||||
|
dirname = os.path.dirname(entry.name).replace("\\", "/")
|
||||||
|
|
||||||
|
# We create all dictionary entries up to root (""). We need them *all*
|
||||||
|
# because even if a directory holds no files it will contain at least
|
||||||
|
# a tree.
|
||||||
|
key = dirname
|
||||||
|
while key != "":
|
||||||
|
if not key in contents:
|
||||||
|
contents[key] = list()
|
||||||
|
key = os.path.dirname(key).replace("\\", "/")
|
||||||
|
|
||||||
|
contents[dirname].append(entry)
|
||||||
|
|
||||||
|
# Sort keys (= directories) by length, descending. This means that we'll
|
||||||
|
# always encounter a given path before its parent, which is all we need,
|
||||||
|
# since for each directory D we'll need to modify its parent P to add
|
||||||
|
# D's tree.
|
||||||
|
sorted_paths = sorted(contents.keys(), key=len, reverse=True)
|
||||||
|
|
||||||
|
sha = None
|
||||||
|
|
||||||
|
for path in sorted_paths:
|
||||||
|
tree = GitTree()
|
||||||
|
|
||||||
|
for entry in contents[path]:
|
||||||
|
# An entry can be a normal GitIndexEntry read from the index, or
|
||||||
|
# a tree we've created.
|
||||||
|
if isinstance(entry, GitIndexEntry):
|
||||||
|
leaf_mode = f"{entry.mode_type:02o}{entry.mode_perms:04o}".encode("ascii")
|
||||||
|
leaf = GitTreeLeaf(mode=leaf_mode, path=os.path.basename(entry.name), sha=entry.sha)
|
||||||
|
else: # Tree. We've stored it as a pair: (basename, SHA)
|
||||||
|
leaf = GitTreeLeaf(mode=b"040000", path=entry[0], sha=entry[1])
|
||||||
|
|
||||||
|
tree.items.append(leaf)
|
||||||
|
|
||||||
|
sha = object_write(tree, repo)
|
||||||
|
|
||||||
|
parent = os.path.dirname(path).replace("\\", "/")
|
||||||
|
base = os.path.basename(path)
|
||||||
|
contents[parent].append((base, sha))
|
||||||
|
|
||||||
|
return sha
|
||||||
|
|
||||||
|
def commit_create(repo, tree, parent, author, timestamp, message):
|
||||||
|
commit = GitCommit()
|
||||||
|
commit.kvlm[b"tree"] = tree.encode("ascii")
|
||||||
|
if parent:
|
||||||
|
commit.kvlm[b'parent'] = parent.encode("ascii")
|
||||||
|
|
||||||
|
offset = int(timestamp.astimezone().utcoffset().total_seconds())
|
||||||
|
hours = offset // 3600
|
||||||
|
minutes = (offset & 3600) // 60
|
||||||
|
tz = f"{'+' if offset > 0 else '-'}{hours:02}{minutes:02}"
|
||||||
|
|
||||||
|
if author == None:
|
||||||
|
author = ""
|
||||||
|
author = author + timestamp.strftime(" %S ") + tz
|
||||||
|
|
||||||
|
commit.kvlm[b"author"] = author.encode("utf8")
|
||||||
|
commit.kvlm[b"committer"] = author.encode("utf8")
|
||||||
|
commit.kvlm[None] = message.encode("utf8")
|
||||||
|
|
||||||
|
return object_write(commit, repo)
|
||||||
|
|
||||||
|
def cmd_commit(args):
|
||||||
|
repo = repo_find()
|
||||||
|
index = index_read(repo)
|
||||||
|
tree = tree_from_index(repo, index)
|
||||||
|
|
||||||
|
commit = commit_create(repo,
|
||||||
|
tree,
|
||||||
|
object_find(repo, "HEAD"),
|
||||||
|
gitconfig_user_get(gitconfig_read()),
|
||||||
|
datetime.now(),
|
||||||
|
args.message)
|
||||||
|
|
||||||
|
# Update HEAD so our commit is now the tip of the active branch.
|
||||||
|
active_branch = branch_get_active(repo)
|
||||||
|
if active_branch: # If on a branch, update that branch
|
||||||
|
with open(GitRepository.repo_file(repo, join_path("refs/heads", active_branch)), "w") as fd:
|
||||||
|
fd.write(commit + "\n")
|
||||||
|
else: # Otherwise, we update HEAD itself.
|
||||||
|
with open(repo_file(repo, "HEAD"), "w") as fd:
|
||||||
|
fd.write(commit + "\n")
|
||||||
|
Loading…
Reference in New Issue
Block a user