Hello community,

here is the log from the commit of package python-xonsh for openSUSE:Factory 
checked in at 2020-03-24 22:37:26
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-xonsh (Old)
 and      /work/SRC/openSUSE:Factory/.python-xonsh.new.3160 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-xonsh"

Tue Mar 24 22:37:26 2020 rev:2 rq:787855 version:0.9.15

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-xonsh/python-xonsh.changes        
2020-03-17 13:07:52.797694598 +0100
+++ /work/SRC/openSUSE:Factory/.python-xonsh.new.3160/python-xonsh.changes      
2020-03-24 22:39:02.253284639 +0100
@@ -1,0 +2,26 @@
+Tue Mar 24 15:07:37 UTC 2020 - [email protected]
+
+- version update to 0.9.15
+  **Added:**
+  * Adds documentation for how to setup an emacs editing mode for xonsh.
+  * New ``$XONSH_TRACE_SUBPROC`` environment variable.
+  * Added ``-l``, ``-c`` and ``-a`` options to ``xexec``, works now like 
``exec``
+    in bash/zsh
+  * **$HISTCONTROL** - *errordups* support for history-sqlite backend
+  **Changed:**
+  * ``-l`` switch works like bash, loads environment in non-interactive shell
+  * The xonsh pytest plugin no longer messes up the test order for pytest. Xsh 
test
+    are still executed first to avoid a bug were other tests would prevent 
``test_*.xsh``
+    files to run correctly.
+  * New repo name for xxh
+  **Fixed:**
+  * Correctly follow symlinks when using dot-dot paths with cd -P.
+  * ``execx`` does not require the input string to be newline-terminated.
+  * ``evalx`` accepts newline-terminated input string.
+  * Fixed issue where negative exit codes (such as those produced
+    by core dumps) where treated as logical successes when chaining
+    processes with other boolean expressions.
+  * Fixed XONSH_TRACE_SUBPROC for pipeline command.
+  * updated CONTRIBUTING.rst about running pylint for changed files
+
+-------------------------------------------------------------------

Old:
----
  xonsh-0.9.14.tar.gz

New:
----
  xonsh-0.9.15.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-xonsh.spec ++++++
--- /var/tmp/diff_new_pack.Ivz2kS/_old  2020-03-24 22:39:03.445285218 +0100
+++ /var/tmp/diff_new_pack.Ivz2kS/_new  2020-03-24 22:39:03.445285218 +0100
@@ -19,7 +19,7 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define skip_python2 1
 Name:           python-xonsh
-Version:        0.9.14
+Version:        0.9.15
 Release:        0
 Summary:        Python-powered, cross-platform, Unix-gazing shell
 License:        BSD-2-Clause

++++++ xonsh-0.9.14.tar.gz -> xonsh-0.9.15.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/CHANGELOG.rst 
new/xonsh-0.9.15/CHANGELOG.rst
--- old/xonsh-0.9.14/CHANGELOG.rst      2020-02-28 22:07:39.000000000 +0100
+++ new/xonsh-0.9.15/CHANGELOG.rst      2020-03-19 21:38:46.000000000 +0100
@@ -4,6 +4,51 @@
 
 .. current developments
 
+v0.9.15
+====================
+
+**Added:**
+
+* Adds documentation for how to setup an emacs editing mode for xonsh.
+* New ``$XONSH_TRACE_SUBPROC`` environment variable.
+* Added ``-l``, ``-c`` and ``-a`` options to ``xexec``, works now like ``exec``
+  in bash/zsh
+* **$HISTCONTROL** - *errordups* support for history-sqlite backend
+
+**Changed:**
+
+* ``-l`` switch works like bash, loads environment in non-interactive shell
+* The xonsh pytest plugin no longer messes up the test order for pytest. Xsh 
test
+  are still executed first to avoid a bug were other tests would prevent 
``test_*.xsh`` 
+  files to run correctly.
+* New repo name for xxh
+
+**Fixed:**
+
+* Correctly follow symlinks when using dot-dot paths with cd -P.
+* ``execx`` does not require the input string to be newline-terminated.
+* ``evalx`` accepts newline-terminated input string.
+* Fixed issue where negative exit codes (such as those produced
+  by core dumps) where treated as logical successes when chaining
+  processes with other boolean expressions.
+* Fixed XONSH_TRACE_SUBPROC for pipeline command.
+* updated CONTRIBUTING.rst about running pylint for changed files
+
+**Authors:**
+
+* Anthony Scopatz
+* Morten Enemark Lund
+* David Strobach
+* anki-code
+* Samuel Lotz
+* Gyuri Horak
+* Noortheen Raja
+* Gabriel Vogel
+* anki
+* Jerzy Drozdz
+
+
+
 v0.9.14
 ====================
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/PKG-INFO new/xonsh-0.9.15/PKG-INFO
--- old/xonsh-0.9.14/PKG-INFO   2020-02-28 22:12:08.000000000 +0100
+++ new/xonsh-0.9.15/PKG-INFO   2020-03-19 21:41:58.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: xonsh
-Version: 0.9.14
+Version: 0.9.15
 Summary: Python-powered, cross-platform, Unix-gazing shell
 Home-page: https://github.com/xonsh/xonsh
 Author: Anthony Scopatz
@@ -38,7 +38,7 @@
         - `gitsome <https://github.com/donnemartin/gitsome>`_: A supercharged 
Git/shell autocompleter with GitHub integration.
         - `rever <https://regro.github.io/rever-docs/>`_: Cross-platform 
software release tool.
         - `Regro autotick bot <https://github.com/regro/cf-scripts>`_: Regro 
Conda-Forge autoticker.
-        - `xxh <https://github.com/xonssh/xxh>`_: Using xonsh wherever you go 
through the ssh.
+        - `xxh <https://github.com/xxh/xxh>`_: Using xonsh wherever you go 
through the ssh.
         
 Platform: Cross Platform
 Classifier: Programming Language :: Python :: 3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/README.rst new/xonsh-0.9.15/README.rst
--- old/xonsh-0.9.14/README.rst 2020-02-28 21:45:23.000000000 +0100
+++ new/xonsh-0.9.15/README.rst 2020-03-15 22:38:09.000000000 +0100
@@ -29,4 +29,4 @@
 - `gitsome <https://github.com/donnemartin/gitsome>`_: A supercharged 
Git/shell autocompleter with GitHub integration.
 - `rever <https://regro.github.io/rever-docs/>`_: Cross-platform software 
release tool.
 - `Regro autotick bot <https://github.com/regro/cf-scripts>`_: Regro 
