Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

client: thefuck intergration #81

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 107 additions & 24 deletions client/main/dpcs
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,32 @@ from random import sample
from string import ascii_lowercase
from string import ascii_uppercase
from string import digits
import errno
import json
import subprocess
import sys

from requests import get
from requests import post
from requests import ConnectionError
from requests import RequestException
from thefuck import const as thefuck_const
from thefuck import logs as thefuck_logs
from thefuck.conf import settings as thefuck_settings
from thefuck.corrector import get_rules
from thefuck.corrector import organize_commands
from thefuck.exceptions import NoRuleMatched
from thefuck.types import Command
from thefuck.ui import read_actions
from thefuck.ui import CommandSelector

from dpcs_client.settings import read_settings
from dpcs_client.systemcheck import systemcheck

EXIT_OK = 0


def generate_report(exit_code, stderr_output):
def generate_report(exit_code, stderr_output, script):
"""Generate a report which will be sent to the DCPS server.

Arguments
Expand All @@ -32,6 +43,9 @@ def generate_report(exit_code, stderr_output):
stderr_output : string
The output written on stderr by the failed process

script : string
The script run by user

Return
------
template : dict
Expand All @@ -40,8 +54,8 @@ def generate_report(exit_code, stderr_output):
template = {
"crash_report": {
"application": {
# TO DO - implementation depends on the way how the daemon is
# implemented
'name': script,
'version': ""
},
"system_info": {},
"exit_code": exit_code,
Expand Down Expand Up @@ -75,6 +89,29 @@ def handle_request_error(exception, dpcs_message):
print(exception.response.text, file=sys.stderr)


def handle_script(script):
"""Show interactive question.

Arguments
---------
script : string
The solution script.
"""

print("How would you like to use this solution?")
resp = ''
while resp != 'q' and resp != 'r' and resp != 's' and resp != 'p':
resp = raw_input("(q) - ignore & quit, (r) - run, " +
"(s) - save, (p) - print\n")

if resp == 's':
save_script(script)
elif resp == 'r':
run_script(script)
elif resp == 'p':
print(script)


def rand_fname(parent_path, prefix, suffix, length=4):
"""Create a random filename for storing the solution script.

Expand Down Expand Up @@ -143,6 +180,56 @@ def save_script(script):
print("The script produced by DPCS is available in " +
filename)


def try_the_fuck(script, stout, sterr):
"""Use thefuck library internals to solve easy problems

Arguments
---------
script : string
The command given by the user

stout : string
Script's standard output.

sterr : string
Script's error output.
"""
thefuck_settings.init()
command = Command(script=script, stdout=stout, stderr=sterr)

# Removes history rule in order to prevent running dpcs recursively
rules = filter(lambda rule: rule.name != 'history', get_rules())

corrected_commands = organize_commands((
corrected for rule in rules
if rule.is_match(command)
for corrected in rule.get_corrected_commands(command)
))

try:
selector = CommandSelector(corrected_commands)
except NoRuleMatched:
return

thefuck_logs.confirm_text(selector.value)

for action in read_actions():
if action == thefuck_const.ACTION_SELECT:
sys.stderr.write('\n')
handle_script(selector.value.script)
exit(0)
elif action == thefuck_const.ACTION_ABORT:
sys.stderr.write('\n')
return
elif action == thefuck_const.ACTION_PREVIOUS:
selector.previous()
thefuck_logs.confirm_text(selector.value)
elif action == thefuck_const.ACTION_NEXT:
selector.next()
thefuck_logs.confirm_text(selector.value)


if __name__ == '__main__':

if len(sys.argv) != 2:
Expand All @@ -152,24 +239,31 @@ if __name__ == '__main__':
server_address = read_settings()['server_address']

p = subprocess.Popen(sys.argv[1],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True)
_, output = p.communicate()
stout, sterr = p.communicate()
code = p.returncode

print(output)
# TO IMPROVE: the code below will change the order of printing
print(stout, end="")
print(sterr, end="")

if code != EXIT_OK:

try_the_fuck(sys.argv[1], stout, sterr)

api_description_url = server_address + "vd1/paths/"
try:
response = get(api_description_url)
except ConnectionError as e:
print("Error: DPCS coudln't connect with the server")
exit(errno.EHOSTUNREACH)
except RequestException as e:
#handle_request_error(
# e, "DPCS couldn't get api description"
#)
print("DPCS server: Offline")
exit(2)
handle_request_error(
e, "DPCS couldn't get api description"
)
exit(errno.EHOSTDOWN)

api_paths = response.json()
crash_report_url = server_address + api_paths["crash-reports"]
Expand All @@ -178,7 +272,7 @@ if __name__ == '__main__':
'Content-Type': 'application/json'
}

report = generate_report(code, output)
report = generate_report(code, sterr)

try:
response = post(crash_report_url,
Expand All @@ -188,23 +282,12 @@ if __name__ == '__main__':
handle_request_error(
e, "DPCS couldn't post crash information"
)
exit(3)
exit(errno.EINVAL)

script = '#No known solution have been found'
if 'crash_report_ack' in response.json():
script = response.json()['crash_report_ack'][
'solution']['shell_script']

print("DPCS might have found a solution to your problem!")
print("How would you like to use it?")
resp = ''
while resp != 'q' and resp != 'r' and resp != 's' and resp != 'p':
resp = raw_input("(q) - ignore & quit, (r) - run, " +
"(s) - save, (p) - print\n")

if resp == 's':
save_script(script)
elif resp == 'r':
run_script(script)
elif resp == 'p':
print(script)
handle_script(script)