test/gravatar_test: check for https:// URL

d53ec734cb9a183e9b50ffe86dabe631834651b5 broke the Gravatar test
because it was checking for a http:// URL from url_for_email(), but that
commit changed the generated URL to use https://.  Update the test to
check for a https:// URL.

Signed-off-by: Daniel Harding <dharding@living180.net>
Merge pull request #397 from living180/fix_tests

tests: fix Gravatar test

Signed-off-by: David Aguilar <davvid@gmail.com>
tests/gravatar: another https:// fix

ffbd258b00ae8736af1b8ad6bbe7c3dd2fd8caba was supposed to fix the
Gravatar test, but there were actually two places where http:// was
changed to https://, and that commit only corrected for one.  Correct
the other one here.

Signed-off-by: Daniel Harding <dharding@living180.net>
Merge pull request #398 from living180/fix_tests2

tests: complete Gravatar test fix

Signed-off-by: David Aguilar <davvid@gmail.com>
widgets.diff: simplify DiffEditor.has_selection()

When I added the DiffEditor.has_selection() method, I missed the fact
that QTextCursor has a hasSelection() method.  Simplify
DiffEditor.has_selection() by reimplmenting it in terms of
QTextCursor.hasSelection().

Signed-off-by: Daniel Harding <dharding@living180.net>
diffparse: rewrite with improved accuracy

Previously, the DiffParser.process_diff_selection() method took the
contents of the text selection and searched for it in the output of git
diff to determine which subset of the diff to process.  Most of the time
this worked, but if only a small portion of the diff was selected, such
that the selection appeared multiple times in the diff, the wrong part
of the diff might be processed.  This is especially bad when performing
a Revert operation, because the user can lose data if reverting the
wrong lines.

This commit provides a complete rewrite of the cola.diffparse module
such that the Stage/Unstage/Revert operations should (modulo any bugs)
always process exactly the line(s) selected by the user.

Following is a summary of the changes, starting from the DiffParser
class and working outward:

Simplify the purpose of the DiffParser class.  It no longer knows
anything about models or how to apply changes to the index or the
worktree.  Nor does it call out to git anymore to load any data about
the diff.  The initializer now takes just two parameters:  the filename
(or relative path) of the file being diffed, and the actual text of the
diff (without the diff header).  The initializer uses a new standalone
function _parse_diff() to convert the diff text to a list of _DiffHunk
objects, which are stored on the instance in the hunks attribute.
DiffParser now has just two methods, the first of which is
generate_patch().  It takes the indexes of the first and last lines of
the diff to include in the patch, along with an optional boolean flag
indicating if a reverse patch should be generated.  It returns a string
containing the patch (including the diff header, generated using the
filename passed to the initializer), or None if the resulting patch
would not change anything.  The second method is generate_hunk_patch(),
which is a simple wrapper around the generate_hunk() method.  It takes a
single line index along with a reverse flag, and generates patch using
only the hunk containing the specified line.

Next is the ApplyDiffSelection command class, which is the sole user of
the DiffParser class.  Update the initializer to replace the offset and
selection_text parameters (indicating the start and contents of the
selection, respectively), with three parameters indicating the indexes
of the first and last selected lines (or of the line containing the
cursor if there is no selection), along with a boolean indicating if
there is actually any text selected or not (to differentiate between a
selection on a single line versus no selection at all).  Merge the
functionality of the old DiffParser.process_diff_selection() method into
the do() method.  This method now first constructs a DiffParser
instance, passing it the filename and diff text from the model.  It then
uses the has_selection attribute to call either the generate_patch() or
the generate_hunk_patch() method of the DiffParser instance, depending
on whether or not there is a selection.  Finally, if the resulting patch
is not None, it writes it to a temporary file which is passed to either
the model's apply_diff_to_worktree() or apply_diff() methods, depending
on the operation being performed (Revert vs. Stage/Unstage).  It then
logs the status and updates the model as before.

Lastly, update the DiffEditor widget class.  Add a selected_lines()
method, which returns the indexes of the first and last selected lines
(or of the line containing the cursor if there is no selection).  Update
the process_diff_selection() method to use this new method along with
the has_selection() method to pass the appropriate line indexes and the
has_selection flag when constructing the ApplyDiffSelection command.
Also, to reflect the change to ApplyDiffSelection, replace the staged
parameter with a reverse parameter, and update the callers of the
process_diff_selection() method appropriately.

In addition, update the tests to reflect these changes, and remove the
diff-*-reverse.txt fixtures as they are no longer needed (the code now
converts the forward diff to a reverse diff when necessary).

Signed-off-by: Daniel Harding <dharding@living180.net>
Merge pull request #399 from living180/diffparser_work

diff: rewrite DiffParser

Signed-off-by: David Aguilar <davvid@gmail.com>
utils: use builtin Python tempfile module

Reimplement tmp_file_pattern() and tmp_filename() using primitives from
Python's tempfile module.  Remove the tmp_dir() function and instead use
tempfile.gettempdir() to increase portability.  (tmp_dir() hard-coded
'/tmp' as a fallback, which doesn't work on Windows.)  Also change
tmp_filename() to use tempfile.mkstemp() to avoid (mostly theoretical)
race conditions in the generation of the temporary filename.

Signed-off-by: Daniel Harding <dharding@living180.net>
cmds: better temp file cleanup

Use try/finally blocks to ensure that files created by
utils.tmp_filename() are always removed even in case of an exception.

Signed-off-by: Daniel Harding <dharding@living180.net>
utils: fix tmp_file_pattern()'s pattern

tmp_file_pattern() was returning a regex-style pattern, which was then
being passed to glob.glob().  As a result, it did not match the paths it
was intended to.  Update tmp_file_pattern() to return a glob-style
pattern.

Signed-off-by: Daniel Harding <dharding@living180.net>
Merge pull request #400 from living180/temp_work

utils: better temp file handling

Signed-off-by: David Aguilar <davvid@gmail.com>
doc: add v2.1.0 release notes draft

Signed-off-by: David Aguilar <davvid@gmail.com>
dag: rename --count to --max-count for consistency with git-log

Signed-off-by: David Aguilar <davvid@gmail.com>
dag: pass unknown arguments along to git-log

Use parse_known_args() and arrange for all unknown arguments to be
passed along to git-log via the dag query.  This allows any git-log
specific option to be passed to git-dag without its command-line parser
getting in the way.

Closes #389

Signed-off-by: David Aguilar <davvid@gmail.com>