Conda-Forge autoticker.
-- `xxh <https://github.com/xonssh/xxh>`_: Using xonsh wherever you go through 
the ssh.
+- `xxh <https://github.com/xxh/xxh>`_: Using xonsh wherever you go through the 
ssh.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/tests/aliases/test_xexec.py 
new/xonsh-0.9.15/tests/aliases/test_xexec.py
--- old/xonsh-0.9.14/tests/aliases/test_xexec.py        1970-01-01 
01:00:00.000000000 +0100
+++ new/xonsh-0.9.15/tests/aliases/test_xexec.py        2020-03-01 
20:01:11.000000000 +0100
@@ -0,0 +1,84 @@
+import os
+import inspect
+import pytest
+import sys
+
+from xonsh.aliases import xexec
+
+
[email protected]
+def mockexecvpe(monkeypatch):
+    def mocked_execvpe(_command, _args, _env):
+        pass
+
+    monkeypatch.setattr(os, "execvpe", mocked_execvpe)
+
+
+def test_noargs(mockexecvpe):
+    assert xexec([]) == (None, "xonsh: exec: no args specified\n", 1)
+
+
+def test_missing_command(mockexecvpe):
+    assert xexec(["-a", "foo"]) == (None, "xonsh: exec: no command 
specified\n", 1)
+    assert xexec(["-c"]) == (None, "xonsh: exec: no command specified\n", 1)
+    assert xexec(["-l"]) == (None, "xonsh: exec: no command specified\n", 1)
+
+
+def test_command_not_found(monkeypatch):
+
+    dummy_error_msg = "This is dummy error message, file not found or 
something like that"
+    command = "non_existing_command"
+
+    def mocked_execvpe(_command, _args, _env):
+        raise FileNotFoundError(2, dummy_error_msg)
+    monkeypatch.setattr(os, "execvpe", mocked_execvpe)
+
+    assert xexec([command]) == (None,
+                                "xonsh: exec: file not found: {}: {}" 
"\n".format(dummy_error_msg, command),
+                                1)
+
+
+def test_help(mockexecvpe):
+    assert xexec(["-h"]) == inspect.getdoc(xexec)
+    assert xexec(["--help"]) == inspect.getdoc(xexec)
+
+
+def test_a_switch(monkeypatch):
+    called = {}
+
+    def mocked_execvpe(command, args, env):
+        called.update({"command": command, "args": args, "env": env})
+
+    monkeypatch.setattr(os, "execvpe", mocked_execvpe)
+    proc_name = "foo"
+    command = "bar"
+    command_args = ["1"]
+    xexec(["-a", proc_name, command] + command_args)
+    assert called["command"] == command
+    assert called["args"][0] == proc_name
+    assert len(called["args"]) == len([command] + command_args)
+
+
+def test_l_switch(monkeypatch):
+    called = {}
+
+    def mocked_execvpe(command, args, env):
+        called.update({"command": command, "args": args, "env": env})
+
+    monkeypatch.setattr(os, "execvpe", mocked_execvpe)
+    command = "bar"
+    xexec(["-l", command, "1"])
+
+    assert called["args"][0].startswith("-")
+
+
+def test_c_switch(monkeypatch):
+    called = {}
+
+    def mocked_execvpe(command, args, env):
+        called.update({"command": command, "args": args, "env": env})
+
+    monkeypatch.setattr(os, "execvpe", mocked_execvpe)
+    command = "sleep"
+    xexec(["-c", command, "1"])
+    assert called["env"] == {}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/tests/test_environ.py 
new/xonsh-0.9.15/tests/test_environ.py
--- old/xonsh-0.9.14/tests/test_environ.py      2020-02-28 21:45:23.000000000 
+0100
+++ new/xonsh-0.9.15/tests/test_environ.py      2020-03-19 16:51:32.000000000 
+0100
@@ -101,6 +101,14 @@
     assert "ignoredups" in env["HISTCONTROL"]
 
 
+def test_histcontrol_ignoreerr_ignoredups_erase_dups():
+    env = Env(HISTCONTROL="ignoreerr,ignoredups,ignoreerr,erasedups")
+    assert len(env["HISTCONTROL"]) == 3
+    assert "ignoreerr" in env["HISTCONTROL"]
+    assert "ignoredups" in env["HISTCONTROL"]
+    assert "erasedups" in env["HISTCONTROL"]
+
+
 def test_swap():
     env = Env(VAR="wakka")
     assert env["VAR"] == "wakka"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/tests/test_execer.py 
new/xonsh-0.9.15/tests/test_execer.py
--- old/xonsh-0.9.14/tests/test_execer.py       2019-02-08 17:46:55.000000000 
+0100
+++ new/xonsh-0.9.15/tests/test_execer.py       2020-03-19 16:51:32.000000000 
+0100
@@ -2,7 +2,13 @@
 """Tests the xonsh lexer."""
 import os
 
-from tools import check_eval, check_parse, skip_if_on_unix, skip_if_on_windows
+from tools import (
+    check_eval,
+    check_exec,
+    check_parse,
+    skip_if_on_unix,
+    skip_if_on_windows,
+)
 
 import pytest
 
@@ -138,3 +144,12 @@
 )
 def test_two_echo_line_cont(code):
     assert check_parse(code)
+
+
+def test_eval_eol():
+    assert check_eval("0") and check_eval("0\n")
+
+
+def test_exec_eol():
+    locs = dict()
+    assert check_exec("a=0", locs=locs) and check_exec("a=0\n", locs=locs)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/tests/test_history_sqlite.py 
new/xonsh-0.9.15/tests/test_history_sqlite.py
--- old/xonsh-0.9.14/tests/test_history_sqlite.py       2018-12-07 
17:18:21.000000000 +0100
+++ new/xonsh-0.9.15/tests/test_history_sqlite.py       2020-03-19 
16:51:32.000000000 +0100
@@ -169,6 +169,27 @@
     assert -1 == hist.rtns[-1]
 
 
