Beispiel #1
0
 def run(self, workspace=None):
     if workspace is None:
         workspace = 'https://%s/' % G.DEFAULT_HOST
     for d in self.window.folders():
         floo_file = os.path.join(d, '.floo')
         try:
             floo_info = open(floo_file, 'r').read()
             wurl = json.loads(floo_info).get('url')
             utils.parse_url(wurl)
             # TODO: check if workspace actually exists
             workspace = wurl
             break
         except Exception:
             pass
     self.window.show_input_panel('Workspace URL:', workspace, self.on_input, None, None)
 def run(self, workspace=None):
     if workspace is None:
         workspace = 'https://%s/' % G.DEFAULT_HOST
     for d in self.window.folders():
         floo_file = os.path.join(d, '.floo')
         try:
             floo_info = open(floo_file, 'r').read()
             wurl = json.loads(floo_info).get('url')
             utils.parse_url(wurl)
             # TODO: check if workspace actually exists
             workspace = wurl
             break
         except Exception:
             pass
     self.window.show_input_panel('Workspace URL:', workspace, self.on_input, None, None)
Beispiel #3
0
    def join_workspace(self, context, host, name, owner, possible_dirs=None):
        utils.reload_settings()

        # legacy urls in emacs...
        if owner and owner[:2] == "r/":
            owner = owner[2:]

        if not utils.can_auth():
            success = yield self.create_or_link_account, context, host, False
            if not success:
                return
            utils.reload_settings()

        possible_dirs = possible_dirs or []
        for d in possible_dirs:
            info = utils.read_floo_file(d)
            if not info:
                continue
            try:
                parsed_url = utils.parse_url(info["url"])
            except Exception:
                parsed_url = None

            if (
                parsed_url
                and parsed_url["host"] == host
                and parsed_url["workspace"] == name
                and parsed_url["owner"] == owner
            ):
                self.remote_connect(context, host, owner, name, d)
                return

        try:
            d = utils.get_persistent_data()["workspaces"][owner][name]["path"]
        except Exception:
            d = ""

        if d and os.path.isdir(d):
            self.remote_connect(context, host, owner, name, d)
            return

        d = d or os.path.join(G.SHARE_DIR or G.BASE_DIR, owner, name)
        join_action = utils.JOIN_ACTION.PROMPT
        while True:
            d = yield self.user_dir, context, "Save workspace files to: ", d
            if not d:
                return
            d = os.path.realpath(os.path.expanduser(d))
            if not os.path.isdir(d):
                y_or_n = yield self.user_y_or_n, context, "%s is not a directory. Create it? " % d, "Create Directory"
                if not y_or_n:
                    return
                utils.mkdir(d)
                if not os.path.isdir(d):
                    msg.error("Couldn't create directory", d)
                    continue
                join_action = utils.JOIN_ACTION.DOWNLOAD
            if os.path.isdir(d):
                self.remote_connect(context, host, owner, name, d, join_action)
                return
Beispiel #4
0
    def join_workspace_by_url(self, context, workspace_url, possible_dirs=None):
        try:
            d = utils.parse_url(workspace_url)
        except Exception as e:
            return editor.error_message(str_e(e))

        return self.join_workspace(context, d['host'], d['workspace'], d['owner'], possible_dirs)
Beispiel #5
0
    def join_workspace_by_url(self, context, workspace_url, possible_dirs=None):
        try:
            d = utils.parse_url(workspace_url)
        except Exception as e:
            return editor.error_message(str_e(e))

        return self.join_workspace(context, d['host'], d['workspace'], d['owner'], possible_dirs)
Beispiel #6
0
    def join_workspace(self, context, host, name, owner, possible_dirs=None):
        utils.reload_settings()

        # legacy urls in emacs...
        if owner and owner[:2] == "r/":
            owner = owner[2:]

        if not utils.can_auth():
            success = yield self.create_or_link_account, context, host, False
            if not success:
                return
            utils.reload_settings()

        possible_dirs = possible_dirs or []
        for d in possible_dirs:
            info = utils.read_floo_file(d)
            if not info:
                continue
            try:
                parsed_url = utils.parse_url(info['url'])
            except Exception:
                parsed_url = None

            if parsed_url and parsed_url['host'] == host and parsed_url[
                    'workspace'] == name and parsed_url['owner'] == owner:
                self.remote_connect(context, host, owner, name, d)
                return

        try:
            d = utils.get_persistent_data()['workspaces'][owner][name]['path']
        except Exception:
            d = ''

        if d and os.path.isdir(d):
            self.remote_connect(context, host, owner, name, d)
            return

        # TODO: make per-host settings fully general
        host_share_dir = G.AUTH.get(host, {}).get('share_dir')
        d = d or os.path.join(host_share_dir or G.SHARE_DIR or G.BASE_DIR,
                              owner, name)
        join_action = utils.JOIN_ACTION.PROMPT
        while True:
            d = yield self.user_dir, context, 'Save workspace files to: ', d
            if not d:
                return
            d = os.path.realpath(os.path.expanduser(d))
            if not os.path.isdir(d):
                y_or_n = yield self.user_y_or_n, context, '%s is not a directory. Create it? ' % d, "Create Directory"
                if not y_or_n:
                    return
                utils.mkdir(d)
                if not os.path.isdir(d):
                    msg.error("Couldn't create directory", d)
                    continue
                join_action = utils.JOIN_ACTION.DOWNLOAD
            if os.path.isdir(d):
                self.remote_connect(context, host, owner, name, d, join_action)
                return
Beispiel #7
0
    def join_workspace(self, context, host, name, owner, possible_dirs=None):
        utils.reload_settings()

        # legacy urls in emacs...
        if owner and owner[:2] == "r/":
            owner = owner[2:]

        if not utils.can_auth():
            success = yield self.create_or_link_account, context, host, False
            if not success:
                return
            utils.reload_settings()

        possible_dirs = possible_dirs or []
        for d in possible_dirs:
            info = utils.read_floo_file(d)
            if not info:
                continue
            try:
                parsed_url = utils.parse_url(info['url'])
            except Exception:
                parsed_url = None

            if parsed_url and parsed_url['host'] == host and parsed_url['workspace'] == name and parsed_url['owner'] == owner:
                self.remote_connect(context, host, owner, name, d)
                return

        try:
            d = utils.get_persistent_data()['workspaces'][owner][name]['path']
        except Exception:
            d = ''

        if d and os.path.isdir(d):
            self.remote_connect(context, host, owner, name, d)
            return

        # TODO: make per-host settings fully general
        host_share_dir = G.AUTH.get(host, {}).get('share_dir')
        d = d or os.path.join(host_share_dir or G.SHARE_DIR or G.BASE_DIR, owner, name)
        join_action = utils.JOIN_ACTION.PROMPT
        while True:
            d = yield self.user_dir, context, 'Save workspace files to: ', d
            if not d:
                return
            d = os.path.realpath(os.path.expanduser(d))
            if not os.path.isdir(d):
                y_or_n = yield self.user_y_or_n, context, '%s is not a directory. Create it? ' % d, "Create Directory"
                if not y_or_n:
                    return
                utils.mkdir(d)
                if not os.path.isdir(d):
                    msg.error("Couldn't create directory", d)
                    continue
                join_action = utils.JOIN_ACTION.DOWNLOAD
            if os.path.isdir(d):
                self.remote_connect(context, host, owner, name, d, join_action)
                return
def floobits_join_workspace(workspace_url, d='', upload_path=None):
    editor.line_endings = _get_line_endings()
    msg.debug('workspace url is %s' % workspace_url)
    try:
        result = utils.parse_url(workspace_url)
    except Exception as e:
        return msg.error(str(e))

    if d:
        utils.mkdir(d)
    else:
        try:
            d = utils.get_persistent_data()['workspaces'][result['owner']][result['workspace']]['path']
        except Exception:
            d = os.path.realpath(os.path.join(G.COLAB_DIR, result['owner'], result['workspace']))

    prompt = 'Save workspace files to: '
    if not os.path.isdir(d):
        while True:
            d = vim_input(prompt, d, 'dir')
            if d == '':
                continue
            d = os.path.realpath(os.path.expanduser(d))
            if os.path.isfile(d):
                prompt = '%s is not a directory. Enter an existing path or a path I can create: ' % d
                continue
            if not os.path.isdir(d):
                try:
                    utils.mkdir(d)
                except Exception as e:
                    prompt = 'Couldn\'t make dir %s: %s ' % (d, str(e))
                    continue
            break
    d = os.path.realpath(os.path.abspath(d) + os.sep)
    try:
        utils.add_workspace_to_persistent_json(result['owner'], result['workspace'], workspace_url, d)
    except Exception as e:
        return msg.error('Error adding workspace to persistent.json: %s' % str(e))

    G.PROJECT_PATH = d
    vim.command('cd %s' % G.PROJECT_PATH)
    msg.debug('Joining workspace %s' % workspace_url)

    floobits_stop_everything()
    try:
        conn = VimHandler(result['owner'], result['workspace'])
        if upload_path:
            conn.once('room_info', lambda: G.AGENT.upload(upload_path))
        reactor.connect(conn, result['host'], result['port'], result['secure'])
    except Exception as e:
        msg.error(str(e))
        tb = traceback.format_exc()
        msg.debug(tb)
    if not G.TIMERS:
        start_event_loop()
