diff --git a/README.md b/README.md index 9240761..08cd12f 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,34 @@ [![Build Status](https://travis-ci.org/cs01/gdbgui.svg?branch=master)](https://travis-ci.org/cs01/gdbgui) -Still under active development, with a changing codebase/api. - # A browser-based gui for GDB +The goal of this project is to reduce the learning curve of GDB to zero, including autocompletion and documentation of all commands. + Made with a lightweight Python server (Flask), and JavaScript for the frontend. Simply run the server, then view the page. Tested on Ubuntu 16.04 with Chrome. ## Installation and Use +Either + + pip install gdbgui + +Or + git clone https://github.com/cs01/gdbgui pip install -r gdbgui/requirements.txt - gdbgui/gdbgui/backend.py + + +Then + + python -m gdbgui.backend * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) Then open `http://127.0.0.1:5000/` in a browser and enjoy! -A pip install package will be released when codebase is more stable ## Compatibility Tested on Python versions + * 2.7 * 3.3 * 3.4 diff --git a/gdbgui/MANIFEST.in b/gdbgui/MANIFEST.in new file mode 100644 index 0000000..458c04b --- /dev/null +++ b/gdbgui/MANIFEST.in @@ -0,0 +1,2 @@ +recursive-include static +recursive-include templates diff --git a/gdbgui/backend.py b/gdbgui/backend.py index 47b0748..a63a534 100755 --- a/gdbgui/backend.py +++ b/gdbgui/backend.py @@ -1,15 +1,18 @@ #!/usr/bin/env python -from flask import Flask, render_template, jsonify, session +from flask import Flask, render_template, jsonify import os import argparse from flask import request import signal -from ipdb import set_trace as db from pygdbmi.gdbcontroller import GdbController +import webbrowser + BASE_PATH = os.path.dirname(os.path.realpath(__file__)) TEMPLATE_DIR = os.path.join(BASE_PATH, 'templates') STATIC_DIR = os.path.join(BASE_PATH, 'static') +DEFAULT_HOST = '0.0.0.0' +DEFAULT_PORT = 5000 app = Flask(__name__, template_folder=TEMPLATE_DIR, static_folder=STATIC_DIR) @@ -17,6 +20,7 @@ app.jinja_env.add_extension('pyjade.ext.jinja.PyJadeExtension') gdb = None + def server_error(obj): return jsonify(obj), 500 @@ -26,24 +30,24 @@ def client_error(obj): def get_extra_files(): - extra_dirs = ['.'] - extra_files = extra_dirs[:] - for extra_dir in extra_dirs: - for dirname, dirs, files in os.walk(extra_dir): - for filename in files: - filename = os.path.join(dirname, filename) - if os.path.isfile(filename): - extra_files.append(filename) + extra_files = [] + for dirname, dirs, files in os.walk(TEMPLATE_DIR): + for filename in files: + filename = os.path.join(dirname, filename) + if os.path.isfile(filename): + extra_files.append(filename) return extra_files @app.route('/') def gdbgui(): + """Render the main gdbgui interface""" return render_template('gdbgui.jade') @app.route('/run_gdb_command', methods=['POST']) def run_gdb_command(): + """Run a gdb command""" if gdb is not None: try: cmd = request.form.get('cmd') or request.form.getlist('cmd[]') @@ -54,8 +58,10 @@ def run_gdb_command(): else: return client_error({'message': 'gdb is not running'}) + @app.route('/get_gdb_response') def get_gdb_response(): + """Return output from gdb.get_gdb_response""" if gdb is not None: try: response = gdb.get_gdb_response() @@ -68,7 +74,7 @@ def get_gdb_response(): @app.route('/read_file') def read_file(): - """Used to get contents of source files that are being debugged""" + """Read a file and return its contents as an array""" path = request.args.get('path') if path and os.path.isfile(path): try: @@ -83,8 +89,8 @@ def read_file(): def signal_handler(signal, frame): - """handle ctrl+c (SIGINT) and make sure the child process is killed!""" - global gdb + """handle ctrl+c (SIGINT) to make sure the child gdb process is killed""" + print("Received signal %s. Shutting down gdbgui." % signal) if gdb is not None: try: gdb.exit() @@ -96,6 +102,7 @@ def signal_handler(signal, frame): def quit_backend(): + """Shutdown the flask server. Used when programmitcally testing gdbgui""" gdb.exit() func = request.environ.get('werkzeug.server.shutdown') if func is None: @@ -103,31 +110,39 @@ def quit_backend(): func() -def setup_backend(serve=True, port=5000, debug=False): +def open_browser(host, port): + if host.startswith('http'): + url = '%s:%s' % (host, port) + else: + url = 'http://%s:%s' % (host, port) + print(" * Opening gdbgui in browser (%s)" % url) + webbrowser.open(url) + + +def setup_backend(serve=True, host=DEFAULT_HOST, port=DEFAULT_PORT, debug=False, view=True): """Run the server of the gdb gui""" - global app, gdb + global gdb signal.signal(signal.SIGINT, signal_handler) gdb = GdbController() app.secret_key = 'iusahjpoijeoprkge[0irokmeoprgk890' app.debug = debug app.config['TEMPLATES_AUTO_RELOAD'] = True + if serve: - extra_files = [] - for dirname, dirs, files in os.walk(TEMPLATE_DIR): - for filename in files: - filename = os.path.join(dirname, filename) - if os.path.isfile(filename): - extra_files.append(filename) - app.run(port=port, extra_files=extra_files) + if view: + open_browser(host, port) + app.run(host=host, port=port, extra_files=get_extra_files()) def main(): """Entry point from command line""" parser = argparse.ArgumentParser() - parser.add_argument("--port", default=5000) + parser.add_argument("--port", default=DEFAULT_PORT) + parser.add_argument("--host", default=DEFAULT_HOST) parser.add_argument("--debug", action='store_true') + parser.add_argument("--view", action='store_true') args = parser.parse_args() - setup_backend(port=args.port, debug=args.debug) + setup_backend(serve=True, host=args.host, port=args.port, debug=args.debug, view=args.view) if __name__ == '__main__': diff --git a/requirements.txt b/requirements.txt index ce7f9af..87e93f0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,23 +1,3 @@ -backports.shutil-get-terminal-size==1.0.0 -click==6.6 -decorator==4.0.10 Flask==0.11.1 -ipdb==0.10.1 -ipython==5.1.0 -ipython-genutils==0.1.0 -itsdangerous==0.24 -Jinja2==2.8 -MarkupSafe==0.23 -pathlib2==2.1.0 -pexpect==4.2.1 -pickleshare==0.7.4 -prompt-toolkit==1.0.7 -ptyprocess==0.5.1 pygdbmi==0.0.1.9 -Pygments==2.1.3 pyjade==4.0.0 -simplegeneric==0.8.1 -six==1.10.0 -traitlets==4.2.2 -wcwidth==0.1.7 -Werkzeug==0.11.11 diff --git a/setup.py b/setup.py index 91158d1..6803c20 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ import sys # from distutils.core import setup, EXCLUDE_FROM_PACKAGES = [] -version = '0.0.0.3' +version = '0.0.0.4' class TestCommand (Command): @@ -42,6 +42,7 @@ setup( install_requires=[ 'Flask>=0.11.1', 'pygdbmi>=0.0.1.9', + 'pyjade>=4.0.0' ], classifiers=[ 'Intended Audience :: Developers',