+def test_histcontrol_erase_dup(hist, xonsh_builtins):
+    """Test HISTCONTROL=erasedups"""
+
+    xonsh_builtins.__xonsh__.env["HISTCONTROL"] = "erasedups"
+    assert len(hist) == 0
+
+    hist.append({"inp": "ls foo", "rtn": 2})
+    hist.append({"inp": "ls foobazz", "rtn": 0})
+    hist.append({"inp": "ls foo", "rtn": 0})
+    hist.append({"inp": "ls foobazz", "rtn": 0})
+    hist.append({"inp": "ls foo", "rtn": 0})
+    assert len(hist) == 2
+    assert len(hist.inps) == 5
+
+    items = list(hist.items())
+    assert "ls foo" == items[-1]["inp"]
+    assert "ls foobazz" == items[-2]["inp"]
+    assert items[-2]["frequency"] == 2
+    assert items[-1]["frequency"] == 3
+
+
 @pytest.mark.parametrize(
     "index, exp",
     [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/tests/test_integrations.py 
new/xonsh-0.9.15/tests/test_integrations.py
--- old/xonsh-0.9.14/tests/test_integrations.py 2020-02-28 21:45:23.000000000 
+0100
+++ new/xonsh-0.9.15/tests/test_integrations.py 2020-03-02 02:23:41.000000000 
+0100
@@ -559,3 +559,11 @@
     "verify pipe between subprocesses doesn't throw an exception"
     check_run_xonsh(cmd, fmt, exp)
 
+
+@skip_if_on_windows
+def test_negative_exit_codes_fail():
+    # see issue 3309
+    script = 'python -c "import os; os.abort()" && echo OK\n'
+    out, err, rtn = run_xonsh(script)
+    assert "OK" is not out
+    assert "OK" is not err
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/tests/test_lib/tools.py 
new/xonsh-0.9.15/tests/test_lib/tools.py
--- old/xonsh-0.9.14/tests/test_lib/tools.py    2020-02-28 20:11:11.000000000 
+0100
+++ new/xonsh-0.9.15/tests/test_lib/tools.py    2020-03-19 16:51:32.000000000 
+0100
@@ -174,8 +174,6 @@
 
 
 def check_exec(input, **kwargs):
-    if not input.endswith("\n"):
-        input += "\n"
     builtins.__xonsh__.execer.exec(input, **kwargs)
     return True
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/tests/testfile 
new/xonsh-0.9.15/tests/testfile
--- old/xonsh-0.9.14/tests/testfile     1970-01-01 01:00:00.000000000 +0100
+++ new/xonsh-0.9.15/tests/testfile     2018-11-08 19:25:07.000000000 +0100
@@ -0,0 +1 @@
+                                                                               
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                              tcgetattr                         
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                tcgetattr                                                       
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                             tcsetattr          
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                               isatty                                           
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                       
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/tests/tools.py 
new/xonsh-0.9.15/tests/tools.py
--- old/xonsh-0.9.14/tests/tools.py     2020-02-28 20:11:11.000000000 +0100
+++ new/xonsh-0.9.15/tests/tools.py     2020-03-19 16:51:32.000000000 +0100
@@ -174,8 +174,6 @@
 
 
 def check_exec(input, **kwargs):
-    if not input.endswith("\n"):
-        input += "\n"
     builtins.__xonsh__.execer.exec(input, **kwargs)
     return True
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/tests/tttt new/xonsh-0.9.15/tests/tttt
--- old/xonsh-0.9.14/tests/tttt 1970-01-01 01:00:00.000000000 +0100
+++ new/xonsh-0.9.15/tests/tttt 2018-10-02 04:48:49.000000000 +0200
@@ -0,0 +1 @@
+Wow mom!
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/__amalgam__.py 
new/xonsh-0.9.15/xonsh/__amalgam__.py
--- old/xonsh-0.9.14/xonsh/__amalgam__.py       2020-02-28 22:12:08.000000000 
+0100
+++ new/xonsh-0.9.15/xonsh/__amalgam__.py       2020-03-19 21:41:58.000000000 
+0100
@@ -12347,10 +12347,10 @@
     env = builtins.__xonsh__.env
     old = env["PWD"]
     new = os.path.join(old, newdir)
-    absnew = os.path.abspath(new)
 
     if follow_symlinks:
-        absnew = os.path.realpath(absnew)
+        new = os.path.realpath(new)
+    absnew = os.path.abspath(new)
 
     try:
         os.chdir(absnew)
@@ -15866,7 +15866,7 @@
         rtn = self.returncode
         if (
             rtn is not None
-            and rtn > 0
+            and rtn != 0
             and builtins.__xonsh__.env.get("RAISE_SUBPROC_ERROR")
         ):
             try:
@@ -18323,8 +18323,8 @@
     @property
     def style_name(self):
         """Current XONSH_COLOR_STYLE value"""
-        env = builtins.__xonsh__.env
-        env_style_name = env.get("XONSH_COLOR_STYLE")
+        env = getattr(builtins.__xonsh__, "env", {})
+        env_style_name = env.get("XONSH_COLOR_STYLE", "default")
         if self._style_name is None or self._style_name != env_style_name:
             self._style_name = env_style_name
             self._style = self._dtyped = None
@@ -18546,6 +18546,7 @@
         "XONSH_STDERR_POSTFIX": (is_string, ensure_string, ensure_string),
         "XONSH_STORE_STDOUT": (is_bool, to_bool, bool_to_str),
         "XONSH_STORE_STDIN": (is_bool, to_bool, bool_to_str),
+        "XONSH_TRACE_SUBPROC": (is_bool, to_bool, bool_to_str),
         "XONSH_TRACEBACK_LOGFILE": (is_logfile_opt, to_logfile_opt, 
logfile_opt_to_str),
         "XONSH_DATETIME_FORMAT": (is_string, ensure_string, ensure_string),
     }
@@ -18725,6 +18726,7 @@
         "XONSH_HISTORY_SIZE": (8128, "commands"),
         "XONSH_LOGIN": False,
         "XONSH_PROC_FREQUENCY": 1e-4,
+        "XONSH_TRACE_SUBPROC": False,
         "XONSH_SHOW_TRACEBACK": False,
         "XONSH_STDERR_PREFIX": "",
         "XONSH_STDERR_POSTFIX": "",
@@ -18922,8 +18924,10 @@
             "that determine what commands are saved to the history list. By "
             "default all commands are saved. The option ``ignoredups`` will 
not "
             "save the command if it matches the previous command. The option "
-            "'ignoreerr' will cause any commands that fail (i.e. return 
non-zero "
-            "exit status) to not be added to the history list.",
+            "``ignoreerr`` will cause any commands that fail (i.e. return 
non-zero "
+            "exit status) to not be added to the history list. The option "
+            "``erasedups`` will remove all previous commands that matches and 
updates the frequency. "
+            "Note: ``erasedups`` is supported only in sqlite backend).",
             store_as_str=True,
         ),
         "IGNOREEOF": VarDocs("Prevents Ctrl-D from exiting the shell."),
@@ -19283,6 +19287,9 @@
             "xonsh process threads sleep for while running command pipelines. "
             "The value has units of seconds [s]."
         ),
