Skip to content

Commit

Permalink
Merge branch '0.0.13-dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
rcaloras committed Sep 20, 2015
2 parents c92befd + 10f14c1 commit e66f142
Show file tree
Hide file tree
Showing 23 changed files with 298 additions and 45 deletions.
26 changes: 26 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
language: python
python:
- "2.6"
- "2.7"
before_install:
# To install bats and test our shell/bash functions
- sudo add-apt-repository ppa:duggan/bats --yes
- sudo apt-get update -qq
- sudo apt-get install -qq bats
- sudo apt-get install -qq zsh

# For bats functional tests
env:
- functional_test="true"

# command to install dependencies
install: "pip install ."

# command to run tests
script:
- py.test
- bats tests/shell

notifications:
email:
on_success: never
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
==========
Bashhub saves every terminal command entered across all sessions and systems and provides powerful querying across all commands.

[![Build Status](https://travis-ci.org/rcaloras/bashhub-client.svg)](https://travis-ci.org/rcaloras/bashhub-client)

###Bashhub provides
- Super command search by using context about how commands are executed.
- e.g. the directory, session, system, exit status, etc.
Expand Down
10 changes: 6 additions & 4 deletions bashhub/bashhub.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import sys
import os

from model import Command
from model import CommandForm
from model import UserContext
import rest_client
import bashhub_setup
Expand All @@ -24,10 +24,12 @@ def print_version(ctx, param, value):
click.echo('Bashhub %s' % __version__)
ctx.exit()

@click.group()

CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])

@click.group(context_settings=CONTEXT_SETTINGS)
@click.option('-V', '--version', default=False, is_flag=True, callback=print_version,
help='Display version', expose_value=False, is_eager=True)

def bashhub():
"""Bashhub command line client"""
pass
Expand All @@ -54,7 +56,7 @@ def save(command, path, pid, process_start_time, exit_status):
return

context = UserContext(pid, pid_start_time, BH_USER_ID, BH_SYSTEM_ID)
command = Command(command, path, exit_status, context)
command = CommandForm(command, path, exit_status, context)
rest_client.save_command(command)

@bashhub.command()
Expand Down
4 changes: 2 additions & 2 deletions bashhub/bashhub_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ def register_new_system(register_system):
url = BH_URL + "/system/register"
headers = {'content-type': 'application/json'}
try:
print register_system.to_JSON()
response = requests.post(url, data=register_system.to_JSON(), headers=headers)
response.raise_for_status()
return response.json()
Expand Down Expand Up @@ -166,7 +165,8 @@ def main():
if is_new_user:
register_user = get_new_user_information()
user_id = rest_client.register_user(register_user)

if user_id != None:
print("Registered new user {0}\n".format(register_user.username))
else:
user_id = get_existing_user_information()

Expand Down
17 changes: 11 additions & 6 deletions bashhub/bh.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
from requests import ConnectionError
import cli.app
import os
import io

from model import MinCommand
from bashhub_globals import *
import rest_client
from interactive_search import InteractiveSearch
from i_search import InteractiveSearch

@cli.app.CommandLineApp
def bh(app):
Expand Down Expand Up @@ -44,13 +45,17 @@ def bh(app):

def print_commands(commands):
for command in reversed(commands):
print(command)
print(command.command)

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

bh.add_param("-n", "--number", help="Limit the number of previous commands. \
Default is 100.", default=100, type=int)
Expand Down
137 changes: 137 additions & 0 deletions bashhub/i_search.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#!/usr/bin/env python

import npyscreen
import datetime
import curses
import time
import rest_client
import curses

class CommandList(npyscreen.MultiLineAction):
def __init__(self, *args, **keywords):
super(CommandList, self).__init__(*args, **keywords)
self.command_handlers = {}

# Any non highlited command handlers
self.add_handlers({
"q": self.exit_app,
curses.ascii.ESC : self.exit_app
})

# All handlers for when a command is highlighted
self.add_command_handlers({
curses.ascii.NL: self.select_command,
curses.ascii.CR: self.select_command,
curses.ascii.SP: self.go_to_command_details,
ord("i"): self.go_to_command_details
})

# Disable handling of ALL mouse events right now. Without this we're
# unable to select text when inside of interactive search. This is
# convenient for access to the clipboard since on bash it'll
# automatically execute the command. Eventually find a way to allow this.
# It'd be nice to allow clicking to select a line.
curses.mousemask(0)

def exit_app(self, vl):
self.parent.parentApp.switchForm(None)

def display_value(self, vl):
return "{0}".format(vl)

def add_command_handlers(self, command_handlers):
self.command_handlers = command_handlers
# wire up to use npyscreens h_act_on_hightlited
event_handlers = dict((key, self.h_act_on_highlighted) for (key, value) in
command_handlers.items())
self.add_handlers(event_handlers)

def actionHighlighted(self, command, keypress):
if keypress in self.command_handlers:
return self.command_handlers[keypress](command)

def go_to_command_details(self, command):
command_details = rest_client.get_command(command.uuid)
self.parent.parentApp.getForm('EDITRECORDFM').value = command_details
self.parent.parentApp.switchForm('EDITRECORDFM')