Beispiel #9
0
def join_workspace(workspace_url, on_auth=None):
    global agent
    msg.debug("workspace url is %s" % workspace_url)

    try:
        result = utils.parse_url(workspace_url)
    except Exception as e:
        return msg.error(str(e))

    G.PROJECT_PATH = os.path.realpath(
        os.path.join(G.COLAB_DIR, result['owner'], result['workspace']))
    utils.mkdir(os.path.dirname(G.PROJECT_PATH))

    d = ''
    # TODO: really bad prompt here
    prompt = "Give me a directory to sync data to (or just press enter): "
    if not os.path.isdir(G.PROJECT_PATH):
        while True:
            d = vim_input(prompt, d, "dir")
            if d == '':
                utils.mkdir(G.PROJECT_PATH)
                break
            d = os.path.realpath(os.path.expanduser(d))
            if os.path.isfile(d):
                prompt = '%s is not a directory. Enter an existing path (or press enter): ' % d
                continue
            if not os.path.isdir(d):
                try:
                    utils.mkdir(d)
                except Exception as e:
                    prompt = "Couldn't make dir: %s because %s " % (d, str(e))
                    continue
            try:
                os.symlink(d, G.PROJECT_PATH)
                break
            except Exception as e:
                return msg.error("Couldn't create symlink from %s to %s: %s" %
                                 (d, G.PROJECT_PATH, str(e)))

    G.PROJECT_PATH = os.path.realpath(G.PROJECT_PATH + os.sep)
    vim.command('cd %s' % G.PROJECT_PATH)
    msg.debug("joining workspace %s" % workspace_url)

    stop_everything()
    try:
        start_event_loop()
        agent = AgentConnection(on_auth=on_auth, Protocol=Protocol, **result)
        # owner and workspace name are slugfields so this should be safe
        agent.connect()
    except Exception as e:
        msg.error(str(e))
        tb = traceback.format_exc()
        msg.debug(tb)
        stop_everything()
Beispiel #10
0
 def find_workspace(workspace_url):
     r = api.get_workspace_by_url(workspace_url)
     if r.code < 400:
         return r
     try:
         result = utils.parse_url(workspace_url)
         d = utils.get_persistent_data()
         del d['workspaces'][result['owner']][result['name']]
         utils.update_persistent_data(d)
     except Exception as e:
         msg.debug(str_e(e))
 def find_workspace(workspace_url):
     r = api.get_workspace_by_url(workspace_url)
     if r.code < 400:
         return r
     try:
         result = utils.parse_url(workspace_url)
         d = utils.get_persistent_data()
         del d['workspaces'][result['owner']][result['name']]
         utils.update_persistent_data(d)
     except Exception as e:
         msg.debug(str_e(e))
 def find_workspace(workspace_url):
     r = api.get_workspace_by_url(workspace_url)
     if r.code < 400:
         on_room_info_waterfall.add(ignore.create_flooignore, dir_to_share)
         on_room_info_waterfall.add(lambda: G.AGENT.upload(dir_to_share, on_room_info_msg))
         return r
     try:
         result = utils.parse_url(workspace_url)
         d = utils.get_persistent_data()
         del d['workspaces'][result['owner']][result['name']]
         utils.update_persistent_data(d)
     except Exception as e:
         msg.debug(unicode(e))
     return
Beispiel #13
0
    def prejoin_workspace(self, workspace_url, dir_to_share, api_args):
        try:
            result = utils.parse_url(workspace_url)
        except Exception as e:
            msg.error(str_e(e))
            return False

        host = result.get('host')
        if not api.get_basic_auth(host):
            raise ValueError(
                'No auth credentials for %s. Please add a username and secret for %s in your ~/.floorc.json'
                % (host, host))

        try:
            w = api.get_workspace_by_url(workspace_url)
        except Exception as e:
            editor.error_message('Error opening url %s: %s' %
                                 (workspace_url, str_e(e)))
            return False

        if w.code >= 400:
            try:
                d = utils.get_persistent_data()
                try:
                    del d['workspaces'][result['owner']][result['name']]
                except Exception:
                    pass
                try:
                    del d['recent_workspaces'][workspace_url]
                except Exception:
                    pass
                utils.update_persistent_data(d)
            except Exception as e:
                msg.debug(str_e(e))
            return False

        msg.debug('workspace: ', json.dumps(w.body))
        anon_perms = w.body.get('perms', {}).get('AnonymousUser', [])
        msg.debug('api args: ', api_args)
        new_anon_perms = api_args.get('perms', {}).get('AnonymousUser', [])
        # TODO: prompt/alert user if going from private to public
        if set(anon_perms) != set(new_anon_perms):
            msg.debug(str(anon_perms), str(new_anon_perms))
            w.body['perms']['AnonymousUser'] = new_anon_perms
            response = api.update_workspace(workspace_url, w.body)
            msg.debug(str(response.body))
        utils.add_workspace_to_persistent_json(w.body['owner'], w.body['name'],
                                               workspace_url, dir_to_share)
        return result
Beispiel #14
0
    def prejoin_workspace(self, workspace_url, dir_to_share, api_args):
        try:
            result = utils.parse_url(workspace_url)
        except Exception as e:
            msg.error(str_e(e))
            return False

        host = result.get("host")
        if not api.get_basic_auth(host):
            raise ValueError(
                "No auth credentials for %s. Please add a username and secret for %s in your ~/.floorc.json"
                % (host, host)
            )

        try:
            w = api.get_workspace_by_url(workspace_url)
        except Exception as e:
            editor.error_message("Error opening url %s: %s" % (workspace_url, str_e(e)))
            return False

        if w.code >= 400:
            try:
                d = utils.get_persistent_data()
                try:
                    del d["workspaces"][result["owner"]][result["name"]]
                except Exception:
                    pass
                try:
                    del d["recent_workspaces"][workspace_url]
                except Exception:
                    pass
                utils.update_persistent_data(d)
            except Exception as e:
                msg.debug(str_e(e))
            return False

        msg.debug("workspace: ", json.dumps(w.body))
        anon_perms = w.body.get("perms", {}).get("AnonymousUser", [])
        msg.debug("api args: ", api_args)
        new_anon_perms = api_args.get("perms", {}).get("AnonymousUser", [])
        # TODO: prompt/alert user if going from private to public
        if set(anon_perms) != set(new_anon_perms):
            msg.debug(str(anon_perms), str(new_anon_perms))
            w.body["perms"]["AnonymousUser"] = new_anon_perms
            response = api.update_workspace(workspace_url, w.body)
            msg.debug(str(response.body))
        utils.add_workspace_to_persistent_json(w.body["owner"], w.body["name"], workspace_url, dir_to_share)
        return result
Beispiel #15
0
 def find_workspace(workspace_url):
     try:
         api.get_workspace_by_url(workspace_url)
     except HTTPError:
         try:
             result = utils.parse_url(workspace_url)
             d = utils.get_persistent_data()
             del d['workspaces'][result['owner']][result['name']]
             utils.update_persistent_data(d)
         except Exception as e:
             msg.debug(unicode(e))
         return False
     on_room_info_waterfall.add(on_room_info_msg)
     on_room_info_waterfall.add(ignore.create_flooignore, dir_to_share)
     on_room_info_waterfall.add(Listener.create_buf, dir_to_share)
     return True
 def find_workspace(workspace_url):
     try:
         api.get_workspace_by_url(workspace_url)
     except HTTPError:
         try:
             result = utils.parse_url(workspace_url)
             d = utils.get_persistent_data()
             del d['workspaces'][result['owner']][result['name']]
             utils.update_persistent_data(d)
         except Exception as e:
             msg.debug(unicode(e))
         return False
     on_room_info_waterfall.add(on_room_info_msg)
     on_room_info_waterfall.add(ignore.create_flooignore, dir_to_share)
     on_room_info_waterfall.add(Listener.create_buf, dir_to_share)
     return True
 def find_workspace(workspace_url):
     if ssl is False:
         # No ssl module (broken Sublime Text). Just behave as if the workspace exists.
         return True
     try:
         api.get_workspace_by_url(workspace_url)
     except HTTPError:
         try:
             result = utils.parse_url(workspace_url)
             d = utils.get_persistent_data()
             del d['workspaces'][result['owner']][result['name']]
             utils.update_persistent_data(d)
         except Exception as e:
             msg.debug(unicode(e))
         return False
     on_room_info_waterfall.add(on_room_info_msg)
     on_room_info_waterfall.add(ignore.create_flooignore, dir_to_share)
     on_room_info_waterfall.add(Listener.create_buf, dir_to_share)
     return True