+        "XONSH_TRACE_SUBPROC": VarDocs(
+            "Set to ``True`` to show arguments list of every executed 
subprocess command."
+        ),
         "XONSH_SHOW_TRACEBACK": VarDocs(
             "Controls if a traceback is shown if exceptions occur in the 
shell. "
             "Set to ``True`` to always show traceback or ``False`` to always 
hide. "
@@ -21364,7 +21371,7 @@
 
 
 def xexec(args, stdin=None):
-    """exec [-h|--help] command [args...]
+    """exec [-h|--help] [-cl] [-a name] command [args...]
 
     exec (also aliased as xexec) uses the os.execvpe() function to
     replace the xonsh process with the specified program. This provides
@@ -21374,6 +21381,13 @@
         bash $
 
     The '-h' and '--help' options print this message and exit.
+    If the '-l' option is supplied, the shell places a dash at the
+    beginning of the zeroth argument passed to command to simulate login
+    shell.
+    The '-c' option causes command to be executed with an empty environment.
+    If '-a' is supplied, the shell passes name as the zeroth argument
+    to the executed command.
+
 
     Notes
     -----
@@ -21387,18 +21401,40 @@
     """
     if len(args) == 0:
         return (None, "xonsh: exec: no args specified\n", 1)
-    elif args[0] == "-h" or args[0] == "--help":
+
+    parser = argparse.ArgumentParser(add_help=False)
+    parser.add_argument("-h", "--help", action="store_true")
+    parser.add_argument("-l", dest="login", action="store_true")
+    parser.add_argument("-c", dest="clean", action="store_true")
+    parser.add_argument("-a", dest="name", nargs="?")
+    parser.add_argument("command", nargs=argparse.REMAINDER)
+    args = parser.parse_args(args)
+
+    if args.help:
         return inspect.getdoc(xexec)
-    else:
+
+    if len(args.command) == 0:
+        return (None, "xonsh: exec: no command specified\n", 1)
+
+    command = args.command[0]
+    if args.name is not None:
+        args.command[0] = args.name
+    if args.login:
+        args.command[0] = "-{}".format(args.command[0])
+
+    denv = {}
+    if not args.clean:
         denv = builtins.__xonsh__.env.detype()
-        try:
-            os.execvpe(args[0], args, denv)
-        except FileNotFoundError as e:
-            return (
-                None,
-                "xonsh: exec: file not found: {}: {}" "\n".format(e.args[1], 
args[0]),
-                1,
-            )
+
+    try:
+        os.execvpe(command, args.command, denv)
+    except FileNotFoundError as e:
+        return (
+            None,
+            "xonsh: exec: file not found: {}: {}"
+            "\n".format(e.args[1], args.command[0]),
+            1,
+        )
 
 
 class AWitchAWitch(argparse.Action):
@@ -22520,6 +22556,9 @@
 
     Lastly, the captured argument affects only the last real command.
     """
+    if builtins.__xonsh__.env.get("XONSH_TRACE_SUBPROC"):
+        print("TRACE SUBPROC: %s" % str(cmds), file=sys.stderr)
+
     specs = cmds_to_specs(cmds, captured=captured)
     captured = specs[-1].captured
     if captured == "hiddenobject":
@@ -23234,6 +23273,7 @@
         if isinstance(input, types.CodeType):
             code = input
         else:
+            input = input.rstrip("\n")
             if filename is None:
                 filename = self.filename
             code = self.compile(
@@ -23263,6 +23303,8 @@
         if isinstance(input, types.CodeType):
             code = input
         else:
+            if not input.endswith("\n"):
+                input += "\n"
             if filename is None:
                 filename = self.filename
             code = self.compile(
@@ -24034,7 +24076,11 @@
     env = builtins.__xonsh__.env
     rc = shell_kwargs.get("rc", None)
     rc = env.get("XONSHRC") if rc is None else rc
-    if args.mode != XonshMode.interactive and not args.force_interactive:
+    if (
+        args.mode != XonshMode.interactive
+        and not args.force_interactive
+        and not args.login
+    ):
         #  Don't load xonshrc if not interactive shell
         rc = None
     events.on_pre_rc.fire()
@@ -24071,7 +24117,8 @@
         "cacheall": args.cacheall,
         "ctx": builtins.__xonsh__.ctx,
     }
-    if args.login:
+    if args.login or sys.argv[0].startswith("-"):
+        args.login = True
         shell_kwargs["login"] = True
     if args.norc:
         shell_kwargs["rc"] = ()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/__init__.py 
new/xonsh-0.9.15/xonsh/__init__.py
--- old/xonsh-0.9.14/xonsh/__init__.py  2020-02-28 22:12:08.000000000 +0100
+++ new/xonsh-0.9.15/xonsh/__init__.py  2020-03-19 21:41:58.000000000 +0100
@@ -1,4 +1,4 @@
-__version__ = "0.9.14"
+__version__ = "0.9.15"
 
 
 # amalgamate exclude jupyter_kernel parser_table parser_test_table pyghooks
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/aliases.py 
new/xonsh-0.9.15/xonsh/aliases.py
--- old/xonsh-0.9.14/xonsh/aliases.py   2020-02-28 21:45:27.000000000 +0100
+++ new/xonsh-0.9.15/xonsh/aliases.py   2020-03-01 20:01:11.000000000 +0100
@@ -610,7 +610,7 @@
 
 
 def xexec(args, stdin=None):
-    """exec [-h|--help] command [args...]
+    """exec [-h|--help] [-cl] [-a name] command [args...]
 
     exec (also aliased as xexec) uses the os.execvpe() function to
     replace the xonsh process with the specified program. This provides
@@ -620,6 +620,13 @@
         bash $
 
     The '-h' and '--help' options print this message and exit.
+    If the '-l' option is supplied, the shell places a dash at the
+    beginning of the zeroth argument passed to command to simulate login
+    shell.
+    The '-c' option causes command to be executed with an empty environment.
+    If '-a' is supplied, the shell passes name as the zeroth argument
+    to the executed command.
+
 
     Notes
     -----
@@ -633,18 +640,40 @@
     """
     if len(args) == 0:
         return (None, "xonsh: exec: no args specified\n", 1)
-    elif args[0] == "-h" or args[0] == "--help":
+
+    parser = argparse.ArgumentParser(add_help=False)
+    parser.add_argument("-h", "--help", action="store_true")
+    parser.add_argument("-l", dest="login", action="store_true")
+    parser.add_argument("-c", dest="clean", action="store_true")
+    parser.add_argument("-a", dest="name", nargs="?")
+    parser.add_argument("command", nargs=argparse.REMAINDER)
+    args = parser.parse_args(args)
+
+    if args.help:
         return inspect.getdoc(xexec)
-    else:
+
+    if len(args.command) == 0:
+        return (None, "xonsh: exec: no command specified\n", 1)
+
+    command = args.command[0]
+    if args.name is not None:
+        args.command[0] = args.name
+    if args.login:
+        args.command[0] = "-{}".format(args.command[0])
+
+    denv = {}
+    if not args.clean:
         denv = builtins.__xonsh__.env.detype()
-        try:
-            os.execvpe(args[0], args, denv)
-        except FileNotFoundError as e:
-            return (
-                None,
-                "xonsh: exec: file not found: {}: {}" "\n".format(e.args[1], 
args[0]),
-                1,
-            )
+
+    try:
+        os.execvpe(command, args.command, denv)
+    except FileNotFoundError as e:
+        return (
+            None,
+            "xonsh: exec: file not found: {}: {}"
+            "\n".format(e.args[1], args.command[0]),
+            1,
+        )
 
 
 class AWitchAWitch(argparse.Action):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/built_ins.py 
new/xonsh-0.9.15/xonsh/built_ins.py
--- old/xonsh-0.9.14/xonsh/built_ins.py 2020-02-28 21:45:23.000000000 +0100
+++ new/xonsh-0.9.15/xonsh/built_ins.py 2020-03-15 22:38:09.000000000 +0100
@@ -934,6 +934,9 @@
 
     Lastly, the captured argument affects only the last real command.
     """
+    if builtins.__xonsh__.env.get("XONSH_TRACE_SUBPROC"):
+        print("TRACE SUBPROC: %s" % str(cmds), file=sys.stderr)
+
     specs = cmds_to_specs(cmds, captured=captured)
     captured = specs[-1].captured
     if captured == "hiddenobject":
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/dev.githash 
new/xonsh-0.9.15/xonsh/dev.githash
--- old/xonsh-0.9.14/xonsh/dev.githash  2020-02-28 20:11:22.000000000 +0100
+++ new/xonsh-0.9.15/xonsh/dev.githash  2020-03-19 16:51:53.000000000 +0100
@@ -1 +1 @@
-777bdc73|Feb 23 13:28:31 2020
\ No newline at end of file
+feeb6315|Mar 19 10:50:33 2020
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/dirstack.py 
new/xonsh-0.9.15/xonsh/dirstack.py
--- old/xonsh-0.9.14/xonsh/dirstack.py  2018-11-16 16:20:26.000000000 +0100
+++ new/xonsh-0.9.15/xonsh/dirstack.py  2020-03-15 22:38:09.000000000 +0100
@@ -147,10 +147,10 @@
     env = builtins.__xonsh__.env
     old = env["PWD"]
     new = os.path.join(old, newdir)
-    absnew = os.path.abspath(new)
 
     if follow_symlinks:
-        absnew = os.path.realpath(absnew)
+        new = os.path.realpath(new)
+    absnew = os.path.abspath(new)
 
     try:
         os.chdir(absnew)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/environ.py 
new/xonsh-0.9.15/xonsh/environ.py
--- old/xonsh-0.9.14/xonsh/environ.py   2020-02-28 21:45:23.000000000 +0100
+++ new/xonsh-0.9.15/xonsh/environ.py   2020-03-19 16:51:32.000000000 +0100
@@ -403,8 +403,8 @@
     @property
     def style_name(self):
         """Current XONSH_COLOR_STYLE value"""
-        env = builtins.__xonsh__.env
-        env_style_name = env.get("XONSH_COLOR_STYLE")
+        env = getattr(builtins.__xonsh__, "env", {})
+        env_style_name = env.get("XONSH_COLOR_STYLE", "default")
         if self._style_name is None or self._style_name != env_style_name:
             self._style_name = env_style_name
             self._style = self._dtyped = None
@@ -626,6 +626,7 @@
         "XONSH_STDERR_POSTFIX": (is_string, ensure_string, ensure_string),
         "XONSH_STORE_STDOUT": (is_bool, to_bool, bool_to_str),
         "XONSH_STORE_STDIN": (is_bool, to_bool, bool_to_str),
+        "XONSH_TRACE_SUBPROC": (is_bool, to_bool, bool_to_str),
         "XONSH_TRACEBACK_LOGFILE": (is_logfile_opt, to_logfile_opt, 
logfile_opt_to_str),
         "XONSH_DATETIME_FORMAT": (is_string, ensure_string, ensure_string),
     }
@@ -805,6 +806,7 @@
         "XONSH_HISTORY_SIZE": (8128, "commands"),
         "XONSH_LOGIN": False,
         "XONSH_PROC_FREQUENCY": 1e-4,
+        "XONSH_TRACE_SUBPROC": False,
         "XONSH_SHOW_TRACEBACK": False,
         "XONSH_STDERR_PREFIX": "",
         "XONSH_STDERR_POSTFIX": "",
@@ -1002,8 +1004,10 @@
             "that determine what commands are saved to the history list. By "
             "default all commands are saved. The option ``ignoredups`` will 
not "
             "save the command if it matches the previous command. The option "
-            "'ignoreerr' will cause any commands that fail (i.e. return 
non-zero "
-            "exit status) to not be added to the history list.",
+            "``ignoreerr`` will cause any commands that fail (i.e. return 
non-zero "
+            "exit status) to not be added to the history list. The option "
+            "``erasedups`` will remove all previous commands that matches and 
updates the frequency. "
+            "Note: ``erasedups`` is supported only in sqlite backend).",
             store_as_str=True,
         ),
         "IGNOREEOF": VarDocs("Prevents Ctrl-D from exiting the shell."),
