1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
from __future__ import annotations
import contextlib
import os
import subprocess
from pathlib import Path
from types import TracebackType
import pygit2
from pygitweb.config import settings
from pygitweb.tasks import create_board_for_project
class Project:
"""
Plugin API: Project - the root class for a project which is always a directory, and _may_ contain a git repository.
"""
def __init__(
self,
path: os.PathLike[str] | str,
remote_url: str | None = None,
create_task_board: bool = False,
do_maintenance: bool = False,
) -> None:
self.path: str = str(Path(path))
self.remote_url: str | None = remote_url
os.makedirs(self.path)
if self.remote_url:
pygit2.clone_repository(self.remote_url, self.path, bare=True)
else:
pygit2.init_repository(self.path, bare=True)
self.repo: pygit2.Repository = pygit2.Repository(self.path)
if create_task_board:
create_board_for_project(Path(self.path).name, name="Tasks", description="")
if do_maintenance:
with contextlib.suppress(subprocess.SubprocessError, FileNotFoundError):
subprocess.run(
[settings.GIT, "-C", self.path, "maintenance", "start"],
capture_output=True,
timeout=60,
)
def __enter__(self) -> Project:
return self
def __exit__(
self,
exc_type: type[BaseException] | None,
exc_value: BaseException | None,
traceback: TracebackType | None,
) -> None:
self.repo.free()
def __del__(self) -> None:
self.repo.free()
@classmethod
def form_content(cls) -> str:
return (
'<label class="form-label" for="pull_from_remote">Pull from remote</label>'
'<input type="url" class="form-control" id="pull_from_remote" name="pull_from_remote" '
'placeholder="https://example.com/repo.git or ssh://git@host/repo.git or git://host/repo.git">'
'<small class="form-hint">Optional. Use an <code>ssh://</code>, <code>git://</code>, '
"or <code>https://</code> URL to clone an existing repository.</small>"
)