Skip to content

Commit e66f142

Browse files
committed
Merge branch '0.0.13-dev'
2 parents c92befd + 10f14c1 commit e66f142

23 files changed

+298
-45
lines changed

.travis.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
language: python
2+
python:
3+
- "2.6"
4+
- "2.7"
5+
before_install:
6+
# To install bats and test our shell/bash functions
7+
- sudo add-apt-repository ppa:duggan/bats --yes
8+
- sudo apt-get update -qq
9+
- sudo apt-get install -qq bats
10+
- sudo apt-get install -qq zsh
11+
12+
# For bats functional tests
13+
env:
14+
- functional_test="true"
15+
16+
# command to install dependencies
17+
install: "pip install ."
18+
19+
# command to run tests
20+
script:
21+
- py.test
22+
- bats tests/shell
23+
24+
notifications:
25+
email:
26+
on_success: never

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
==========
33
Bashhub saves every terminal command entered across all sessions and systems and provides powerful querying across all commands.
44

5+
[![Build Status](https://travis-ci.org/rcaloras/bashhub-client.svg)](https://travis-ci.org/rcaloras/bashhub-client)
6+
57
###Bashhub provides
68
- Super command search by using context about how commands are executed.
79
- e.g. the directory, session, system, exit status, etc.

bashhub/bashhub.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import sys
77
import os
88

9-
from model import Command
9+
from model import CommandForm
1010
from model import UserContext
1111
import rest_client
1212
import bashhub_setup
@@ -24,10 +24,12 @@ def print_version(ctx, param, value):
2424
click.echo('Bashhub %s' % __version__)
2525
ctx.exit()
2626

27-
@click.group()
27+
28+
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
29+
30+
@click.group(context_settings=CONTEXT_SETTINGS)
2831
@click.option('-V', '--version', default=False, is_flag=True, callback=print_version,
2932
help='Display version', expose_value=False, is_eager=True)
30-
3133
def bashhub():
3234
"""Bashhub command line client"""
3335
pass
@@ -54,7 +56,7 @@ def save(command, path, pid, process_start_time, exit_status):
5456
return
5557

5658
context = UserContext(pid, pid_start_time, BH_USER_ID, BH_SYSTEM_ID)
57-
command = Command(command, path, exit_status, context)
59+
command = CommandForm(command, path, exit_status, context)
5860
rest_client.save_command(command)
5961

6062
@bashhub.command()

bashhub/bashhub_setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ def register_new_system(register_system):
5555
url = BH_URL + "/system/register"
5656
headers = {'content-type': 'application/json'}
5757
try:
58-
print register_system.to_JSON()
5958
response = requests.post(url, data=register_system.to_JSON(), headers=headers)
6059
response.raise_for_status()
6160
return response.json()
@@ -166,7 +165,8 @@ def main():
166165
if is_new_user:
167166
register_user = get_new_user_information()
168167
user_id = rest_client.register_user(register_user)
169-
168+
if user_id != None:
169+
print("Registered new user {0}\n".format(register_user.username))
170170
else:
171171
user_id = get_existing_user_information()
172172

bashhub/bh.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
from requests import ConnectionError
88
import cli.app
99
import os
10+
import io
1011

1112
from model import MinCommand
1213
from bashhub_globals import *
1314
import rest_client
14-
from interactive_search import InteractiveSearch
15+
from i_search import InteractiveSearch
1516

1617
@cli.app.CommandLineApp
1718
def bh(app):
@@ -44,13 +45,17 @@ def bh(app):
4445

4546
def print_commands(commands):
4647
for command in reversed(commands):
47-
print(command)
48+
print(command.command)
4849

4950
def run_interactive(commands):
50-
i_search = InteractiveSearch(commands)
51-
command = i_search.run()
52-
f = open(BH_HOME + '/response.bh','w+')
53-
print(command, file=f)
51+
i_search = InteractiveSearch(commands, rest_client)
52+
i_search.run()
53+
# numpy bullshit since it doesn't return anything.
54+
# Consider submitting a patchset for it.
55+
command = i_search.return_value
56+
if command is not None:
57+
f = io.open(BH_HOME + '/response.bh','w+', encoding='utf-8')
58+
print(unicode(command.command), file=f)
5459

5560
bh.add_param("-n", "--number", help="Limit the number of previous commands. \
5661
Default is 100.", default=100, type=int)

bashhub/i_search.py

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
#!/usr/bin/env python
2+
3+
import npyscreen
4+
import datetime
5+
import curses
6+
import time
7+
import rest_client
8+
import curses
9+
10+
class CommandList(npyscreen.MultiLineAction):
11+
def __init__(self, *args, **keywords):
12+
super(CommandList, self).__init__(*args, **keywords)
13+
self.command_handlers = {}
14+
15+
# Any non highlited command handlers
16+
self.add_handlers({
17+
"q": self.exit_app,
18+
curses.ascii.ESC : self.exit_app
19+
})
20+
21+
# All handlers for when a command is highlighted
22+
self.add_command_handlers({
23+
curses.ascii.NL: self.select_command,
24+
curses.ascii.CR: self.select_command,
25+
curses.ascii.SP: self.go_to_command_details,
26+
ord("i"): self.go_to_command_details
27+
})
28+
29+
# Disable handling of ALL mouse events right now. Without this we're
30+
# unable to select text when inside of interactive search. This is
31+
# convenient for access to the clipboard since on bash it'll
32+
# automatically execute the command. Eventually find a way to allow this.
33+
# It'd be nice to allow clicking to select a line.
34+
curses.mousemask(0)
35+
36+
def exit_app(self, vl):
37+
self.parent.parentApp.switchForm(None)
38+
39+
def display_value(self, vl):
40+
return "{0}".format(vl)
41+
42+
def add_command_handlers(self, command_handlers):
43+
self.command_handlers = command_handlers
44+
# wire up to use npyscreens h_act_on_hightlited
45+
event_handlers = dict((key, self.h_act_on_highlighted) for (key, value) in
46+
command_handlers.items())
47+
self.add_handlers(event_handlers)
48+
49+
def actionHighlighted(self, command, keypress):
50+
if keypress in self.command_handlers:
51+
return self.command_handlers[keypress](command)
52+
53+
def go_to_command_details(self, command):
54+
command_details = rest_client.get_command(command.uuid)
55+
self.parent.parentApp.getForm('EDITRECORDFM').value = command_details
56+
self.parent.parentApp.switchForm('EDITRECORDFM')
57+
58+
def select_command(self, command):
59+
self.parent.parentApp.return_value = command
60+
self.parent.parentApp.switchForm(None)
61+
62+
class CommandListDisplay(npyscreen.FormMutt):
63+
MAIN_WIDGET_CLASS = CommandList
64+
#COMMAND_WIDGET_CLASS = None
65+
66+
def beforeEditing(self):
67+
self.wStatus1.value = "Bashhub Commands "
68+
self.update_list()
69+
70+
def update_list(self):
71+
self.wMain.values = self.parentApp.commands
72+
self.wMain.display()
73+
74+
class EditRecord(npyscreen.ActionForm):
75+
76+
def __init__(self, *args, **keywords):
77+
super(EditRecord, self).__init__()
78+
self.add_handlers({
79+
"q": self.previous_form,
80+
curses.ascii.ESC : self.exit_app
81+
})
82+
83+
def create(self):
84+
self.value = None
85+
self.command = self.add(npyscreen.TitleFixedText, name = "Command:")
86+
self.path = self.add(npyscreen.TitleFixedText, name = "Path:")
87+
self.created = self.add(npyscreen.TitleFixedText, name = "Created At:")
88+
self.exit_status = self.add(npyscreen.TitleFixedText, name = "Exit Status:")
89+
self.system_name = self.add(npyscreen.TitleFixedText, name = "System Name:")
90+
self.session_id = self.add(npyscreen.TitleFixedText, name = "Session Id:")
91+
self.uuid = self.add(npyscreen.TitleFixedText, name = "UUID:")
92+
93+
def exit_app(self, vl):
94+
self.parentApp.switchForm(None)
95+
96+
def previous_form(self, vl):
97+
self.parentApp.switchFormPrevious()
98+
99+
def beforeEditing(self):
100+
if self.value:
101+
record = self.value
102+
self.name = "Command Details"
103+
date_string = datetime.datetime.fromtimestamp(record.created/1000).strftime('%Y-%m-%d %H:%M:%S')
104+
self.created.value = date_string
105+
self.command.value = record.command
106+
self.path.value = record.path
107+
108+
# Handle old commands that don't have exit status
109+
exit_status = "None" if record.exit_status is None else str(record.exit_status)
110+
self.exit_status.value = exit_status
111+
112+
self.system_name.value = record.system_name
113+
self.session_id.value = record.session_id
114+
self.uuid.value = record.uuid
115+
116+
else:
117+
self.command = "not found"
118+
119+
def on_ok(self):
120+
self.parentApp.switchFormPrevious()
121+
122+
def on_cancel(self):
123+
self.parentApp.switchFormPrevious()
124+
125+
126+
class InteractiveSearch(npyscreen.NPSAppManaged):
127+
128+
def __init__(self, commands, rest_client=None):
129+
super(InteractiveSearch, self).__init__()
130+
self.commands = commands
131+
self.rest_client = rest_client
132+
self.return_value = None
133+
134+
def onStart(self):
135+
self.addForm("MAIN", CommandListDisplay)
136+
self.addForm("EDITRECORDFM", EditRecord)
137+

bashhub/model/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from .command import *
2+
from .command_form import *
23
from .system import *
34
from .min_command import MinCommand
45
from .status_view import StatusView

bashhub/model/command.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,26 @@
22
from bson.objectid import ObjectId
33
from time import *
44
import jsonpickle
5-
import json
65
import sys
76
import uuid
87
from serializable import Serializable
98

109
class Command(Serializable):
11-
def __init__(self, command, path, exit_status, context):
12-
self.uuid = uuid.uuid1().__str__()
10+
11+
def __init__(self, command, path, uuid, username,
12+
system_name, session_id, created, id, exit_status = None):
1313
self.command = command
14-
self.created = time()*1000
1514
self.path = path
16-
self.exitStatus = exit_status
17-
self.context = context
15+
self.uuid = uuid
16+
self.exit_status = exit_status
17+
self.username = username
18+
self.system_name = system_name
19+
self.session_id = session_id
20+
self.created = created
21+
self.id = id
22+
23+
# Optional fields not set by jsonpickle.
24+
exit_status = None
1825

1926
class RegisterUser(Serializable):
2027
def __init__(self, email, username, password, registration_code = ""):
@@ -28,13 +35,5 @@ def __init__(self, username, password):
2835
self.username = username
2936
self.password = password
3037

31-
3238
def to_JSON(self):
3339
return jsonpickle.encode(self)
34-
35-
class UserContext(Serializable):
36-
def __init__(self, process_id, start_time, user_id, system_id):
37-
self.process_id = long(process_id)
38-
self.start_time = start_time
39-
self.user_id = user_id
40-
self.system_id = system_id

bashhub/model/command_form.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from time import *
2+
import uuid
3+
from serializable import Serializable
4+
5+
class CommandForm(Serializable):
6+
def __init__(self, command, path, exit_status, context):
7+
self.uuid = uuid.uuid4().__str__()
8+
self.command = command
9+
self.path = path
10+
self.exit_status = exit_status
11+
self.context = context
12+
self.created = time()*1000
13+
14+
15+
class UserContext(Serializable):
16+
def __init__(self, process_id, start_time, user_id, system_id):
17+
self.process_id = long(process_id)
18+
self.start_time = start_time
19+
self.user_id = user_id
20+
self.system_id = system_id

bashhub/model/min_command.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66

77
class MinCommand(Serializable):
88

9-
def __init__(self, command, created):
9+
def __init__(self, command, created, uuid):
1010
self.command = command
1111
self.created = created
12+
self.created = uuid
1213

1314
def __str__(self):
1415
return self.command.encode('utf8')

0 commit comments

Comments
 (0)