Beispiel #18
0
def share_dir(dir_to_share):
    dir_to_share = os.path.expanduser(dir_to_share)
    dir_to_share = utils.unfuck_path(dir_to_share)
    dir_to_share = os.path.abspath(dir_to_share)

    workspace_name = os.path.basename(dir_to_share)
    floo_workspace_dir = os.path.join(G.COLAB_DIR, G.USERNAME, workspace_name)

    if os.path.isfile(dir_to_share):
        return msg.error('give me a directory please')

    if not os.path.isdir(dir_to_share):
        return msg.error('The directory %s doesn\'t appear to exist' %
                         dir_to_share)

    floo_file = os.path.join(dir_to_share, '.floo')
    # look for the .floo file for hints about previous behavior
    info = {}
    try:
        floo_info = open(floo_file, 'rb').read().decode('utf-8')
        info = json.loads(floo_info)
    except (IOError, OSError):
        pass
    except Exception:
        msg.warn("couldn't read the floo_info file: %s" % floo_file)

    workspace_url = info.get('url')
    if workspace_url:
        try:
            result = utils.parse_url(workspace_url)
        except Exception as e:
            msg.error(str(e))
        else:
            workspace_name = result['workspace']
            floo_workspace_dir = os.path.join(G.COLAB_DIR, result['owner'],
                                              result['workspace'])
            # they have previously joined the workspace
            if os.path.realpath(floo_workspace_dir) == os.path.realpath(
                    dir_to_share):
                # it could have been deleted, try to recreate it if possible
                # TODO: org or something here?
                if result['owner'] == G.USERNAME:
                    try:
                        api.create_workspace({'name': workspace_name})
                        msg.debug('Created workspace %s' % workspace_url)
                    except Exception as e:
                        msg.debug('Tried to create workspace' + str(e))
                # they wanted to share teh dir, so always share it
                return join_workspace(
                    workspace_url,
                    lambda x: agent.protocol.create_buf(dir_to_share,
                                                        force=True))

    # link to what they want to share
    try:
        utils.mkdir(os.path.dirname(floo_workspace_dir))
        os.symlink(dir_to_share, floo_workspace_dir)
    except OSError as e:
        if e.errno != 17:
            raise
    except Exception as e:
        return msg.error("Couldn't create symlink from %s to %s: %s" %
                         (dir_to_share, floo_workspace_dir, str(e)))

    # make & join workspace
    create_workspace(workspace_name, floo_workspace_dir, dir_to_share)
    def run(self, workspace_url, agent_conn_kwargs=None, upload=None):
        agent_conn_kwargs = agent_conn_kwargs or {}
        self.upload = upload

        def get_workspace_window():
            workspace_window = None
            for w in sublime.windows():
                for f in w.folders():
                    if utils.unfuck_path(f) == utils.unfuck_path(G.PROJECT_PATH):
                        workspace_window = w
                        break
            return workspace_window

        def set_workspace_window(cb):
            workspace_window = get_workspace_window()
            if workspace_window is None:
                return utils.set_timeout(set_workspace_window, 50, cb)
            G.WORKSPACE_WINDOW = workspace_window
            cb()

        def open_workspace_window(cb):
            if PY2:
                open_workspace_window2(cb)
            else:
                open_workspace_window3(cb)

        def open_workspace_window2(cb):
            if sublime.platform() == 'linux':
                subl = open('/proc/self/cmdline').read().split(chr(0))[0]
            elif sublime.platform() == 'osx':
                floorc = utils.load_floorc_json()
                subl = floorc.get('SUBLIME_EXECUTABLE')
                if not subl:
                    settings = sublime.load_settings('Floobits.sublime-settings')
                    subl = settings.get('sublime_executable', '/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl')
                if not os.path.exists(subl):
                    return sublime.error_message('''Can't find your Sublime Text executable at %s.
Please add "sublime_executable": "/path/to/subl" to your ~/.floorc.json and restart Sublime Text''' % subl)
            elif sublime.platform() == 'windows':
                subl = sys.executable
            else:
                raise Exception('WHAT PLATFORM ARE WE ON?!?!?')

            command = [subl]
            if get_workspace_window() is None:
                command.append('--new-window')
            command.append('--add')
            command.append(G.PROJECT_PATH)

            msg.debug('command:', command)
            p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            poll_result = p.poll()
            msg.debug('poll:', poll_result)

            set_workspace_window(cb)

        def open_workspace_window3(cb):
            def finish(w):
                G.WORKSPACE_WINDOW = w
                msg.debug('Setting project data. Path: %s' % G.PROJECT_PATH)
                G.WORKSPACE_WINDOW.set_project_data({'folders': [{'path': G.PROJECT_PATH}]})
                cb()

            def get_empty_window():
                for w in sublime.windows():
                    project_data = w.project_data()
                    try:
                        folders = project_data.get('folders', [])
                        if len(folders) == 0 or not folders[0].get('path'):
                            # no project data. co-opt this window
                            return w
                    except Exception as e:
                        print(str_e(e))

            def wait_empty_window(i):
                if i > 10:
                    print('Too many failures trying to find an empty window. Using active window.')
                    return finish(sublime.active_window())
                w = get_empty_window()
                if w:
                    return finish(w)
                return utils.set_timeout(wait_empty_window, 50, i + 1)

            w = get_workspace_window() or get_empty_window()
            if w:
                return finish(w)

            sublime.run_command('new_window')
            wait_empty_window(0)

        def make_dir(d):
            d = os.path.realpath(os.path.expanduser(d))

            if not os.path.isdir(d):
                make_dir = sublime.ok_cancel_dialog('%s is not a directory. Create it?' % d)
                if not make_dir:
                    return self.window.show_input_panel('%s is not a directory. Enter an existing path:' % d, d, None, None, None)
                try:
                    utils.mkdir(d)
                except Exception as e:
                    return sublime.error_message('Could not create directory %s: %s' % (d, str_e(e)))
            G.PROJECT_PATH = d

            if self.upload:
                result['upload'] = d
            else:
                result['upload'] = ""

            utils.add_workspace_to_persistent_json(result['owner'], result['workspace'], workspace_url, d)
            open_workspace_window(lambda: run_agent(**result))

        @utils.inlined_callbacks
        def run_agent(owner, workspace, host, port, secure, upload):
            if G.AGENT:
                msg.debug('Stopping agent.')
                reactor.stop()
                G.AGENT = None
            try:
                auth = G.AUTH.get(host)
                if not auth:
                    success = yield link_account, host
                    if not success:
                        return
                    auth = G.AUTH.get(host)
                conn = SublimeConnection(owner, workspace, auth, upload)
                reactor.connect(conn, host, port, secure)
            except Exception as e:
                msg.error(str_e(e))

        try:
            result = utils.parse_url(workspace_url)
        except Exception as e:
            return sublime.error_message(str_e(e))

        utils.reload_settings()
        if not utils.can_auth():
            return create_or_link_account()

        d = utils.get_persistent_data()
        try:
            G.PROJECT_PATH = d['workspaces'][result['owner']][result['workspace']]['path']
        except Exception:
            msg.log('%s/%s not in persistent.json' % (result['owner'], result['workspace']))
            G.PROJECT_PATH = ''

        msg.log('Project path is %s' % G.PROJECT_PATH)

        if not os.path.isdir(G.PROJECT_PATH):
            default_dir = None
            for w in sublime.windows():
                if default_dir:
                    break
                for d in self.window.folders():
                    floo_file = os.path.join(d, '.floo')
                    try:
                        floo_info = open(floo_file, 'r').read()
                        wurl = json.loads(floo_info).get('url')
                        if wurl == workspace_url:
                            # TODO: check if workspace actually exists
                            default_dir = d
                            break
                    except Exception:
                        pass

            default_dir = default_dir or os.path.realpath(os.path.join(G.COLAB_DIR, result['owner'], result['workspace']))

            return self.window.show_input_panel('Save workspace in directory:', default_dir, make_dir, None, None)

        open_workspace_window(lambda: run_agent(upload=upload, **result))
Beispiel #20
0
    def share_dir(self, dir_to_share, perms=None):
        dir_to_share = os.path.expanduser(dir_to_share)
        dir_to_share = utils.unfuck_path(dir_to_share)
        workspace_name = os.path.basename(dir_to_share)
        G.PROJECT_PATH = os.path.realpath(dir_to_share)
        msg.debug('%s %s %s' % (G.USERNAME, workspace_name, G.PROJECT_PATH))

        if os.path.isfile(dir_to_share):
            return msg.error('%s is a file. Give me a directory please.' % dir_to_share)

        try:
            utils.mkdir(dir_to_share)
        except Exception:
            return msg.error("The directory %s doesn't exist and I can't make it." % dir_to_share)

        floo_file = os.path.join(dir_to_share, '.floo')

        info = {}
        try:
            floo_info = open(floo_file, 'rb').read().decode('utf-8')
            info = json.loads(floo_info)
        except (IOError, OSError):
            pass
        except Exception:
            msg.debug("Couldn't read the floo_info file: %s" % floo_file)

        workspace_url = info.get('url')
        if workspace_url:
            try:
                result = utils.parse_url(workspace_url)
            except Exception as e:
                msg.error(str(e))
            else:
                workspace_name = result['workspace']
                try:
                    # TODO: blocking. beachballs sublime 2 if API is super slow
                    api.get_workspace_by_url(workspace_url)
                except HTTPError:
                    workspace_url = None
                    workspace_name = os.path.basename(dir_to_share)
                else:
                    utils.add_workspace_to_persistent_json(result['owner'], result['workspace'], workspace_url, dir_to_share)

        workspace_url = utils.get_workspace_by_path(dir_to_share) or workspace_url

        if workspace_url:
            try:
                api.get_workspace_by_url(workspace_url)
            except HTTPError:
                pass
            else:
                return self.remote_connect(workspace_url, lambda this: this.protocol.create_buf(dir_to_share))

        def on_done(data, choices=None):
            self.create_workspace({}, workspace_name, dir_to_share, owner=data.get('response'), perms=perms)

        orgs = api.get_orgs_can_admin()
        orgs = json.loads(orgs.read().decode('utf-8'))
        if len(orgs) == 0:
            return on_done({'response': G.USERNAME})
        i = 0
        choices = []
        choices.append([G.USERNAME, i])
        for o in orgs:
            i += 1
            choices.append([o['name'], i])

        self.get_input('Create workspace for [press tab for completion]: ', '', on_done, choices=choices)
    def run(self, workspace_url, agent_conn_kwargs=None):
        agent_conn_kwargs = agent_conn_kwargs or {}

        def get_workspace_window():
            workspace_window = None
            for w in sublime.windows():
                for f in w.folders():
                    if f == G.PROJECT_PATH:
                        workspace_window = w
                        break
            return workspace_window

        def set_workspace_window(cb):
            workspace_window = get_workspace_window()
            if workspace_window is None:
                return utils.set_timeout(set_workspace_window, 50, cb)
            G.WORKSPACE_WINDOW = workspace_window
            cb()

        def truncate_chat_view(chat_view, cb):
            if chat_view:
                chat_view.set_read_only(False)
                chat_view.run_command('floo_view_replace_region', {'r': [0, chat_view.size()], 'data': ''})
                chat_view.set_read_only(True)
            cb()

        def create_chat_view(cb):
            with open(os.path.join(G.BASE_DIR, 'msgs.floobits.log'), 'a') as msgs_fd:
                msgs_fd.write('')
            get_or_create_chat(lambda chat_view: truncate_chat_view(chat_view, cb))

        def open_workspace_window2(cb):
            if sublime.platform() == 'linux':
                subl = open('/proc/self/cmdline').read().split(chr(0))[0]
            elif sublime.platform() == 'osx':
                # TODO: totally explodes if you install ST2 somewhere else
                settings = sublime.load_settings('Floobits.sublime-settings')
                subl = settings.get('sublime_executable', '/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl')
                if not os.path.exists(subl):
                    return sublime.error_message('Can\'t find your Sublime Text executable at %s. Please add "sublime_executable /path/to/subl" to your ~/.floorc and restart Sublime Text' % subl)
            elif sublime.platform() == 'windows':
                subl = sys.executable
            else:
                raise Exception('WHAT PLATFORM ARE WE ON?!?!?')

            command = [subl]
            if get_workspace_window() is None:
                command.append('--new-window')
            command.append('--add')
            command.append(G.PROJECT_PATH)

            # Maybe no msg view yet :(
            print('command:', command)
            p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            poll_result = p.poll()
            print('poll:', poll_result)

            set_workspace_window(lambda: create_chat_view(cb))

        def open_workspace_window3(cb):
            G.WORKSPACE_WINDOW = get_workspace_window()
            if not G.WORKSPACE_WINDOW:
                G.WORKSPACE_WINDOW = sublime.active_window()
            msg.debug('Setting project data. Path: %s' % G.PROJECT_PATH)
            G.WORKSPACE_WINDOW.set_project_data({'folders': [{'path': G.PROJECT_PATH}]})
            create_chat_view(cb)

        def open_workspace_window(cb):
            if PY2:
                open_workspace_window2(cb)
            else:
                open_workspace_window3(cb)

        def run_agent(owner, workspace, host, port, secure):
            global on_room_info_waterfall
            if G.AGENT:
                msg.debug('Stopping agent.')
                G.AGENT.stop()
                G.AGENT = None

            on_room_info_waterfall.add(update_recent_workspaces, {'url': workspace_url})

            try:
                msg.debug("agent_conn_kwargs: %s" % str(agent_conn_kwargs))
                G.AGENT = AgentConnection(owner=owner, workspace=workspace, host=host, port=port, secure=secure,
                                          on_room_info=on_room_info_waterfall.call, **agent_conn_kwargs)
                on_room_info_waterfall = utils.Waterfall()
                Listener.reset()
                G.AGENT.connect()
            except Exception as e:
                print(e)
                tb = traceback.format_exc()
                print(tb)

        def make_dir(d):
            d = os.path.realpath(os.path.expanduser(d))

            if not os.path.isdir(d):
                make_dir = sublime.ok_cancel_dialog('%s is not a directory. Create it?' % d)
                if not make_dir:
                    return self.window.show_input_panel('%s is not a directory. Enter an existing path:' % d, d, None, None, None)
                try:
                    utils.mkdir(d)
                except Exception as e:
                    return sublime.error_message('Could not create directory %s: %s' % (d, str(e)))

            G.PROJECT_PATH = d
            add_workspace_to_persistent_json(result['owner'], result['workspace'], workspace_url, d)
            open_workspace_window(lambda: run_agent(**result))

        try:
            result = utils.parse_url(workspace_url)
        except Exception as e:
            return sublime.error_message(str(e))

        utils.reload_settings()
        if not (G.USERNAME and G.SECRET):
            return create_or_link_account()

        d = utils.get_persistent_data()
        try:
            G.PROJECT_PATH = d['workspaces'][result['owner']][result['workspace']]['path']
        except Exception as e:
            G.PROJECT_PATH = ''

        print('Project path is %s' % G.PROJECT_PATH)

        if not os.path.isdir(G.PROJECT_PATH):
            default_dir = os.path.realpath(os.path.join(G.COLAB_DIR, result['owner'], result['workspace']))
            return self.window.show_input_panel('Save workspace in directory:', default_dir, make_dir, None, None)

        open_workspace_window(lambda: run_agent(**result))
