|
| 1 | +#!/usr/bin/env python |
| 2 | +""" |
| 3 | +A script to update footer links for all tutorial pages |
| 4 | +""" |
| 5 | + |
| 6 | +import sys,os,re |
| 7 | + |
| 8 | +class TutorialIndex(object): |
| 9 | + |
| 10 | + footermark = u"<!--automatically generated footer-->" |
| 11 | + |
| 12 | + def __init__(self,link,chapter=None,title=None,parent=None): |
| 13 | + """Create a new TutorialIndex |
| 14 | +
|
| 15 | + :param link: A link to this page, relative to parent's link |
| 16 | + :param chapter: The chapter number, e.g. "Chapter 5" |
| 17 | + :param title: The chapter title, e.g. "Writing Docstrings" |
| 18 | + :param parent: The TutorialIndex which references this one |
| 19 | + """ |
| 20 | + self.link = link |
| 21 | + self.chapter = chapter |
| 22 | + self.title = title |
| 23 | + self.parent = parent |
| 24 | + self.children = [] |
| 25 | + |
| 26 | + def parse(self): |
| 27 | + """Parse the index, add a footer, and do the same for each child |
| 28 | + found in the '# Index' section (if any). |
| 29 | +
|
| 30 | + Caution, this method overwrites any existing footer sections on this |
| 31 | + file and all children! |
| 32 | + """ |
| 33 | + |
| 34 | + #Recognise and parse "<CHAPTER>: (<TITLE>)[<LINK>]" |
| 35 | + indexentry = re.compile("^(.*)[:-].*\[([^]]*)\]\(([^)]*)\).*$") |
| 36 | + |
| 37 | + filename = self.rootlink() |
| 38 | + |
| 39 | + with open(filename,"rw+") as file: |
| 40 | + line = file.readline() |
| 41 | + had_footer=False |
| 42 | + |
| 43 | + # Parse file for index, truncate prior footer, and append footermark |
| 44 | + in_index = False |
| 45 | + while line: |
| 46 | + if line[0] == u"#": #That's a header, not a comment |
| 47 | + if u"index" in line.lower(): |
| 48 | + in_index = True |
| 49 | + else: |
| 50 | + in_index = False |
| 51 | + elif line.strip() == TutorialIndex.footermark: # Footer already! |
| 52 | + had_footer=True |
| 53 | + file.truncate() |
| 54 | + break |
| 55 | + elif in_index: |
| 56 | + # look for 'Chapter 1: [Title](link)' |
| 57 | + result = indexentry.match(line) |
| 58 | + if result: |
| 59 | + chapter,title,link = result.groups() |
| 60 | + child = TutorialIndex(link,chapter,title,self) |
| 61 | + self.children.append(child) |
| 62 | + |
| 63 | + line = file.readline() |
| 64 | + |
| 65 | + # Append footer |
| 66 | + if not had_footer: |
| 67 | + file.write(u"\n") |
| 68 | + file.write(TutorialIndex.footermark) |
| 69 | + file.write(u"\n") |
| 70 | + footer = self.makefooter() |
| 71 | + file.write(footer) |
| 72 | + |
| 73 | + # Recurse to children |
| 74 | + for child in self.children: |
| 75 | + child.parse() |
| 76 | + |
| 77 | + def rootlink(self): |
| 78 | + """Convert self.link to an absolute path relative to the root TutorialIndex |
| 79 | + :return: The path to this TutorialIndex relative to the root index |
| 80 | + """ |
| 81 | + if self.parent is None: |
| 82 | + return self.link |
| 83 | + parentlink = self.parent.rootlink() |
| 84 | + |
| 85 | + return os.path.join(os.path.dirname(parentlink),self.link) |
| 86 | + |
| 87 | + def makefooter(self): |
| 88 | + lines = ["---","","Navigation:"] |
| 89 | + # Iterate over parents |
| 90 | + p = self.parent |
| 91 | + linkmd = [self.makename()] #reverse order (self to root) |
| 92 | + while p is not None: |
| 93 | + name = p.makename() |
| 94 | + # Get a path to p relative to our own path |
| 95 | + link = os.path.relpath(p.rootlink(),os.path.dirname(self.rootlink())) |
| 96 | + linkmd.append("[{}]({})".format(name,link)) |
| 97 | + p = p.parent |
| 98 | + linkmd.reverse() |
| 99 | + lines.append("\n| ".join(linkmd)) |
| 100 | + |
| 101 | + lines.append("") |
| 102 | + |
| 103 | + if self.parent is not None: |
| 104 | + pos = self.parent.children.index(self) #Should always work |
| 105 | + if pos > 0: |
| 106 | + prev = self.parent.children[pos-1] |
| 107 | + name = prev.makename() |
| 108 | + link = os.path.relpath(prev.rootlink(),os.path.dirname(self.rootlink())) |
| 109 | + lines.append("Prev: [{}]({})".format(name,link)) |
| 110 | + lines.append("") |
| 111 | + if pos < len(self.parent.children)-1: |
| 112 | + next = self.parent.children[pos+1] |
| 113 | + name = next.makename() |
| 114 | + link = os.path.relpath(next.rootlink(),os.path.dirname(self.rootlink())) |
| 115 | + lines.append("Next: [{}]({})".format(name,link)) |
| 116 | + lines.append("") |
| 117 | + |
| 118 | + #lines.append(self.makename()+", "+self.link) |
| 119 | + return "\n".join(lines) |
| 120 | + |
| 121 | + def makename(self): |
| 122 | + """ Return a name, like "<CHAPTER>: <TITLE>" |
| 123 | + """ |
| 124 | + if self.chapter: |
| 125 | + name = self.chapter |
| 126 | + if self.title: |
| 127 | + name += ": " + self.title |
| 128 | + elif self.title: |
| 129 | + name = self.title |
| 130 | + else: |
| 131 | + name = self.link #last resort |
| 132 | + |
| 133 | + return name |
| 134 | + |
| 135 | + def __repr__(self): |
| 136 | + return "TutorialIndex({self.link!r},{self.chapter!r},{self.title!r},{parent!r})" \ |
| 137 | + .format(self=self,parent=self.parent.title if self.parent else None) |
| 138 | + |
| 139 | +if __name__ == "__main__": |
| 140 | + root = TutorialIndex("README.md",title="BioJava Tutorial") |
| 141 | + |
| 142 | + root.parse() |
| 143 | + |
| 144 | + # Output tree |
| 145 | + def pr(node,indent=""): |
| 146 | + print "{}{}\t{}".format(indent,node.link,node.rootlink()) |
| 147 | + for n in node.children: |
| 148 | + pr(n,indent+"\t") |
| 149 | + |
| 150 | + pr(root) |
0 commit comments