def select_command(self, command):
self.parent.parentApp.return_value = command
self.parent.parentApp.switchForm(None)

class CommandListDisplay(npyscreen.FormMutt):
MAIN_WIDGET_CLASS = CommandList
#COMMAND_WIDGET_CLASS = None

def beforeEditing(self):
self.wStatus1.value = "Bashhub Commands "
self.update_list()

def update_list(self):
self.wMain.values = self.parentApp.commands
self.wMain.display()

class EditRecord(npyscreen.ActionForm):

def __init__(self, *args, **keywords):
super(EditRecord, self).__init__()
self.add_handlers({
"q": self.previous_form,
curses.ascii.ESC : self.exit_app
})

def create(self):
self.value = None
self.command = self.add(npyscreen.TitleFixedText, name = "Command:")
self.path = self.add(npyscreen.TitleFixedText, name = "Path:")
self.created = self.add(npyscreen.TitleFixedText, name = "Created At:")
self.exit_status = self.add(npyscreen.TitleFixedText, name = "Exit Status:")
self.system_name = self.add(npyscreen.TitleFixedText, name = "System Name:")
self.session_id = self.add(npyscreen.TitleFixedText, name = "Session Id:")
self.uuid = self.add(npyscreen.TitleFixedText, name = "UUID:")

def exit_app(self, vl):
self.parentApp.switchForm(None)

def previous_form(self, vl):
self.parentApp.switchFormPrevious()

def beforeEditing(self):
if self.value:
record = self.value
self.name = "Command Details"
date_string = datetime.datetime.fromtimestamp(record.created/1000).strftime('%Y-%m-%d %H:%M:%S')
self.created.value = date_string
self.command.value = record.command
self.path.value = record.path

# Handle old commands that don't have exit status
exit_status = "None" if record.exit_status is None else str(record.exit_status)
self.exit_status.value = exit_status

self.system_name.value = record.system_name
self.session_id.value = record.session_id
self.uuid.value = record.uuid

else:
self.command = "not found"

def on_ok(self):
self.parentApp.switchFormPrevious()

def on_cancel(self):
self.parentApp.switchFormPrevious()


class InteractiveSearch(npyscreen.NPSAppManaged):

def __init__(self, commands, rest_client=None):
super(InteractiveSearch, self).__init__()
self.commands = commands
self.rest_client = rest_client
self.return_value = None

def onStart(self):
self.addForm("MAIN", CommandListDisplay)
self.addForm("EDITRECORDFM", EditRecord)

1 change: 1 addition & 0 deletions bashhub/model/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .command import *
from .command_form import *
from .system import *
from .min_command import MinCommand
from .status_view import StatusView
Expand Down
27 changes: 13 additions & 14 deletions bashhub/model/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,26 @@
from bson.objectid import ObjectId
from time import *
import jsonpickle
import json
import sys
import uuid
from serializable import Serializable

class Command(Serializable):
def __init__(self, command, path, exit_status, context):
self.uuid = uuid.uuid1().__str__()

def __init__(self, command, path, uuid, username,
system_name, session_id, created, id, exit_status = None):
self.command = command
self.created = time()*1000
self.path = path
self.exitStatus = exit_status
self.context = context
self.uuid = uuid
self.exit_status = exit_status
self.username = username
self.system_name = system_name
self.session_id = session_id
self.created = created
self.id = id

# Optional fields not set by jsonpickle.
exit_status = None

class RegisterUser(Serializable):
def __init__(self, email, username, password, registration_code = ""):
Expand All @@ -28,13 +35,5 @@ def __init__(self, username, password):
self.username = username
self.password = password


def to_JSON(self):
return jsonpickle.encode(self)

class UserContext(Serializable):
def __init__(self, process_id, start_time, user_id, system_id):
self.process_id = long(process_id)
self.start_time = start_time
self.user_id = user_id
self.system_id = system_id
20 changes: 20 additions & 0 deletions bashhub/model/command_form.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from time import *
import uuid
from serializable import Serializable

class CommandForm(Serializable):
def __init__(self, command, path, exit_status, context):
self.uuid = uuid.uuid4().__str__()
self.command = command
self.path = path
self.exit_status = exit_status
self.context = context
self.created = time()*1000


class UserContext(Serializable):
def __init__(self, process_id, start_time, user_id, system_id):
self.process_id = long(process_id)
self.start_time = start_time
self.user_id = user_id
self.system_id = system_id
3 changes: 2 additions & 1 deletion bashhub/model/min_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@

class MinCommand(Serializable):

def __init__(self, command, created):
def __init__(self, command, created, uuid):
self.command = command
self.created = created
self.created = uuid

def __str__(self):
return self.command.encode('utf8')
Expand Down
3 changes: 3 additions & 0 deletions bashhub/model/serializable.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ def from_JSON(cls, response):

@classmethod
def from_JSON_list(cls, response):

#response = json.load(response)

# Use list comprehension to map every json object
# back to its object with from_JSON
items = [cls.from_JSON(json.dumps(item)) for item in response]
Expand Down
1 change: 0 additions & 1 deletion bashhub/model/status_view.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

from serializable import Serializable

class StatusView(Serializable):
Expand Down
Loading

0 comments on commit e66f142

Please sign in to comment.