Beispiel #22
0
    def on_input(self, dir_to_share):
        file_to_share = None
        dir_to_share = os.path.expanduser(dir_to_share)
        dir_to_share = os.path.realpath(utils.unfuck_path(dir_to_share))
        workspace_name = os.path.basename(dir_to_share)
        workspace_url = None
        print(G.COLAB_DIR, G.USERNAME, workspace_name)

        def find_workspace(workspace_url):
            try:
                api.get_workspace_by_url(workspace_url)
            except HTTPError:
                try:
                    result = utils.parse_url(workspace_url)
                    d = utils.get_persistent_data()
                    del d['workspaces'][result['owner']][result['name']]
                    utils.update_persistent_data(d)
                except Exception as e:
                    msg.debug(unicode(e))
                return False
            on_room_info_waterfall.add(on_room_info_msg)
            on_room_info_waterfall.add(ignore.create_flooignore, dir_to_share)
            on_room_info_waterfall.add(Listener.create_buf, dir_to_share)
            return True

        if os.path.isfile(dir_to_share):
            file_to_share = dir_to_share
            dir_to_share = os.path.dirname(dir_to_share)
        else:
            try:
                utils.mkdir(dir_to_share)
            except Exception:
                return sublime.error_message(
                    'The directory %s doesn\'t exist and I can\'t make it.' %
                    dir_to_share)

            floo_file = os.path.join(dir_to_share, '.floo')

            info = {}
            try:
                floo_info = open(floo_file, 'rb').read().decode('utf-8')
                info = json.loads(floo_info)
            except (IOError, OSError):
                pass
            except Exception:
                print('Couldn\'t read the floo_info file: %s' % floo_file)

            workspace_url = info.get('url')
            try:
                result = utils.parse_url(workspace_url)
            except Exception:
                workspace_url = None
            if workspace_url and find_workspace(workspace_url):
                add_workspace_to_persistent_json(result['owner'],
                                                 result['workspace'],
                                                 workspace_url, dir_to_share)
                return self.window.run_command(
                    'floobits_join_workspace', {
                        'workspace_url': workspace_url,
                        'agent_conn_kwargs': {
                            'get_bufs': False
                        }
                    })

        for owner, workspaces in utils.get_persistent_data(
        )['workspaces'].items():
            for name, workspace in workspaces.items():
                if workspace['path'] == dir_to_share:
                    workspace_url = workspace['url']
                    if find_workspace(workspace_url):
                        return self.window.run_command(
                            'floobits_join_workspace', {
                                'workspace_url': workspace_url,
                                'agent_conn_kwargs': {
                                    'get_bufs': False
                                }
                            })

        # make & join workspace
        on_room_info_waterfall.add(ignore.create_flooignore, dir_to_share)
        on_room_info_waterfall.add(Listener.create_buf, file_to_share
                                   or dir_to_share)

        def on_done(owner):
            self.window.run_command(
                'floobits_create_workspace', {
                    'workspace_name': workspace_name,
                    'dir_to_share': dir_to_share,
                    'api_args': self.api_args,
                    'owner': owner[0],
                })

        orgs = api.get_orgs_can_admin()
        orgs = json.loads(orgs.read().decode('utf-8'))
        if len(orgs) == 0:
            return on_done([G.USERNAME])

        orgs = [[org['name'],
                 'Create workspace under %s' % org['name']] for org in orgs]
        orgs.insert(0, [G.USERNAME, 'Create workspace under %s' % G.USERNAME])
        self.window.show_quick_panel(
            orgs, lambda index: index < 0 or on_done(orgs[index]))
    def on_input(self, dir_to_share):
        file_to_share = None
        dir_to_share = os.path.expanduser(dir_to_share)
        dir_to_share = os.path.realpath(utils.unfuck_path(dir_to_share))
        workspace_name = os.path.basename(dir_to_share)
        workspace_url = None
        print(G.COLAB_DIR, G.USERNAME, workspace_name)

        def find_workspace(workspace_url):
            try:
                api.get_workspace_by_url(workspace_url)
            except HTTPError:
                try:
                    result = utils.parse_url(workspace_url)
                    d = utils.get_persistent_data()
                    del d['workspaces'][result['owner']][result['name']]
                    utils.update_persistent_data(d)
                except Exception as e:
                    msg.debug(unicode(e))
                return False
            on_room_info_waterfall.add(on_room_info_msg)
            on_room_info_waterfall.add(ignore.create_flooignore, dir_to_share)
            on_room_info_waterfall.add(Listener.create_buf, dir_to_share)
            return True

        if os.path.isfile(dir_to_share):
            file_to_share = dir_to_share
            dir_to_share = os.path.dirname(dir_to_share)
        else:
            try:
                utils.mkdir(dir_to_share)
            except Exception:
                return sublime.error_message('The directory %s doesn\'t exist and I can\'t make it.' % dir_to_share)

            floo_file = os.path.join(dir_to_share, '.floo')

            info = {}
            try:
                floo_info = open(floo_file, 'rb').read().decode('utf-8')
                info = json.loads(floo_info)
            except (IOError, OSError):
                pass
            except Exception:
                print('Couldn\'t read the floo_info file: %s' % floo_file)

            workspace_url = info.get('url')
            try:
                result = utils.parse_url(workspace_url)
            except Exception:
                workspace_url = None
            if workspace_url and find_workspace(workspace_url):
                add_workspace_to_persistent_json(result['owner'], result['workspace'], workspace_url, dir_to_share)
                return self.window.run_command('floobits_join_workspace', {
                    'workspace_url': workspace_url,
                    'agent_conn_kwargs': {'get_bufs': False}})

        for owner, workspaces in utils.get_persistent_data()['workspaces'].items():
            for name, workspace in workspaces.items():
                if workspace['path'] == dir_to_share:
                    workspace_url = workspace['url']
                    if find_workspace(workspace_url):
                        return self.window.run_command('floobits_join_workspace', {
                            'workspace_url': workspace_url,
                            'agent_conn_kwargs': {'get_bufs': False}})

        # make & join workspace
        on_room_info_waterfall.add(ignore.create_flooignore, dir_to_share)
        on_room_info_waterfall.add(Listener.create_buf, file_to_share or dir_to_share)

        def on_done(owner):
            self.window.run_command('floobits_create_workspace', {
                'workspace_name': workspace_name,
                'dir_to_share': dir_to_share,
                'api_args': self.api_args,
                'owner': owner[0],
            })

        orgs = api.get_orgs_can_admin()
        orgs = json.loads(orgs.read().decode('utf-8'))
        if len(orgs) == 0:
            return on_done([G.USERNAME])

        orgs = [[org['name'], 'Create workspace under %s' % org['name']] for org in orgs]
        orgs.insert(0, [G.USERNAME, 'Create workspace under %s' % G.USERNAME])
        self.window.show_quick_panel(orgs, lambda index: index < 0 or on_done(orgs[index]))
    def run(self, workspace_url, agent_conn_kwargs=None):
        agent_conn_kwargs = agent_conn_kwargs or {}

        def get_workspace_window():
            workspace_window = None
            for w in sublime.windows():
                for f in w.folders():
                    if utils.unfuck_path(f) == utils.unfuck_path(G.PROJECT_PATH):
                        workspace_window = w
                        break
            return workspace_window

        def set_workspace_window(cb):
            workspace_window = get_workspace_window()
            if workspace_window is None:
                return utils.set_timeout(set_workspace_window, 50, cb)
            G.WORKSPACE_WINDOW = workspace_window
            cb()

        def open_workspace_window(cb):
            if PY2:
                open_workspace_window2(cb)
            else:
                open_workspace_window3(cb)

        def open_workspace_window2(cb):
            if sublime.platform() == 'linux':
                subl = open('/proc/self/cmdline').read().split(chr(0))[0]
            elif sublime.platform() == 'osx':
                # TODO: totally explodes if you install ST2 somewhere else
                settings = sublime.load_settings('Floobits.sublime-settings')
                subl = settings.get('sublime_executable', '/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl')
                if not os.path.exists(subl):
                    return sublime.error_message('''Can't find your Sublime Text executable at %s.
Please add "sublime_executable /path/to/subl" to your ~/.floorc and restart Sublime Text''' % subl)
            elif sublime.platform() == 'windows':
                subl = sys.executable
            else:
                raise Exception('WHAT PLATFORM ARE WE ON?!?!?')

            command = [subl]
            if get_workspace_window() is None:
                command.append('--new-window')
            command.append('--add')
            command.append(G.PROJECT_PATH)

            msg.debug('command:', command)
            p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            poll_result = p.poll()
            msg.debug('poll:', poll_result)

            set_workspace_window(cb)

        def open_workspace_window3(cb):
            def finish(w):
                G.WORKSPACE_WINDOW = w
                msg.debug('Setting project data. Path: %s' % G.PROJECT_PATH)
                G.WORKSPACE_WINDOW.set_project_data({'folders': [{'path': G.PROJECT_PATH}]})
                cb()

            def get_empty_window():
                for w in sublime.windows():
                    project_data = w.project_data()
                    try:
                        folders = project_data.get('folders', [])
                        if len(folders) == 0 or not folders[0].get('path'):
                            # no project data. co-opt this window
                            return w
                    except Exception as e:
                        print(e)

            def wait_empty_window(i):
                if i > 10:
                    print('Too many failures trying to find an empty window. Using active window.')
                    return finish(sublime.active_window())
                w = get_empty_window()
                if w:
                    return finish(w)
                return utils.set_timeout(wait_empty_window, 50, i + 1)

            w = get_workspace_window() or get_empty_window()
            if w:
                return finish(w)

            sublime.run_command('new_window')
            wait_empty_window(0)

        def make_dir(d):
            d = os.path.realpath(os.path.expanduser(d))

            if not os.path.isdir(d):
                make_dir = sublime.ok_cancel_dialog('%s is not a directory. Create it?' % d)
                if not make_dir:
                    return self.window.show_input_panel('%s is not a directory. Enter an existing path:' % d, d, None, None, None)
                try:
                    utils.mkdir(d)
                except Exception as e:
                    return sublime.error_message('Could not create directory %s: %s' % (d, str(e)))

            G.PROJECT_PATH = d
            utils.add_workspace_to_persistent_json(result['owner'], result['workspace'], workspace_url, d)
            open_workspace_window(lambda: run_agent(**result))

        def run_agent(owner, workspace, host, port, secure):
            global on_room_info_waterfall
            if G.AGENT:
                msg.debug('Stopping agent.')
                reactor.stop()
                G.AGENT = None
            on_room_info_waterfall.add(update_recent_workspaces, {'url': workspace_url})
            try:
                conn = SublimeConnection(owner, workspace, agent_conn_kwargs.get('get_bufs', True))
                reactor.connect(conn, host, port, secure)
                conn.once('room_info', on_room_info_waterfall.call)
                on_room_info_waterfall = utils.Waterfall()
            except Exception as e:
                print(e)
                tb = traceback.format_exc()
                print(tb)

        try:
            result = utils.parse_url(workspace_url)
        except Exception as e:
            return sublime.error_message(str(e))

        utils.reload_settings()
        if not (G.USERNAME and G.SECRET):
            return create_or_link_account()

        d = utils.get_persistent_data()
        try:
            G.PROJECT_PATH = d['workspaces'][result['owner']][result['workspace']]['path']
        except Exception as e:
            G.PROJECT_PATH = ''

        print('Project path is %s' % G.PROJECT_PATH)

        if not os.path.isdir(G.PROJECT_PATH):
            default_dir = os.path.realpath(os.path.join(G.COLAB_DIR, result['owner'], result['workspace']))
            return self.window.show_input_panel('Save workspace in directory:', default_dir, make_dir, None, None)

        open_workspace_window(lambda: run_agent(**result))
