hg site extension
 
(Arne Babenhauserheide)
2014-02-09: merge default into releases releases 0.5.1

merge default into releases

diff --git a/.bugs/bugs b/.bugs/bugs
--- a/.bugs/bugs
+++ b/.bugs/bugs
@@ -4,7 +4,7 @@ offer different and customizeable ways t
 Add a list of branches, heads and tags to the summary page.  | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:0fde104c4206be8245ff0716ee2e91ea3971db8f, time:1319147651.17
 include incoming commits, so I can easily check if I should pull a fork - and visitors can see what they can find in the fork. | owner:, open:False, id:14e7a48faa8965f947695744cc40d0f2bc25023b, time:1365863785.15
 if b is used: a bugtracker: issue/<id>/<name>                | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:1d631d51ff06b3bdca50e21da3d6a00bcb801c85, time:1319147632.52
-avoid writing and subsequently uploading all bugs on each push | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:1fc514f333292b9ffded1f7dbcbc9a9330666972, time:1391919333.98
+avoid writing and subsequently uploading all bugs on each push | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:1fc514f333292b9ffded1f7dbcbc9a9330666972, time:1391919333.98
 add css classes and ids everywhere, so this can be styled with CSS. | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:2699812cf02c803fa338daf9ae039c43a30a0b5f, time:1322090683.01
 get mtimes from the repo instead of querying the FTP server. We know which files were changed. | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:29210503551d0eafca67dda8d6fffbd40bf837dc, time:1319213074.57
 FIX: revision 0 is omitted: change that :)                   | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:29396f1753e45b5a37ffa0ce04d96c876d6b6722, time:1319209563.68
@@ -15,11 +15,15 @@ tags do not have a heading on the overvi
 only write .statichgrepo print.css style.css and index.html when their data changed \(or \-\-force\) → read them and compare the contents. | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:4f02149269a60fca85aa040116b2789d98c906f2, time:1319212903.98
 line numbers with anchors -                                  | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:4fe09a1f0303ba6270042ca70d2bec4d60a1249e, time:1352070288.56
 sort tags in reverse order                                   | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:61d256ab154e64597be604d6298daa545d4a96c7, time:1322159250.01
+link from summary to readme                                  | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:6277e6577b3f48f9b358565f29885685f2872d29, time:1391966374.92
 add proper caching of every ftp directory listing.           | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:750692931106d78ffc38c1ed63013c4dac4099dd, time:1319175393.07
 fork-/clone-info for each entry in [paths] with its incoming data (if it has some): | owner:, open:False, id:8621575e4016752e8987c8b294dfa9166f77eff3, time:1319147671.39
+style: add round borders and color for tags and branches in the log | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:87f1c0eb28cfcc23e6fe41d3c30fee7329e355d1, time:1391920088.81
+forks should contain the site-title, too, so that users can go back. | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:8e994b6fdba3a3d1882c6758f9cde0f333ed28ec, time:1391963766.44
 escape html entities in bug details, too, not only in the bug listing. | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:90c4ae8b49e006a131b61f1ab0697ca83f00021e, time:1351789362.97
 partial localization of strings - files to Dateien - is worse than none. | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:921fb80eb2a2fbf57e0f6db0a949ead872624f8f, time:1351635128.79
-More complex Readme parsing.                                 | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:94fbade896adbf6f696cfdb331021437dff3f30e, time:1319147671.39
+More complex Readme parsing.                                 | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:94fbade896adbf6f696cfdb331021437dff3f30e, time:1319147671.39
+diffs: add syntax highlighting                               | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:ad1855d35fb272aee5c13bd29c6a34400d9e4bf8, time:1391920250.64
 make the link from the /commit/*.html pages to the /src/*/[index.html] pages more obvious | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:ad936eaaba1693f7c44bd59916a19e6f3b3db27e, time:1319209748.93
 cache FTP directory listings for much faster upload of already existing sites. | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:b1f6dfdaccc0346adaf0d42d361bbc2de00ee176, time:1319208814.12
 Idea: hg clone/push ftp://host.tld/path/to/repo → hg site --upload | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:b4693d2677e0a2b4ef9ee5dfbbe8c4742924604c, time:1319147779.76
