Replace

Wiki Replacement

Problems with Pmwiki

  1. Pmwiki metadata is stored along with content in pmwiki's files. This makes it very difficult to parse.
  2. Pmwiki is no longer actively maintained
  3. Pmwiki depends upon PHP which we lack a developer community for
  4. Pmwiki's markup is not very popular or familiar to new users
  5. Pmwiki is limited to web only, but we will need to offer access to multiple protocols like gopher, email, and telnet to avoid censorship

Strict Requirements

  1. Support basic functionality for older web browsers like w3m, lynx, netsurf, dillo, mothra. Users must be able to at least read wiki pages, and preferably write/administrate. These browsers have limited javascript support, or none at all.
  2. Avoid unreasonable privacy or censorship concerns. Google Go should be avoided because of the potential for always-on telemetry, and because Google has the ability to ban entire countries like Iran and Russia.
  3. Do not require the use of any SQL or noSQL databases. Keep it optional.
  4. Revision control should be handled by a separate utility rather than by the wiki itself. (For example, use got or CVS for versioning)
  5. The code should be simple enough so our teammates can regularly maintain and contribute to it.
  6. User-written content should be stored in plain text files in a simple markup language.
  7. It must be possible for users to be able to read and write articles outside of the web
  8. It must be possible for users to be able to administrate the wiki from outside of the web
  9. Follow the principles of progressive enhancement. Core functionality should be present for users with limited clients, and extra functionality can be available for users with more featureful clients.
  10. Web contributors must be allowed to provide extra web functionality.

Preferences

  1. For languages, perl, C, korn shell, and lisp are preferred because that is what our network will actively teach
  2. Using got for revision control is preferred because it is an openbsd project and avoids the complexity of git
  3. Prefer John Gruber's markdown (https://daringfireball.net/projects/markdown/) because it is simple and well known by many users

Possible Solution:

  1. Consider switching the web wiki to ikiwiki or something similar. Ikiwiki uses a proper revision control system (could be git or got). It is written in perl, which our network will have developers for
  2. A pmwiki markup to markdown translator will be needed to obtain the markdownfiles for the new wiki.

Proposed Markdown:

  1. start with what ikiwiki already has for the base: https://ikiwiki.info/ikiwiki/
  2. I have created a possible parser that takes pmwiki files and converts to markdown.
  3. pmWiki Cookbook to produce markdown output https://www.pmwiki.org/wiki/Cookbook/MarkdownOutput
  4. pmwiki2markdown parser
    import sys, re, os

    def read_file(filename):
        data = {}
        with open(filename, 'r') as f:
            for line in f:
                line = line.strip()
                if '=' in line:
                    # ignores the diff values
                    if ':' in line and '=' in line and line.index(':') < line.index('='):
                        break
                    else:
                        key, value = line.split('=', 1)
                        data[key] = value
                elif line == '':
                    break
        return data

    def create_markdown(filename):
        print(f"--- {filename} ---")
        # Read the data from the file
        data=read_file(filename)

        title = ""
        text = ""

        # Extract the relevant information
        #if 'title' in data.keys():
        #    title=data['title']
        if 'text' in data.keys():
            text=data['text']

        # Perform pmwiki-to-markdown replacements

        text = text.replace("%0a","\n")
        markdown_text = (
            text.replace("\n\n", "\n")
                .replace("\n", "\n\n")
                .replace("'''", "**")
                .replace("''", "_")
                .replace("[@","##STARTCODEBLOCK##\n")
                .replace("@]","##ENDCODEBLOCK##\n")
                .replace("!!! ","### ")
                .replace("!! ","## ")
                .replace("! ","# ")
                .replace("@@","`")
        )

        # Replace the title text with a # heading
        markdown_text =  re.sub(r'^\(:title (.*?)\:\)$', r'# \1', markdown_text, flags=re.MULTILINE)

        markdown_text = markdown_text.split("\n")
        codeblock=0
        index_to_be_removed = []
        for index,value in enumerate(markdown_text):
            if(value =="##STARTCODEBLOCK##"):
                index_to_be_removed.append(index)
                codeblock=1
            elif(value =="##ENDCODEBLOCK##"):
                index_to_be_removed.append(index)
                codeblock=0
            else:
                if(codeblock==1):
                    markdown_text[index] = "    "+value

        # Reversing Indices List
        indicesList = sorted(index_to_be_removed, reverse=True)

        # Traversing in the indices list
        for indx in indicesList:

            # checking whether the corresponding iterator index is less than the list length
            if indx < len(markdown_text):

                # removing element by index using pop() function
                markdown_text.pop(indx)

        markdown_text = "\n".join(markdown_text)

        #change the wikilinks to ikiwiki format
        # Instead of [[link|text to display]] make it [text to display||link]
        markdown_text = re.sub(r'\[\[(.*?)\|(.*?)\]\]', r'[[\2|\1]]', markdown_text)

        return markdown_text

    name = sys.argv[1]
    if(len(name.split("."))>1):
        folder_name,file_name = name.split(".")
        if(not os.path.exists(os.path.join("output",folder_name.lower()))):
            os.makedirs(os.path.join("output",folder_name.lower()))
        with open(os.path.join("output",folder_name.lower(),f"{file_name.lower()}.mdwn"),'w+') as output:
            output.write(create_markdown(name))
    else:
        with open(os.path.join("output",f"{name}.mdwn"),'w+') as output:
            output.write(create_markdown(name))