summaryrefslogtreecommitdiff
path: root/filter.json
AgeCommit message (Expand)Author
2021-06-02First cut at project-independent version of these scriptsRob Austein
16'>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 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
#!/usr/bin/env python3

import fnmatch
import hashlib
import json
import os
import shutil
import sqlite3
import sys
import time
import urllib.parse
import argparse

import trac2md

wiki_query = '''
  SELECT
    name, 
    author,
    version, 
    time / 1000000 AS time, 
    text 
  FROM wiki
  ORDER BY
    name, version
'''

attachment_query = '''
  SELECT
    id,
    filename,
    size,
    author,
    description,
    ipnr,
    time / 1000000 AS createdtime
  FROM
    attachment
  WHERE
    type = 'wiki'
  ORDER BY
    filename, time
'''

def attachment_link(row):
    h   = lambda whatever: hashlib.sha1(whatever.encode()).hexdigest()
    h1  = h(row.id)
    h2  = h(row.filename)
    fn2 = os.path.splitext(row["filename"])[1]
    return \
        os.path.join("attachments", "wiki", h1[:3], h1, h2 + fn2), \
        os.path.join("pelican", "content", row.id, row.filename)

class Filter:

    def __init__(self, filename = "tools/filter.json"):
        with open(filename) as f:
            filter = json.load(f)
        if not all(action in "-+" for action, pattern in filter):
            sys.exit("Bad action \"{}\" in filter".format(action))
        self.filter = tuple((action == "+", pattern) for action, pattern in filter)

    def __call__(self, name):
        for action, pattern in self.filter:
            if fnmatch.fnmatch(name, pattern):
                return action
        return True

class Row(sqlite3.Row):

    def __getattr__(self, name):
        return self[name]

    @property
    def isotime(self):
        return time.strftime("%Y-%m-%d %H:%M", time.gmtime(self.time))

def markdown_header(row, first_published):
    if row.name in first_published:
        modtime = "Modified: {}\n".format(row.isotime)
    else:
        modtime = ""
        first_published[row.name] = row.isotime
    return "Title: {}\nAuthor: {}\nDate: {}\n{}\n".format(row.name, row.author, first_published[row.name], modtime)

def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--source-url")
    args = ap.parse_args()

    for dn in ("wiki", "pelican"):
        if os.path.exists(dn):
            shutil.rmtree(dn)

    for dn in ("wiki", "pelican/content"):
        os.makedirs(dn)

    os.link("pelicanconf.py", "pelican/pelicanconf.py")

    wiki_to_markdown = trac2md.Trac2Markdown(args.source_url)

    keep = Filter()

    first_published = {}

    db = sqlite3.connect("trac.db")
    db.row_factory = Row

    for row in db.execute(wiki_query):
        if keep(row.name):
            with open("wiki/{}.trac".format(urllib.parse.quote(row.name, "")), "w") as f:
                f.write(row.text)
            md = markdown_header(row, first_published) + wiki_to_markdown(row.text, row.name)
            fn = "pelican/content/{}.md".format(row.name)
            dn = os.path.dirname(fn)
            if not os.path.exists(dn):
                os.makedirs(dn)
            with open(fn, "w") as f:
                f.write(md)

    for row in db.execute(attachment_query):
        src, dst = attachment_link(row)
        #print("{} => {}".format(dst, src))
        if not os.path.isdir(os.path.dirname(dst)):
            os.makedirs(os.path.dirname(dst))
        os.link(src, dst)

    db.close()

if __name__ == "__main__":
    main()