wyag/libwyag/repository.py
2019-03-23 11:21:25 +01:00

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)