wip: work on history show

This commit is contained in:
Hugo Wang 2016-11-26 00:48:06 +08:00
parent 6bde45459e
commit b0a292401d
6 changed files with 98 additions and 65 deletions

View file

@ -1,4 +1,5 @@
import threading
import uuid
class HistoryGC(threading.Thread):
@ -6,16 +7,13 @@ class HistoryGC(threading.Thread):
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.rtns = None
self.last_cmd_rtn = None
self.last_cmd_out = None
def __iter__(self):
for cmd, ts, index in []:
yield (cmd, ts, index)
def append(self, cmd):
pass
@ -23,7 +21,13 @@ class HistoryBase:
pass
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

View file

@ -1,15 +1,34 @@
# -*- coding: utf-8 -*-
"""Implements the xonsh history backend."""
import sys
import collections
import json
from xonsh.history.base import HistoryBase
class DummyHistory(HistoryBase):
def append(self, cmd):
print('DummyHistory append: {}'.format(cmd), file=sys.stderr)
pass
def flush(self, at_exit=False):
print('DummyHistory flush ...', file=sys.stderr)
pass
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))

View file

@ -402,16 +402,21 @@ class JsonHistory(HistoryBase):
self.gc = JsonHistoryGC(wait_for_shell=False, size=size)
return self.gc
def session_items(self, **kwargs):
return iter(self)
def session_items(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 all_items(self, **kwargs):
def items(self, **kwargs):
"""
Returns all history as found in XONSH_DATA_DIR.
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
for f in _get_history_files():
try:
@ -421,23 +426,13 @@ class JsonHistory(HistoryBase):
continue
commands = json_file.load()['cmds']
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
# 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):
"""Display information about the shell history."""
data = collections.OrderedDict()
data['backend'] = 'json'
data['sessionid'] = str(self.sessionid)
data['filename'] = self.filename
data['length'] = len(self)
@ -450,19 +445,6 @@ class JsonHistory(HistoryBase):
lines = ['{0}: {1}'.format(k, v) for k, v in data.items()]
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):
"""Retrieve history parts based on filtering rules,
see ``History`` docs for more info. Accepts one of

View file

@ -52,7 +52,7 @@ def _xh_all_parser(hist=None, **kwargs):
"""Returns all history items."""
if hist is None:
hist = builtins.__xonsh_history__
return hist.all_items()
return hist.items()
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:
commands = reversed(list(commands))
if not ns.numerate and not ns.timestamp:
for c, _, _ in commands:
print(c, file=stdout)
for c in commands:
print(c['inp'], file=stdout)
elif not ns.timestamp:
for c, _, i in commands:
print('{}: {}'.format(i, c), file=stdout)
for c in commands:
print('{}: {}'.format(c['ind'], c['inp']), file=stdout)
elif not ns.numerate:
for c, ts, _ in commands:
dt = datetime.datetime.fromtimestamp(ts).ctime()
print('({}) {}'.format(dt, c), file=stdout)
for c in commands:
dt = datetime.datetime.fromtimestamp(c['ts']).ctime()
print('({}) {}'.format(dt, c['inp']), file=stdout)
else:
for c, ts, i in commands:
dt = datetime.datetime.fromtimestamp(ts).ctime()
print('{}:({}) {}'.format(i, dt, c), file=stdout)
for c in commands:
dt = datetime.datetime.fromtimestamp(c['ts']).ctime()
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."""
hist.show_info(ns)
hist.show_info(ns, stdout=stdout, stderr=stderr)
@xla.lazyobject
@ -222,7 +222,7 @@ def _HIST_MAIN_ACTIONS():
'show': _hist_show,
'id': lambda ns, hist, stdout, stderr: print(hist.sessionid, 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,
'gc': _hist_gc,
}

View file

@ -1,18 +1,26 @@
# -*- coding: utf-8 -*-
"""Implements the xonsh history backend via sqlite3."""
import builtins
import collections
import json
import os
import sqlite3
import time
from xonsh.history.base import HistoryBase
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():
data_dir = builtins.__xonsh_env__.get('XONSH_DATA_DIR')
data_dir = xt.expanduser_abs_path(data_dir)
db_file = os.path.join(data_dir, 'xonsh-history.sqlite')
db_file = _xh_sqlite_get_file_name()
return sqlite3.connect(db_file)
@ -34,7 +42,7 @@ def _xh_sqlite_insert_command(cursor, cmd):
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()
@ -54,8 +62,11 @@ def xh_sqlite_items():
class SqliteHistory(HistoryBase):
def __init__(self, gc=True, **kwargs):
super().__init__(gc=gc, **kwargs)
def __init__(self, filename=None, **kwargs):
super().__init__(**kwargs)
if filename is None:
filename = _xh_sqlite_get_file_name()
self.filename = filename
self.last_cmd_inp = None
def append(self, cmd):
@ -67,13 +78,30 @@ class SqliteHistory(HistoryBase):
# Skipping failed cmd
return
self.last_cmd_inp = cmd['inp'].rstrip()
t = time.time()
xh_sqlite_append_history(cmd)
print('history cmd: {} took {:.4f}s'.format(cmd, time.time() - t))
def flush(self, at_exit=False):
print('TODO: SqliteHistory flush() called')
def items(self):
i = 0
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))

View file

@ -105,7 +105,7 @@ def _rp_create_parser(p=None):
return p
def _rp_main_action(ns, h=None):
def _rp_main_action(ns, h=None, stdout=None, stderr=None):
replayer = Replayer(ns.path)
hist = replayer.replay(merge_envs=ns.merge_envs, target=ns.target)
print('----------------------------------------------------------------')