(Arne Babenhauserheide)
2012-10-30: merged default into stable for release. releases 0.2 merged default into stable for release.
diff --git a/.bugs/bugs b/.bugs/bugs
--- a/.bugs/bugs
+++ b/.bugs/bugs
@@ -8,14 +8,16 @@ get mtimes from the repo instead of quer
FIX: revision 0 is omitted: change that :) | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:29396f1753e45b5a37ffa0ce04d96c876d6b6722, time:1319209563.68
parse the pushed repo, not the local one. | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:2c26d62b62e3656ebcce43e7a24f627594911fb5, time:1322115065.37
revisions more structured, as list or similar. | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:39cacfc83da6f6beecafdb745823d7f01018206b, time:1322159357.88
+tags do not have a heading on the overview anymore | owner:, open:True, id:485d0b451f18b5eae517b34466622b0d52340d8e, time:1351620233.63
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
sort tags in reverse order | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:61d256ab154e64597be604d6298daa545d4a96c7, time:1322159250.01
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:True, id:8621575e4016752e8987c8b294dfa9166f77eff3, time:1319147671.39
+fork-/clone-info for each entry in [paths] with its incoming data (if it has some): | owner:, open:False, id:8621575e4016752e8987c8b294dfa9166f77eff3, time:1319147671.39
+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
-make the link from the /commit/*.html pages to the /src/*/[index.html] pages more obvious | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:ad936eaaba1693f7c44bd59916a19e6f3b3db27e, time:1319209748.93
+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:True, id:b4693d2677e0a2b4ef9ee5dfbbe8c4742924604c, time:1319147779.76
+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
add linenumbers to the src files. | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:b7bab6f46da7d224f97d0dac55a617d3a464d301, time:1319147678.56
commits as commit/<rev>/ for long term viability. .html as suffix is not as long lived as a simple dirname. | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:baaad4bdc13d7155048ce6a9dde92dc857b6a1ac, time:1319148414.16
clone/<pathname>/ → incoming log (commits) + possibly an associated issue in b. | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:c58557260a47597ac5057703e26a94df190a2a5d, time:1319147661.8
@@ -24,4 +26,5 @@ check the hgweb templating for parsing t
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:True, 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
+do not show closed branches | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:fbae7e95ed65dc314770126b614fe40d52e61f89, time:1351633799.8
allow setting user, password, server and path vie .hg/hgrc. | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:fc575156316d56b70fda64725984b66cc8a2cfde, time:1322118134.69
diff --git a/README.txt b/README.txt
--- a/README.txt
+++ b/README.txt
@@ -4,13 +4,13 @@ Create and/or upload a static copy of th
You can get it via `hg clone http://draketo.de/proj/hgsite/`
-The main goal is sharing Mercurial on servers with only 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).
+The main goal is sharing code with Mercurial on servers who 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).
-Only changed files are uploaded, based on the time they were last
-modified, so uploads can be reasonably fast.
+On upload, only changed files are uploaded, based on the time they
+were last modified, so uploads can be reasonably fast.
Install:
@@ -22,10 +22,13 @@ Install:
Usage:
-$ hg site [-n sitename] -u user:password@ftp.host.tld/path/to/dir
-→ that’s how this site gets created.
+$ hg push [-f] --sitename "sitename" ftp://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.
-To upload the site when you push, you can use a hook in .hg/hgrc. This is what I use:
+To upload the site when you push it anywhere, you can use a hook in .hg/hgrc. This is what I use:
[hooks]
post-push = hg site -n site -u user:password@ftp.host.tld/path/to/dir
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 2011 Arne Babenhauserheide
+__copyright__ = """Copyright 2012 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.
@@ -65,7 +65,20 @@ templates = {
<h1>{forkname} <small>(fork of <a href="../../">{reponame}</a>, found at {forkuri})</small></h1>
""",
"foot": "</body></html>\n",
- "screenstyle": """ """,
+ "screenstyle": """
+.bugnumbers {
+ font-size: x-small;
+ vertical-align: super;
+}
+.openbugnumber, .openbugnumber a {
+ color: #f00;
+ text-decoration: none;
+}
+.resolvedbugnumber, .resolvedbugnumber a {
+ color: #00f;
+ text-decoration: none;
+}
+""",
"printstyle": """ """,
"manifesthead": """<h2>""" + _("Commit (click to see the diff)")+""": <a href='../../commit/{hex}.html'>{hex}</a></h2>
<p>{desc}</p><p>{user}</p>
@@ -95,6 +108,76 @@ def contentequals(filepath, content):
except IOError: return False # file does not exist. Empty != not existing.
# TODO: check: return True if content is None?
+def bisenabled():
+ """Check if the b extension is enabled to decide if we want to add
+ a bug listing."""
+ enabled = extensions.enabled()
+ if "b" in enabled:
+ return True
+
+def splitbugline(line):
+ """Split a b extension bug line into the ID and the description."""
+ try:
+ bugid = line.split("-")[0].strip()
+ except IndexError:
+ return "", line
+ description = "".join(line.split("-")[1:]).lstrip()
+ return bugid, description
+
+def getbugdetails(ui, repo, bugid):
+ """Get the details for a bug."""
+ # first get the details
+ ui.pushbuffer()
+ req = dispatch.request(["b", "details", bugid], ui=ui, repo=repo)
+ dispatch.dispatch(req)
+ return ui.popbuffer()
+
+def getbugfullid(details, bugid):
+ """Get the real ID of a bug from its detailed info. If it’s not available, just give the short bugid"""
+ try:
+ idline = [i for i in details.splitlines() if i.startswith("ID: ")][0]
+ except IndexError: # no id line
+ return bugid
+ realid = idline[4:].strip()
+ return realid
+
+class BBug(object):
+ """A b-extension bug."""
+ def __init__(self, shortid, fullid, description, state, details=""):
+ self.shortid, self.fullid, self.description, self.state, self.details = shortid, fullid, description, state, details
+
+def getbuginfo(ui, repo, bugline):
+ """Get information about a bug from its bugline."""
+ shortid, description = splitbugline(bugline)
+ details = getbugdetails(ui, repo, shortid)
+ fullid = getbugfullid(details, shortid)
+ return shortid, fullid, description, details
+
+def getbugs(ui, repo):
+ """Get all bugs."""
+ if not bisenabled():
+ return [], []
+ # run the b command to get all open bugs
+ ui.pushbuffer()
+ req = dispatch.request(["b"], ui=ui, repo=repo)
+ dispatch.dispatch(req)
+ openbuglines = [line for line in ui.popbuffer().splitlines() if "-" in line]
+ # similarly get all resolved bugs
+ ui.pushbuffer()
+ req = dispatch.request(["b", "list", "-r"], ui=ui, repo=repo)
+ dispatch.dispatch(req)
+ resolvedbuglines = [line for line in ui.popbuffer().splitlines() if "-" in line]
+ # now turn them into a list of bugs
+ openbugs = []
+ for bugline in openbuglines:
+ bugid, fullid, description, details = getbuginfo(ui, repo, bugline)
+ openbugs.append(BBug(bugid, fullid, description, "open", details))
+ resolvedbugs = []
+ for bugline in resolvedbuglines:
+ bugid, fullid, description, details = getbuginfo(ui, repo, bugline)
+ resolvedbugs.append(BBug(bugid, fullid, description, "resolved", details))
+ return openbugs, resolvedbugs
+
def parsereadme(filepath, truncated=False):
"""Parse the readme file"""
with open(filepath) as r:
@@ -114,7 +197,6 @@ def overviewlogstring(ui, repo, revs, te
t.show(ctx)
return ui.popbuffer()
-
def writeoverview(ui, repo, target, name):
"""Create the overview page"""
overview = ""
@@ -132,7 +214,17 @@ def writeoverview(ui, repo, target, name
overview += "</div>"
break
# now the links to the log and the files.
- overview += "\n<p id='nav'><a href='commits'>changelog</a> | <a href='src/" + repo["tip"].hex() + "/'>files</a>"
+ overview += "\n<p id='nav'><a href='commits'>" + _("changelog") + "</a> | <a href='src/" + repo["tip"].hex() + "/'>" + _("files") + "</a>"
+ # and the bugs
+ openbugs, resolvedbugs = getbugs(ui, repo)
+ if openbugs or resolvedbugs:
+ overview += " | <a href=\"bugs\">" + _("bugs") + "</a>"
+ if openbugs:
+ overview += " <span class=\"bugnumbers\">(<span class=\"openbugnumber\"><a href=\"bugs#open\">" + str(len(openbugs)) + "!</a></span> "
+ else:
+ overview += " <span class=\"bugnumber openbugnumberzero\">0</span>"
+ overview += "<span class=\"bugnumber resolvedbugnumber\"><a href=\"bugs#resolved\">" + str(len(resolvedbugs)) + "√</a></span>)</span>"
+
# and the forks
forks = getforkinfo(ui, target)
if forks:
@@ -143,9 +235,9 @@ def writeoverview(ui, repo, target, name
overview += "<small>(" + str(len(incoming))
outgoing, fn, localother = getoutgoing(ui, repo, otheruri=forkuri, othername=forkname)
overview += "<small>↓↑</small>" + str(len(outgoing)) + ")</small> "
-
+
overview += "</p>"
-
+
# now add the 5 most recent log entries
# divert all following ui output to a string, so we can just use standard functions
overview += "\n<div id='shortlog'><h2>Changes (<a href='commits'>full changelog</a>)</h2>\n"
@@ -163,8 +255,9 @@ def writeoverview(ui, repo, target, name
for branch, heads in repo.branchmap().items():
if branch and branch != "default": # not default
branches.extend(heads)
-
+
try:
+ # FIXME: For some reason this does not seem to give the tags anymore.
tags = repo._tags
except AttributeError:
tags = []
@@ -203,7 +296,7 @@ def writeoverview(ui, repo, target, name
overview += "<div id='readme'><h2>"+_("Readme")+"</h2>\n"
overview += readme
overview += "</div>"
-
+
# finish the overview
overview += templates["foot"]
indexfile = os.path.join(target, "index.html")
@@ -214,7 +307,7 @@ def writeoverview(ui, repo, target, name
def writelog(ui, repo, target, name):
"""Write the full changelog, in steps of 100."""
commits = os.path.join(target, "commits")
-
+
# create the folders
if not os.path.isdir(commits):
os.makedirs(commits)
@@ -222,7 +315,7 @@ def writelog(ui, repo, target, name):
d = commits+"-"+str(i+1)+"00"
if not os.path.isdir(d):
os.makedirs(d)
-
+
# create the log files
t = cmdutil.changeset_templater(ui, repo, patch=False, diffopts=None, mapfile=None, buffered=False)
t.use_template(templates["commitlog"].replace("{relativepath}", "../"))
@@ -243,13 +336,13 @@ def writelog(ui, repo, target, name):
else:
d = commits
logs.append([os.path.join(d, "index.html"), ""])
-
+
logs[-1][-1] += templates["head"].replace("{reponame}", "<a href='../'>"+name+"</a>").replace("{title}", name)
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()
-
+
for filepath,data in logs:
data += templates["foot"].replace("{reponame}", "<a href='../'>"+name+"</a>")
if not contentequals(filepath,data):
@@ -258,7 +351,7 @@ def writelog(ui, repo, target, name):
def getlocalother(repo, ui, otheruri, othername):
"""Get a local clone of the repo identified by uri and name within .hg/paths.
-
+
This creates that local clone!
"""
# if we cannot get the changes via bundlerepo, we create a
@@ -296,7 +389,7 @@ def getincoming(ui, repo, otheruri, othe
if isftpuri or isfreenetpriv:
chlist = []
return chlist, cleanupfn, other
-
+
if not other:
other = hg.peer(repo, {}, otheruri)
ui.pushbuffer() # ignore ui events
@@ -326,10 +419,10 @@ def getoutgoing(ui, repo, otheruri, othe
if isftpuri or isfreenetpriv:
chlist = []
return chlist, cleanupfn, other
-
+
if not other:
other = hg.peer(repo, {}, otheruri)
-
+
def outgoingchanges(repo, other):
from mercurial import discovery
fco = discovery.findcommonoutgoing
@@ -342,7 +435,7 @@ def getoutgoing(ui, repo, otheruri, othe
return o
other.ui.pushbuffer() # ignore ui events
-
+
try:
chlist = outgoingchanges(repo, other)
except (AttributeError, util.Abort):
@@ -350,11 +443,10 @@ def getoutgoing(ui, repo, otheruri, othe
other = getlocalother(repo, ui, otheruri, othername)
other.ui.pushbuffer()
chlist = outgoingchanges(repo, other)
-
+
other.ui.popbuffer()
return chlist, cleanupfn, other
-
def getforkinfo(ui, target):
"""Name and Uri of all forks."""
forks = dict(ui.configitems("paths"))
@@ -378,18 +470,18 @@ def getforkdata(ui, repo, target, name,
"""Write the site for a single fork."""
# make sure the forkdir exists.
other = hg.peer(repo, {}, forkuri)
-
+
# incrementally build the html
html = templates["forkhead"].replace(
"{forkname}", forkname).replace(
"{reponame}", name).replace(
"{forkuri}", safeuri(forkuri))
-
+
# prepare the log templater
t = cmdutil.changeset_templater(ui, repo, patch=False, diffopts=None, mapfile=None, buffered=False)
t.use_template(templates["commitlog"].replace(
"{relativepath}", "../"))
-
+
# Add incoming commits
html += "<div id='incoming'><h2>Incoming commits</h2>"
chlist, cleanupfn, localother = getincoming(ui, repo, otheruri=forkuri, other=other, othername=forkname)
@@ -400,11 +492,11 @@ def getforkdata(ui, repo, target, name,
t.show(ctx)
html += ui.popbuffer()
cleanupfn()
-
+
# add outgoing commits
html += "<div id='outgoing'><h2>Outgoing commits</h2>"
chlist, cleanupfn, localother = getoutgoing(ui, repo, forkuri, other=other, othername=forkname)
-
+
ui.pushbuffer()
for ch in chlist:
ctx = repo.changectx(ch)
@@ -421,7 +513,7 @@ def getforkdir(target, forkname):
def writeforks(ui, repo, target, name):
"""Write an info-page for each fork, defined in hg paths.
-
+
relevant data: incoming commits, outgoing commits, branches and bookmarks not in fork or not in repo. Short: incoming (commits, branches, bookmarks), outgoing (incoming first means, we consider this repo to be the main repo).
"""
forkinfo = getforkinfo(ui, target)
@@ -436,15 +528,14 @@ def writeforks(ui, repo, target, name):
f.write(
getforkdata(ui, repo, target, name, forkname, forkuri))
-
def writecommits(ui, repo, target, name, force=False):
"""Write all not yet existing commit files."""
commit = os.path.join(target, "commit")
-
+
# create the folders
if not os.path.isdir(commit):
os.makedirs(commit)
-
+
t = cmdutil.changeset_templater(ui, repo, patch=False, diffopts=None, mapfile=None, buffered=False)
t.use_template(templates["commitlog"].replace("{relativepath}", "../"))
for c in range(len(repo.changelog)):
@@ -462,6 +553,54 @@ def writecommits(ui, repo, target, name,
cf.write("<pre>"+ui.popbuffer().replace("<", "<")+"</pre>")
cf.write(templates["foot"].replace("{reponame}", "<a href='../'>"+name+"</a>"))
+#: html escape codes thanks to http://wiki.python.org/moin/EscapingHtml
+htmlescapetable = {
+ "&": "&",
+ '"': """,
+ "'": "'",
+ ">": ">",
+ "<": "<",
+ }
+
+def htmlescape(text):
+ """Produce entities within text."""
+ return "".join(htmlescapetable.get(c,c) for c in text)
+
+def writebugs(ui, repo, target, name):
+ """Write bug information, a listing and the details for each bug."""
+ bugdir = os.path.join(target, "bugs")
+
+ # create the bugs folder
+ if not os.path.isdir(bugdir):
+ os.makedirs(bugdir)
+
+ # get all bugs
+ openbugs, resolvedbugs = getbugs(ui, repo)
+ # write the bugs list
+ bugslist = os.path.join(bugdir, "index.html")
+ content = "<h2 id=\"open\">Open Bugs</h2>\n<ul>"
+ for bug in openbugs:
+ content += "<li><a href=\"" + bug.fullid + ".html\">" + bug.shortid + "</a> - " + htmlescape(bug.description) + "</li>\n"
+ content += "</ul>\n"
+ content += "<h2 id=\"resolved\">Resolved Bugs</h2>\n<ul>"
+ for bug in resolvedbugs:
+ content += "<li><a href=\"" + bug.fullid + ".html\">" + bug.shortid + "</a> - " + htmlescape(bug.description) + "</li>\n"
+ content += "</ul>\n"
+ with open(bugslist, "w") as f:
+ f.write(templates["head"].replace("{reponame}", "<a href='../'>"+name+"</a>").replace("{title}", name))
+ f.write(content)
+ f.write(templates["foot"].replace("{reponame}", "<a href='../'>"+name+"</a>"))
+ # write all bug details
+ for bug in openbugs + resolvedbugs:
+ bugsfile = bugslist = os.path.join(bugdir, bug.fullid + ".html")
+ content = "<h2>" + bug.description + "</h2>\n"
+ content += "<pre>" + bug.details + "</pre>\n"
+ content += "<hr>"
+ content += "- <a href=\"index.html\">" + _("all bugs") + "</a> -"
+ with open(bugsfile, "w") as bf:
+ bf.write(templates["head"].replace("{reponame}", "<a href='../'>"+name+"</a>").replace("{title}", name))
+ bf.write(content)
+ bf.write(templates["foot"].replace("{reponame}", "<a href='../'>"+name+"</a>"))
def escapename(filename):
"""escape index.html as .index.html and .ind… as ..ind… and so fort."""
@@ -469,7 +608,6 @@ def escapename(filename):
return "." + filename
else: return filename
-
def parsesrcdata(data):
"""Parse a src file into a html file."""
return "<pre>"+data.replace("<", "<")+"</pre>"
@@ -484,7 +622,10 @@ def rawpath(target, ctx, filename):
def ctxdiffstat(ui, repo, ctx):
"""Get the diffstat of a change context."""
- command = "log -r " + ctx.hex() + " --stat --color=never"
+ if "color" in extensions.enabled():
+ command = "log -r " + ctx.hex() + " --stat --color=never"
+ else:
+ command = "log -r " + ctx.hex() + " --stat"
req = dispatch.request(command.split(), ui=ui, repo=repo)
ui.pushbuffer()
dispatch.dispatch(req)
@@ -496,6 +637,7 @@ def ctxdiffstat(ui, repo, ctx):
"[0;31m", "").replace(
"[0m","")
+
def createindex(ui, repo, target, ctx):
"""Create an index page for the changecontext: the commit message + the user + all files in the changecontext."""
# first the head
@@ -515,7 +657,7 @@ def createindex(ui, repo, target, ctx):
def writesourcetree(ui, repo, target, name, force, rawfiles=False):
"""Write manifests for all commits and websites for all files.
-
+
* For each file, write sites for all revisions where the file was changed: under src/<hex>/path as html site (with linenumbers and maybe colored source), under raw/<hex>/<path> as plain files. If there is an index.html file, write it as .index.html. If there also is .index.html, turn it to ..index.html, …
* For each commit write an index with links to the included files at their latest revisions before/at the commit.
"""
@@ -577,12 +719,12 @@ def parsesite(ui, repo, target, **opts):
return
with open(idfile, "w") as i:
i.write("")
-
+
if opts["sitename"]:
name = opts["sitename"]
elif target != "static": name = target
else: name = os.path.basename(repo.root)
-
+
# first the stylesheets
screenstyle = opts["screenstyle"]
screenfile = os.path.join(target, "style.css")
@@ -598,22 +740,24 @@ def parsesite(ui, repo, target, **opts):
elif not contentequals(printfile, templates["printstyle"]):
with open(printfile, "w") as f:
f.write(templates["printstyle"])
-
+
# then the overview
writeoverview(ui, repo, target, name)
-
+
# and the log
writelog(ui, repo, target, name)
-
+
# and all commit files
writecommits(ui, repo, target, name, force=opts["force"])
-
+
# and all file data
writesourcetree(ui, repo, target, name, force=opts["force"])
-
+
# and all forks
writeforks(ui, repo, target, name)
-
+
+ # and all bugs
+ writebugs(ui, repo, target, name)
def addrepo(ui, repo, target, bookmarks, force):
"""Add the repo to the target and make sure it is up to date."""
@@ -622,7 +766,7 @@ def addrepo(ui, repo, target, bookmarks,
except mercurial.error.RepoError, e:
# already exists
pass
-
+
ui.pushbuffer()
if bookmarks:
commands.push(ui, repo, dest=target, bookmark=repo._bookmarks, force=force)
@@ -630,7 +774,6 @@ def addrepo(ui, repo, target, bookmarks,
commands.push(ui, repo, dest=target, force=force)
ui.popbuffer()
-
def upload(ui, repo, target, ftpstring, force):
"""upload the repo to the FTP server identified by the ftp string."""
try:
@@ -648,9 +791,9 @@ def upload(ui, repo, target, ftpstring,
except socket.timeout:
ui.warn(_("connection to "), server, _(" timed out after "), timeout, _(" seconds.\n"))
return
-
+
ui.status(ftp.getwelcome(), "\n")
-
+
# create the target dir.
serverdir = os.path.dirname(ftppath)
serverdirparts = ftppath.split("/")
@@ -662,26 +805,26 @@ def upload(ui, repo, target, ftpstring,
sd = os.path.join(sd, sdp)
if not sd in ftp.nlst(sdo):
ftp.mkd(sd)
-
-
+
+
ftp.cwd(ftppath)
if not ftp.pwd() == "/" + ftppath:
ui.warn(_("not in the correct ftp directory. Cowardly bailing out.\n"))
return
-
+
#ftp.dir()
#return
ftpfeatures = ftp.sendcmd("FEAT")
featuremtime = " MDTM" in ftpfeatures.splitlines()
_ftplistcache = set()
-
+
for d, dirnames, filenames in os.walk(target):
for filename in filenames:
localfile = os.path.join(d, filename)
serverfile = localfile[len(target)+1:]
serverdir = os.path.dirname(serverfile)
serverdirparts = serverdir.split("/")
-# print serverdirparts, serverfile
+ # print serverdirparts, serverfile
with open(localfile, "rb") as f:
sd = serverdirparts[0]
if sd and not sd in _ftplistcache: # should happen only once per superdir
@@ -694,7 +837,7 @@ def upload(ui, repo, target, ftpstring,
except ftplib.error_perm, resp:
ui.warn(_("could not create directory "), sd, ": " , resp, "\n")
else: _ftplistcache.add(sd)
-
+
for sdp in serverdirparts[1:]:
sdold = sd
sd = os.path.join(sd, sdp)
@@ -710,7 +853,7 @@ def upload(ui, repo, target, ftpstring,
except ftplib.error_perm, resp:
ui.warn(_("could not create directory "),
sd, ": " , resp, "\n")
-
+
if not serverfile in _ftplistcache: # should happen for existing files only once per dir.
_ftplistcache.update(set(ftp.nlst(serverdir)))
if not serverfile in _ftplistcache or force:
@@ -720,7 +863,7 @@ def upload(ui, repo, target, ftpstring,
else:
ui.status(_("uploading "), serverfile,
_(" because it is not yet online.\n"))
-
+
ftp.storbinary("STOR "+ serverfile, f)
else:
# reupload the file if the file on the server is older than the local file.
@@ -734,8 +877,6 @@ def upload(ui, repo, target, ftpstring,
_(" because it is newer than the file on the FTP server.\n"))
ftp.storbinary("STOR "+ serverfile, f)
-
-
def staticsite(ui, repo, target=None, **opts):
"""Create a static copy of the repository and/or upload it to an FTP server."""
if repo.root == target:
@@ -754,7 +895,6 @@ def staticsite(ui, repo, target=None, **
# upload the repo
upload(ui, repo, target, opts["upload"], opts["force"])
-
cmdtable = {
# "command-name": (function-call, options-list, help-string)
"site": (staticsite,
@@ -912,10 +1052,10 @@ def test():
showcall(["hg", "--config", "extensions.site="+__file__, "site", "-B", "-n", "mysite"])
# check if uploading works: Only a valid test, if you have a
# post-push hook which does the uploading
- showcall(["hg", "--config", "extensions.site="+__file__, "push"])
+ # showcall(["hg", "--config", "extensions.site="+__file__, "push"])
# check if push directly to ftp works. Requires the path draketo
# to be set up in .hg/hgrc as ftp://user:password/path
- showcall(["hg", "--config", "extensions.site="+__file__, "push", "draketo", "--sitename", "site extension"])
+ # showcall(["hg", "--config", "extensions.site="+__file__, "push", "draketo", "--sitename", "hg site extension"])
if __name__ == "__main__":
test()