diff options
Diffstat (limited to 'g2h')
| -rwxr-xr-x | g2h | 36 | ||||
| -rw-r--r-- | g2h/__init__.py | 0 | ||||
| -rw-r--r-- | g2h/cli.py | 42 | ||||
| -rw-r--r-- | g2h/commit_page.py | 36 | ||||
| -rw-r--r-- | g2h/file.py | 27 | ||||
| -rw-r--r-- | g2h/file_page.py | 47 | ||||
| -rw-r--r-- | g2h/git.py | 23 | ||||
| -rw-r--r-- | g2h/log_page.py | 47 | ||||
| -rw-r--r-- | g2h/overview_page.py | 19 | ||||
| -rw-r--r-- | g2h/page.py | 21 | ||||
| -rw-r--r-- | g2h/page_factory.py | 30 | ||||
| -rw-r--r-- | g2h/tree.py | 2 | ||||
| -rw-r--r-- | g2h/tree_page.py | 73 |
13 files changed, 36 insertions, 367 deletions
@@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +SCRIPT_DIR=$(dirname $(readlink -f $0)) +VENV_DIR="${SCRIPT_DIR}/.venv/" +ACTIVATE_SCRIPT="${SCRIPT_DIR}/.venv/bin/activate" + +if [ ! -f "${ACTIVATE_SCRIPT}" ]; then + echo "Virtual environment not found. Creating..." + python3 -m venv "${VENV_DIR}" + if [ $? -ne 0 ]; then + echo "Failed to create virtual environment." + exit 1 + fi + echo "Virtual environment created at ${VENV_DIR}." + + source "${ACTIVATE_SCRIPT}" + if [ $? -ne 0 ]; then + echo "Failed to activate virtual environment." + exit 1 + fi + + pip install -r "${SCRIPT_DIR}/requirements.txt" + if [ $? -ne 0 ]; then + echo "Failed to install project dependencies." + exit 1 + fi + echo "Project dependencies installed." +else + source "${ACTIVATE_SCRIPT}" + if [ $? -ne 0 ]; then + echo "Failed to activate virtual environment." + exit 1 + fi +fi + +python3 -m src.g2h.cli "$@" diff --git a/g2h/__init__.py b/g2h/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/g2h/__init__.py +++ /dev/null diff --git a/g2h/cli.py b/g2h/cli.py deleted file mode 100644 index 3f60b82..0000000 --- a/g2h/cli.py +++ /dev/null @@ -1,42 +0,0 @@ -import argparse -import os - -from .git import Git -from .page_factory import PageFactory - -def parse_args(): - parser = argparse.ArgumentParser( - prog='g2h', - description='Convert a git repository into markdown files Hugo can understand.') - # TODO: Defaults for these two values should be $PWD. - parser.add_argument('repo_path', help='Path to the root of git repository') - parser.add_argument('out_dir', help='Path to where the generated files should be stored') - parser.add_argument('--name', help='Name of the project. Default: directory name of repo') - parser.add_argument('--content-subdir', help='Subdir(s) where the page will be served from. Default: None', default='') - - return parser.parse_args() - -def main(): - args = parse_args() - git = Git(args.repo_path) - - branches = sorted(git.get_branches(), key=lambda b: b.commit.committed_date, reverse=True) - commits = git.get_commits() - head = git.get_head() - # TODO: Fix this for repo_path=(.|~) - project_name = args.name if args.name is not None else os.path.basename(args.repo_path) - tags = sorted(git.get_tags(), key=lambda t: t.commit.committed_date, reverse=True) - - factory = PageFactory(args.out_dir, project_name, args.content_subdir) - factory.new_overview(branches, tags, head).render() - factory.new_log(commits, branches, tags, head).render() - for commit in commits: - factory.new_commit(commit).render() - tree = factory.new_tree(commit, '', git.get_repo()) - for tree_page in tree.build_pages(factory): - tree_page.render() - for file in tree_page.get_files(): - factory.new_file(commit, file).render() - -if __name__ == '__main__': - main() diff --git a/g2h/commit_page.py b/g2h/commit_page.py deleted file mode 100644 index 84374e6..0000000 --- a/g2h/commit_page.py +++ /dev/null @@ -1,36 +0,0 @@ -import os - -from .page import Page - -def _redact_local_segment(local_segment): - if len(local_segment) == 0: - return '' - if len(local_segment) < 6: - return local_segment[0] + '...' - return local_segment[:2] + '...' - -def redact_email(email): - if email is None or len(email) == 0: - return '' - - if '@' not in email: - return _redact_local_segment(email) - - local, domain = email.split('@') - redacted_local = _redact_local_segment(local) - - return redacted_local + '@' + domain - -class CommitPage(Page): - def __init__(self, out_dir, name, commit, content_subdir): - super(CommitPage, self).__init__('commit.md', out_dir, os.path.join(commit.hexsha, '_index.md'), name, content_subdir) - self.commit = commit - - def context(self): - return { - 'commit': self.commit, - 'title': self.name + ': ' + self.commit.hexsha, - 'redacted_email': redact_email(self.commit.author.email), - 'content_subdir': self.content_subdir, - 'this_commit': self.commit - } diff --git a/g2h/file.py b/g2h/file.py deleted file mode 100644 index e07f251..0000000 --- a/g2h/file.py +++ /dev/null @@ -1,27 +0,0 @@ -import os - -def generate_breadcrumbs(content_subdir, commit, dir, files): - breadcrumbs = '[/](/{})'.format(os.path.join(content_subdir, tree_join(commit, ''))) - subpath = '' - for segment in dir.split(os.sep): - if not segment or len(segment) == 0: - continue - subpath = os.path.join(subpath, sanitize_file_name(segment, files)) - breadcrumbs += '/[{}](/{})'.format(segment, os.path.join(content_subdir, tree_join(commit, subpath))) - return breadcrumbs - - -def sanitize_file_name(file_name, files): - if not file_name.startswith('.'): - return file_name - - file_names = [ f.name for f in files ] - for i in range(1, 10): - new_name = file_name.replace('.', '_' * i, 1) - if not new_name in file_names: - return new_name - - raise RuntimeError('Couldn not find unused sanitized file name') - -def tree_join(commit, path): - return os.path.join(commit.hexsha, 't', path) diff --git a/g2h/file_page.py b/g2h/file_page.py deleted file mode 100644 index a558254..0000000 --- a/g2h/file_page.py +++ /dev/null @@ -1,47 +0,0 @@ -import base64 -import filetype -import os - -from .file import generate_breadcrumbs, sanitize_file_name, tree_join -from .page import Page -from .tree import safe_join - -def bytes_to_content(file_bytes): - if not file_bytes: - return (None, 'empty') - try: - text = file_bytes.decode('utf-8') - return (text, 'text') - except UnicodeError: - if filetype.is_image(file_bytes): - # TODO: Refer to the static file once that's implemented. - img = base64.b64encode(file_bytes) - return (img.decode('utf-8'), 'image') - - return (None, None) - -class FilePage(Page): - def __init__(self, out_dir, name, commit, file_name, file_path, content_subdir): - tree = safe_join(commit.tree, file_path) - super(FilePage, self).__init__('file.md', out_dir, os.path.join(tree_join(commit, file_path), sanitize_file_name(file_name, tree.blobs) + '.md'), name, content_subdir) - self.commit = commit - self.file_name = file_name - self.file_path = file_path - self.tree = tree - - def read_file(self): - return self.tree.join(self.file_name).data_stream.read() - - def context(self): - file_bytes = self.read_file() - content, file_type = bytes_to_content(file_bytes) - - return { - 'breadcrumbs': generate_breadcrumbs(self.content_subdir, self.commit, os.path.join(self.file_path, self.file_name), self.tree.blobs), - 'content': content, - 'content_subdir': self.content_subdir, - 'file_extension': os.path.splitext(self.file_name)[1].lstrip('.'), - 'title': self.name + ': ' + self.file_name, - 'this_commit': self.commit, - 'type': file_type - } diff --git a/g2h/git.py b/g2h/git.py deleted file mode 100644 index 283135c..0000000 --- a/g2h/git.py +++ /dev/null @@ -1,23 +0,0 @@ -import git - -class Git: - def __init__(self, repo_path): - try: - self.repo = git.Repo(repo_path) - except git.InvalidGitRepositoryError: - raise ValueError(f"Invalid git repository at {repo_path}") - - def get_branches(self): - return self.repo.branches - - def get_commits(self): - return list(self.repo.iter_commits()) - - def get_head(self): - return self.repo.head.commit - - def get_repo(self): - return self.repo - - def get_tags(self): - return self.repo.tags diff --git a/g2h/log_page.py b/g2h/log_page.py deleted file mode 100644 index b8df839..0000000 --- a/g2h/log_page.py +++ /dev/null @@ -1,47 +0,0 @@ -import os - -from .page import Page - -def ref_names_for_commit(refs, commit_sha): - ref_names = [] - if refs is None: - return ref_names - for ref in refs: - if ref.commit.hexsha == commit_sha: - ref_names.append(ref.name) - - return ref_names - -class LogPage(Page): - def __init__(self, out_dir, name, commits, branches, tags, content_subdir, latest_commit): - super(LogPage, self).__init__('log.md', out_dir, 'l.md', name, content_subdir) - self.commits = commits - self.branches = branches - self.tags = tags - self.latest_commit = latest_commit - - def _commits_with_refs(self): - commits_context = [] - for commit in self.commits: - refs = ref_names_for_commit(self.branches, commit.hexsha) + ref_names_for_commit(self.tags, commit.hexsha) - commit_context = { - 'committed_datetime': commit.committed_datetime, - 'hexsha': commit.hexsha, - 'refs': refs, - 'summary': commit.summary - } - commits_context.append(commit_context) - return commits_context - - def context(self): - commits_context = [] - if self.commits is not None: - commits_context = self._commits_with_refs() - - return { - 'commits': commits_context, - 'content_subdir': self.content_subdir, - 'title': self.name + ': Log', - 'this_commit': self.latest_commit - } - diff --git a/g2h/overview_page.py b/g2h/overview_page.py deleted file mode 100644 index 145a8d7..0000000 --- a/g2h/overview_page.py +++ /dev/null @@ -1,19 +0,0 @@ -from .page import Page - -class OverviewPage(Page): - def __init__(self, out_dir, name, branches, tags, content_subdir, latest_commit): - super(OverviewPage, self).__init__('overview.md', out_dir, '_index.md', name, content_subdir) - self.branches = branches - self.tags = tags - self.latest_commit = latest_commit - - def context(self): - return { - 'branches': self.branches, - 'content_subdir': self.content_subdir, - 'latest_commit_date': self.latest_commit.committed_datetime, - 'tags': self.tags, - 'title': self.name, - 'this_commit': self.latest_commit - } - diff --git a/g2h/page.py b/g2h/page.py deleted file mode 100644 index b829a88..0000000 --- a/g2h/page.py +++ /dev/null @@ -1,21 +0,0 @@ -from jinja2 import Environment, FileSystemLoader -import os - -class Page: - def __init__(self, template_file, out_dir, out_file, name, content_subdir): - self.out_file_path = os.path.join(out_dir, out_file) - self.name = name - self.content_subdir = content_subdir - template_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'templates')) - self.template = Environment(loader=FileSystemLoader(template_dir)).get_template(template_file) - - def context(self): - # TODO: Probably better to delegate to a method here so name and subdir don't have to be - # passed around as much. - raise NotImplementedError("Must override context") - - def render(self): - content = self.template.render(self.context()) - os.makedirs(os.path.dirname(self.out_file_path), exist_ok=True) - with open(self.out_file_path, 'w', encoding='utf-8') as f: - f.write(content) diff --git a/g2h/page_factory.py b/g2h/page_factory.py deleted file mode 100644 index 4a46f14..0000000 --- a/g2h/page_factory.py +++ /dev/null @@ -1,30 +0,0 @@ -import os - -from .commit_page import CommitPage -from .file_page import FilePage -from .overview_page import OverviewPage -from .log_page import LogPage -from .tree_page import TreePage - -class PageFactory: - def __init__(self, out_dir, name, content_subdir): - self.out_dir = out_dir - self.name = name - self.content_subdir = content_subdir - - def new_commit(self, commit): - return CommitPage(self.out_dir, self.name, commit, self.content_subdir) - - def new_file(self, commit, path): - filename = os.path.basename(path) - dir = os.path.dirname(path) - return FilePage(self.out_dir, self.name, commit, filename, dir, self.content_subdir) - - def new_overview(self, branches, tags, head): - return OverviewPage(self.out_dir, self.name, branches, tags, self.content_subdir, head) - - def new_log(self, commits, branches, tags, head): - return LogPage(self.out_dir, self.name, commits, branches, tags, self.content_subdir, head) - - def new_tree(self, commit, tree_segment, repo): - return TreePage(self.out_dir, self.name, commit, tree_segment, repo, self.content_subdir) diff --git a/g2h/tree.py b/g2h/tree.py deleted file mode 100644 index bd8116c..0000000 --- a/g2h/tree.py +++ /dev/null @@ -1,2 +0,0 @@ -def safe_join(tree, path): - return tree.join(path) if path else tree diff --git a/g2h/tree_page.py b/g2h/tree_page.py deleted file mode 100644 index df65a33..0000000 --- a/g2h/tree_page.py +++ /dev/null @@ -1,73 +0,0 @@ -import os - -from .file import generate_breadcrumbs, sanitize_file_name, tree_join -from .page import Page -from .tree import safe_join - -class TreePage(Page): - def __init__(self, out_dir, name, commit, sub_tree, repo, content_subdir): - tree = safe_join(commit.tree, sub_tree) - super(TreePage, self).__init__('tree.md', out_dir, os.path.join(tree_join(commit, tree.path), '_index.md'), name, content_subdir) - self.tree = tree - self.repo = repo - self.commit = commit - self.sub_tree = sub_tree - - def _generate_entries(self, nodes): - entries = [] - for node in nodes: - latest_commit = next(self.repo.iter_commits(self.commit, max_count=1, paths=node.path)) - name = node.name - file_name = name - if node.type == 'tree': - name += '/' - file_name = name - else: - file_name = sanitize_file_name(name, self.tree.blobs) - entry = { - 'file_name': file_name, - 'name': name, - 'modified': latest_commit.committed_datetime - } - entries.append(entry) - return entries - - def _get_entries(self): - files = self._generate_entries(self.tree.blobs) - dirs = self._generate_entries(self.tree.trees) - files.sort(key=lambda x: x['name']) - dirs.sort(key=lambda x: x['name']) - return dirs + files - - def context(self): - return { - 'breadcrumbs': generate_breadcrumbs(self.content_subdir, self.commit, self.sub_tree, self.tree.blobs), - 'content_subdir': self.content_subdir, - 'entries': self._get_entries(), - # TODO: Make this fit the rest of the system. - 'subdir': '/'.join([self.content_subdir, tree_join(self.commit, self.tree.path)]), - 'this_commit': self.commit, - 'title': self.name + ': Tree' - } - - def build_pages(self, factory): - visited = set() - remaining = [self.sub_tree] - tree_pages = [] - while remaining: - current = remaining.pop() - if not current in visited: - visited.add(current) - tree = safe_join(self.commit.tree, current) - tree_pages.append(factory.new_tree(self.commit, tree.path, self.repo)) - for sub_tree in tree.trees: - remaining.append(sub_tree.path) - - return tree_pages - - def get_files(self): - file_paths = [] - for blob in self.tree.blobs: - file_paths.append(blob.path) - - return file_paths |