diff --git a/Makefile.local b/Makefile.local index d2e0c7a8..7699c208 100644 --- a/Makefile.local +++ b/Makefile.local @@ -1,7 +1,7 @@ # -*- makefile-gmake -*- .PHONY: all -all: notmuch notmuch-shared build-man build-info ruby-bindings python-cffi-bindings notmuch-git +all: notmuch notmuch-shared build-man build-info ruby-bindings python-cffi-bindings notmuch-git nmbug ifeq ($(MAKECMDGOALS),) ifeq ($(shell cat .first-build-message 2>/dev/null),) @NOTMUCH_FIRST_BUILD=1 $(MAKE) --no-print-directory all @@ -50,6 +50,10 @@ notmuch-git: notmuch-git.py cp $< $@ chmod ugo+x $@ +CLEAN := $(CLEAN) nmbug +nmbug: notmuch-git + ln -s $< $@ + .PHONY: dist dist: $(TAR_FILE) diff --git a/doc/Makefile.local b/doc/Makefile.local index d43ef269..2f67f4de 100644 --- a/doc/Makefile.local +++ b/doc/Makefile.local @@ -131,6 +131,7 @@ install-man: ${MAN_GZIP_FILES} install -m0644 $(filter %.5.gz,$(MAN_GZIP_FILES)) $(DESTDIR)/$(mandir)/man5 install -m0644 $(filter %.7.gz,$(MAN_GZIP_FILES)) $(DESTDIR)/$(mandir)/man7 cd $(DESTDIR)/$(mandir)/man1 && ln -sf notmuch.1.gz notmuch-setup.1.gz + cd $(DESTDIR)/$(mandir)/man1 && ln -sf notmuch-git.1.gz nmbug.1.gz endif ifneq ($(HAVE_SPHINX)$(HAVE_MAKEINFO),11) diff --git a/doc/man1/notmuch-git.rst b/doc/man1/notmuch-git.rst index 86f246b6..6a2d7fcd 100644 --- a/doc/man1/notmuch-git.rst +++ b/doc/man1/notmuch-git.rst @@ -7,7 +7,9 @@ notmuch-git SYNOPSIS ======== -**notmuch** **git** [-h] [-C *repo*] [-p *prefix*] [-v] [-l *log level*] *subcommand* +**notmuch** **git** [-h] [-N] [-C *repo*] [-p *prefix*] [-v] [-l *log level*] *subcommand* + +**nmbug** [-h] [-C *repo*] [-p *prefix*] [-v] [-l *log level*] *subcommand* DESCRIPTION =========== @@ -25,12 +27,17 @@ Supported options for `notmuch git` include show help message and exit +.. option:: -N, --nmbug + + Set defaults for :option:`--tag-prefix` and :option:`--git-dir` suitable for the + :any:`notmuch` bug tracker + .. option:: -C , --git-dir Operate on git repository *repo*. See :ref:`repo_location` for defaults. -.. option:: -p , --tag-prefix +.. option:: -p , --tag-prefix Operate only on tags with prefix *prefix*. See :ref:`prefix_val` for defaults. @@ -239,6 +246,10 @@ value to locate the git repository. - Environment variable :envvar:`NOTMUCH_GIT_DIR`. +- If invoked as `nmbug` or with the :option:`--nmbug` option, + :code:`$HOME/.nmbug`; otherwise + :code:`$XDG_DATA_HOME/notmuch/$NOTMUCH_PROFILE/git`. + .. _prefix_val: PREFIX VALUE @@ -251,9 +262,15 @@ value to define the tag prefix. - Environment variable :envvar:`NOTMUCH_GIT_PREFIX`. +- If invoked as `nmbug` or with the :option:`--nmbug` option, + :code:`notmuch::`, otherwise the empty string. + ENVIRONMENT =========== +Variable :envvar:`NOTMUCH_PROFILE` influences :ref:`repo_location`. +If it is unset, 'default' is assumed. + .. envvar:: NOTMUCH_GIT_DIR Default location of git repository. Overriden by :option:`--git-dir`. diff --git a/notmuch-git.py b/notmuch-git.py index e419cdf7..9d5c7876 100644 --- a/notmuch-git.py +++ b/notmuch-git.py @@ -425,6 +425,13 @@ def init(remote=None): This wraps 'git init' with a few extra steps to support subsequent status and commit commands. """ + from pathlib import Path + parent = Path(NOTMUCH_GIT_DIR).parent + try: + _os.makedirs(parent) + except FileExistsError: + pass + _spawn(args=['git', '--git-dir', NOTMUCH_GIT_DIR, 'init', '--initial-branch=master', '--quiet', '--bare'], wait=True) _git(args=['config', 'core.logallrefupdates', 'true'], wait=True) @@ -861,9 +868,19 @@ def _notmuch_config_get(key): stdout=_subprocess.PIPE, wait=True) if status != 0: _LOG.error("failed to run notmuch config") - sys.exit(1) + _sys.exit(1) return stdout.rstrip() +# based on BaseDirectory.save_data_path from pyxdg (LGPL2+) +def xdg_data_path(profile): + resource = _os.path.join('notmuch',profile,'git') + assert not resource.startswith('/') + _home = _os.path.expanduser('~') + xdg_data_home = _os.environ.get('XDG_DATA_HOME') or \ + _os.path.join(_home, '.local', 'share') + path = _os.path.join(xdg_data_home, resource) + return path + if __name__ == '__main__': import argparse @@ -875,8 +892,11 @@ if __name__ == '__main__': help='Git repository to operate on.') parser.add_argument( '-p', '--tag-prefix', metavar='PREFIX', - default = _os.getenv('NOTMUCH_GIT_PREFIX', 'notmuch::'), + default = None, help='Prefix of tags to operate on.') + parser.add_argument( + '-N', '--nmbug', action='store_true', + help='Set defaults for --tag-prefix and --git-dir for the notmuch bug tracker') parser.add_argument( '-l', '--log-level', choices=['critical', 'error', 'warning', 'info', 'debug'], @@ -987,16 +1007,36 @@ if __name__ == '__main__': args = parser.parse_args() + nmbug_mode = False + notmuch_profile = _os.getenv('NOTMUCH_PROFILE','default') + + if args.nmbug or _os.path.basename(__file__) == 'nmbug': + nmbug_mode = True + if args.git_dir: NOTMUCH_GIT_DIR = args.git_dir else: - NOTMUCH_GIT_DIR = _os.path.expanduser( - _os.getenv('NOTMUCH_GIT_DIR', _os.path.join('~', '.nmbug'))) - _NOTMUCH_GIT_DIR = _os.path.join(NOTMUCH_GIT_DIR, '.git') - if _os.path.isdir(_NOTMUCH_GIT_DIR): - NOTMUCH_GIT_DIR = _NOTMUCH_GIT_DIR + if nmbug_mode: + default = _os.path.join('~', '.nmbug') + else: + default = xdg_data_path(notmuch_profile) + + NOTMUCH_GIT_DIR = _os.path.expanduser(_os.getenv('NOTMUCH_GIT_DIR', default)) + + _NOTMUCH_GIT_DIR = _os.path.join(NOTMUCH_GIT_DIR, '.git') + if _os.path.isdir(_NOTMUCH_GIT_DIR): + NOTMUCH_GIT_DIR = _NOTMUCH_GIT_DIR + + if args.tag_prefix: + TAG_PREFIX = args.tag_prefix + else: + if nmbug_mode: + prefix = 'notmuch::' + else: + prefix = '' + + TAG_PREFIX = _os.getenv('NOTMUCH_GIT_PREFIX', prefix) - TAG_PREFIX = args.tag_prefix _ENCODED_TAG_PREFIX = _hex_quote(TAG_PREFIX, safe='+@=,') # quote ':' if args.log_level: @@ -1009,12 +1049,16 @@ if __name__ == '__main__': if _notmuch_config_get('built_with.sexp_queries') != 'true': _LOG.error("notmuch git needs sexp query support") - sys.exit(1) + _sys.exit(1) if not getattr(args, 'func', None): parser.print_usage() _sys.exit(1) + # The following two lines are used by the test suite. + _LOG.debug('prefix = {:s}'.format(TAG_PREFIX)) + _LOG.debug('repository = {:s}'.format(NOTMUCH_GIT_DIR)) + if args.func == help: arg_names = ['command'] else: diff --git a/test/T850-git.sh b/test/T850-git.sh index db76dae9..98233055 100755 --- a/test/T850-git.sh +++ b/test/T850-git.sh @@ -19,28 +19,28 @@ test_begin_subtest "clone" test_expect_success "notmuch git -p '' -C tags.git clone remote.git" test_begin_subtest "commit" -notmuch git -C tags.git -p '' commit +notmuch git -C tags.git commit git -C tags.git ls-tree -r --name-only HEAD | xargs dirname | sort -u | sed s,tags/,id:, > OUTPUT notmuch search --output=messages '*' | sort > EXPECTED test_expect_equal_file_nonempty EXPECTED OUTPUT test_begin_subtest "commit, with quoted tag" -notmuch git -C clone2.git -p '' clone tags.git +notmuch git -C clone2.git clone tags.git git -C clone2.git ls-tree -r --name-only HEAD | grep /inbox > BEFORE notmuch tag '+"quoted tag"' '*' -notmuch git -C clone2.git -p '' commit +notmuch git -C clone2.git commit notmuch tag '-"quoted tag"' '*' git -C clone2.git ls-tree -r --name-only HEAD | grep /inbox > AFTER test_expect_equal_file_nonempty BEFORE AFTER test_begin_subtest "commit (incremental)" notmuch tag +test id:20091117190054.GU3165@dottiness.seas.harvard.edu -notmuch git -C tags.git -p '' commit +notmuch git -C tags.git commit git -C tags.git ls-tree -r --name-only HEAD | grep 20091117190054 | sort > OUTPUT echo "--------------------------------------------------" >> OUTPUT notmuch tag -test id:20091117190054.GU3165@dottiness.seas.harvard.edu -notmuch git -C tags.git -p '' commit +notmuch git -C tags.git commit git -C tags.git ls-tree -r --name-only HEAD | grep 20091117190054 | sort >> OUTPUT cat < EXPECTED @@ -62,7 +62,7 @@ git -C tags.git ls-tree -r --name-only HEAD | grep 20091117190054 | sort > OUTPUT echo "--------------------------------------------------" >> OUTPUT notmuch tag -test::one id:20091117190054.GU3165@dottiness.seas.harvard.edu -notmuch git -C tags.git -p '' commit +notmuch git -C tags.git commit git -C tags.git ls-tree -r --name-only HEAD | grep 20091117190054 | sort >> OUTPUT cat < EXPECTED @@ -77,12 +77,12 @@ test_expect_equal_file_nonempty EXPECTED OUTPUT test_begin_subtest "checkout" notmuch dump > BEFORE notmuch tag -inbox '*' -notmuch git -C tags.git -p '' checkout +notmuch git -C tags.git checkout notmuch dump > AFTER test_expect_equal_file_nonempty BEFORE AFTER test_begin_subtest "archive" -notmuch git -C tags.git -p '' archive | tar tf - | \ +notmuch git -C tags.git archive | tar tf - | \ grep 20091117190054.GU3165@dottiness.seas.harvard.edu | sort > OUTPUT cat < EXPECTED tags/20091117190054.GU3165@dottiness.seas.harvard.edu/ @@ -90,32 +90,32 @@ tags/20091117190054.GU3165@dottiness.seas.harvard.edu/inbox tags/20091117190054.GU3165@dottiness.seas.harvard.edu/signed tags/20091117190054.GU3165@dottiness.seas.harvard.edu/unread EOF -notmuch git -C tags.git -p '' checkout +notmuch git -C tags.git checkout test_expect_equal_file EXPECTED OUTPUT test_begin_subtest "status" notmuch tag +test id:20091117190054.GU3165@dottiness.seas.harvard.edu -notmuch git -C tags.git -p '' status > OUTPUT +notmuch git -C tags.git status > OUTPUT cat < EXPECTED A 20091117190054.GU3165@dottiness.seas.harvard.edu test EOF -notmuch git -C tags.git -p '' checkout +notmuch git -C tags.git checkout test_expect_equal_file EXPECTED OUTPUT test_begin_subtest "fetch" notmuch tag +test2 id:20091117190054.GU3165@dottiness.seas.harvard.edu -notmuch git -C remote.git -p '' commit +notmuch git -C remote.git commit notmuch tag -test2 id:20091117190054.GU3165@dottiness.seas.harvard.edu -notmuch git -C tags.git -p '' fetch -notmuch git -C tags.git -p '' status > OUTPUT +notmuch git -C tags.git fetch +notmuch git -C tags.git status > OUTPUT cat < EXPECTED a 20091117190054.GU3165@dottiness.seas.harvard.edu test2 EOF -notmuch git -C tags.git -p '' checkout +notmuch git -C tags.git checkout test_expect_equal_file EXPECTED OUTPUT test_begin_subtest "merge" -notmuch git -C tags.git -p '' merge +notmuch git -C tags.git merge notmuch dump id:20091117190054.GU3165@dottiness.seas.harvard.edu | grep -v '^#' > OUTPUT cat < EXPECTED +inbox +signed +test2 +unread -- id:20091117190054.GU3165@dottiness.seas.harvard.edu @@ -124,10 +124,10 @@ test_expect_equal_file EXPECTED OUTPUT test_begin_subtest "push" notmuch tag +test3 id:20091117190054.GU3165@dottiness.seas.harvard.edu -notmuch git -C tags.git -p '' commit +notmuch git -C tags.git commit notmuch tag -test3 id:20091117190054.GU3165@dottiness.seas.harvard.edu -notmuch git -C tags.git -p '' push -notmuch git -C remote.git -p '' checkout +notmuch git -C tags.git push +notmuch git -C remote.git checkout notmuch dump id:20091117190054.GU3165@dottiness.seas.harvard.edu | grep -v '^#' > OUTPUT cat < EXPECTED +inbox +signed +test2 +test3 +unread -- id:20091117190054.GU3165@dottiness.seas.harvard.edu @@ -145,4 +145,69 @@ env NOTMUCH_CONFIG = CWD/notmuch-config EOF test_expect_equal_file EXPECTED OUTPUT +test_begin_subtest "--nmbug argument sets defaults" +notmuch git -ldebug --nmbug status |& grep '^\(prefix\|repository\)' | notmuch_dir_sanitize > OUTPUT +cat < EXPECTED +prefix = notmuch:: +repository = CWD/home/.nmbug +EOF +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "invoke as nmbug sets defaults" +"$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^\(prefix\|repository\)' | notmuch_dir_sanitize > OUTPUT +cat < EXPECTED +prefix = notmuch:: +repository = CWD/home/.nmbug +EOF +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "env variable NOTMUCH_GIT_DIR works when invoked as nmbug" +NOTMUCH_GIT_DIR=`pwd`/foo "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^repository' | notmuch_dir_sanitize > OUTPUT +cat < EXPECTED +repository = CWD/foo +EOF +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "env variable NOTMUCH_GIT_DIR works when invoked as 'notmuch git'" +NOTMUCH_GIT_DIR=`pwd`/remote.git notmuch git -ldebug status |& grep '^repository' | notmuch_dir_sanitize > OUTPUT +cat < EXPECTED +repository = CWD/remote.git +EOF +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "env variable NOTMUCH_GIT_PREFIX works when invoked as nmbug" +NOTMUCH_GIT_PREFIX=foo:: "$NOTMUCH_BUILDDIR"/nmbug -ldebug status |& grep '^prefix' | notmuch_dir_sanitize > OUTPUT +cat < EXPECTED +prefix = foo:: +EOF +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "env variable NOTMUCH_GIT_PREFIX works when invoked as 'notmuch git'" +NOTMUCH_GIT_PREFIX=env:: notmuch git -ldebug status |& grep '^prefix' | notmuch_dir_sanitize > OUTPUT +cat < EXPECTED +prefix = env:: +EOF +test_expect_equal_file EXPECTED OUTPUT + + +test_begin_subtest "init, xdg default location" +repo=home/.local/share/notmuch/default/git +notmuch git -ldebug init |& grep '^repository' | notmuch_dir_sanitize > OUTPUT +git -C $repo rev-parse --absolute-git-dir | notmuch_dir_sanitize >> OUTPUT +cat < EXPECTED +repository = CWD/$repo +CWD/$repo +EOF +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "init, xdg default location, with profile" +repo=home/.local/share/notmuch/work/git +NOTMUCH_PROFILE=work notmuch git -ldebug init |& grep '^repository' | notmuch_dir_sanitize > OUTPUT +git -C $repo rev-parse --absolute-git-dir | notmuch_dir_sanitize >> OUTPUT +cat < EXPECTED +repository = CWD/$repo +CWD/$repo +EOF +test_expect_equal_file EXPECTED OUTPUT + test_done