@@ -29,10 +33,11 @@ clone/<pathname>/ → incoming log (comm
 only write bug files if their content differs from the content on disk to avoid reuploading them without need | owner:, open:True, id:c7b2cf5fdbc68160530a08e1d651c23a1f49fc01, time:1365865229.49
 incoming commits have no diffstat                            | owner:, open:True, id:cf36e24ae03073dd92827cbd151e3ca0a6d1dd52, time:1365872088.99
 no longer create raw files, since they can’t be served by all webservers and waste bandwidth and space (they are no longer linked anyway). | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:d1010e1933648f65af37d969bfb45f8d834fc8bb, time:1319148721.49
-add a footer which links back to hgsite                      | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:ed55d92709329e81b8d619c4d2a9aa97361fefd8, time:1365863559.31
+add a footer which links back to hgsite                      | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:ed55d92709329e81b8d619c4d2a9aa97361fefd8, time:1365863559.31
 check the hgweb templating for parsing the site.             | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:ef17f01dbe8ee58536fa8b345eb18d1efc639f15, time:1319208643.38
 maybe more advanced bookmarks pushing.                       | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:ef8c12bfcc99686efc1f685a9be0be0c78922ca5, time:1322115049.48
 crashes on missing readme.                                   | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:f4232c8a52fff730a4c63525ad597c063135e576, time:1332936115.69
 Treat branch heads specially: link on the main page.         | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:f531c27b38f9ea1749ded312f4f468c9ac33b930, time:1319147696.96
+add sjl javascripts                                          | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:f8c1a090f67f6697e21b69ea9a5a09b46bc459d5, time:1391963730.83
 do not show closed branches                                  | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:fbae7e95ed65dc314770126b614fe40d52e61f89, time:1351633799.8
 allow setting user, password, server and path vie .hg/hgrc.  | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:fc575156316d56b70fda64725984b66cc8a2cfde, time:1322118134.69
diff --git a/README.txt b/README.txt
--- a/README.txt
+++ b/README.txt
@@ -1,32 +1,73 @@
-hg site
+hg site: static repositories
+============================
 
-Create and/or upload a static copy of the repository.
+Get it via `hg clone http://draketo.de/proj/hgsite/`
 
-You can get it via `hg clone http://draketo.de/proj/hgsite/`
+With hg site you can say goodbye to vendor lock-in.
 
-The main goal is sharing code with Mercurial on servers which only offer
-FTP access and statically served files, while providing the same
+
+Description
+-----------
+
+The goal of hg site is sharing code over commodity servers which only
+offer FTP access and statically served files, while providing the same
 information as hg serve and full solutions like bitbucket and
-gitorious (naturally without the interactivity).
+gitorious (naturally without the interactivity, but you can always
+clone the repo to interact).
 
-On upload, only changed files are uploaded, based on the time they
-were last modified, so uploads can be reasonably fast.
+Thanks to the static http support of Mercurial, the clone and browse
+URLs are the same, so you can look at the site with your webbrowser or
+clone the repository with Mercurial using the same URL.
 
-Install:
+The fork detection allows tieing multiple platforms together: It
+tracks repositories from any source for which Mercurial can calculate
+incoming and outgoing changes. And since the bugtracking happens via
+the b-extension, your bugtracking follows your code wherever you go.
 
-* Clone this repo.
+
+Features
+--------
+
+- shows the history, branches, tags and bookmarks
+- shows bugs tracked via the [b-extension][]
+- shows the readme
+- shows forks defined as paths in `.hg/hgrc` - from any source hg supports
+- uploads only  changed files (based on the time they
+were last modified), so uploads can be reasonably fast.
+- Supports FTP and FTPS. Use the latter if you can (just use URLs starting with `ftps://`)
+- static site (no vulnerabilities, little dependencies, high performance)
+
+[b-extension]: http://mercurial.selenic.com/wiki/bExtension "Distributed Bug Tracking: Get bugs resolved, not organized"
+
+
+Installation
+------------
+
+* Clone this repo.  
   hg clone http://draketo.de/proj/hgsite/
-* add this to the [extensions] section in your ~/.hgrc
-  site = path/to/staticsite.py
+* add this to the [extensions] section in your ~/.hgrc  
+  site = path/to/staticsite.py  
   if you have no [extensions] section, add it.
 
-Usage:
 
-$ hg push [-f] --sitename "sitename" ftp://user:password@ftp.host.tld/path/to/dir
-→ that’s how this site gets created. 
+Usage
+-----
+
+    $ hg push [-f] --sitename "sitename" ftps://user:password@ftp.host.tld/path/to/dir
+
+→ that’s how this site gets created.  
   With -f it is reuploaded completely, 
-  otherwise only the changes get uploaded.
-  defining the ftp://… in [paths] in .hg/hgrc works.
+  otherwise only the changes get uploaded.  
+  defining the ftp://… or ftps://… in [paths] in .hg/hgrc works.
+
+If you want to make this easier, add an alias to your .hg/hgrc:
+
+    [paths]
+    ftp = ftps://user:password@ftp.host.tld/path/to/dir
+    [alias]
+    pushsite = push --sitename "sitename" ftp
+
+Then just use `hg pushsite` to upload.
 
 To upload the site when you push it anywhere, you can use a hook in .hg/hgrc. This is what I use: 
 
@@ -34,24 +75,40 @@ To upload the site when you push it anyw
     post-push = hg site -n site -u user:password@ftp.host.tld/path/to/dir
 
 
-$ hg site --help
-hg site [options] [folder]
+Basic Options
+-------------
 
-Create a static copy of the repository and/or upload it to an FTP server.
+    $ hg site --help
+    hg site [options] [folder]
+    
+    Create a static copy of the repository and/or upload it to an FTP server.
+    
+    use "hg help -e site" to show help for the site extension
+    
+    options:
+    
+     -n --name VALUE         the repo name. Default: folder or last segment of the
+                             repo-path.
+     -u --upload VALUE       upload the repo to the given ftp host. Format:
+                             user:password@host/path/to/dir
+     -f --force              force recreating all commit files. Slow.
+     -s --screenstyle VALUE  use a custom stylesheet for display on screen
+     -p --printstyle VALUE   use a custom stylesheet for printing
+        --mq                 operate on patch repository
+    
+    use "hg -v help site" to show global options
+    
 
-use "hg help -e site" to show help for the site extension
+Customization
+-------------
 
-options:
+To change the appearance of your site, create it once and then copy style.css and print.css from `._site/`. Adapt them and use -s path/to/your/screen.css and  -p path/to/your/print.css to use your adaptions.
 
- -n --name VALUE         the repo name. Default: folder or last segment of the
-                         repo-path.
- -u --upload VALUE       upload the repo to the given ftp host. Format:
-                         user:password@host/path/to/dir
- -f --force              force recreating all commit files. Slow.
- -s --screenstyle VALUE  use a custom stylesheet for display on screen
- -p --printstyle VALUE   use a custom stylesheet for printing
-    --mq                 operate on patch repository
 
-use "hg -v help site" to show global options
+
+Notes
+-----
+
+Copyright 2012 till 2014 Arne Babenhauserheide, Licensed under GPLv2 or later.
 
 Related: git2html → http://hssl.cs.jhu.edu/~neal/git2html/
diff --git a/staticsite.py b/staticsite.py
--- a/staticsite.py
+++ b/staticsite.py
@@ -11,7 +11,7 @@ serve and full solutions like bitbucket 
 without the interactivity).
 """
 
-__copyright__ = """Copyright 2012 till 2013 Arne Babenhauserheide
+__copyright__ = """Copyright 2012 till 2014 Arne Babenhauserheide
 
 This software may be used and distributed according to the terms of the
 GNU General Public License version 2 or any later version.
@@ -24,6 +24,7 @@ import mercurial
 import ftplib
 import socket
 import datetime
+import codecs
 from mercurial import cmdutil, util, scmutil
 from mercurial import commands, dispatch
 from mercurial.i18n import _
@@ -76,16 +77,17 @@ templates = {
 </head>
 <body>
 <div class="wrap">
-<div class="top group fullwidth">
-<header>{forkname} <small>(fork of <a href="../../">{reponame}</a>, found at {forkuri})</small></header>
+<div class="top group">
+<header id="maintitle"><a href="../../">{reponame}</a></header>
+<nav id="forknav">{forkname} <small>(fork found at {forkuri})</small></header></nav>
 </div>
 <div class="hr"> </div>
 <div class="content">
 """,
     "foot": """<div class="hrb"> </div><footer>
                 <p>
-                    Site made with the <a href="http://draketo.de/proj/hgsite">hg staticsite extension</a>, 
-                    Design based on the site from <a href="https://stevelosh.com">Steve Losh</a>
+                    Site made with the <a href="http://draketo.de/proj/hgsite">hg site extension</a> by Arne Babenhauserheide, 
+                    Design based on the site from <a href="http://stevelosh.com">Steve Losh</a>
                 </p>
             </footer></div><!-- /content --></div><!-- /wrap--></body></html>\n""",
     # this screenstyle is mostly from the wonderful site http://stevelosh.com and licensed under MIT
