mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-06 17:30:59 +01:00
wip: work on history show
This commit is contained in:
parent
6bde45459e
commit
b0a292401d
6 changed files with 98 additions and 65 deletions
|
@ -1,4 +1,5 @@
|
||||||
import threading
|
import threading
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
|
||||||
class HistoryGC(threading.Thread):
|
class HistoryGC(threading.Thread):
|
||||||
|
@ -6,16 +7,13 @@ class HistoryGC(threading.Thread):
|
||||||
|
|
||||||
|
|
||||||
class HistoryBase:
|
class HistoryBase:
|
||||||
def __init__(self, gc=True, **kwargs):
|
def __init__(self, sessionid=None, gc=True, **kwargs):
|
||||||
|
self.sessionid = uuid.uuid4() if sessionid is None else sessionid
|
||||||
self.gc = HistoryGC() if gc else None
|
self.gc = HistoryGC() if gc else None
|
||||||
self.rtns = None
|
self.rtns = None
|
||||||
self.last_cmd_rtn = None
|
self.last_cmd_rtn = None
|
||||||
self.last_cmd_out = None
|
self.last_cmd_out = None
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
for cmd, ts, index in []:
|
|
||||||
yield (cmd, ts, index)
|
|
||||||
|
|
||||||
def append(self, cmd):
|
def append(self, cmd):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -23,7 +21,13 @@ class HistoryBase:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def items(self):
|
def items(self):
|
||||||
return []
|
"""Display all history items."""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
def show_info(self):
|
def session_items(self):
|
||||||
|
"""Display history items of current session."""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def show_info(self, ns, stdout=None, stderr=None):
|
||||||
|
"""Display information about the shell history."""
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -1,15 +1,34 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""Implements the xonsh history backend."""
|
"""Implements the xonsh history backend."""
|
||||||
import sys
|
import collections
|
||||||
|
import json
|
||||||
|
|
||||||
from xonsh.history.base import HistoryBase
|
from xonsh.history.base import HistoryBase
|
||||||
|
|
||||||
|
|
||||||
class DummyHistory(HistoryBase):
|
class DummyHistory(HistoryBase):
|
||||||
def append(self, cmd):
|
def append(self, cmd):
|
||||||
print('DummyHistory append: {}'.format(cmd), file=sys.stderr)
|
pass
|
||||||
|
|
||||||
def flush(self, at_exit=False):
|
def flush(self, at_exit=False):
|
||||||
print('DummyHistory flush ...', file=sys.stderr)
|
pass
|
||||||
|
|
||||||
def items(self):
|
def items(self):
|
||||||
yield {'inp': 'dummy in action\n'}
|
"""Display all history items."""
|
||||||
|
yield {'inp': 'dummy in action', 'ts': 1464652800, 'ind': 0}
|
||||||
|
|
||||||
|
def session_items(self):
|
||||||
|
"""Display history items of current session."""
|
||||||
|
return self.items()
|
||||||
|
|
||||||
|
def show_info(self, ns, stdout=None, stderr=None):
|
||||||
|
"""Display information about the shell history."""
|
||||||
|
data = collections.OrderedDict()
|
||||||
|
data['backend'] = 'dummy'
|
||||||
|
data['sessionid'] = str(self.sessionid)
|
||||||
|
if ns.json:
|
||||||
|
s = json.dumps(data)
|
||||||
|
print(s, file=stdout)
|
||||||
|
else:
|
||||||
|
for k, v in data.items():
|
||||||
|
print('{}: {}'.format(k, v))
|
||||||
|
|
|
@ -402,16 +402,21 @@ class JsonHistory(HistoryBase):
|
||||||
self.gc = JsonHistoryGC(wait_for_shell=False, size=size)
|
self.gc = JsonHistoryGC(wait_for_shell=False, size=size)
|
||||||
return self.gc
|
return self.gc
|
||||||
|
|
||||||
def session_items(self, **kwargs):
|
def session_items(self):
|
||||||
return iter(self)
|
"""Display history items of current session."""
|
||||||
|
ind = 0
|
||||||
|
for item, tss in zip(self.inps, self.tss):
|
||||||
|
yield {'inp': item.rstrip(), 'ind': ind, 'ts': tss[0]}
|
||||||
|
ind += 1
|
||||||
|
|
||||||
# TODO: merge methods all_items() and items() to one
|
def items(self, **kwargs):
|
||||||
def all_items(self, **kwargs):
|
|
||||||
"""
|
"""
|
||||||
Returns all history as found in XONSH_DATA_DIR.
|
Returns all history as found in XONSH_DATA_DIR.
|
||||||
|
|
||||||
return format: (cmd, start_time, index)
|
return format: (cmd, start_time, index)
|
||||||
"""
|
"""
|
||||||
|
while self.gc.is_alive():
|
||||||
|
time.sleep(0.011) # gc sleeps for 0.01 secs, sleep a beat longer
|
||||||
ind = 0
|
ind = 0
|
||||||
for f in _get_history_files():
|
for f in _get_history_files():
|
||||||
try:
|
try:
|
||||||
|
@ -421,23 +426,13 @@ class JsonHistory(HistoryBase):
|
||||||
continue
|
continue
|
||||||
commands = json_file.load()['cmds']
|
commands = json_file.load()['cmds']
|
||||||
for c in commands:
|
for c in commands:
|
||||||
yield (c['inp'].rstrip(), c['ts'][0], ind)
|
yield {'inp': c['inp'].rstrip(), 'ts': c['ts'][0], 'ind': ind}
|
||||||
ind += 1
|
ind += 1
|
||||||
|
|
||||||
# TODO: merge methods all_items() and items() to one
|
|
||||||
def items(self):
|
|
||||||
while self.gc.is_alive():
|
|
||||||
time.sleep(0.011) # gc sleeps for 0.01 secs, sleep a beat longer
|
|
||||||
files = self.gc.files()
|
|
||||||
for _, _, f in files:
|
|
||||||
with open(self.filename, 'r', newline='\n') as f:
|
|
||||||
hist = xlj.LazyJSON(f).load()
|
|
||||||
for command in hist['cmds']:
|
|
||||||
yield dict(command)
|
|
||||||
|
|
||||||
def show_info(self, ns, stdout=None, stderr=None):
|
def show_info(self, ns, stdout=None, stderr=None):
|
||||||
"""Display information about the shell history."""
|
"""Display information about the shell history."""
|
||||||
data = collections.OrderedDict()
|
data = collections.OrderedDict()
|
||||||
|
data['backend'] = 'json'
|
||||||
data['sessionid'] = str(self.sessionid)
|
data['sessionid'] = str(self.sessionid)
|
||||||
data['filename'] = self.filename
|
data['filename'] = self.filename
|
||||||
data['length'] = len(self)
|
data['length'] = len(self)
|
||||||
|
@ -450,19 +445,6 @@ class JsonHistory(HistoryBase):
|
||||||
lines = ['{0}: {1}'.format(k, v) for k, v in data.items()]
|
lines = ['{0}: {1}'.format(k, v) for k, v in data.items()]
|
||||||
print('\n'.join(lines), file=stdout)
|
print('\n'.join(lines), file=stdout)
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
"""Get current session history.
|
|
||||||
|
|
||||||
Yields
|
|
||||||
------
|
|
||||||
tuple
|
|
||||||
``tuple`` of the form (cmd, start_time, index).
|
|
||||||
"""
|
|
||||||
start_times = (start for start, end in self.tss)
|
|
||||||
names = (name.rstrip() for name in self.inps)
|
|
||||||
for ind, (c, t) in enumerate(zip(names, start_times)):
|
|
||||||
yield (c, t, ind)
|
|
||||||
|
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
"""Retrieve history parts based on filtering rules,
|
"""Retrieve history parts based on filtering rules,
|
||||||
see ``History`` docs for more info. Accepts one of
|
see ``History`` docs for more info. Accepts one of
|
||||||
|
|
|
@ -52,7 +52,7 @@ def _xh_all_parser(hist=None, **kwargs):
|
||||||
"""Returns all history items."""
|
"""Returns all history items."""
|
||||||
if hist is None:
|
if hist is None:
|
||||||
hist = builtins.__xonsh_history__
|
hist = builtins.__xonsh_history__
|
||||||
return hist.all_items()
|
return hist.items()
|
||||||
|
|
||||||
|
|
||||||
def _xh_find_histfile_var(file_list, default=None):
|
def _xh_find_histfile_var(file_list, default=None):
|
||||||
|
@ -187,24 +187,24 @@ def _hist_show(ns, hist=None, stdout=None, stderr=None):
|
||||||
if ns.reverse:
|
if ns.reverse:
|
||||||
commands = reversed(list(commands))
|
commands = reversed(list(commands))
|
||||||
if not ns.numerate and not ns.timestamp:
|
if not ns.numerate and not ns.timestamp:
|
||||||
for c, _, _ in commands:
|
for c in commands:
|
||||||
print(c, file=stdout)
|
print(c['inp'], file=stdout)
|
||||||
elif not ns.timestamp:
|
elif not ns.timestamp:
|
||||||
for c, _, i in commands:
|
for c in commands:
|
||||||
print('{}: {}'.format(i, c), file=stdout)
|
print('{}: {}'.format(c['ind'], c['inp']), file=stdout)
|
||||||
elif not ns.numerate:
|
elif not ns.numerate:
|
||||||
for c, ts, _ in commands:
|
for c in commands:
|
||||||
dt = datetime.datetime.fromtimestamp(ts).ctime()
|
dt = datetime.datetime.fromtimestamp(c['ts']).ctime()
|
||||||
print('({}) {}'.format(dt, c), file=stdout)
|
print('({}) {}'.format(dt, c['inp']), file=stdout)
|
||||||
else:
|
else:
|
||||||
for c, ts, i in commands:
|
for c in commands:
|
||||||
dt = datetime.datetime.fromtimestamp(ts).ctime()
|
dt = datetime.datetime.fromtimestamp(c['ts']).ctime()
|
||||||
print('{}:({}) {}'.format(i, dt, c), file=stdout)
|
print('{}:({}) {}'.format(c['ind'], dt, c['inp']), file=stdout)
|
||||||
|
|
||||||
|
|
||||||
def _hist_info(ns, hist, stdout=None, stderr=None):
|
def _xh_hist_info(ns, hist, stdout=None, stderr=None):
|
||||||
"""Display information about the shell history."""
|
"""Display information about the shell history."""
|
||||||
hist.show_info(ns)
|
hist.show_info(ns, stdout=stdout, stderr=stderr)
|
||||||
|
|
||||||
|
|
||||||
@xla.lazyobject
|
@xla.lazyobject
|
||||||
|
@ -222,7 +222,7 @@ def _HIST_MAIN_ACTIONS():
|
||||||
'show': _hist_show,
|
'show': _hist_show,
|
||||||
'id': lambda ns, hist, stdout, stderr: print(hist.sessionid, file=stdout),
|
'id': lambda ns, hist, stdout, stderr: print(hist.sessionid, file=stdout),
|
||||||
'file': lambda ns, hist, stdout, stderr: print(hist.filename, file=stdout),
|
'file': lambda ns, hist, stdout, stderr: print(hist.filename, file=stdout),
|
||||||
'info': _hist_info,
|
'info': _xh_hist_info,
|
||||||
'diff': xdh._dh_main_action,
|
'diff': xdh._dh_main_action,
|
||||||
'gc': _hist_gc,
|
'gc': _hist_gc,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,26 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""Implements the xonsh history backend via sqlite3."""
|
"""Implements the xonsh history backend via sqlite3."""
|
||||||
import builtins
|
import builtins
|
||||||
|
import collections
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import time
|
|
||||||
|
|
||||||
from xonsh.history.base import HistoryBase
|
from xonsh.history.base import HistoryBase
|
||||||
import xonsh.tools as xt
|
import xonsh.tools as xt
|
||||||
|
|
||||||
|
|
||||||
|
def _xh_sqlite_get_file_name():
|
||||||
|
envs = builtins.__xonsh_env__
|
||||||
|
file_name = envs.get('XONSH_HISTORY_SQLITE_FILE')
|
||||||
|
if not file_name:
|
||||||
|
data_dir = envs.get('XONSH_DATA_DIR')
|
||||||
|
file_name = os.path.join(data_dir, 'xonsh-history.sqlite')
|
||||||
|
return xt.expanduser_abs_path(file_name)
|
||||||
|
|
||||||
|
|
||||||
def _xh_sqlite_get_conn():
|
def _xh_sqlite_get_conn():
|
||||||
data_dir = builtins.__xonsh_env__.get('XONSH_DATA_DIR')
|
db_file = _xh_sqlite_get_file_name()
|
||||||
data_dir = xt.expanduser_abs_path(data_dir)
|
|
||||||
db_file = os.path.join(data_dir, 'xonsh-history.sqlite')
|
|
||||||
return sqlite3.connect(db_file)
|
return sqlite3.connect(db_file)
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,7 +42,7 @@ def _xh_sqlite_insert_command(cursor, cmd):
|
||||||
|
|
||||||
|
|
||||||
def _xh_sqlite_get_records(cursor):
|
def _xh_sqlite_get_records(cursor):
|
||||||
cursor.execute('SELECT inp FROM xonsh_history ORDER BY tsb')
|
cursor.execute('SELECT inp, tsb FROM xonsh_history ORDER BY tsb')
|
||||||
return cursor.fetchall()
|
return cursor.fetchall()
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,8 +62,11 @@ def xh_sqlite_items():
|
||||||
|
|
||||||
|
|
||||||
class SqliteHistory(HistoryBase):
|
class SqliteHistory(HistoryBase):
|
||||||
def __init__(self, gc=True, **kwargs):
|
def __init__(self, filename=None, **kwargs):
|
||||||
super().__init__(gc=gc, **kwargs)
|
super().__init__(**kwargs)
|
||||||
|
if filename is None:
|
||||||
|
filename = _xh_sqlite_get_file_name()
|
||||||
|
self.filename = filename
|
||||||
self.last_cmd_inp = None
|
self.last_cmd_inp = None
|
||||||
|
|
||||||
def append(self, cmd):
|
def append(self, cmd):
|
||||||
|
@ -67,13 +78,30 @@ class SqliteHistory(HistoryBase):
|
||||||
# Skipping failed cmd
|
# Skipping failed cmd
|
||||||
return
|
return
|
||||||
self.last_cmd_inp = cmd['inp'].rstrip()
|
self.last_cmd_inp = cmd['inp'].rstrip()
|
||||||
t = time.time()
|
|
||||||
xh_sqlite_append_history(cmd)
|
xh_sqlite_append_history(cmd)
|
||||||
print('history cmd: {} took {:.4f}s'.format(cmd, time.time() - t))
|
|
||||||
|
|
||||||
def flush(self, at_exit=False):
|
def flush(self, at_exit=False):
|
||||||
print('TODO: SqliteHistory flush() called')
|
print('TODO: SqliteHistory flush() called')
|
||||||
|
|
||||||
def items(self):
|
def items(self):
|
||||||
|
i = 0
|
||||||
for item in xh_sqlite_items():
|
for item in xh_sqlite_items():
|
||||||
yield {'inp': item[0]}
|
yield {'inp': item[0], 'ts': item[1], 'ind': i}
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
def session_items(self):
|
||||||
|
"""Display history items of current session."""
|
||||||
|
return self.items()
|
||||||
|
|
||||||
|
def show_info(self, ns, stdout=None, stderr=None):
|
||||||
|
"""Display information about the shell history."""
|
||||||
|
data = collections.OrderedDict()
|
||||||
|
data['backend'] = 'sqlite'
|
||||||
|
data['sessionid'] = str(self.sessionid)
|
||||||
|
data['filename'] = self.filename
|
||||||
|
if ns.json:
|
||||||
|
s = json.dumps(data)
|
||||||
|
print(s, file=stdout)
|
||||||
|
else:
|
||||||
|
for k, v in data.items():
|
||||||
|
print('{}: {}'.format(k, v))
|
||||||
|
|
|
@ -105,7 +105,7 @@ def _rp_create_parser(p=None):
|
||||||
return p
|
return p
|
||||||
|
|
||||||
|
|
||||||
def _rp_main_action(ns, h=None):
|
def _rp_main_action(ns, h=None, stdout=None, stderr=None):
|
||||||
replayer = Replayer(ns.path)
|
replayer = Replayer(ns.path)
|
||||||
hist = replayer.replay(merge_envs=ns.merge_envs, target=ns.target)
|
hist = replayer.replay(merge_envs=ns.merge_envs, target=ns.target)
|
||||||
print('----------------------------------------------------------------')
|
print('----------------------------------------------------------------')
|
||||||
|
|
Loading…
Add table
Reference in a new issue