Beispiel #25
0
    def on_input(self, dir_to_share):
        file_to_share = None
        dir_to_share = os.path.expanduser(dir_to_share)
        dir_to_share = os.path.realpath(utils.unfuck_path(dir_to_share))
        workspace_name = os.path.basename(dir_to_share)
        workspace_url = None

        # TODO: use prejoin_workspace instead
        def find_workspace(workspace_url):
            r = api.get_workspace_by_url(workspace_url)
            if r.code < 400:
                return r
            try:
                result = utils.parse_url(workspace_url)
                d = utils.get_persistent_data()
                del d['workspaces'][result['owner']][result['name']]
                utils.update_persistent_data(d)
            except Exception as e:
                msg.debug(str_e(e))

        def join_workspace(workspace_url):
            try:
                w = find_workspace(workspace_url)
            except Exception as e:
                sublime.error_message('Error: %s' % str_e(e))
                return False
            if not w:
                return False
            msg.debug('workspace: %s', json.dumps(w.body))
            # if self.api_args:
            anon_perms = w.body.get('perms', {}).get('AnonymousUser', [])
            new_anon_perms = self.api_args.get('perms').get(
                'AnonymousUser', [])
            # TODO: warn user about making a private workspace public
            if set(anon_perms) != set(new_anon_perms):
                msg.debug(str(anon_perms), str(new_anon_perms))
                w.body['perms']['AnonymousUser'] = new_anon_perms
                response = api.update_workspace(workspace_url, w.body)
                msg.debug(str(response.body))
            utils.add_workspace_to_persistent_json(w.body['owner'],
                                                   w.body['name'],
                                                   workspace_url, dir_to_share)
            self.window.run_command('floobits_join_workspace',
                                    {'workspace_url': workspace_url})
            return True

        if os.path.isfile(dir_to_share):
            file_to_share = dir_to_share
            dir_to_share = os.path.dirname(dir_to_share)

        try:
            utils.mkdir(dir_to_share)
        except Exception:
            sublime.error_message(
                'The directory %s doesn\'t exist and I can\'t create it.' %
                dir_to_share)
            return

        floo_file = os.path.join(dir_to_share, '.floo')

        info = {}
        try:
            floo_info = open(floo_file, 'r').read()
            info = json.loads(floo_info)
        except (IOError, OSError):
            pass
        except Exception:
            msg.error('Couldn\'t read the floo_info file: %s' % floo_file)

        workspace_url = info.get('url')
        try:
            utils.parse_url(workspace_url)
        except Exception:
            workspace_url = None

        if workspace_url and join_workspace(workspace_url):
            return

        for owner, workspaces in utils.get_persistent_data(
        )['workspaces'].items():
            for name, workspace in workspaces.items():
                if workspace['path'] == dir_to_share:
                    workspace_url = workspace['url']
                    if join_workspace(workspace_url):
                        return

        auth = yield editor.select_auth, self.window, G.AUTH
        if not auth:
            return

        username = auth.get('username')
        host = auth['host']

        def on_done(owner):
            msg.log('Colab dir: %s, Username: %s, Workspace: %s/%s' %
                    (G.COLAB_DIR, username, owner[0], workspace_name))
            self.window.run_command(
                'floobits_create_workspace', {
                    'workspace_name': workspace_name,
                    'dir_to_share': dir_to_share,
                    'upload': file_to_share or dir_to_share,
                    'api_args': self.api_args,
                    'owner': owner[0],
                    'host': host,
                })

        try:
            r = api.get_orgs_can_admin(host)
        except IOError as e:
            sublime.error_message('Error getting org list: %s' % str_e(e))
            return

        if r.code >= 400 or len(r.body) == 0:
            on_done([username])
            return

        orgs = [[org['name'],
                 'Create workspace owned by %s' % org['name']]
                for org in r.body]
        orgs.insert(0, [username, 'Create workspace owned by %s' % username])
        self.window.show_quick_panel(
            orgs, lambda index: index < 0 or on_done(orgs[index]))