@@ -368,8 +370,8 @@ body .wrap{
 body .wrap .top header{
     float:left;font-family:'OFL Sorts Mill Goudy','OFL Sorts Mill Goudy TT',serif;font-size:23px;line-height:50px;text-transform:lowercase;padding-left:2px;width:210px;
 }
-body .wrap .top .fullwidth header{
-    float:left;font-family:'OFL Sorts Mill Goudy','OFL Sorts Mill Goudy TT',serif;font-size:23px;line-height:50px;text-transform:lowercase;padding-left:2px;width:100%;
+body .wrap .top.fullwidth header{
+    float:left;font-family:'OFL Sorts Mill Goudy','OFL Sorts Mill Goudy TT',serif;font-size:23px;line-height:50px;text-transform:lowercase;padding-left:2px;width:610px;
 }
 body .wrap .top header .amp{
     font-style:italic;
@@ -385,6 +387,9 @@ body .wrap .top nav{
     because we can have a long lis tof forks and use <sup> elements for the bugs.*/
     font:normal 18px/35px 'OFL Sorts Mill Goudy','OFL Sorts Mill Goudy TT',serif;text-align:right;text-transform:lowercase;padding-right:2px;width:398px;float:left;
 }
+body .wrap .top nav#forknav{
+    font:normal 18px/50px 'OFL Sorts Mill Goudy','OFL Sorts Mill Goudy TT',serif;text-align:right;text-transform:lowercase;padding-right:2px;width:398px;float:left;
+}
 body .wrap .top nav .sep{
     padding:0 4px;color:#666;
 }
@@ -517,6 +522,22 @@ div.screenshots img{
 .flattr{
     float:right;padding-top:1px;
 }
+#shortlog a, #branches a, #tags a, #bookmarks a, #incoming a, #outgoing a, #log a{
+    text-decoration:none;color:gray;
+}
+#shortlog a:hover, #branches a:hover, #tags a:hover, #bookmarks a:hover, #incoming a:hover, #outgoing a:hover, #log a{
+    text-decoration:underline;
+}
+#intro{
+    color:#353535;font:normal 23px/25px Palatino,"Palatino Linotype",serif;text-rendering:optimizeLegibility;font-style:italic;padding-left:50px;padding-right:50px;padding-bottom:20px;padding-top:15px;/*background:#eeeeee;border:solid thin lightgray;border-radius:25px;*/
+}
+#introtoreadmelink{
+    color: lightgray;
+}
+#readme>pre{
+    background:#fdfdfd;color:#353535;font:normal 18px/25px Palatino,"Palatino Linotype",serif;text-rendering:optimizeLegibility;
+/*font-family:Consolas,Menlo,"Courier New",monospace;*/
+}
 """,
     # this printstyle is from the wonderful site http://stevelosh.com and licensed under MIT
     "printstyle": """ 
