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 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

View file

@ -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))

View file

@ -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

View file

@ -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,
} }

View file

@ -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))

View file

@ -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('----------------------------------------------------------------')