From c88a5eee8db078d2032d040b4d45fbb1e4e617d4 Mon Sep 17 00:00:00 2001 From: bnewbold Date: Sun, 16 Jul 2017 15:30:28 -0700 Subject: final feature adds and updates for now --- TODO.md | 7 +--- divergence | 108 +++++++++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 88 insertions(+), 27 deletions(-) diff --git a/TODO.md b/TODO.md index fa4db51..5de919e 100644 --- a/TODO.md +++ b/TODO.md @@ -1,10 +1,5 @@ TODO: -- extract title, and/or page ID from pandoc yaml header. maybe even space? -- update checking doesn't actually work -- fuzzy page title matching bug -- optional header (flag) -- optional table of contents (flag) -- "force update" (flag) +- cleanup asserts into proper exceptions Nice to have, but unlikely to be implemented: - more than just markdown (restructured text, html, etc) diff --git a/divergence b/divergence index f35b098..e54805f 100755 --- a/divergence +++ b/divergence @@ -4,11 +4,12 @@ License: MIT Author: Bryan Newbold Date: July 2017 -See README +See README.md and LICENSE. """ from __future__ import print_function import re +import json import sys, os import difflib import argparse @@ -19,13 +20,20 @@ import logging as log class DivergenceProgram: - def __init__(self, user, password, url, space, force_update=False): + def __init__(self, user, password, url, space, + force_update=False, + include_toc=False, + include_header=True): self.api = requests.Session() self.api.auth = (user, password) self.api.headers.update({'Content-Type': 'application/json'}) self.base_url = url - self.space = space + self.default_space = space self.force_update = force_update + self.include_toc = include_toc + self.include_header = include_header + # TODO: clean up this code duplication... use pandoc data directory + # instead? self.pandoc_helper_path = None for p in ('./pandoc_confluence.lua', '/usr/local/lib/divergence/pandoc_confluence.lua', @@ -36,26 +44,48 @@ class DivergenceProgram: if self.pandoc_helper_path is None: log.error("Could not find pandoc helper (pandoc_confluence.lua), bailing") sys.exit(-1) + self.pandoc_meta_path = None + for p in ('./meta-json.template', + '/usr/local/lib/divergence/meta-json.template', + '/usr/lib/divergence/meta-json.template'): + if os.path.exists(p): + self.pandoc_meta_path = p + break + if self.pandoc_meta_path is None: + log.error("Could not find pandoc helper (meta-json.template), bailing") + sys.exit(-1) - def get_page(self, title): + def get_page(self, title, space_key=None, page_id=None): """ Returns None if not found, otherwise a dict with id, space, and body (in storage format) """ - resp = self.api.get(self.base_url + "/rest/api/content", - params={"spaceKey": self.space, - "title": title, - "expand": "body.storage,body.editor,version,space", - "type": "page"}) + if space_key is None: + space_key = self.default_space + if not page_id: + resp = self.api.get(self.base_url + "/rest/api/content", + params={"spaceKey": space_key, + "title": title, + "expand": "body.storage,body.editor,version,space", + "type": "page"}) + else: + resp = self.api.get(self.base_url + "/rest/api/content/%d" % int(page_id), + params={"expand": "body.storage,body.editor,version,space", + "type": "page"}) log.debug(resp) log.debug(resp.content) assert resp.status_code == 200 respj = resp.json() - if respj['size'] == 0: - return None - assert respj['size'] == 1, "Expect single result for title lookup" - page = respj['results'][0] - assert page['space']['key'].upper() == self.space.upper(), "Expect spaces to match" + if not page_id: + if respj['size'] == 0: + assert page_id is None, "Couldn't fetch given page id" + return None + assert respj['size'] == 1, "Expect single result for title lookup" + page = respj['results'][0] + else: + # We did a fetch by page_id directly + page = respj + assert page['space']['key'].upper() == space_key.upper(), "Expect spaces to match" return {"id": int(page['id']), "version": int(page['version']['number']), @@ -76,9 +106,11 @@ class DivergenceProgram: assert resp.status_code == 200 return resp.json()['value'] - def create_page(self, title, body): + def create_page(self, title, body, space_key=None): + if space_key is None: + space_key = self.default_space resp = self.api.post(self.base_url + "/rest/api/content", - json={"space": { "key": self.space }, + json={"space": { "key": space_key }, "type": "page", "title": title, "body": { @@ -111,7 +143,26 @@ class DivergenceProgram: proc = subprocess.run(["pandoc", "-t", self.pandoc_helper_path, f], stdout=subprocess.PIPE) assert proc.returncode == 0 - return proc.stdout.decode('UTF-8') + body = proc.stdout.decode('UTF-8') + if self.include_toc: + body = """ + 1 + 3 +""" + body + if self.include_header: + body = """ + +

This page was generated automatically from Markdown using the + 'divergence' tool. Edits will need to be merged manually.

+
+
\n""" + body + return body + + def metadata(self, f): + proc = subprocess.run(["pandoc", "--template", self.pandoc_meta_path, f], + stdout=subprocess.PIPE) + assert proc.returncode == 0 + return json.loads(proc.stdout.decode('UTF-8')) def strip_tags(self, text): """ @@ -122,13 +173,19 @@ class DivergenceProgram: def run(self, files): for f in files: - title = self.title_from_path(f) + meta = self.metadata(f) + title = meta.get('confluence-page-title', + self.title_from_path(f)) + space_key = meta.get('confluence-space-key', + self.default_space) + page_id = meta.get('confluence-page-id') log.debug(title) body = self.convert(f) - prev = self.get_page(title) + prev = self.get_page(title, space_key=space_key, page_id=page_id) log.debug(prev) + log.debug(self.metadata(f)) if prev is None: - self.create_page(title, body) + self.create_page(title, body, space_key=space_key) print(f + ": created") else: prev_body = self.strip_tags(prev['body_editor']) @@ -168,6 +225,12 @@ required environment variables: parser.add_argument("-f", "--force", action='store_true', help='Forces an update even if we think nothing has changed') + parser.add_argument("--no-header", + action='store_true', + help='Disables inserting disclaimer headers into the confluence document') + parser.add_argument("--toc", + action='store_true', + help='Inserts table-of-contents into the confluence document') parser.add_argument("FILE", nargs='+') args = parser.parse_args() @@ -202,7 +265,10 @@ required environment variables: parser.exit(-1, "This script depends on 'pandoc', which doesn't " "seem to be installed.\n") - dp = DivergenceProgram(user, password, url, args.space_key, force_update=args.force) + dp = DivergenceProgram(user,password, url, args.space_key, + force_update=args.force, + include_header=not args.no_header, + include_toc=args.toc) dp.run(args.FILE) if __name__ == '__main__': -- cgit v1.2.3