def main(argv=None):
    if argv is None:
        argv = sys.argv[1:]
    args = parse_global_args(argv)
    type_system.interactive = True
    line = args.commands
    timeout_thread = None
    timeout_stop_event = threading.Event()
    if args.timeout:
        timeout_thread = threading.Thread(target=timeout_thread_handler, args=(args.timeout, timeout_stop_event))
        timeout_thread.daemon = True
        timeout_thread.start()
    shell = HierarchicalShell('iotile')
    shell.root_add("registry", "iotile.core.dev.annotated_registry,registry")
    shell.root_add("config", "iotile.core.dev.config,ConfigManager")
    shell.root_add('hw', "iotile.core.hw.hwmanager,HardwareManager")
    reg = ComponentRegistry()
    plugins = reg.list_plugins()
    for key, val in plugins.items():
        shell.root_add(key, val)
    finished = False
    try:
        if len(line) > 0:
            finished = shell.invoke(line)
    except IOTileException as exc:
        print(exc.format())
        SharedLoop.stop()
        return 1
    except Exception:
        traceback.print_exc()
        SharedLoop.stop()
        return 1
    if args.quit or finished:
        SharedLoop.stop()
        return 0
    setup_completion(shell)
    try:
        while True:
            try:
                linebuf = input("(%s) " % shell.context_name())
                if len(linebuf) > 0 and linebuf[0] == '
                    continue
            except KeyboardInterrupt:
                print("")
                continue
            try:
                finished = shell.invoke_string(linebuf)
            except KeyboardInterrupt:
                print("")
                if timeout_stop_event.is_set():
                    break
            except IOTileException as exc:
                print(exc.format())
            except Exception:
                traceback.print_exc()
            if shell.finished():
                break
    except EOFError:
        print("")
    except KeyboardInterrupt:
        print("")
    finally:
        SharedLoop.stop()
    if timeout_thread is not None:
        timeout_stop_event.set()
        timeout_thread.join()