144 lines
3.8 KiB
Python
144 lines
3.8 KiB
Python
import os
|
|
import configparser
|
|
|
|
|
|
class GitRepository(object):
|
|
"""A git repository"""
|
|
|
|
"foo/"
|
|
worktree = None
|
|
"foo/.git"
|
|
gitdir = None
|
|
"foo/.git/config"
|
|
conf = None
|
|
|
|
def __init__(self, path, force=False):
|
|
self.worktree = path
|
|
self.gitdir = os.path.join(path, ".git")
|
|
|
|
if not (force or os.path.isdir(self.gitdir)):
|
|
raise Exception("Not a Git repository %s" % path)
|
|
|
|
# Read configuration file in .git/config
|
|
self.conf = configparser.ConfigParser()
|
|
cf = repo_file(self, "config")
|
|
|
|
if cf and os.path.exists(cf):
|
|
self.conf.read([cf])
|
|
elif not force:
|
|
raise Exception("Configuration file missing")
|
|
|
|
if not force:
|
|
vers = int(self.conf.get("core", "repositoryformatversion"))
|
|
# control that core.repositoryformatversion is 0
|
|
if vers != 0 and not force:
|
|
raise Exception("Unsupported repositoryformatversion %s" % vers)
|
|
|
|
|
|
def repo_path(repo, *path):
|
|
"""Compute path under repo's gitdir."""
|
|
return os.path.join(repo.gitdir, *path)
|
|
|
|
|
|
def repo_file(repo, *path, mkdir=False):
|
|
"""
|
|
Same as repo_path, but create dirname(*path) if absent. For
|
|
example, repo_file(r, \"refs\" \"remotes\", \"origin\", \"HEAD\") will create
|
|
.git/refs/remotes/origin.
|
|
"""
|
|
|
|
if repo_dir(repo, *path[:-1], mkdir=mkdir):
|
|
return repo_path(repo, *path)
|
|
|
|
|
|
def repo_dir(repo, *path, mkdir=False):
|
|
"""Same as repo_path, but mkdir *path if absent if mkdir."""
|
|
|
|
path = repo_path(repo, *path)
|
|
|
|
if os.path.exists(path):
|
|
if os.path.isdir(path):
|
|
return path
|
|
else:
|
|
raise Exception("Not a directory %s" % path)
|
|
|
|
if mkdir:
|
|
os.makedirs(path)
|
|
return path
|
|
else:
|
|
return None
|
|
|
|
|
|
def create_repo(path):
|
|
"""Create a new repository at path."""
|
|
|
|
repo = GitRepository(path, True)
|
|
|
|
# First, we make sure the path either doesn't exist or is an
|
|
# empty dir.
|
|
|
|
if os.path.exists(repo.worktree):
|
|
if not os.path.isdir(repo.worktree):
|
|
raise Exception("%s is not a directory!" % path)
|
|
if os.listdir(repo.worktree):
|
|
raise Exception("%s is not empty!" % path)
|
|
else:
|
|
os.makedirs(repo.worktree)
|
|
|
|
repo_dir(repo, "branches", mkdir=True)
|
|
repo_dir(repo, "objects", mkdir=True)
|
|
repo_dir(repo, "refs", "tags", mkdir=True)
|
|
repo_dir(repo, "refs", "heads", mkdir=True)
|
|
|
|
# .git/description
|
|
with open(repo_file(repo, "description"), "w") as f:
|
|
f.write(
|
|
"Unnamed repository; edit this file 'description' to name the repository.\n"
|
|
)
|
|
|
|
# .git/HEAD
|
|
with open(repo_file(repo, "HEAD"), "w") as f:
|
|
f.write("ref: refs/heads/master\n")
|
|
|
|
with open(repo_file(repo, "config"), "w") as f:
|
|
config = repo_default_config()
|
|
config.write(f)
|
|
|
|
return repo
|
|
|
|
|
|
def repo_default_config():
|
|
ret = configparser.ConfigParser()
|
|
|
|
ret.add_section("core")
|
|
ret.set("core", "repositoryformatversion", "0")
|
|
ret.set("core", "filemode", "false")
|
|
ret.set("core", "bare", "false")
|
|
|
|
return ret
|
|
|
|
|
|
def repo_find(path=".", required=True):
|
|
"""
|
|
Look for a repository, starting at current directory and recursing back until /.
|
|
"""
|
|
path = os.path.realpath(path)
|
|
|
|
if os.path.isdir(os.path.join(path, ".git")):
|
|
return GitRepository(path)
|
|
|
|
# If we haven't returned, recurse in parent, if w
|
|
parent = os.path.realpath(os.path.join(path, ".."))
|
|
|
|
if parent == path:
|
|
# Bottom case
|
|
# os.path.join("/", "..") == "/":
|
|
# If parent==path, then path is root.
|
|
if required:
|
|
raise Exception("No git directory.")
|
|
else:
|
|
return None
|
|
|
|
# Recursive case
|
|
return repo_find(parent, required)
|