@@ -1363,6 +1367,9 @@
             "xonsh process threads sleep for while running command pipelines. "
             "The value has units of seconds [s]."
         ),
+        "XONSH_TRACE_SUBPROC": VarDocs(
+            "Set to ``True`` to show arguments list of every executed 
subprocess command."
+        ),
         "XONSH_SHOW_TRACEBACK": VarDocs(
             "Controls if a traceback is shown if exceptions occur in the 
shell. "
             "Set to ``True`` to always show traceback or ``False`` to always 
hide. "
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/execer.py 
new/xonsh-0.9.15/xonsh/execer.py
--- old/xonsh-0.9.14/xonsh/execer.py    2019-10-01 22:38:03.000000000 +0200
+++ new/xonsh-0.9.15/xonsh/execer.py    2020-03-19 16:51:32.000000000 +0100
@@ -145,6 +145,7 @@
         if isinstance(input, types.CodeType):
             code = input
         else:
+            input = input.rstrip("\n")
             if filename is None:
                 filename = self.filename
             code = self.compile(
@@ -174,6 +175,8 @@
         if isinstance(input, types.CodeType):
             code = input
         else:
+            if not input.endswith("\n"):
+                input += "\n"
             if filename is None:
                 filename = self.filename
             code = self.compile(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/history/__amalgam__.py 
new/xonsh-0.9.15/xonsh/history/__amalgam__.py
--- old/xonsh-0.9.14/xonsh/history/__amalgam__.py       2020-02-28 
22:12:08.000000000 +0100
+++ new/xonsh-0.9.15/xonsh/history/__amalgam__.py       2020-03-19 
21:41:58.000000000 +0100
@@ -685,6 +685,11 @@
 # amalgamated time
 # amalgamated xonsh.history.base
 # amalgamated xonsh.tools
+XH_SQLITE_CACHE = threading.local()
+XH_SQLITE_TABLE_NAME = "xonsh_history"
+XH_SQLITE_CREATED_SQL_TBL = "CREATED_SQL_TABLE"
+
+
 def _xh_sqlite_get_file_name():
     envs = builtins.__xonsh__.env
     file_name = envs.get("XONSH_HISTORY_SQLITE_FILE")
@@ -705,35 +710,84 @@
 
     Columns:
         info - JSON formatted, reserved for future extension.
+        frequency - in case of HISTCONTROL=erasedups,
+        it tracks the frequency of the inputs. helps in sorting autocompletion
     """
+    if not getattr(XH_SQLITE_CACHE, XH_SQLITE_CREATED_SQL_TBL, False):
+        cursor.execute(
+            """
+            CREATE TABLE IF NOT EXISTS {}
+                 (inp TEXT,
+                  rtn INTEGER,
+                  tsb REAL,
+                  tse REAL,
+                  sessionid TEXT,
+                  out TEXT,
+                  info TEXT,
+                  frequency INTEGER default 1
+                 )
+        """.format(
+                XH_SQLITE_TABLE_NAME
+            )
+        )
+        # add frequency column if not exists for backward compatibility
+        try:
+            cursor.execute(
+                "ALTER TABLE "
+                + XH_SQLITE_TABLE_NAME
+                + " ADD COLUMN frequency INTEGER default 1"
+            )
+        except sqlite3.OperationalError:
+            pass
+
+        # mark that this function ran for this session
+        setattr(XH_SQLITE_CACHE, XH_SQLITE_CREATED_SQL_TBL, True)
+
+
+def _xh_sqlite_get_frequency(cursor, input):
+    # type: (sqlite3.Cursor, str) -> int
+    sql = "SELECT sum(frequency) FROM {} WHERE 
inp=?".format(XH_SQLITE_TABLE_NAME)
+    cursor.execute(sql, (input,))
+    return cursor.fetchone()[0] or 0
+
+
+def _xh_sqlite_erase_dups(cursor, input):
+    freq = _xh_sqlite_get_frequency(cursor, input)
+    sql = "DELETE FROM {} WHERE inp=?".format(XH_SQLITE_TABLE_NAME)
+    cursor.execute(sql, (input,))
+    return freq
+
+
+def _sql_insert(cursor, values):
+    # type: (sqlite3.Cursor, dict) -> None
+    """handy function to run insert query"""
+    sql = "INSERT INTO {} ({}) VALUES ({});"
+    fields = ", ".join(values)
+    marks = ", ".join(["?"] * len(values))
     cursor.execute(
-        """
-        CREATE TABLE IF NOT EXISTS xonsh_history
-             (inp TEXT,
-              rtn INTEGER,
-              tsb REAL,
-              tse REAL,
-              sessionid TEXT,
-              out TEXT,
-              info TEXT
-             )
-    """
+        sql.format(XH_SQLITE_TABLE_NAME, fields, marks), tuple(values.values())
     )
 
 
-def _xh_sqlite_insert_command(cursor, cmd, sessionid, store_stdout):
-    sql = "INSERT INTO xonsh_history (inp, rtn, tsb, tse, sessionid"
+def _xh_sqlite_insert_command(cursor, cmd, sessionid, store_stdout, 
remove_duplicates):
     tss = cmd.get("ts", [None, None])
-    params = [cmd["inp"].rstrip(), cmd["rtn"], tss[0], tss[1], sessionid]
+    values = collections.OrderedDict(
+        [
+            ("inp", cmd["inp"].rstrip()),
+            ("rtn", cmd["rtn"]),
+            ("tsb", tss[0]),
+            ("tse", tss[1]),
+            ("sessionid", sessionid),
+        ]
+    )
     if store_stdout and "out" in cmd:
-        sql += ", out"
-        params.append(cmd["out"])
+        values["out"] = cmd["out"]
     if "info" in cmd:
-        sql += ", info"
         info = json.dumps(cmd["info"])
-        params.append(info)
-    sql += ") VALUES (" + ("?, " * len(params)).rstrip(", ") + ")"
-    cursor.execute(sql, tuple(params))
+        values["info"] = info
+    if remove_duplicates:
+        values["frequency"] = _xh_sqlite_erase_dups(cursor, values["inp"]) + 1
+    _sql_insert(cursor, values)
 
 
 def _xh_sqlite_get_count(cursor, sessionid=None):
@@ -747,7 +801,7 @@
 
 
 def _xh_sqlite_get_records(cursor, sessionid=None, limit=None, 
newest_first=False):
-    sql = "SELECT inp, tsb, rtn FROM xonsh_history "
+    sql = "SELECT inp, tsb, rtn, frequency FROM xonsh_history "
     params = []
     if sessionid is not None:
         sql += "WHERE sessionid = ? "
@@ -775,11 +829,13 @@
     return result.rowcount
 
 
-def xh_sqlite_append_history(cmd, sessionid, store_stdout, filename=None):
+def xh_sqlite_append_history(
+    cmd, sessionid, store_stdout, filename=None, remove_duplicates=False
+):
     with _xh_sqlite_get_conn(filename=filename) as conn:
         c = conn.cursor()
         _xh_sqlite_create_history_table(c)
-        _xh_sqlite_insert_command(c, cmd, sessionid, store_stdout)
+        _xh_sqlite_insert_command(c, cmd, sessionid, store_stdout, 
remove_duplicates)
         conn.commit()
 
 
@@ -853,9 +909,11 @@
         self.outs = []
         self.tss = []
 
+        # during init rerun create command
+        setattr(XH_SQLITE_CACHE, XH_SQLITE_CREATED_SQL_TBL, False)
+
     def append(self, cmd):
         envs = builtins.__xonsh__.env
-        opts = envs.get("HISTCONTROL")
         inp = cmd["inp"].rstrip()
         self.inps.append(inp)
         store_stdout = envs.get("XONSH_STORE_STDOUT", False)
@@ -875,22 +933,23 @@
             return
         self._last_hist_inp = inp
         xh_sqlite_append_history(
-            cmd, str(self.sessionid), store_stdout, filename=self.filename
+            cmd,
+            str(self.sessionid),
+            store_stdout,
+            filename=self.filename,
+            remove_duplicates=("erasedups" in opts),
         )
 
-    def all_items(self, newest_first=False):
+    def all_items(self, newest_first=False, session_id=None):
         """Display all history items."""
-        for item in xh_sqlite_items(filename=self.filename, 
newest_first=newest_first):
-            yield {"inp": item[0], "ts": item[1], "rtn": item[2]}
+        for inp, ts, rtn, freq in xh_sqlite_items(
+            filename=self.filename, newest_first=newest_first, 
sessionid=session_id
+        ):
+            yield {"inp": inp, "ts": ts, "rtn": rtn, "frequency": freq}
 
     def items(self, newest_first=False):
         """Display history items of current session."""
-        for item in xh_sqlite_items(
-            sessionid=str(self.sessionid),
-            filename=self.filename,
-            newest_first=newest_first,
-        ):
-            yield {"inp": item[0], "ts": item[1], "rtn": item[2]}
+        yield from self.all_items(newest_first, session_id=str(self.sessionid))
 
     def info(self):
         data = collections.OrderedDict()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/history/sqlite.py 
new/xonsh-0.9.15/xonsh/history/sqlite.py
--- old/xonsh-0.9.14/xonsh/history/sqlite.py    2018-10-02 14:52:12.000000000 
+0200
+++ new/xonsh-0.9.15/xonsh/history/sqlite.py    2020-03-19 16:51:32.000000000 
+0100
@@ -12,6 +12,10 @@
 from xonsh.history.base import History
 import xonsh.tools as xt
 
+XH_SQLITE_CACHE = threading.local()
+XH_SQLITE_TABLE_NAME = "xonsh_history"
+XH_SQLITE_CREATED_SQL_TBL = "CREATED_SQL_TABLE"
+
 
 def _xh_sqlite_get_file_name():
     envs = builtins.__xonsh__.env
@@ -33,35 +37,84 @@
 
     Columns:
         info - JSON formatted, reserved for future extension.
+        frequency - in case of HISTCONTROL=erasedups,
+        it tracks the frequency of the inputs. helps in sorting autocompletion
     """
+    if not getattr(XH_SQLITE_CACHE, XH_SQLITE_CREATED_SQL_TBL, False):
+        cursor.execute(
+            """
+            CREATE TABLE IF NOT EXISTS {}
+                 (inp TEXT,
+                  rtn INTEGER,
+                  tsb REAL,
+                  tse REAL,
+                  sessionid TEXT,
+                  out TEXT,
+                  info TEXT,
+                  frequency INTEGER default 1
+                 )
+        """.format(
+                XH_SQLITE_TABLE_NAME
+            )
+        )
+        # add frequency column if not exists for backward compatibility
+        try:
+            cursor.execute(
+                "ALTER TABLE "
+                + XH_SQLITE_TABLE_NAME
+                + " ADD COLUMN frequency INTEGER default 1"
+            )
+        except sqlite3.OperationalError:
+            pass
+
+        # mark that this function ran for this session
+        setattr(XH_SQLITE_CACHE, XH_SQLITE_CREATED_SQL_TBL, True)
+
+
+def _xh_sqlite_get_frequency(cursor, input):
+    # type: (sqlite3.Cursor, str) -> int
+    sql = "SELECT sum(frequency) FROM {} WHERE 
inp=?".format(XH_SQLITE_TABLE_NAME)
+    cursor.execute(sql, (input,))
+    return cursor.fetchone()[0] or 0
+
+
+def _xh_sqlite_erase_dups(cursor, input):
+    freq = _xh_sqlite_get_frequency(cursor, input)
+    sql = "DELETE FROM {} WHERE inp=?".format(XH_SQLITE_TABLE_NAME)
+    cursor.execute(sql, (input,))
+    return freq
+
+
+def _sql_insert(cursor, values):
+    # type: (sqlite3.Cursor, dict) -> None
+    """handy function to run insert query"""
+    sql = "INSERT INTO {} ({}) VALUES ({});"
+    fields = ", ".join(values)
+    marks = ", ".join(["?"] * len(values))
     cursor.execute(
-        """
-        CREATE TABLE IF NOT EXISTS xonsh_history
-             (inp TEXT,
-              rtn INTEGER,
-              tsb REAL,
-              tse REAL,
-              sessionid TEXT,
-              out TEXT,
-              info TEXT
-             )
-    """
+        sql.format(XH_SQLITE_TABLE_NAME, fields, marks), tuple(values.values())
     )
 
 
-def _xh_sqlite_insert_command(cursor, cmd, sessionid, store_stdout):
-    sql = "INSERT INTO xonsh_history (inp, rtn, tsb, tse, sessionid"
+def _xh_sqlite_insert_command(cursor, cmd, sessionid, store_stdout, 
remove_duplicates):
     tss = cmd.get("ts", [None, None])
-    params = [cmd["inp"].rstrip(), cmd["rtn"], tss[0], tss[1], sessionid]
+    values = collections.OrderedDict(
+        [
+            ("inp", cmd["inp"].rstrip()),
+            ("rtn", cmd["rtn"]),
+            ("tsb", tss[0]),
+            ("tse", tss[1]),
+            ("sessionid", sessionid),
+        ]
+    )
     if store_stdout and "out" in cmd:
-        sql += ", out"
-        params.append(cmd["out"])
+        values["out"] = cmd["out"]
     if "info" in cmd:
-        sql += ", info"
         info = json.dumps(cmd["info"])
-        params.append(info)
-    sql += ") VALUES (" + ("?, " * len(params)).rstrip(", ") + ")"
-    cursor.execute(sql, tuple(params))
+        values["info"] = info
+    if remove_duplicates:
+        values["frequency"] = _xh_sqlite_erase_dups(cursor, values["inp"]) + 1
+    _sql_insert(cursor, values)
 
 
 def _xh_sqlite_get_count(cursor, sessionid=None):
@@ -75,7 +128,7 @@
 
 
 def _xh_sqlite_get_records(cursor, sessionid=None, limit=None, 
newest_first=False):
-    sql = "SELECT inp, tsb, rtn FROM xonsh_history "
+    sql = "SELECT inp, tsb, rtn, frequency FROM xonsh_history "
     params = []
     if sessionid is not None:
         sql += "WHERE sessionid = ? "
@@ -103,11 +156,13 @@
     return result.rowcount
 
 
-def xh_sqlite_append_history(cmd, sessionid, store_stdout, filename=None):
+def xh_sqlite_append_history(
+    cmd, sessionid, store_stdout, filename=None, remove_duplicates=False
+):
     with _xh_sqlite_get_conn(filename=filename) as conn:
         c = conn.cursor()
         _xh_sqlite_create_history_table(c)
-        _xh_sqlite_insert_command(c, cmd, sessionid, store_stdout)
+        _xh_sqlite_insert_command(c, cmd, sessionid, store_stdout, 
remove_duplicates)
         conn.commit()
 
 
@@ -181,9 +236,11 @@
         self.outs = []
         self.tss = []
 
+        # during init rerun create command
+        setattr(XH_SQLITE_CACHE, XH_SQLITE_CREATED_SQL_TBL, False)
+
     def append(self, cmd):
         envs = builtins.__xonsh__.env
-        opts = envs.get("HISTCONTROL")
         inp = cmd["inp"].rstrip()
         self.inps.append(inp)
         store_stdout = envs.get("XONSH_STORE_STDOUT", False)
@@ -203,22 +260,23 @@
             return
         self._last_hist_inp = inp
         xh_sqlite_append_history(
-            cmd, str(self.sessionid), store_stdout, filename=self.filename
+            cmd,
+            str(self.sessionid),
+            store_stdout,
+            filename=self.filename,
+            remove_duplicates=("erasedups" in opts),
         )
 
-    def all_items(self, newest_first=False):
+    def all_items(self, newest_first=False, session_id=None):
         """Display all history items."""
-        for item in xh_sqlite_items(filename=self.filename, 
newest_first=newest_first):
-            yield {"inp": item[0], "ts": item[1], "rtn": item[2]}
+        for inp, ts, rtn, freq in xh_sqlite_items(
+            filename=self.filename, newest_first=newest_first, 
sessionid=session_id
+        ):
+            yield {"inp": inp, "ts": ts, "rtn": rtn, "frequency": freq}
 
     def items(self, newest_first=False):
         """Display history items of current session."""
-        for item in xh_sqlite_items(
-            sessionid=str(self.sessionid),
-            filename=self.filename,
-            newest_first=newest_first,
-        ):
-            yield {"inp": item[0], "ts": item[1], "rtn": item[2]}
+        yield from self.all_items(newest_first, session_id=str(self.sessionid))
 
     def info(self):
         data = collections.OrderedDict()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/main.py 
new/xonsh-0.9.15/xonsh/main.py
--- old/xonsh-0.9.14/xonsh/main.py      2019-10-10 21:55:08.000000000 +0200
+++ new/xonsh-0.9.15/xonsh/main.py      2020-03-01 20:01:11.000000000 +0100
@@ -292,7 +292,11 @@
     env = builtins.__xonsh__.env
     rc = shell_kwargs.get("rc", None)
     rc = env.get("XONSHRC") if rc is None else rc
-    if args.mode != XonshMode.interactive and not args.force_interactive:
+    if (
+        args.mode != XonshMode.interactive
+        and not args.force_interactive
+        and not args.login
+    ):
         #  Don't load xonshrc if not interactive shell
         rc = None
     events.on_pre_rc.fire()
@@ -329,7 +333,8 @@
         "cacheall": args.cacheall,
         "ctx": builtins.__xonsh__.ctx,
     }
-    if args.login:
+    if args.login or sys.argv[0].startswith("-"):
+        args.login = True
         shell_kwargs["login"] = True
     if args.norc:
         shell_kwargs["rc"] = ()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/proc.py 
new/xonsh-0.9.15/xonsh/proc.py
--- old/xonsh-0.9.14/xonsh/proc.py      2020-02-28 21:45:23.000000000 +0100
+++ new/xonsh-0.9.15/xonsh/proc.py      2020-03-02 02:23:41.000000000 +0100
@@ -2288,7 +2288,7 @@
         rtn = self.returncode
         if (
             rtn is not None
-            and rtn > 0
+            and rtn != 0
             and builtins.__xonsh__.env.get("RAISE_SUBPROC_ERROR")
         ):
             try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/pytest_plugin.py 
new/xonsh-0.9.15/xonsh/pytest_plugin.py
--- old/xonsh-0.9.14/xonsh/pytest_plugin.py     2018-10-12 16:43:39.000000000 
+0200
+++ new/xonsh-0.9.15/xonsh/pytest_plugin.py     2020-03-15 22:38:09.000000000 
+0100
@@ -14,7 +14,17 @@
 
 
 def pytest_collection_modifyitems(items):
-    items.sort(key=lambda x: 0 if isinstance(x, XshFunction) else 1)
+    """ Move xsh test first to work around a bug in normal
+        pytest cleanup. The order of tests are otherwise preserved.
+    """
+    xsh_items = []
+    other_items = []
+    for item in items:
+        if isinstance(item, XshFunction):
+            xsh_items.append(item)
+        else:
+            other_items.append(item)
+    items[:] = xsh_items + other_items
 
 
 def _limited_traceback(excinfo):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh.egg-info/PKG-INFO 
new/xonsh-0.9.15/xonsh.egg-info/PKG-INFO
--- old/xonsh-0.9.14/xonsh.egg-info/PKG-INFO    2020-02-28 22:12:06.000000000 
+0100
+++ new/xonsh-0.9.15/xonsh.egg-info/PKG-INFO    2020-03-19 21:41:55.000000000 
+0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: xonsh
-Version: 0.9.14
+Version: 0.9.15
 Summary: Python-powered, cross-platform, Unix-gazing shell
 Home-page: https://github.com/xonsh/xonsh
 Author: Anthony Scopatz
@@ -38,7 +38,7 @@
         - `gitsome <https://github.com/donnemartin/gitsome>`_: A supercharged 
Git/shell autocompleter with GitHub integration.
         - `rever <https://regro.github.io/rever-docs/>`_: Cross-platform 
software release tool.
         - `Regro autotick bot <https://github.com/regro/cf-scripts>`_: Regro 
Conda-Forge autoticker.
-        - `xxh <https://github.com/xonssh/xxh>`_: Using xonsh wherever you go 
through the ssh.
+        - `xxh <https://github.com/xxh/xxh>`_: Using xonsh wherever you go 
through the ssh.
         
 Platform: Cross Platform
 Classifier: Programming Language :: Python :: 3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh.egg-info/SOURCES.txt 
new/xonsh-0.9.15/xonsh.egg-info/SOURCES.txt
--- old/xonsh-0.9.14/xonsh.egg-info/SOURCES.txt 2020-02-28 22:12:06.000000000 
+0100
+++ new/xonsh-0.9.15/xonsh.egg-info/SOURCES.txt 2020-03-19 21:41:55.000000000 
+0100
@@ -61,9 +61,12 @@
 tests/test_xonsh.xsh
 tests/test_xontribs.py
 tests/test_xoreutils.py
+tests/testfile
 tests/tools.py
+tests/tttt
 tests/aliases/__init__.py
 tests/aliases/test_source.py
+tests/aliases/test_xexec.py
 tests/bin/.someotherdotfile
 tests/bin/cat
 tests/bin/cat.bat


Reply via email to