Beispiel #26
0
    def run(self, workspace_url, agent_conn_kwargs=None):
        agent_conn_kwargs = agent_conn_kwargs or {}

        def get_workspace_window():
            workspace_window = None
            for w in sublime.windows():
                for f in w.folders():
                    if f == G.PROJECT_PATH:
                        workspace_window = w
                        break
            return workspace_window

        def set_workspace_window(cb):
            workspace_window = get_workspace_window()
            if workspace_window is None:
                return utils.set_timeout(set_workspace_window, 50, cb)
            G.WORKSPACE_WINDOW = workspace_window
            cb()

        def truncate_chat_view(chat_view, cb):
            if chat_view:
                chat_view.set_read_only(False)
                chat_view.run_command('floo_view_replace_region', {
                    'r': [0, chat_view.size()],
                    'data': ''
                })
                chat_view.set_read_only(True)
            cb()

        def create_chat_view(cb):
            with open(os.path.join(G.BASE_DIR, 'msgs.floobits.log'),
                      'a') as msgs_fd:
                msgs_fd.write('')
            get_or_create_chat(
                lambda chat_view: truncate_chat_view(chat_view, cb))

        def open_workspace_window2(cb):
            if sublime.platform() == 'linux':
                subl = open('/proc/self/cmdline').read().split(chr(0))[0]
            elif sublime.platform() == 'osx':
                # TODO: totally explodes if you install ST2 somewhere else
                settings = sublime.load_settings('Floobits.sublime-settings')
                subl = settings.get(
                    'sublime_executable',
                    '/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl'
                )
                if not os.path.exists(subl):
                    return sublime.error_message(
                        'Can\'t find your Sublime Text executable at %s. Please add "sublime_executable /path/to/subl" to your ~/.floorc and restart Sublime Text'
                        % subl)
            elif sublime.platform() == 'windows':
                subl = sys.executable
            else:
                raise Exception('WHAT PLATFORM ARE WE ON?!?!?')

            command = [subl]
            if get_workspace_window() is None:
                command.append('--new-window')
            command.append('--add')
            command.append(G.PROJECT_PATH)

            # Maybe no msg view yet :(
            print('command:', command)
            p = subprocess.Popen(command,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
            poll_result = p.poll()
            print('poll:', poll_result)

            set_workspace_window(lambda: create_chat_view(cb))

        def open_workspace_window3(cb):
            G.WORKSPACE_WINDOW = get_workspace_window()
            if not G.WORKSPACE_WINDOW:
                G.WORKSPACE_WINDOW = sublime.active_window()
            msg.debug('Setting project data. Path: %s' % G.PROJECT_PATH)
            G.WORKSPACE_WINDOW.set_project_data(
                {'folders': [{
                    'path': G.PROJECT_PATH
                }]})
            create_chat_view(cb)

        def open_workspace_window(cb):
            if PY2:
                open_workspace_window2(cb)
            else:
                open_workspace_window3(cb)

        def run_agent(owner, workspace, host, port, secure):
            global on_room_info_waterfall
            if G.AGENT:
                msg.debug('Stopping agent.')
                G.AGENT.stop()
                G.AGENT = None

            on_room_info_waterfall.add(update_recent_workspaces,
                                       {'url': workspace_url})

            try:
                msg.debug("agent_conn_kwargs: %s" % str(agent_conn_kwargs))
                G.AGENT = AgentConnection(
                    owner=owner,
                    workspace=workspace,
                    host=host,
                    port=port,
                    secure=secure,
                    on_room_info=on_room_info_waterfall.call,
                    **agent_conn_kwargs)
                on_room_info_waterfall = utils.Waterfall()
                Listener.reset()
                G.AGENT.connect()
            except Exception as e:
                print(e)
                tb = traceback.format_exc()
                print(tb)

        def make_dir(d):
            d = os.path.realpath(os.path.expanduser(d))

            if not os.path.isdir(d):
                make_dir = sublime.ok_cancel_dialog(
                    '%s is not a directory. Create it?' % d)
                if not make_dir:
                    return self.window.show_input_panel(
                        '%s is not a directory. Enter an existing path:' % d,
                        d, None, None, None)
                try:
                    utils.mkdir(d)
                except Exception as e:
                    return sublime.error_message(
                        'Could not create directory %s: %s' % (d, str(e)))

            G.PROJECT_PATH = d
            add_workspace_to_persistent_json(result['owner'],
                                             result['workspace'],
                                             workspace_url, d)
            open_workspace_window(lambda: run_agent(**result))

        try:
            result = utils.parse_url(workspace_url)
        except Exception as e:
            return sublime.error_message(str(e))

        utils.reload_settings()
        if not (G.USERNAME and G.SECRET):
            return create_or_link_account()

        d = utils.get_persistent_data()
        try:
            G.PROJECT_PATH = d['workspaces'][result['owner']][
                result['workspace']]['path']
        except Exception as e:
            G.PROJECT_PATH = ''

        print('Project path is %s' % G.PROJECT_PATH)

        if not os.path.isdir(G.PROJECT_PATH):
            default_dir = os.path.realpath(
                os.path.join(G.COLAB_DIR, result['owner'],
                             result['workspace']))
            return self.window.show_input_panel('Save workspace in directory:',
                                                default_dir, make_dir, None,
                                                None)

        open_workspace_window(lambda: run_agent(**result))
    def on_input(self, dir_to_share):
        file_to_share = None
        dir_to_share = os.path.expanduser(dir_to_share)
        dir_to_share = os.path.realpath(utils.unfuck_path(dir_to_share))
        workspace_name = os.path.basename(dir_to_share)
        workspace_url = None
        print(G.COLAB_DIR, G.USERNAME, workspace_name)

        def find_workspace(workspace_url):
            r = api.get_workspace_by_url(workspace_url)
            if r.code < 400:
                on_room_info_waterfall.add(ignore.create_flooignore, dir_to_share)
                on_room_info_waterfall.add(lambda: G.AGENT.upload(dir_to_share, on_room_info_msg))
                return r
            try:
                result = utils.parse_url(workspace_url)
                d = utils.get_persistent_data()
                del d['workspaces'][result['owner']][result['name']]
                utils.update_persistent_data(d)
            except Exception as e:
                msg.debug(unicode(e))
            return

        def join_workspace(workspace_url):
            try:
                w = find_workspace(workspace_url)
            except Exception as e:
                sublime.error_message('Error: %s' % str(e))
                return False
            if not w:
                return False
            msg.debug('workspace: %s', json.dumps(w.body))
            # if self.api_args:
            anon_perms = w.body.get('perms', {}).get('AnonymousUser', [])
            new_anon_perms = self.api_args.get('perms').get('AnonymousUser', [])
            if set(anon_perms) != set(new_anon_perms):
                msg.debug(str(anon_perms), str(new_anon_perms))
                w.body['perms']['AnonymousUser'] = new_anon_perms
                response = api.update_workspace(w.body['owner'], w.body['name'], w.body)
                msg.debug(str(response.body))
            utils.add_workspace_to_persistent_json(w.body['owner'], w.body['name'], workspace_url, dir_to_share)
            self.window.run_command('floobits_join_workspace', {
                'workspace_url': workspace_url,
                'agent_conn_kwargs': {'get_bufs': False}})
            return True

        if os.path.isfile(dir_to_share):
            file_to_share = dir_to_share
            dir_to_share = os.path.dirname(dir_to_share)

        try:
            utils.mkdir(dir_to_share)
        except Exception:
            return sublime.error_message('The directory %s doesn\'t exist and I can\'t make it.' % dir_to_share)

        floo_file = os.path.join(dir_to_share, '.floo')

        info = {}
        try:
            floo_info = open(floo_file, 'r').read()
            info = json.loads(floo_info)
        except (IOError, OSError):
            pass
        except Exception:
            msg.error('Couldn\'t read the floo_info file: %s' % floo_file)

        workspace_url = info.get('url')
        try:
            utils.parse_url(workspace_url)
        except Exception:
            workspace_url = None

        if workspace_url and join_workspace(workspace_url):
            return

        for owner, workspaces in utils.get_persistent_data()['workspaces'].items():
            for name, workspace in workspaces.items():
                if workspace['path'] == dir_to_share:
                    workspace_url = workspace['url']
                    if join_workspace(workspace_url):
                        return

        # make & join workspace
        on_room_info_waterfall.add(ignore.create_flooignore, dir_to_share)
        on_room_info_waterfall.add(lambda: G.AGENT.upload(file_to_share or dir_to_share, on_room_info_msg))

        def on_done(owner):
            self.window.run_command('floobits_create_workspace', {
                'workspace_name': workspace_name,
                'dir_to_share': dir_to_share,
                'api_args': self.api_args,
                'owner': owner[0],
            })

        try:
            r = api.get_orgs_can_admin()
        except IOError as e:
            return sublime.error_message('Error getting org list: %s' % str(e))

        if r.code >= 400 or len(r.body) == 0:
            return on_done([G.USERNAME])

        orgs = [[org['name'], 'Create workspace under %s' % org['name']] for org in r.body]
        orgs.insert(0, [G.USERNAME, 'Create workspace under %s' % G.USERNAME])
        self.window.show_quick_panel(orgs, lambda index: index < 0 or on_done(orgs[index]))
Beispiel #28
0
def main():
    if not os.path.exists(G.FLOORC_JSON_PATH):
        migrations.migrate_floorc()
    utils.reload_settings()
    default_auth = G.AUTH.get(G.DEFAULT_HOST, {})
    parser = optparse.OptionParser(usage=usage)

    parser.add_option("-u", "--username",
                      dest="username",
                      default=default_auth.get('username'),
                      help="Your Floobits username")

    parser.add_option("-s", "--secret",
                      dest="secret",
                      default=default_auth.get('secret'),
                      help="Your Floobits secret (api key)")

    parser.add_option("-c", "--create",
                      dest="create",
                      default=False,
                      action="store_true",
                      help="The terminal name to create")

    parser.add_option("--host",
                      dest="host",
                      default=G.DEFAULT_HOST,
                      help="The host to connect to. Deprecated. Use --url instead.")

    parser.add_option("-p", "--port",
                      dest="port",
                      default=G.DEFAULT_PORT,
                      help="The port to connect to. Deprecated. Use --url instead.")

    parser.add_option("-w", "--workspace",
                      dest="workspace",
                      help="The workspace name. --owner is required with this option. Deprecated. Use --url instead.")

    parser.add_option("-o", "--owner",
                      dest="owner",
                      help="The workspace owner. --workspace is required with this option. Deprecated. Use --url instead.")

    parser.add_option("-l", "--list",
                      dest="list",
                      default=False,
                      action="store_true",
                      help="List all terminals in the workspace")

    parser.add_option("--unsafe",
                      dest="safe",
                      default=True,
                      action="store_false",
                      help="Less safe terminal. This allows other users to send enter in your terminal.")

    parser.add_option("--no-ssl",
                      dest="use_ssl",
                      default=True,
                      action="store_false",
                      help="Do not use this option unless you know what you are doing!")

    parser.add_option("--url",
                      dest="workspace_url",
                      default=None,
                      help="The URL of the workspace to connect to.")

    parser.add_option("--resize",
                      dest="resize",
                      default=False,
                      action="store_true",
                      help="Resize your terminal to the host terminal size.")

    parser.add_option("-P", "--preserve-ps1",
                      dest="set_prompt",
                      default=True,
                      action="store_false",
                      help="Don't change $PS1 (bash/zsh prompt)")

    parser.add_option("-v", "--version",
                      dest="version",
                      default=False,
                      action="store_true",
                      help="Print version")

    options, args = parser.parse_args()

    if options.version:
        print('flootty %s' % version.FLOOTTY_VERSION)
        return

    default_term_name = ""
    if options.create:
        default_term_name = "ftty"

    term_name = args and args[0] or default_term_name

    if options.workspace and options.owner and options.workspace_url:
        # TODO: confusing
        parser.error("You can either specify --workspace and --owner, or --url, but not both.")

    if bool(options.workspace) != bool(options.owner):
        parser.error("You must specify a workspace and owner or neither.")

    for opt in ['owner', 'workspace']:
        if getattr(options, opt):
            print('%s is deprecated. Please use --url instead.' % opt)

    if not options.workspace or not options.owner:
        floo = {}
        if options.workspace_url:
            floo = utils.parse_url(options.workspace_url)
        else:
            for floo_path in walk_up(os.path.realpath('.')):
                try:
                    floo = json.loads(open(os.path.join(floo_path, '.floo'), 'rb').read().decode('utf-8'))
                    floo = utils.parse_url(floo['url'])
                except Exception:
                    pass
                else:
                    break
        options.host = floo.get('host')
        options.workspace = floo.get('workspace')
        options.owner = floo.get('owner')
        options.use_ssl = floo.get('secure')
        if not options.port:
            options.port = floo.get('port')
        if not options.host:
            options.host = floo.get('host')

    if options.host is None:
        options.host = G.DEFAULT_HOST

    if options.host != G.DEFAULT_HOST and options.secret == default_auth.get('secret'):
        auth = G.AUTH.get(options.host)
        if not auth:
            return die("Please add credentials for %s in ~/.floorc.json" % options.host)
        options.username = auth.get('username')
        options.secret = auth.get('secret')

    if not options.workspace or not options.owner:
        try:
            now_editing = get_now_editing_workspaces()
        except Exception as e:
            print(str_e(e))
        else:
            if len(now_editing.body) == 1:
                options.workspace = now_editing.body[0]['name']
                options.owner = now_editing.body[0]['owner']
        # TODO: list possible workspaces to join if > 1 is active

    if options.list:
        if len(term_name) != 0:
            die("I don't understand why you gave me a positional argument.")

    for opt in ['workspace', 'owner', 'username', 'secret']:
        if not getattr(options, opt):
            parser.error('%s not given' % opt)

    color_reset = '\033[0m'
    if options.safe:
        green = '\033[92m'
        print('%sTerminal is safe. Other users will not be able to send [enter]%s' % (green, color_reset))
    else:
        yellorange = '\033[93m'
        print('%sTerminal is unsafe. Other users will be able to send [enter]. Be wary!%s' % (yellorange, color_reset))

    f = Flootty(options, term_name)
    G.AGENT = f
    atexit.register(f.cleanup)
    f.connect_to_internet()
    f.select()
Beispiel #29
0
def main():
    utils.reload_settings()
    default_auth = G.AUTH.get(G.DEFAULT_HOST, {})
    parser = optparse.OptionParser(usage=usage)

    parser.add_option("-u",
                      "--username",
                      dest="username",
                      default=default_auth.get('username'),
                      help="Your Floobits username")

    parser.add_option("-s",
                      "--secret",
                      dest="secret",
                      default=default_auth.get('secret'),
                      help="Your Floobits secret (api key)")

    parser.add_option("-c",
                      "--create",
                      dest="create",
                      default=False,
                      action="store_true",
                      help="The terminal name to create")

    parser.add_option(
        "--host",
        dest="host",
        default=G.DEFAULT_HOST,
        help="The host to connect to. Deprecated. Use --url instead.")

    parser.add_option(
        "-p",
        "--port",
        dest="port",
        default=G.DEFAULT_PORT,
        help="The port to connect to. Deprecated. Use --url instead.")

    parser.add_option(
        "-w",
        "--workspace",
        dest="workspace",
        help=
        "The workspace name. --owner is required with this option. Deprecated. Use --url instead."
    )

    parser.add_option(
        "-o",
        "--owner",
        dest="owner",
        help=
        "The workspace owner. --workspace is required with this option. Deprecated. Use --url instead."
    )

    parser.add_option("-l",
                      "--list",
                      dest="list",
                      default=False,
                      action="store_true",
                      help="List all terminals in the workspace")

    parser.add_option(
        "--unsafe",
        dest="safe",
        default=True,
        action="store_false",
        help=
        "Less safe terminal. This allows other users to send enter in your terminal."
    )

    parser.add_option(
        "--no-ssl",
        dest="use_ssl",
        default=True,
        action="store_false",
        help="Do not use this option unless you know what you are doing!")

    parser.add_option("--url",
                      dest="workspace_url",
                      default=None,
                      help="The URL of the workspace to connect to.")

    parser.add_option("--resize",
                      dest="resize",
                      default=False,
                      action="store_true",
                      help="Resize your terminal to the host terminal size.")

    parser.add_option(
        "--shell",
        dest="shell",
        default=os.environ.get("SHELL", None),
        help="The shell you would like to use with flootty. Defaults to $SHELL."
    )

    parser.add_option("-P",
                      "--preserve-ps1",
                      dest="set_prompt",
                      default=True,
                      action="store_false",
                      help="Don't change $PS1 (bash/zsh prompt)")

    parser.add_option("-v",
                      "--version",
                      dest="version",
                      default=False,
                      action="store_true",
                      help="Print version")

    options, args = parser.parse_args()

    if options.version:
        print('flootty %s' % version.FLOOTTY_VERSION)
        return

    default_term_name = ""
    if options.create:
        default_term_name = "ftty"

    term_name = args and args[0] or default_term_name

    if options.workspace and options.owner and options.workspace_url:
        # TODO: confusing
        parser.error(
            "You can either specify --workspace and --owner, or --url, but not both."
        )

    if bool(options.workspace) != bool(options.owner):
        parser.error("You must specify a workspace and owner or neither.")

    for opt in ['owner', 'workspace']:
        if getattr(options, opt):
            print('%s is deprecated. Please use --url instead.' % opt)

    if not options.workspace or not options.owner:
        floo = {}
        if options.workspace_url:
            floo = utils.parse_url(options.workspace_url)
        else:
            for floo_path in walk_up(os.path.realpath('.')):
                try:
                    floo = json.loads(
                        open(os.path.join(floo_path, '.floo'),
                             'rb').read().decode('utf-8'))
                    floo = utils.parse_url(floo['url'])
                except Exception:
                    pass
                else:
                    break
        options.host = floo.get('host')
        options.workspace = floo.get('workspace')
        options.owner = floo.get('owner')
        options.use_ssl = floo.get('secure')
        if not options.port:
            options.port = floo.get('port')
        if not options.host:
            options.host = floo.get('host')

    if options.host is None:
        options.host = G.DEFAULT_HOST

    if options.host != G.DEFAULT_HOST and options.secret == default_auth.get(
            'secret'):
        auth = G.AUTH.get(options.host)
        if not auth:
            return die("Please add credentials for %s in ~/.floorc.json" %
                       options.host)
        options.username = auth.get('username')
        options.secret = auth.get('secret')

    if not options.workspace or not options.owner:
        try:
            now_editing = get_now_editing_workspaces()
        except Exception as e:
            print(str_e(e))
        else:
            if len(now_editing.body) == 1:
                options.workspace = now_editing.body[0]['name']
                options.owner = now_editing.body[0]['owner']
        # TODO: list possible workspaces to join if > 1 is active

    if options.list:
        if len(term_name) != 0:
            die("I don't understand why you gave me a positional argument.")

    for opt in ['username', 'secret']:
        if not getattr(options, opt):
            parser.error(
                '%s not given. Please use --%s or add credentials to ~/.floorc.json'
                % (opt, opt))

    for opt in ['workspace', 'owner']:
        if not getattr(options, opt):
            parser.error('%s not given' % opt)

    color_reset = '\033[0m'
    if not G.FLOOTTY_SAFE:
        options.safe = G.FLOOTTY_SAFE
    if options.safe:
        green = '\033[92m'
        print(
            '%sTerminal is safe. Other users will not be able to send [enter]%s'
            % (green, color_reset))
    else:
        yellorange = '\033[93m'
        print(
            '%sTerminal is unsafe. Other users will be able to send [enter]. Be wary!%s'
            % (yellorange, color_reset))

    f = Flootty(options, term_name)
    G.AGENT = f
    atexit.register(f.cleanup)
    f.connect_to_internet()
    f.select()
    def on_input(self, dir_to_share):
        file_to_share = None
        dir_to_share = os.path.expanduser(dir_to_share)
        dir_to_share = os.path.realpath(utils.unfuck_path(dir_to_share))
        workspace_name = os.path.basename(dir_to_share)
        workspace_url = None

        # TODO: use prejoin_workspace instead
        def find_workspace(workspace_url):
            r = api.get_workspace_by_url(workspace_url)
            if r.code < 400:
                return r
            try:
                result = utils.parse_url(workspace_url)
                d = utils.get_persistent_data()
                del d['workspaces'][result['owner']][result['name']]
                utils.update_persistent_data(d)
            except Exception as e:
                msg.debug(str_e(e))

        def join_workspace(workspace_url):
            try:
                w = find_workspace(workspace_url)
            except Exception as e:
                sublime.error_message('Error: %s' % str_e(e))
                return False
            if not w:
                return False
            msg.debug('workspace: %s', json.dumps(w.body))
            # if self.api_args:
            anon_perms = w.body.get('perms', {}).get('AnonymousUser', [])
            new_anon_perms = self.api_args.get('perms').get('AnonymousUser', [])
            # TODO: warn user about making a private workspace public
            if set(anon_perms) != set(new_anon_perms):
                msg.debug(str(anon_perms), str(new_anon_perms))
                w.body['perms']['AnonymousUser'] = new_anon_perms
                response = api.update_workspace(workspace_url, w.body)
                msg.debug(str(response.body))
            utils.add_workspace_to_persistent_json(w.body['owner'], w.body['name'], workspace_url, dir_to_share)
            self.window.run_command('floobits_join_workspace', {'workspace_url': workspace_url})
            return True

        if os.path.isfile(dir_to_share):
            file_to_share = dir_to_share
            dir_to_share = os.path.dirname(dir_to_share)

        try:
            utils.mkdir(dir_to_share)
        except Exception:
            sublime.error_message('The directory %s doesn\'t exist and I can\'t create it.' % dir_to_share)
            return

        floo_file = os.path.join(dir_to_share, '.floo')

        info = {}
        try:
            floo_info = open(floo_file, 'r').read()
            info = json.loads(floo_info)
        except (IOError, OSError):
            pass
        except Exception:
            msg.error('Couldn\'t read the floo_info file: %s' % floo_file)

        workspace_url = info.get('url')
        try:
            utils.parse_url(workspace_url)
        except Exception:
            workspace_url = None

        if workspace_url and join_workspace(workspace_url):
            return

        for owner, workspaces in utils.get_persistent_data()['workspaces'].items():
            for name, workspace in workspaces.items():
                if workspace['path'] == dir_to_share:
                    workspace_url = workspace['url']
                    if join_workspace(workspace_url):
                        return

        auth = yield editor.select_auth, self.window, G.AUTH
        if not auth:
            return

        username = auth.get('username')
        host = auth['host']

        def on_done(owner):
            msg.log('Colab dir: %s, Username: %s, Workspace: %s/%s' % (G.COLAB_DIR, username, owner[0], workspace_name))
            self.window.run_command('floobits_create_workspace', {
                'workspace_name': workspace_name,
                'dir_to_share': dir_to_share,
                'upload': file_to_share or dir_to_share,
                'api_args': self.api_args,
                'owner': owner[0],
                'host': host,
            })

        try:
            r = api.get_orgs_can_admin(host)
        except IOError as e:
            sublime.error_message('Error getting org list: %s' % str_e(e))
            return

        if r.code >= 400 or len(r.body) == 0:
            on_done([username])
            return

        orgs = [[org['name'], 'Create workspace owned by %s' % org['name']] for org in r.body]
        orgs.insert(0, [username, 'Create workspace owned by %s' % username])
        self.window.show_quick_panel(orgs, lambda index: index < 0 or on_done(orgs[index]))
Beispiel #31
0
def floobits_join_workspace(workspace_url, d='', upload_path=None):
    editor.line_endings = _get_line_endings()
    msg.debug('workspace url is %s' % workspace_url)
    try:
        result = utils.parse_url(workspace_url)
    except Exception as e:
        return msg.error(str(e))

    if d:
        utils.mkdir(d)
    else:
        try:
            d = utils.get_persistent_data()['workspaces'][result['owner']][
                result['workspace']]['path']
        except Exception:
            d = os.path.realpath(
                os.path.join(G.COLAB_DIR, result['owner'],
                             result['workspace']))

    prompt = 'Save workspace files to: '
    if not os.path.isdir(d):
        while True:
            d = vim_input(prompt, d, 'dir')
            if d == '':
                continue
            d = os.path.realpath(os.path.expanduser(d))
            if os.path.isfile(d):
                prompt = '%s is not a directory. Enter an existing path or a path I can create: ' % d
                continue
            if not os.path.isdir(d):
                try:
                    utils.mkdir(d)
                except Exception as e:
                    prompt = 'Couldn\'t make dir %s: %s ' % (d, str(e))
                    continue
            break
    d = os.path.realpath(os.path.abspath(d) + os.sep)
    try:
        utils.add_workspace_to_persistent_json(result['owner'],
                                               result['workspace'],
                                               workspace_url, d)
    except Exception as e:
        return msg.error('Error adding workspace to persistent.json: %s' %
                         str(e))

    G.PROJECT_PATH = d
    vim.command('cd %s' % G.PROJECT_PATH)
    msg.debug('Joining workspace %s' % workspace_url)

    floobits_stop_everything()
    try:
        conn = VimHandler(result['owner'], result['workspace'])
        if upload_path:
            conn.once('room_info', lambda: G.AGENT.upload(upload_path))
        reactor.connect(conn, result['host'], result['port'], result['secure'])
    except Exception as e:
        msg.error(str(e))
        tb = traceback.format_exc()
        msg.debug(tb)
    if not G.TIMERS:
        start_event_loop()
Beispiel #32
0
    def run(self, workspace_url, agent_conn_kwargs=None, upload=None):
        agent_conn_kwargs = agent_conn_kwargs or {}
        self.upload = upload

        def get_workspace_window():
            workspace_window = None
            for w in sublime.windows():
                for f in w.folders():
                    if utils.unfuck_path(f) == utils.unfuck_path(
                            G.PROJECT_PATH):
                        workspace_window = w
                        break
            return workspace_window

        def set_workspace_window(cb):
            workspace_window = get_workspace_window()
            if workspace_window is None:
                return utils.set_timeout(set_workspace_window, 50, cb)
            G.WORKSPACE_WINDOW = workspace_window
            cb()

        def open_workspace_window(cb):
            if PY2:
                open_workspace_window2(cb)
            else:
                open_workspace_window3(cb)

        def open_workspace_window2(cb):
            if sublime.platform() == 'linux':
                subl = open('/proc/self/cmdline').read().split(chr(0))[0]
            elif sublime.platform() == 'osx':
                floorc = utils.load_floorc_json()
                subl = floorc.get('SUBLIME_EXECUTABLE')
                if not subl:
                    settings = sublime.load_settings(
                        'Floobits.sublime-settings')
                    subl = settings.get(
                        'sublime_executable',
                        '/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl'
                    )
                if not os.path.exists(subl):
                    return sublime.error_message(
                        '''Can't find your Sublime Text executable at %s.
Please add "sublime_executable": "/path/to/subl" to your ~/.floorc.json and restart Sublime Text'''
                        % subl)
            elif sublime.platform() == 'windows':
                subl = sys.executable
            else:
                raise Exception('WHAT PLATFORM ARE WE ON?!?!?')

            command = [subl]
            if get_workspace_window() is None:
                command.append('--new-window')
            command.append('--add')
            command.append(G.PROJECT_PATH)

            msg.debug('command:', command)
            p = subprocess.Popen(command,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
            poll_result = p.poll()
            msg.debug('poll:', poll_result)

            set_workspace_window(cb)

        def open_workspace_window3(cb):
            def finish(w):
                G.WORKSPACE_WINDOW = w
                msg.debug('Setting project data. Path: %s' % G.PROJECT_PATH)
                G.WORKSPACE_WINDOW.set_project_data(
                    {'folders': [{
                        'path': G.PROJECT_PATH
                    }]})
                cb()

            def get_empty_window():
                for w in sublime.windows():
                    project_data = w.project_data()
                    try:
                        folders = project_data.get('folders', [])
                        if len(folders) == 0 or not folders[0].get('path'):
                            # no project data. co-opt this window
                            return w
                    except Exception as e:
                        print(str_e(e))

            def wait_empty_window(i):
                if i > 10:
                    print(
                        'Too many failures trying to find an empty window. Using active window.'
                    )
                    return finish(sublime.active_window())
                w = get_empty_window()
                if w:
                    return finish(w)
                return utils.set_timeout(wait_empty_window, 50, i + 1)

            w = get_workspace_window() or get_empty_window()
            if w:
                return finish(w)

            sublime.run_command('new_window')
            wait_empty_window(0)

        def make_dir(d):
            d = os.path.realpath(os.path.expanduser(d))

            if not os.path.isdir(d):
                make_dir = sublime.ok_cancel_dialog(
                    '%s is not a directory. Create it?' % d)
                if not make_dir:
                    return self.window.show_input_panel(
                        '%s is not a directory. Enter an existing path:' % d,
                        d, None, None, None)
                try:
                    utils.mkdir(d)
                except Exception as e:
                    return sublime.error_message(
                        'Could not create directory %s: %s' % (d, str_e(e)))
            G.PROJECT_PATH = d

            if self.upload:
                result['upload'] = d
            else:
                result['upload'] = ""

            utils.add_workspace_to_persistent_json(result['owner'],
                                                   result['workspace'],
                                                   workspace_url, d)
            open_workspace_window(lambda: run_agent(**result))

        @utils.inlined_callbacks
        def run_agent(owner, workspace, host, port, secure, upload):
            if G.AGENT:
                msg.debug('Stopping agent.')
                reactor.stop()
                G.AGENT = None
            try:
                auth = G.AUTH.get(host)
                if not auth:
                    success = yield link_account, host
                    if not success:
                        return
                    auth = G.AUTH.get(host)
                conn = SublimeConnection(owner, workspace, auth, upload)
                reactor.connect(conn, host, port, secure)
            except Exception as e:
                msg.error(str_e(e))

        try:
            result = utils.parse_url(workspace_url)
        except Exception as e:
            return sublime.error_message(str_e(e))

        utils.reload_settings()
        if not utils.can_auth():
            return create_or_link_account()

        d = utils.get_persistent_data()
        try:
            G.PROJECT_PATH = d['workspaces'][result['owner']][
                result['workspace']]['path']
        except Exception:
            msg.log('%s/%s not in persistent.json' %
                    (result['owner'], result['workspace']))
            G.PROJECT_PATH = ''

        msg.log('Project path is %s' % G.PROJECT_PATH)

        if not os.path.isdir(G.PROJECT_PATH):
            default_dir = None
            for w in sublime.windows():
                if default_dir:
                    break
                for d in self.window.folders():
                    floo_file = os.path.join(d, '.floo')
                    try:
                        floo_info = open(floo_file, 'r').read()
                        wurl = json.loads(floo_info).get('url')
                        if wurl == workspace_url:
                            # TODO: check if workspace actually exists
                            default_dir = d
                            break
                    except Exception:
                        pass

            default_dir = default_dir or os.path.realpath(
                os.path.join(G.COLAB_DIR, result['owner'],
                             result['workspace']))

            return self.window.show_input_panel('Save workspace in directory:',
                                                default_dir, make_dir, None,
                                                None)

        open_workspace_window(lambda: run_agent(upload=upload, **result))