Our repository [1] has a post-update hook that rebuilds the status
page after each push. Since that may happen several times a day, we
might as well show the build time (as well as the date) in the footer.
The trailing 'Z' is the ISO 8601 designator for UTC. Now that we're
showing times, it's nice to be explicit about the timezone we're
using.
The rename from date -> datetime gives us backward-compatibility for
folks that *do* only want the date. We keep the old date formatting
to support those folks.
[1]: http://nmbug.tethera.net/git/nmbug-tags.git
Rather than splitting this context into header-only and footer-only
groups, just dump it all in a shared dict. This will make it easier
to eventually split the header/footer templates out of this script
(e.g. if we want to load them from the config file).
It's useful reference information, but anyone who wants it will look
for and find it. We don't need this front-and-center. Follow the
pattern set by our header template with a triple-quoted string.
The gray <hr> styling is less agressive. IE uses 'color' for drawing
the rule, while Gecko and Opera use the border or 'background-color'
[1].
[1]: https://bugzilla.mozilla.org/show_bug.cgi?id=239386
Prefer a docstring to a header comment so we can use it as the
ArgumentParser description (formatted with 'nmbug-status --help').
Script readers still have it near the top of the file. Since it's a
docstring, use PEP 257's summary-line-and-body format [1].
[1]: http://legacy.python.org/dev/peps/pep-0257/#multi-line-docstrings
The yyyy-mm-dd (actually \d\d\d\d-\d\d-\d\d) for a bit more restrictive
(and self-documentative) than the \w\w\w\w-... that used to be there and
UNRELEASED so that developers can test the latest NEWS converted to mdwn
format before submitting NEWS patches.
If a git repository is non-bare, and core.worktree is not set, git
tries to deduce the worktree. This deduction is not always helpful, e.g.
% git --git-dir=$HOME/.nmbug clean -f
would likely delete most of the files in the current directory
With two branches getting fetched (master and config), the branch
referenced by FETCH_HEAD is ambiguous. For example, I have:
$ cat FETCH_HEAD
41d7bfa7184cc93c9dac139d1674e9530799e3b0 \
not-for-merge branch 'config' of http://nmbug.tethera.net/git/nmbug-tags
acd379ccb973c45713eee9db177efc530f921954 \
not-for-merge branch 'master' of http://nmbug.tethera.net/git/nmbug-tags
(where I wrapped the line by hand). This means that FETCH_HEAD
references the config branch:
$ git rev-parse FETCH_HEAD
41d7bfa7184cc93c9dac139d1674e9530799e3b0
which breaks all of the FETCH_HEAD logic in nmbug (where FETCH_HEAD is
assumed to point to the master branch).
Instead of relying on FETCH_HEAD, use @{upstream} as the
remote-tracking branch that should be merged/diffed/integrated into
HEAD. @{upstream} was added in Git v1.7.0 (2010-02-12) [1], so
relying on it should be fairly safe. One tricky bit is that bare
repositories don't set upstream tracking branches by default:
$ git clone --bare http://nmbug.tethera.net/git/nmbug-tags.git nmbug-bare
$ cd nmbug-bare
$ git remote show origin
* remote origin
Fetch URL: http://nmbug.tethera.net/git/nmbug-tags.git
Push URL: http://nmbug.tethera.net/git/nmbug-tags.git
HEAD branch: master
Local refs configured for 'git push':
config pushes to config (up to date)
master pushes to master (up to date)
While in a non-bare clone:
$ git clone http://nmbug.tethera.net/git/nmbug-tags.git
$ cd nmbug-tags
$ git remote show origin
* remote origin
Fetch URL: http://nmbug.tethera.net/git/nmbug-tags.git
Push URL: http://nmbug.tethera.net/git/nmbug-tags.git
HEAD branch: master
Remote branches:
config tracked
master tracked
Local branch configured for 'git pull':
master merges with remote master
Local ref configured for 'git push':
master pushes to master (up to date)
From the clone docs [2]:
--bare::
Make a 'bare' Git repository…
Also the branch heads at the remote are copied directly
to corresponding local branch heads, without mapping
them to `refs/remotes/origin/`. When this option is
used, neither remote-tracking branches nor the related
configuration variables are created.
To use @{upstream}, we need to the local vs. remote-tracking
distinction, so this commit adds 'nmbug clone', replacing the
previously suggested --bare clone with a non-bare --no-checkout
--separate-git-dir clone into a temporary work directory. After
which:
$ git rev-parse @{upstream}
acd379ccb973c45713eee9db177efc530f921954
gives us the master-branch commit. Existing nmbug users will have to
run the configuration tweaks and re-fetch by hand. If you don't have
any local commits, you could also blow away your NMBGIT repository and
re-clone from scratch:
$ nmbug clone http://nmbug.tethera.net/git/nmbug-tags.git
Besides removing the ambiguity of FETCH_HEAD, this commit allows users
to configure which upstream branch they want nmbug to track via 'git
config', in case they want to change their upstream repository.
[1]: http://git.kernel.org/cgit/git/git.git/tree/Documentation/RelNotes/1.7.0.txt
[2]: http://git.kernel.org/cgit/git/git.git/tree/Documentation/git-clone.txt
Manual pages are now generated and during the generation the version
string is read from `version` file, so this (currently failing) test
checking manual page versions can be removed.
While at it, changed the case pattern *[^0-9.]*
to its portable alternative *[!0-9.]*
Make nmbug-status more generally usable outside of nmbug by not
hardcoding notmuch related things.
This lets anyone publish html search views to mailing list messages
with a custom config file, independent of nmbug.
Add script to generate notmuch test databases using specified versions
of notmuch. This is useful for generating material for database
upgrade tests.
This reuses the test infrastructure to have a sandbox environment for
notmuch new etc.
Python dict() object does not have __values__() function which
OrderedDict().values() (the stub provided in nmbug-status) could call
to provide ordered list of values. By renaming this thinko to
values() will make our stub work as expected -- dict items listed out
in order those were added to the dictionary.
David [1] and Tomi [2] both feel that the user's choice of LANG is not
explicit enough to have such a strong effect on nmbug-status. For
example, cron jobs usually default to LANG=C, and that is going to
give you ASCII output:
$ LANG=C python -c 'import locale; print(locale.getpreferredencoding())'
ANSI_X3.4-1968
Trying to print Unicode author names (and other strings) in that
encoding would crash nmbug-status with a UnicodeEncodeError. To avoid
that, this patch hardcodes UTF-8, which can handle generic Unicode,
and is the preferred encoding (regardless of LANG settings) for
everyone who has chimed in on the list so far. I'd prefer trusting
LANG, but in the absence of any users that prefer non-UTF-8 encodings
I'm fine with this approach.
While we could achieve the same effect on the output content by
dropping the previous patch (nmbug-status: Encode output using the
user's locale), Tomi also wanted UTF-8 hardcoded as the config-file
encoding [2]. Keeping the output encoding patch and then adding this
to hardcode both the config-file and output encodings at once seems
the easiest route, now that fd29d3f (nmbug-status: Decode Popen output
using the user's locale, 2014-02-10) has landed in master.
[1]: id="877g8z4v4x.fsf@zancas.localnet"
http://article.gmane.org/gmane.mail.notmuch.general/17202
[2]: id="m2vbwj79lu.fsf@guru.guru-group.fi"
http://article.gmane.org/gmane.mail.notmuch.general/17209
Instead of always writing UTF-8, allow the user to configure the
output encoding using their locale. This is useful for previewing
output in the terminal, for poor souls that don't use UTF-8 locales
;).
We already had the tbody with a blank row separating threads (which is
not colored); this commit adds a bit of spacing to separate messages
within a thread. It will also add a bit of colored padding above the
first message and below the final message, but the main goal is to add
padding *between* two-row message blocks.
<--- new padding
thread-1, message-1, row-1 (class="message-first")
thread-1, message-1, row-2 (class="message-last")
<--- new padding
spacer tbody with a blank row
<--- new padding
thread-2, message-1, row-1 (class="message-first")
thread-2, message-1, row-2 (class="message-last")
<--- new padding
<--- new padding
thread-2, message-2, row-1 (class="message-first")
thread-2, message-2, row-2 (class="message-last")
<--- new padding
'message-id' and 'from' now have sensitive characters escaped using
xml.sax.saxutils.escape [1]. The 'subject' data was already being
converted to a link into Gmane; I've escape()d that too, so it doesn't
need to be handled ain the same block as 'message-id' and 'from'.
This prevents broken HTML by if subjects etc. contain characters that
would otherwise be interpreted as HTML markup.
[1]: http://docs.python.org/3/library/xml.sax.utils.html#xml.sax.saxutils.escape
Also allow manual id overrides from the JSON config. Sluggin avoids
errors like:
Bad value '#Possible bugs' for attribute href on element a:
Whitespace in fragment component. Use %20 in place of spaces.
from http://validator.w3.org.
I tried just quoting the titles (e.g. 'Possible%20bugs'), but that
didn't work (at least with Firefox 24.2.0). Slugging avoids any
ambiguity over when the quotes are expanded in the client. The specs
are unclear about quoting, saying only [1]:
Value: Any string, with the following restrictions:
must be at least one character long
must not contain any space characters
[1]: http://dev.w3.org/html5/markup/global-attributes.html#common.attrs.id
HTML 5 for the win :). I also de-namespaced the language; the HTML 5
spec allows a vestigial xml:lang attribute, but it's a no-op [1], so I
stripped it.
This shouldn't break anything at tethera, which already serves the
status as text/html:
$ wget -S http://nmbug.tethera.net/status/
--2014-02-02 21:20:39-- http://nmbug.tethera.net/status/
Resolving nmbug.tethera.net... 87.98.215.224
Connecting to nmbug.tethera.net|87.98.215.224|:80... connected.
HTTP request sent, awaiting response...
HTTP/1.1 200 OK
Vary: Accept-Encoding
Content-Type: text/html
...
This also matches the Content-Type in the generated HTML's http-equiv
meta.
[1]: http://www.w3.org/TR/html5/dom.html#the-lang-and-xml:lang-attributes
Tomi Ollila and David Bremner (and presumably others) are running
Python 2.6 on their nmbug-status boxes, so it makes sense to keep
support for that version. This commit adds a really minimal
OrderedDict stub (e.g. it doesn't handle key removal), but it gets the
job done for Page._get_threads. Once we reach a point where Python
2.6 is no longer important (it's already out of it's security-fix
window [1]), we can pull this stub back out.
[1]: http://www.python.org/download/releases/2.6.9/
I was having trouble understanding the logic of the longish print_view
function, so I refactored the output generation into modular bits.
The basic text rendering is handled by Page, which has enough hooks
that HtmlPage can borrow the logic and slot-in HTML generators.
By modularizing the logic it should also be easier to build other
renderers if folks want to customize the layout for other projects.
Timezones
=========
This commit has not effect on the output, except that some dates have
been converted from the sender's timezone to UTC due to:
- val = m.get_header(header)
- ...
- if header == 'date':
- val = str.join(' ', val.split(None)[1:4])
- val = str(datetime.datetime.strptime(val, '%d %b %Y').date())
...
+ value = str(datetime.datetime.utcfromtimestamp(
+ message.get_date()).date())
I also tweaked the HTML header date to be utcnow instead of the local
now() to make all times independent of the generator's local time.
This matches Gmane, which converts all Date headers to UTC (although
they use a 'GMT' suffix). Notmuch uses
g_mime_utils_header_decode_date to calculate the UTC timestamps, but
uses a NULL tz_offset which drops the information we'd need to get
back to the sender's local time [1]. With the generator's local time
arbitrarily different from the sender's and viewer's local time,
sticking with UTC seems the best bet.
[1]: https://developer.gnome.org/gmime/stable/gmime-gmime-utils.html#g-mime-utils-header-decode-date
Make this all one big string, using '...{date}...'.format(date=...) to
inject the date [1]. This syntax was added in Python 2.6, and is
preferred to %-formatting in Python 3 [1].
[1]: http://docs.python.org/2/library/stdtypes.html#str.format
The database in only used for notmuch.Query, so there's no need for
write access. This allows nmbug-status to run while the database is
being updated, without raising:
A Xapian exception occurred opening database: Unable to get write lock on …: already locked
Traceback (most recent call last):
File "./nmbug-status", line 182, in <module>
db = notmuch.Database(mode=notmuch.Database.MODE.READ_WRITE)
File "/…/notmuch/database.py", line 154, in __init__
self.open(path, mode)
File "/…/notmuch/database.py", line 214, in open
raise NotmuchError(status)
notmuch.errors.XapianError
The definitions of Thread, output_with_separator, and print_view were
between the main argparse and view-printing code. Group them together
with our existing read_config at the top of the module, which makes
for easier reading in the main section.
I also:
* Made 'headers' a print_view argument instead of a module-level
global. The list -> tuple conversion avoids having a mutable
default argument, which makes some people jumpy ;).
* Made 'db' a print_view argument instead of relying on the global
namespace to access it from print_view.
Now the suggested usage (listed by 'nmbug-status --help') is:
usage: nmbug-status [-h] [--text] [--config PATH] [--list-views]
[--get-query VIEW]
instead of the less obvious:
usage: nmbug-status [-h] [--text] [--config CONFIG] [--list-views]
[--get-query GET_QUERY]
Avoid:
$ ./nmbug-status --list-views
Traceback (most recent call last):
File "./nmbug-status", line 47, in <module>
'cat-file', 'blob', sha1+':status-config.json'],
TypeError: can't concat bytes to str
by explicitly converting the byte-stream read from Popen into a
Unicode string. On Python 2, this conversion is str -> unicode; on
Python 3 it is bytes -> str.
_ENCODING is derived from the user's locale (or system default) in an
attempt to match Git's output encoding. It may be more robust to skip
the encoding/decoding by using a Python wrapper like pygit2 [1] for
Git access. That's a fairly heavy dependency though, and using the
locale will probably work.
[1]: http://www.pygit2.org/
This is a pretty basic config to get started, generated using 'doxygen
-s -g' and mildly tweaked.
To generate the library man page man/man3/notmuch.3 from lib/notmuch.h
use:
$ doxygen devel/doxygen.cfg
NOTMUCH_VERSION_* macros in lib/notmuch.h are replaced with
LIBNOTMUCH_VERSION_* macros. Check that the values of those
match the LIBNOTMUCH_*_VERSION values in lib/Makefile.local.
New defines NOTMUCH_MAJOR_VERSION, NOTMUCH_MINOR_VERSION and
NOTMUCH_MICRO_VERSION were added to lib/notmuch.h.
Check that these match the current value defined in ./version.
This fixes races in thread-local and global tagging in notmuch-search
(e.g., "+", "-", "a", "*", etc.). Previously, these would modify tags
of new messages that arrived after the search. Now they only operate
on the messages that were in the threads when the search was
performed. This prevents surprises like archiving messages that
arrived in a thread after the search results were shown.
This eliminates `notmuch-search-find-thread-id-region(-search)'
because these functions strongly encouraged racy usage.
This fixes the two broken tests added by the previous patch.
These queries will match exactly the set of messages currently in the
thread, even if more messages later arrive. Two queries are provided:
one for matched messages and one for unmatched messages.
This can be used to fix race conditions with tagging threads from
search results. While tagging based on a thread: query can affect
messages that arrived after the search, tagging based on stable
queries affects only the messages the user was shown in the search UI.
Since we want clients to be able to depend on the presence of these
queries, this ushers in schema version 2.
Previously, the show schema and the search schema used different
"thread" non-terminals. While these schemata don't interact, this is
still confusing, so rename search's "thread" to "thread_summary". To
further limit confusion, prefix all top-level search non-terminals now
begin with "search_".
I find this script pretty useful when figuring out who to blame for
MIME rendering problems.
The notmuch repo will be the new primary home for this script, unless
and until a better home turns up.
After new notmuch release has been published the NEWS and manual
pages have been updated using these 2 programs.
Adding the tools to notmuch repository eases their use, adds more
transparency to the "process" and gives more people chance to
do the updates is one is unavailable to do it at the time being.
Current code does not distinguish between an empty string in the
NMBPREFIX environment variable and the variable being undefined. This
makes it impossible to define an empty prefix, if, e.g. somebody wants
to dump all of their tags with nmbug.