Uhh broken stuff????
This commit is contained in:
parent
cb63969424
commit
4bd53221bb
346
ganarchy.py
346
ganarchy.py
|
@ -23,9 +23,106 @@ import subprocess
|
||||||
import hashlib
|
import hashlib
|
||||||
import hmac
|
import hmac
|
||||||
import jinja2
|
import jinja2
|
||||||
|
import re
|
||||||
|
|
||||||
# default HTML, can be overridden in $XDG_DATA_HOME/ganarchy/template.html or the $XDG_DATA_DIRS (TODO)
|
MIGRATIONS = {
|
||||||
TEMPLATE = """<!DOCTYPE html>
|
"gen-index": (
|
||||||
|
(
|
||||||
|
"""ALTER TABLE "config" ADD COLUMN "title" TEXT"""),
|
||||||
|
(),
|
||||||
|
"supports generating an index page"
|
||||||
|
),
|
||||||
|
"better-project-management": (
|
||||||
|
(
|
||||||
|
"""ALTER TABLE "repos" ADD COLUMN "branch" TEXT""",
|
||||||
|
"""ALTER TABLE "repos" ADD COLUMN "project" TEXT""",
|
||||||
|
"""CREATE UNIQUE INDEX "repos_url_branch_project" ON "repos" ("url", "branch", "project")""",
|
||||||
|
"""CREATE INDEX "repos_project" ON "repos" ("project")""",
|
||||||
|
"""ALTER TABLE "repo_history" ADD COLUMN "branch" TEXT""",
|
||||||
|
"""ALTER TABLE "repo_history" ADD COLUMN "project" TEXT""",
|
||||||
|
"""CREATE INDEX "repo_history_url_branch_project" ON "repo_history" ("url", "branch", "project")"""),
|
||||||
|
(
|
||||||
|
"""DELETE FROM "repos" WHERE "branch" IS NOT NULL OR "project" IS NOT NULL""",
|
||||||
|
"""DELETE FROM "repo_history" WHERE "branch" IS NOT NULL OR "project" IS NOT NULL"""),
|
||||||
|
"supports multiple projects, and allows choosing non-default branches"
|
||||||
|
),
|
||||||
|
"test": (
|
||||||
|
("""-- apply""",),
|
||||||
|
("""-- revert""",),
|
||||||
|
"does nothing"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
data_home = os.environ.get('XDG_DATA_HOME', '')
|
||||||
|
if not data_home:
|
||||||
|
data_home = os.environ['HOME'] + '/.local/share'
|
||||||
|
data_home = data_home + "/ganarchy"
|
||||||
|
|
||||||
|
cache_home = os.environ.get('XDG_CACHE_HOME', '')
|
||||||
|
if not cache_home:
|
||||||
|
cache_home = os.environ['HOME'] + '/.cache'
|
||||||
|
cache_home = cache_home + "/ganarchy"
|
||||||
|
|
||||||
|
config_home = os.environ.get('XDG_CONFIG_HOME', '')
|
||||||
|
if not config_home:
|
||||||
|
config_home = os.environ['HOME'] + '/.config'
|
||||||
|
config_home = config_home + "/ganarchy"
|
||||||
|
|
||||||
|
config_dirs = os.environ.get('XDG_CONFIG_DIRS', '')
|
||||||
|
if not config_dirs:
|
||||||
|
config_dirs = '/etc/xdg'
|
||||||
|
# TODO check if this is correct
|
||||||
|
config_dirs = [config_dir + "/ganarchy" for config_dir in config_dirs.split(':')]
|
||||||
|
|
||||||
|
def get_template_loader():
|
||||||
|
from jinja2 import DictLoader, FileSystemLoader, ChoiceLoader
|
||||||
|
return ChoiceLoader([
|
||||||
|
FileSystemLoader([config_home + "/templates"] + [config_dir + "/templates" for config_dir in config_dirs]),
|
||||||
|
DictLoader({
|
||||||
|
## index.html
|
||||||
|
'index.html': """<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<!--
|
||||||
|
GAnarchy - project homepage generator
|
||||||
|
Copyright (C) 2019 Soni L.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
<title>{{ ganarchy.title|e }}</title>
|
||||||
|
<meta name="description" content="{{ ganarchy.title|e }}" />
|
||||||
|
<!--if your browser doesn't like the following, use a different browser.-->
|
||||||
|
<script type="application/javascript" src="/index.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>{{ ganarchy.title|e }}</h1>
|
||||||
|
<p>This is {{ ganarchy.title|e }}. Currently tracking the following projects:</p>
|
||||||
|
<ul>
|
||||||
|
{% for project in ganarchy.projects -%}
|
||||||
|
<li><a href="/project/{{ project.commit|e }}">{{ project.title|e }}</a>: {{ project.description|e }}</li>
|
||||||
|
{% endfor -%}
|
||||||
|
</ul>
|
||||||
|
<p>Powered by <a href="https://ganarchy.autistic.space/">GAnarchy</a>. AGPLv3-licensed. <a href="https://cybre.tech/SoniEx2/ganarchy">Source Code</a>.</p>
|
||||||
|
<p>
|
||||||
|
<a href="{{ ganarchy.base_url|e }}" onclick="event.preventDefault(); navigator.registerProtocolHandler('web+ganarchy', this.href + '?url=%s', 'GAnarchy');">Register web+ganarchy: URI handler</a>.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
""",
|
||||||
|
## project.html FIXME
|
||||||
|
'project.html': """<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
|
@ -57,7 +154,7 @@ TEMPLATE = """<!DOCTYPE html>
|
||||||
<ul>
|
<ul>
|
||||||
{% for url, msg, img, branch in repos -%}
|
{% for url, msg, img, branch in repos -%}
|
||||||
<li><a href="{{ url|e }}">{{ url|e }}</a>{% if branch %} <span class="branchname">[{{ branch|e }}]</span>{% endif %}: {{ msg|e }}</li>
|
<li><a href="{{ url|e }}">{{ url|e }}</a>{% if branch %} <span class="branchname">[{{ branch|e }}]</span>{% endif %}: {{ msg|e }}</li>
|
||||||
{%- endfor %}
|
{% endfor -%}
|
||||||
</ul>
|
</ul>
|
||||||
<p>Powered by <a href="https://ganarchy.autistic.space/">GAnarchy</a>. AGPLv3-licensed. <a href="https://cybre.tech/SoniEx2/ganarchy">Source Code</a>.</p>
|
<p>Powered by <a href="https://ganarchy.autistic.space/">GAnarchy</a>. AGPLv3-licensed. <a href="https://cybre.tech/SoniEx2/ganarchy">Source Code</a>.</p>
|
||||||
<p>
|
<p>
|
||||||
|
@ -66,45 +163,12 @@ TEMPLATE = """<!DOCTYPE html>
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
"""
|
""",
|
||||||
|
## history.svg FIXME
|
||||||
|
'history.svg': """""",
|
||||||
|
})
|
||||||
|
])
|
||||||
|
|
||||||
MIGRATIONS = {
|
|
||||||
"better-project-management": (
|
|
||||||
(
|
|
||||||
"""ALTER TABLE "repos" ADD COLUMN "branch" TEXT""",
|
|
||||||
"""ALTER TABLE "repos" ADD COLUMN "project" TEXT""",
|
|
||||||
"""CREATE UNIQUE INDEX "repos_url_branch_project" ON "repos" ("url", "branch", "project")""",
|
|
||||||
"""CREATE INDEX "repos_project" ON "repos" ("project")""",
|
|
||||||
"""ALTER TABLE "repo_history" ADD COLUMN "branch" TEXT""",
|
|
||||||
"""ALTER TABLE "repo_history" ADD COLUMN "project" TEXT""",
|
|
||||||
"""CREATE INDEX "repo_history_url_branch_project" ON "repo_history" ("url", "branch", "project")"""),
|
|
||||||
(
|
|
||||||
"""DELETE FROM "repos" WHERE "branch" IS NOT NULL OR "project" IS NOT NULL""",
|
|
||||||
"""DELETE FROM "repo_history" WHERE "branch" IS NOT NULL OR "project" IS NOT NULL"""),
|
|
||||||
"supports multiple projects, and allows choosing non-default branches"
|
|
||||||
),
|
|
||||||
"test": (
|
|
||||||
("""-- apply""",),
|
|
||||||
("""-- revert""",),
|
|
||||||
"does nothing"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
data_home = os.environ['XDG_DATA_HOME']
|
|
||||||
except KeyError:
|
|
||||||
data_home = ''
|
|
||||||
if not data_home:
|
|
||||||
data_home = os.environ['HOME'] + '/.local/share'
|
|
||||||
data_home = data_home + "/ganarchy"
|
|
||||||
|
|
||||||
try:
|
|
||||||
cache_home = os.environ['XDG_CACHE_HOME']
|
|
||||||
except KeyError:
|
|
||||||
cache_home = ''
|
|
||||||
if not cache_home:
|
|
||||||
cache_home = os.environ['HOME'] + '/.cache'
|
|
||||||
cache_home = cache_home + "/ganarchy"
|
|
||||||
|
|
||||||
@click.group()
|
@click.group()
|
||||||
def ganarchy():
|
def ganarchy():
|
||||||
|
@ -122,8 +186,8 @@ def initdb():
|
||||||
c.execute('''CREATE INDEX "repos_active" ON "repos" ("active")''')
|
c.execute('''CREATE INDEX "repos_active" ON "repos" ("active")''')
|
||||||
c.execute('''CREATE TABLE "repo_history" ("entry" INTEGER PRIMARY KEY ASC AUTOINCREMENT, "url" TEXT, "count" INTEGER, "head_commit" TEXT, "branch" TEXT, "project" TEXT)''')
|
c.execute('''CREATE TABLE "repo_history" ("entry" INTEGER PRIMARY KEY ASC AUTOINCREMENT, "url" TEXT, "count" INTEGER, "head_commit" TEXT, "branch" TEXT, "project" TEXT)''')
|
||||||
c.execute('''CREATE INDEX "repo_history_url_branch_project" ON "repo_history" ("url", "branch", "project")''')
|
c.execute('''CREATE INDEX "repo_history_url_branch_project" ON "repo_history" ("url", "branch", "project")''')
|
||||||
c.execute('''CREATE TABLE "config" ("git_commit" TEXT, "base_url" TEXT)''')
|
c.execute('''CREATE TABLE "config" ("git_commit" TEXT, "base_url" TEXT, "title" TEXT)''')
|
||||||
c.execute('''INSERT INTO "config" VALUES ('', '')''')
|
c.execute('''INSERT INTO "config" VALUES ('', '', '')''')
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
@ -131,7 +195,6 @@ def initdb():
|
||||||
@click.argument('commit')
|
@click.argument('commit')
|
||||||
def set_commit(commit):
|
def set_commit(commit):
|
||||||
"""Sets the commit that represents the project."""
|
"""Sets the commit that represents the project."""
|
||||||
import re
|
|
||||||
if not re.fullmatch("[a-fA-F0-9]{40}", commit):
|
if not re.fullmatch("[a-fA-F0-9]{40}", commit):
|
||||||
raise click.BadArgumentUsage("COMMIT must be a git commit hash")
|
raise click.BadArgumentUsage("COMMIT must be a git commit hash")
|
||||||
conn = sqlite3.connect(data_home + "/ganarchy.db")
|
conn = sqlite3.connect(data_home + "/ganarchy.db")
|
||||||
|
@ -143,13 +206,23 @@ def set_commit(commit):
|
||||||
@ganarchy.command()
|
@ganarchy.command()
|
||||||
@click.argument('base-url')
|
@click.argument('base-url')
|
||||||
def set_base_url(base_url):
|
def set_base_url(base_url):
|
||||||
"""Sets the GAnarchy instance's base URL."""
|
"""Sets the GAnarchy instance's base URL. Used for the URI handler."""
|
||||||
conn = sqlite3.connect(data_home + "/ganarchy.db")
|
conn = sqlite3.connect(data_home + "/ganarchy.db")
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
c.execute('''UPDATE "config" SET "base_url"=?''', (base_url,))
|
c.execute('''UPDATE "config" SET "base_url"=?''', (base_url,))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
@ganarchy.command()
|
||||||
|
@click.argument('title')
|
||||||
|
def set_title(title):
|
||||||
|
"""Sets the GAnarchy instance's title. This title is displayed on the index."""
|
||||||
|
conn = sqlite3.connect(data_home + "/ganarchy.db")
|
||||||
|
c = conn.cursor()
|
||||||
|
c.execute('''UPDATE "config" SET "title"=?''', (title,))
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
# TODO move --branch into here?
|
# TODO move --branch into here?
|
||||||
@ganarchy.group()
|
@ganarchy.group()
|
||||||
def repo():
|
def repo():
|
||||||
|
@ -265,28 +338,51 @@ def migrations():
|
||||||
|
|
||||||
migrations()
|
migrations()
|
||||||
|
|
||||||
@ganarchy.command()
|
class GitError(LookupError):
|
||||||
@click.argument('project', required=False)
|
"""Raised when a git operation fails, generally due to a missing commit or branch, or network connection issues."""
|
||||||
def cron_target(project):
|
pass
|
||||||
"""Runs ganarchy as a cron target."""
|
|
||||||
def handle_target(url, branch, project_commit):
|
class Repo:
|
||||||
|
def __init__(self, dbconn, project, url, branch, list_metadata=False):
|
||||||
|
self.url = url
|
||||||
|
self.branch = branch
|
||||||
|
self.project_commit = project.commit
|
||||||
|
|
||||||
if not branch:
|
if not branch:
|
||||||
branchname = "gan" + hashlib.sha256(url.encode("utf-8")).hexdigest()
|
self.branchname = "gan" + hashlib.sha256(url.encode("utf-8")).hexdigest()
|
||||||
branch = "HEAD"
|
self.head = "HEAD"
|
||||||
else:
|
else:
|
||||||
branchname = "gan" + hmac.new(branch.encode("utf-8"), url.encode("utf-8"), "sha256").hexdigest()
|
self.branchname = "gan" + hmac.new(branch.encode("utf-8"), url.encode("utf-8"), "sha256").hexdigest()
|
||||||
branch = "refs/heads/" + branch
|
self.head = "refs/heads/" + branch
|
||||||
|
|
||||||
try:
|
try:
|
||||||
pre_hash = subprocess.check_output(["git", "-C", cache_home, "show", branchname, "-s", "--format=%H", "--"], stderr=subprocess.DEVNULL).decode("utf-8").strip()
|
self.hash = subprocess.check_output(["git", "-C", cache_home, "show", self.branchname, "-s", "--format=%H", "--"], stderr=subprocess.DEVNULL).decode("utf-8").strip()
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
pre_hash = None
|
self.hash = None
|
||||||
|
|
||||||
|
self.message = None
|
||||||
|
if list_metadata:
|
||||||
try:
|
try:
|
||||||
subprocess.check_output(["git", "-C", cache_home, "fetch", "-q", url, "+" + branch + ":" + branchname], stderr=subprocess.STDOUT)
|
self.fetch_metadata()
|
||||||
|
except GitError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def fetch_metadata(self):
|
||||||
|
try:
|
||||||
|
self.message = subprocess.check_output(["git", "-C", cache_home, "show", self.branchname, "-s", "--format=%B", "--"], stderr=subprocess.DEVNULL).decode("utf-8", "replace")
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
raise GitError from e
|
||||||
|
|
||||||
|
def update(self): # FIXME?
|
||||||
|
try:
|
||||||
|
subprocess.check_output(["git", "-C", cache_home, "fetch", "-q", self.url, "+" + self.head + ":" + self.branchname], stderr=subprocess.STDOUT)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
# This may error for various reasons, but some are important: dead links, etc
|
# This may error for various reasons, but some are important: dead links, etc
|
||||||
click.echo(e.output, err=True)
|
click.echo(e.output, err=True)
|
||||||
return None
|
return None
|
||||||
post_hash = subprocess.check_output(["git", "-C", cache_home, "show", branchname, "-s", "--format=%H", "--"], stderr=subprocess.DEVNULL).decode("utf-8").strip()
|
pre_hash = self.hash
|
||||||
|
post_hash = subprocess.check_output(["git", "-C", cache_home, "show", self.branchname, "-s", "--format=%H", "--"], stderr=subprocess.DEVNULL).decode("utf-8").strip()
|
||||||
|
self.hash = post_hash
|
||||||
if not pre_hash:
|
if not pre_hash:
|
||||||
pre_hash = post_hash
|
pre_hash = post_hash
|
||||||
try:
|
try:
|
||||||
|
@ -294,16 +390,99 @@ def cron_target(project):
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
count = 0 # force-pushed
|
count = 0 # force-pushed
|
||||||
try:
|
try:
|
||||||
subprocess.check_call(["git", "-C", cache_home, "merge-base", "--is-ancestor", project_commit, branchname], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
subprocess.check_call(["git", "-C", cache_home, "merge-base", "--is-ancestor", self.project_commit, self.branchname], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||||
return count, post_hash, subprocess.check_output(["git", "-C", cache_home, "show", branchname, "-s", "--format=%B", "--"], stderr=subprocess.DEVNULL).decode("utf-8", "replace")
|
self.fetch_metadata()
|
||||||
except subprocess.CalledProcessError:
|
return count, post_hash, self.message
|
||||||
|
except (subprocess.CalledProcessError, GitError) as e:
|
||||||
|
click.echo(e, err=True)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
class Project:
|
||||||
|
def __init__(self, dbconn, ganarchy, project_commit, list_repos=False):
|
||||||
|
self.commit = project_commit
|
||||||
|
if ganarchy.project_commit == project_commit:
|
||||||
|
project_commit = None
|
||||||
|
self.refresh_metadata()
|
||||||
|
if list_repos:
|
||||||
|
repos = []
|
||||||
|
with dbconn:
|
||||||
|
for (e, url, branch) in dbconn.execute('''SELECT "max"("e"), "url", "branch" FROM (SELECT "max"("T1"."entry") "e", "T1"."url", "T1"."branch" FROM "repo_history" "T1"
|
||||||
|
WHERE (SELECT "active" FROM "repos" "T2" WHERE "url" = "T1"."url" AND "branch" IS "T1"."branch" AND "project" IS ?1)
|
||||||
|
GROUP BY "T1"."url", "T1"."branch"
|
||||||
|
UNION
|
||||||
|
SELECT null, "T3"."url", "T3"."branch" FROM "repos" "T3" WHERE "active" AND "project" IS ?1)
|
||||||
|
GROUP BY "url" ORDER BY "e"''', (project_commit,)):
|
||||||
|
repos.append(Repo(dbconn, self, url, branch))
|
||||||
|
self.repos = repos
|
||||||
|
else:
|
||||||
|
self.repos = None
|
||||||
|
|
||||||
|
def refresh_metadata(self):
|
||||||
|
try:
|
||||||
|
project = subprocess.check_output(["git", "-C", cache_home, "show", self.commit, "-s", "--format=%B", "--"], stderr=subprocess.DEVNULL).decode("utf-8", "replace")
|
||||||
|
project_title, project_desc = (lambda x: x.groups() if x is not None else ('', None))(re.fullmatch('^\\[Project\\]\s+(.+?)(?:\n\n(.+))?$', project, flags=re.ASCII|re.DOTALL|re.IGNORECASE))
|
||||||
|
if not project_title.strip():
|
||||||
|
project_title, project_desc = ("Error parsing project commit",)*2
|
||||||
|
if project_desc:
|
||||||
|
project_desc = project_desc.strip()
|
||||||
|
self.commit_body = project
|
||||||
|
self.title = project_title
|
||||||
|
self.description = project_desc
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
self.commit_body = None
|
||||||
|
self.title = None
|
||||||
|
self.description = None
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
# TODO
|
||||||
|
self.refresh_metadata()
|
||||||
|
|
||||||
|
class GAnarchy:
|
||||||
|
def __init__(self, dbconn, list_projects=False):
|
||||||
|
with dbconn:
|
||||||
|
# TODO
|
||||||
|
#(project_commit, base_url, title) = dbconn.execute('''SELECT "git_commit", "base_url", "title" FROM "config"''').fetchone()
|
||||||
|
(project_commit, base_url) = dbconn.execute('''SELECT "git_commit", "base_url" FROM "config"''').fetchone()
|
||||||
|
title = None
|
||||||
|
self.project_commit = project_commit
|
||||||
|
self.base_url = base_url
|
||||||
|
if not base_url:
|
||||||
|
pass ## TODO
|
||||||
|
if not title:
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
title = "GAnarchy on " + urlparse(base_url).hostname
|
||||||
|
self.title = title
|
||||||
|
if list_projects:
|
||||||
|
projects = []
|
||||||
|
with dbconn:
|
||||||
|
for (project,) in dbconn.execute('''SELECT DISTINCT "project" FROM "repos" '''): # FIXME? *maybe* sort by activity in the future
|
||||||
|
if project == None:
|
||||||
|
project = self.project_commit
|
||||||
|
projects.append(Project(dbconn, ganarchy, project))
|
||||||
|
projects.sort(key=lambda project: project.title)
|
||||||
|
self.projects = projects
|
||||||
|
else:
|
||||||
|
self.projects = None
|
||||||
|
|
||||||
|
|
||||||
|
@ganarchy.command()
|
||||||
|
@click.argument('project', required=False)
|
||||||
|
def cron_target(project):
|
||||||
|
"""Runs ganarchy as a cron target."""
|
||||||
|
# make sure the cache dir exists
|
||||||
os.makedirs(cache_home, exist_ok=True)
|
os.makedirs(cache_home, exist_ok=True)
|
||||||
|
# make sure it is a git repo
|
||||||
subprocess.call(["git", "-C", cache_home, "init", "-q"])
|
subprocess.call(["git", "-C", cache_home, "init", "-q"])
|
||||||
conn = sqlite3.connect(data_home + "/ganarchy.db")
|
conn = sqlite3.connect(data_home + "/ganarchy.db")
|
||||||
c = conn.cursor()
|
instance = GAnarchy(conn, list_projects=project=="index")
|
||||||
c.execute('''SELECT "git_commit", "base_url" FROM "config"''')
|
env = jinja2.Environment(loader=get_template_loader(), autoescape=False)
|
||||||
(project_commit, base_url) = c.fetchone()
|
if project == "index":
|
||||||
|
# render the index
|
||||||
|
template = env.get_template('index.html')
|
||||||
|
click.echo(template.render(ganarchy = instance))
|
||||||
|
return
|
||||||
|
project_commit = instance.project_commit
|
||||||
|
base_url = instance.base_url
|
||||||
if not base_url or not (project or project_commit):
|
if not base_url or not (project or project_commit):
|
||||||
click.echo("No base URL or project commit specified", err=True)
|
click.echo("No base URL or project commit specified", err=True)
|
||||||
return
|
return
|
||||||
|
@ -313,17 +492,16 @@ def cron_target(project):
|
||||||
project_commit = project
|
project_commit = project
|
||||||
entries = []
|
entries = []
|
||||||
generate_html = []
|
generate_html = []
|
||||||
for (e, url, branch) in c.execute('''SELECT "max"("e"), "url", "branch" FROM (SELECT "max"("T1"."entry") "e", "T1"."url", "T1"."branch" FROM "repo_history" "T1"
|
c = conn.cursor()
|
||||||
WHERE (SELECT "active" FROM "repos" "T2" WHERE "url" = "T1"."url" AND "branch" IS "T1"."branch" AND "project" IS ?1)
|
p = Project(conn, instance, project_commit, list_repos=True)
|
||||||
GROUP BY "T1"."url", "T1"."branch"
|
# FIXME: this should be moved into Project.update()
|
||||||
UNION
|
for repo in p.repos:
|
||||||
SELECT null, "T3"."url", "T3"."branch" FROM "repos" "T3" WHERE "active" AND "project" IS ?1)
|
result = repo.update()
|
||||||
GROUP BY "url" ORDER BY "e"''', (project,)):
|
|
||||||
result = handle_target(url, branch, project_commit)
|
|
||||||
if result is not None:
|
if result is not None:
|
||||||
count, post_hash, msg = result
|
count, post_hash, msg = result
|
||||||
entries.append((url, count, post_hash, branch, project))
|
entries.append((repo.url, count, post_hash, repo.branch, project))
|
||||||
generate_html.append((url, msg, count, branch))
|
generate_html.append((repo.url, msg, count, repo.branch))
|
||||||
|
p.refresh_metadata()
|
||||||
# sort stuff twice because reasons
|
# sort stuff twice because reasons
|
||||||
entries.sort(key=lambda x: x[1], reverse=True)
|
entries.sort(key=lambda x: x[1], reverse=True)
|
||||||
generate_html.sort(key=lambda x: x[2], reverse=True)
|
generate_html.sort(key=lambda x: x[2], reverse=True)
|
||||||
|
@ -334,20 +512,16 @@ def cron_target(project):
|
||||||
history = c.execute('''SELECT "count" FROM "repo_history" WHERE "url" = ? AND "branch" IS ? AND "project" IS ? ORDER BY "entry" ASC''', (url, branch, project)).fetchall()
|
history = c.execute('''SELECT "count" FROM "repo_history" WHERE "url" = ? AND "branch" IS ? AND "project" IS ? ORDER BY "entry" ASC''', (url, branch, project)).fetchall()
|
||||||
# TODO process history into SVG
|
# TODO process history into SVG
|
||||||
html_entries.append((url, msg, "", branch))
|
html_entries.append((url, msg, "", branch))
|
||||||
template = jinja2.Template(TEMPLATE)
|
template = env.get_template('project.html')
|
||||||
import re
|
click.echo(template.render(project_title = p.title,
|
||||||
project = subprocess.check_output(["git", "-C", cache_home, "show", project_commit, "-s", "--format=%B", "--"], stderr=subprocess.DEVNULL).decode("utf-8", "replace")
|
project_desc = p.description,
|
||||||
project_title, project_desc = (lambda x: x.groups() if x is not None else ('', None))(re.fullmatch('^\\[Project\\]\s+(.+?)(?:\n\n(.+))?$', project, flags=re.ASCII|re.DOTALL|re.IGNORECASE))
|
project_body = p.commit_body,
|
||||||
if not project_title.strip():
|
project_commit = p.commit,
|
||||||
project_title, project_desc = ("Error parsing project commit",)*2
|
|
||||||
if project_desc:
|
|
||||||
project_desc = project_desc.strip()
|
|
||||||
click.echo(template.render(project_title = project_title,
|
|
||||||
project_desc = project_desc,
|
|
||||||
project_body = project,
|
|
||||||
project_commit = project_commit,
|
|
||||||
repos = html_entries,
|
repos = html_entries,
|
||||||
base_url = base_url))
|
base_url = base_url,
|
||||||
|
# I don't think this thing supports deprecating the above?
|
||||||
|
project = p,
|
||||||
|
ganarchy = instance))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
ganarchy()
|
ganarchy()
|
||||||
|
|
Loading…
Reference in New Issue