Skip to content

Commit fc308e1

Browse files
EDUX CI initial deployment (#3)
* Init deploy DW script Initiating deployment script for dokuwiki. It should be used in the future to automatically transform and upload pages to Edux system from CI. Inspired by cvut/MI-PYT course. * Init deploy DW script Initiating deployment script for dokuwiki. It should be used in the future to automatically transform and upload pages to Edux system from CI. Inspired by cvut/MI-PYT course. * Filters for enhancing transformation Added filters to the app. One for interlinking local documents and second for Haskell syntax highlighting which was not provided by default (need to make use of Pascal there). * Try to setup CI with envvars * Simplify Travis config * Try install pandoc from .deb * Just master branch will be deployed
1 parent fc7470a commit fc308e1

6 files changed

Lines changed: 417 additions & 0 deletions

File tree

.gitignore

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
.Python
11+
build/
12+
develop-eggs/
13+
dist/
14+
downloads/
15+
eggs/
16+
.eggs/
17+
lib/
18+
lib64/
19+
parts/
20+
sdist/
21+
var/
22+
wheels/
23+
*.egg-info/
24+
.installed.cfg
25+
*.egg
26+
MANIFEST
27+
28+
# PyInstaller
29+
# Usually these files are written by a python script from a template
30+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
31+
*.manifest
32+
*.spec
33+
34+
# Installer logs
35+
pip-log.txt
36+
pip-delete-this-directory.txt
37+
38+
# Unit test / coverage reports
39+
htmlcov/
40+
.tox/
41+
.coverage
42+
.coverage.*
43+
.cache
44+
nosetests.xml
45+
coverage.xml
46+
*.cover
47+
.hypothesis/
48+
49+
# Translations
50+
*.mo
51+
*.pot
52+
53+
# Django stuff:
54+
*.log
55+
.static_storage/
56+
.media/
57+
local_settings.py
58+
59+
# Flask stuff:
60+
instance/
61+
.webassets-cache
62+
63+
# Scrapy stuff:
64+
.scrapy
65+
66+
# Sphinx documentation
67+
docs/_build/
68+
69+
# PyBuilder
70+
target/
71+
72+
# Jupyter Notebook
73+
.ipynb_checkpoints
74+
75+
# pyenv
76+
.python-version
77+
78+
# celery beat schedule file
79+
celerybeat-schedule
80+
81+
# SageMath parsed files
82+
*.sage.py
83+
84+
# Environments
85+
.env
86+
.venv
87+
env/
88+
venv/
89+
ENV/
90+
env.bak/
91+
venv.bak/
92+
93+
# Spyder project settings
94+
.spyderproject
95+
.spyproject
96+
97+
# Rope project settings
98+
.ropeproject
99+
100+
# mkdocs documentation
101+
/site
102+
103+
# mypy
104+
.mypy_cache/
105+
106+
# IDE
107+
.idea

.travis.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
language: python
2+
python:
3+
- '3.5'
4+
sudo: true
5+
dist: trusty
6+
install:
7+
- wget https://github.com/jgm/pandoc/releases/download/2.1.1/pandoc-2.1.1-1-amd64.deb
8+
- sudo dpkg -i pandoc-2.1.1-1-amd64.deb
9+
- pip install -r bin/requirements.txt
10+
script:
11+
- python bin/dw_deploy.py tutorials
12+
branches:
13+
only:
14+
- master
15+
env:
16+
global:
17+
- DW_URL: https://edux.fit.cvut.cz/courses/MI-AFP
18+
- DW_NAMESPACE: tutorials:master
19+
- DW_USERNAME: suchama4
20+
- secure: kfeUcNiJ/wCzae4fSgi6m4dze44izWh3g9Yx/jpkwOeoAvEd1K7wf20dUs1dLclBCDechD2x5zjyomSJhg8zkpqDn0/6y/0Q2qtuLHcIihUybnaBg1y0OzvynPfhb9tm6ZxifvwfHPt3KmJ8QZP7EgWzXWoUpu2grrOEDVHza/K5PIyCq+TiK2NGfko/FQmpUKHYeLtcFt/gkX1KfZAJYWbcjWVkt1hhQmFH4w4eh5I4NQk+yvI8LoDzYm/b0XHtd5CCQZ+VOGoM8eKmNfDgmlIKQn6bPQHZUh57iJ7P2HEO5xfXn64fNPshEkqLgXdjRbYIo8kljRBHBkjsu0jfy3w9jCDpJR9FFAJS5ZmMfIiMrrFvbPPjmwXOAMt+ExF/lkJpp1idJoET/JLlz/GSgKdvFQGX3tDG9cNKbvNbUOd03g+FdL9Nh03HhYyFpxat94vZDK8tvm9ctTcF7dg2cW49qSa4OKp+YdBkhFvNPx3M7S5fQ+ODRFoeFhlJt2YMgW1iw8o5o77mPWTN2cGkeXeM6W4+PkN3R10nTOe2H7ZN6N+5u1NBXWCqtzit2Cq9lDSuDjRZwMhwA1znuoBtM4n1Qtz9qFov+48sZIPTk/pqHLVTF6wGpHpT5Hi65XHWqKQsjVM1+2W9dWIB+jhidKi0TlSkwBKQhQlygh7E7sQ=

bin/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
set_env.sh

bin/dw_deploy.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# Markdown to DW deployment script
2+
# inspired by https://github.com/cvut/MI-PYT
3+
import os
4+
import re
5+
6+
import click
7+
import pypandoc
8+
import requests
9+
10+
from lxml import etree
11+
12+
13+
def prefilter_haskellcode(input_md):
14+
"""Make use of pascal to enable haskell code highlighting (in md)"""
15+
return input_md.replace('```haskell', '```pascal')
16+
17+
18+
def postfilter_haskellcode(output_dw):
19+
"""Make use of pascal to enable haskell code highlighting (in dw)"""
20+
return output_dw.replace('<code pascal>', '<code haskell>')
21+
22+
23+
def prefilter_interlinking(input_md):
24+
"""Removed md from local interlinked documents in the same directory"""
25+
return re.sub(r'\[([^\]]*)]\(([^\)\/]*)\.md\)', r'[\1](\2)', input_md)
26+
27+
28+
class DW:
29+
PREFILTERS = [
30+
prefilter_haskellcode,
31+
prefilter_interlinking
32+
]
33+
POSTFILTERS = [
34+
postfilter_haskellcode
35+
]
36+
37+
def __init__(self, url, username, password):
38+
self.url = url + '/doku.php'
39+
self.session = self._init_session(username, password)
40+
41+
@staticmethod
42+
def _find_elem(content, type, attr, value):
43+
tree = etree.HTML(content)
44+
for elem in tree.findall('.//' + type):
45+
if elem.attrib.get(attr) == value:
46+
return elem
47+
return None
48+
49+
def _init_session(self, username, password):
50+
session = requests.Session()
51+
52+
params = {'id': 'start', 'do': 'login'}
53+
r = session.get(self.url, params=params)
54+
sectok_input = self._find_elem(r.text, 'input', 'name', 'sectok')
55+
if sectok_input is None:
56+
raise ValueError('Could not find sectok on login page')
57+
58+
sectok = sectok_input.attrib.get('value', '')
59+
login_data = {
60+
'sectok': sectok,
61+
'id': 'start',
62+
'do': 'login',
63+
'authnProvider': '2',
64+
'u': username,
65+
'p': password,
66+
'r': '1',
67+
}
68+
params['sectok'] = sectok
69+
r = session.post(self.url, params=params, data=login_data)
70+
if 'logout' not in r.text:
71+
raise ValueError('Could not login')
72+
73+
return session
74+
75+
def put_page(self, dw_page, content):
76+
params = {'id': dw_page, 'do': 'edit'}
77+
r = self.session.get(self.url, params=params)
78+
79+
edit_form = self._find_elem(r.text, 'form', 'id', 'dw__editform')
80+
if edit_form is None:
81+
raise ValueError('Could not find edit form on parsed page')
82+
83+
data = {}
84+
for inp in edit_form.findall('.//input'):
85+
name = inp.attrib.get('name')
86+
if not name.startswith('do['):
87+
data[name] = inp.attrib.get('value', '')
88+
89+
data['wikitext'] = content
90+
data['do[save]'] = 'Yes, please!'
91+
92+
self.session.post(r.url, data=data)
93+
94+
def put_md(self, dw_page, file):
95+
self.put_page(dw_page, self._transform_md2dw(file))
96+
97+
@classmethod
98+
def _transform_md2dw(cls, file):
99+
with open(file, mode='r') as f:
100+
content = f.read()
101+
content = cls._apply_filters(cls.PREFILTERS, content)
102+
content = pypandoc.convert_text(content, 'dokuwiki', format='md')
103+
content = cls._apply_filters(cls.POSTFILTERS, content)
104+
return content
105+
106+
@staticmethod
107+
def _apply_filters(filters, text):
108+
for flt in filters:
109+
text = flt(text)
110+
return text
111+
112+
@staticmethod
113+
def join(*args):
114+
return ':'.join(args)
115+
116+
117+
def get_files(root, extension):
118+
files = dict()
119+
ext_mlen = -len(extension)
120+
for file in os.listdir(root):
121+
path = os.path.join(root, file)
122+
if os.path.isfile(path) and file.endswith(extension):
123+
files[file[0:ext_mlen]] = path
124+
return files
125+
126+
127+
@click.command()
128+
@click.argument('root', type=click.Path(exists=True))
129+
@click.option('-d', '--dw-url', help='DokuWiki URL',
130+
envvar='DW_URL', required=True)
131+
@click.option('-u', '--dw-username', help='DokuWiki username',
132+
envvar='DW_USERNAME', required=True)
133+
@click.option('-p', '--dw-password', help='DokuWiki password',
134+
envvar='DW_PASSWORD', required=True)
135+
@click.option('-n', '--dw-namespace', help='Target DokuWiki namespace',
136+
envvar='DW_NAMESPACE', required=True)
137+
def cli(root, dw_url, dw_username, dw_password, dw_namespace):
138+
dw = DW(dw_url, dw_username, dw_password)
139+
markdowns = get_files(root, '.md')
140+
print('Deploying {} markdown file(s) to {}'.format(
141+
len(markdowns), dw_url
142+
))
143+
for name, file in markdowns.items():
144+
qname = dw.join(dw_namespace, name)
145+
print('| ', file, '-->', qname)
146+
dw.put_md(qname, file)
147+
print('Done!')
148+
149+
150+
if __name__ == '__main__':
151+
cli()

bin/requirements.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
click
2+
lxml
3+
pypandoc
4+
requests

0 commit comments

Comments
 (0)