Skip to content

Instantly share code, notes, and snippets.

@thehappycheese
Last active May 8, 2024 03:22
Show Gist options
  • Save thehappycheese/3733d3420fb0eb30575f5b1fbbd1afe4 to your computer and use it in GitHub Desktop.
Save thehappycheese/3733d3420fb0eb30575f5b1fbbd1afe4 to your computer and use it in GitHub Desktop.
A simple python wrapper for git that helps build synthetic repos based on snapshots of some folder
from __future__ import annotations
import subprocess
from pathlib import Path
from typing import Optional
import os
from dataclasses import dataclass
from deprecated import deprecated
from pandas import Timestamp
@dataclass
class RepoInstructions:
actions: list[Action]
@dataclass
class Action:
pass
@dataclass
@deprecated(reason="No longer needed")
class RawCommand(Action):
command: str
@dataclass
class ChangeAndCommit(Action):
pickle_name: str
message: str
date: Timestamp
class GitInit(Action):
pass
@dataclass
class GitRenameBranch(Action):
old_name: str
new_name: str
@dataclass
class GitSwitchBranch(Action):
branch_name: str
create: bool = False
class GitSubprocessWrapper:
cwd: Path
def __init__(self, cwd: Path):
self.cwd = cwd
def run(self, command: str, environment=None):
print(f"Running {command}")
result = subprocess.run(
command,
text=True,
capture_output=True,
env=environment,
cwd=self.cwd,
check=False,
)
if result.returncode != 0:
raise Exception(f"Error running {command}: {result.stderr}")
print(result.stdout)
return result.stdout
def has_changes(self):
status_output = self.run("git status --porcelain")
return bool(status_output.strip())
def commit(self, message: str, commit_date: Optional[Timestamp] = None):
environment = {**os.environ}
if commit_date is not None:
date_str = commit_date.strftime("%Y-%m-%dT%H:%M:%S")
environment = {
**environment,
"GIT_AUTHOR_DATE": date_str,
"GIT_COMMITTER_DATE": date_str,
}
self.run("git add .")
if self.has_changes():
date_part = ""
if commit_date is not None:
author_date = commit_date.strftime("%Y-%m-%dT%H:%M:%S")
date_part = f" --date={author_date}"
self.run(f'git commit -m "{message}"'+date_part, environment=environment)
else:
print("No changes detected, skipping commit.")
# ...
git = GitSubprocessWrapper(output_path)
for action in instructions.actions:
match action:
case GitInit():
git.run("git init")
case GitSwitchBranch(branch_name, create):
if create:
git.run(f"git switch -c {branch_name}")
else:
git.run(f"git switch {branch_name}")
case GitRenameBranch(old_name, new_name):
git.run(f"git branch -M {old_name} {new_name}")
case ChangeAndCommit(pickle_name, message, date):
with (pickle_base_path / pickle_name).open("rb") as f:
data:SearchSets = pickle.load(f)
dump_data(data, output_path)
git.run(f"git add .")
git.commit(message, date)
case GitMerge(branch_name):
git.run(f"git merge {branch_name}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment