DokuWiki

It's better when it's simple

User Tools

Site Tools


Sidebar

Translations of this page?:

Learn about DokuWiki

Advanced Use

Corporate Use

Our Community


Follow us on Facebook, Twitter and other social networks.

tips:edit_dokuwiki_with_text_editors_using_fuse_and_python

Here's some Python source that implements basic FUSE support for editing Wiki pages. It's horribly incomplete and almost fully untested, but appears to work for my testcases. Feel free to extend. No warranty, explicitly reject any possible claims of copyright, etc. Have fun!

#!/usr/bin/env python
 
# This file was originally xmp.py
# Now, only the header survives.
 
import os, sys
from errno import *
from stat import *
from urllib2 import *
from urllib import urlencode
from cookielib import CookieJar
from array import array
from BeautifulSoup import BeautifulStoneSoup
import fcntl
 
import fuse
from fuse import Fuse
 
 
if not hasattr(fuse, '__version__'):
    raise RuntimeError, \
        "your fuse-py doesn't know of fuse.__version__, probably it's too old."
 
fuse.fuse_python_api = (0, 2)
 
# We use a custom file class
fuse.feature_assert('stateful_files', 'has_init')
 
def path2url(path):
	murl = path[1:].split("/")
	return "http://"+"/".join(murl[:-1])+"/doku.php?id="+murl[-1][1:]+"&do=edit"
 
def between(text, a, b):
	apos = text.find(a)
	if apos == -1: return None
	text = text[apos + len(a):]
	bpos = text.find(b)
	if bpos == -1: return None
	return text[:bpos]
 
def acquire(url):
	data = urlopen(url).read()
	res = array('c')
	res.fromstring((BeautifulStoneSoup(data, fromEncoding="utf-8", convertEntities = BeautifulStoneSoup.HTML_ENTITIES).find('textarea', id='wiki__text').contents[0][1:]).encode("utf-8"))
	return res
 
def post(url, posturl, data):
	cook = CookieJar()
	op = build_opener(HTTPCookieProcessor(cook))
	page = op.open(url).read()
	bs = BeautifulStoneSoup(page, convertEntities = BeautifulStoneSoup.HTML_ENTITIES)
	values={}
	def copy(name):
		values[name] = bs.find('input', attrs={'name': name})['value']
	copy('sectok')
	copy('id')
	copy('date')
	copy('prefix')
	copy('suffix')
	copy('changecheck')
	values['wikitext'] = data
	values['do[save]'] = 'Save'
	values['summary'] = ''
	values['minoredit'] = None
	return op.open(Request(posturl, urlencode(values))).read()
 
# was Xmp, shamelessly ripped off
class DokuFucker(Fuse):
 
    def __init__(self, *args, **kw):
 
        Fuse.__init__(self, *args, **kw)
	self.file_class = self.DokuPage
	self.removed = {}
 
    def getattr(self, path):
	# print "O hai '{0}' has {1}".format(path, path.find("/?"))
	if (path.find("/?") != -1):
		t = fuse.Stat()
		t.st_mode = S_IFREG | 0444
		t.st_dev = 0
		t.st_blksize = 0
		t.st_nlink = 1
		# masked for recreation
		if path in self.removed:
			t.st_size = 0
			del self.removed[path]
		else: t.st_size = len(acquire(path2url(path)))
		return t
	else:
		t = fuse.Stat()
		t.st_mode = S_IFDIR | 0755
		t.st_dev = 0
		t.st_blksize = 0
		t.st_nlink = 2
		t.st_size = 0
		return t
 
    def readdir(self, path, offset):
	if path == "/":
		yield fuse.Direntry(".")
		yield fuse.Direntry("..")
		yield fuse.Direntry("test2")
 
    def chmod(self, path, mode):
        return 0 # No-op
 
    def chown(self, path, user, group):
        return 0 # No-op
 
    def truncate(self, path, len):
	# print "Trying to truncate {0} to {1}".format(path, len)
	self.removed[path] = True
	return 0
 
    def unlink(self, path):
	self.removed[path] = True
 
    class DokuPage(object):
 
        def __init__(self, path, flags, *mode):
		# print "Path: " + path
		murl = path[1:].split("/")
		self.url = "http://"+"/".join(murl[:-1])+"/doku.php?id="+murl[-1][1:]+"&do=edit"
		self.posturl = "http://"+"/".join(murl[:-1])+"/doku.php"
		if path in server.removed:
			self.data = ''
			del server.removed[path]
		else:
			self.data = acquire(self.url)
		self.modified = False
		# print "URL: {0}; length {1}".format(self.url, len(self.data))
 
        def read(self, length, offset):
		if offset > len(self.data): return ""
		if offset <= len(self.data) and offset + length > len(self.data): length = len(self.data) - offset
		# print "Read {0} at {1} from {2}".format(length, offset, len(self.data))
		return self.data[offset:offset+length].tostring()
 
        def write(self, buf, offset):
		# if we already have data and try to overwrite it
		# or if we don't have data but try to start at an offset
		# bad things happen
		if (bool(len(self.data)) ^ bool(offset)) or len(self.data) != offset:
			if not offset:
				print "It is my hope that this is the editor starting over. "
				print "Based on that hope I will now erase my internal datastore. "
				print "If I'm wrong, you get data loss. "
				print "So you'd better hope I'm right. >_>"
				self.data = array('c')
			else:
				print "This mode cannot be supported safely! {0} into {1} at {2} ".format(len(buf), len(self.data), offset)
				print "Evidently, my hope that modern editors don't do this, was misplaced. "
				return -EINVAL
 
		self.modified = True
		self.data.extend(buf);
		return len(buf)
 
	def flush(self):
		# POST now
		if self.modified:
			res = post(self.url, self.posturl, self.data.tostring())
 
server = DokuFucker(version="%prog " + fuse.__version__)
server.parse(values=server, errex=1)
server.main()
tips/edit_dokuwiki_with_text_editors_using_fuse_and_python.txt · Last modified: 2010-04-11 09:19 by 79.213.76.201