aboutsummaryrefslogtreecommitdiffstats
path: root/divergence
diff options
context:
space:
mode:
Diffstat (limited to 'divergence')
-rwxr-xr-xdivergence151
1 files changed, 151 insertions, 0 deletions
diff --git a/divergence b/divergence
new file mode 100755
index 0000000..f72d4db
--- /dev/null
+++ b/divergence
@@ -0,0 +1,151 @@
+#!/usr/bin/env python3
+"""
+License: MIT
+Author: Bryan Newbold <bnewbold@archive.org>
+Date: July 2017
+
+See README
+"""
+
+from __future__ import print_function
+import sys, os
+import argparse
+import requests
+import subprocess
+import logging as log
+
+
+class DivergenceProgram:
+
+ def __init__(self, user, password, url, space):
+ self.api = requests.Session()
+ self.api.auth = (user, password)
+ self.api.headers.update({'Content-Type': 'application/json'})
+ self.base_url = url
+ self.space = space
+
+ # TODO: find lua path?
+
+ def get_page(self, title):
+ """
+ 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,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"
+
+ return {"id": int(page['id']),
+ "version": int(page['version']['number']),
+ "space": page['space']['key'],
+ "body": page['body']['storage']['value']}
+
+ def create_page(self, title, body):
+ resp = self.api.post(self.base_url + "/rest/api/content",
+ json={"space": { "key": self.space },
+ "type": "page",
+ "title": title,
+ "body": {
+ "storage": {
+ "representation": "storage",
+ "value": body } } } )
+ log.debug(resp)
+ log.debug(resp.content)
+ assert resp.status_code == 200
+
+ def update_page(self, title, body, page_id, prev_version):
+ resp = self.api.put(self.base_url + "/rest/api/content/%d" % page_id,
+ json={"type": "page",
+ "title": title,
+ "version": {"number": prev_version+1},
+ "body": {
+ "storage": {
+ "representation": "storage",
+ "value": body } } } )
+ log.debug(resp)
+ log.debug(resp.content)
+ assert resp.status_code == 200
+
+ def title_from_path(self, path):
+ title = path.split('.')[0].replace('_', ' ')
+ # TODO: only alphanum and spaces?
+ return title
+
+ def convert(self, f):
+ proc = subprocess.run(["pandoc", "-t", "pandoc_confluence.lua", f],
+ stdout=subprocess.PIPE)
+ assert proc.returncode == 0
+ return proc.stdout.decode('UTF-8')
+
+ def run(self, files):
+
+ for f in files:
+ title = self.title_from_path(f)
+ log.debug(title)
+ body = self.convert(f)
+ prev = self.get_page(title)
+ log.debug(prev)
+ if prev is None:
+ self.create_page(title, body)
+ print(f + ": created")
+ else:
+ if prev['body'] != body:
+ self.update_page(title, body, prev['id'], prev['version'])
+ print(f + ": updated")
+ else:
+ print(f + ": no change")
+
+def main():
+ parser = argparse.ArgumentParser(
+ description="""
+Simple Markdown-to-Confluence uploader, using pandoc and the Confluence REST
+API.
+
+Specify credentials and site URL with environment variables:
+ CONFLUENCE_USER
+ CONFLUENCE_PASSWORD
+ CONFLUENCE_URL
+""")
+ #usage="%(prog)s [options] -s <space-key> <files>")
+ parser.add_argument("-v", "--verbose",
+ action="count",
+ default=0,
+ help="Show more debugging statements (can be repeated)")
+ parser.add_argument("-s", "--space-key",
+ required=True,
+ help='Confluence Space Key (usually like "PROJ" or "~username")')
+ parser.add_argument("FILE", nargs='+')
+
+ args = parser.parse_args()
+
+ if args.verbose > 0:
+ log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
+ else:
+ log.basicConfig(format="%(levelname)s: %(message)s")
+
+ try:
+ user = os.environ['CONFLUENCE_USER']
+ password = os.environ['CONFLUENCE_PASSWORD']
+ url = os.environ['CONFLUENCE_URL']
+ except KeyError:
+ parser.exit(-1, "Need to pass environment variable configs")
+
+ if url.endswith('/'):
+ url = url[:-1]
+
+ dp = DivergenceProgram(user, password, url, args.space_key)
+ dp.run(args.FILE)
+
+if __name__ == '__main__':
+ main()