@@ -688,10 +709,19 @@ def parsereadme(filepath, truncated=Fals
     """Parse the readme file"""
     with open(filepath) as r:
         readme = r.read()
+    # TODO: Markdown parsing belongs here.
     if truncated:
-        return "<pre style=\"white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word;\">" + "\n".join(readme.splitlines()[:5]) + "</pre>"
-    else: 
-        return "<pre style=\"white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word;\">" + readme + "</pre>"
+        text = "\n".join(readme.splitlines()[:6])
+    else:
+        text = readme
+    try: # to use markdown if we can
+        import markdown
+        html = markdown.markdown(
+            unicode(text, encoding="utf-8"), 
+            extensions=["markdown.extensions.extra"]).encode("utf-8")
+        return html
+    except ImportError:
+        return "<pre markdown=\"1\" style=\"white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word;\">" + text + "</pre>"
 
 def overviewlogstring(ui, repo, revs, template=templates["commitlog"]): 
     """Get the string for a log of the given revisions for the overview page."""
@@ -749,6 +779,7 @@ def writeoverview(ui, repo, target, name
             readme_intro = parsereadme(os.path.join(repo.root, f), truncated=True)
             overview += "<div id='intro'>"
             overview += readme_intro
+            overview += """<p id="introtoreadmelink">(<a href="#readme" title="Show me the full Readme">...</a>)</p>"""
             overview += "</div>"
             break
     
@@ -862,10 +893,12 @@ def writelog(ui, repo, target, name):
             logs.append([os.path.join(d, "index.html"), ""])
             
         logs[-1][-1] += templates["head"].replace("{reponame}", "<a href='../'>"+name+"</a>").replace("{title}", name).replace("{nav}", "").replace("{relpath}", "../")
+        logs[-1][-1] += """<div id="log">"""
         for c in range(ck*100+1, min(len(repo.changelog)+1, (ck+1)*100)):
             ctx = repo.changectx(str(-c))
             t.show(ctx)
         logs[-1][-1] += ui.popbuffer()
+        logs[-1][-1] += """"</div>"""
         
     for filepath,data in logs:
         data += templates["foot"].replace("{reponame}", "<a href='../'>"+name+"</a>")
@@ -1037,6 +1070,7 @@ def getforkdata(ui, repo, target, name, 
                 print "Cannot write commits from fork", forkname, "because the repository type does not support getting the changelog."
             else:
                 raise
+    html += "</div><!-- /incoming-->"
     
     ui.pushbuffer()
     for ch in chlist:
@@ -1056,7 +1090,7 @@ def getforkdata(ui, repo, target, name, 
     html += ui.popbuffer()
     cleanupfn()
     
-    html += "</div>"
+    html += "</div><!-- /outgoing-->"
     html += templates["foot"]
     return html