Ejemplo n.º 1
0
    def create_or_link_account(self, context, host, force, cb):
        if host != "floobits.com":
            self.link_account(context, host, cb)
            return
        disable_account_creation = utils.get_persistent_data().get(
            'disable_account_creation')
        if disable_account_creation and not force:
            print(
                'We could not automatically create or link your floobits account. Please go to floobits.com and sign up to use this plugin.'
            )
            return

        if not G.EXPERT_MODE:
            editor.message_dialog(
                'Thank you for installing the Floobits plugin!\n\nLet\'s set up your editor to work with Floobits.'
            )

        choices = [
            'Sign in to Floobits', 'Automatically create a Floobits account',
            'Cancel (see https://floobits.com/help/floorc)'
        ]

        (
            choice, index
        ) = yield self.user_select, context, 'You need an account to use Floobits! Do you want to:', choices, None

        if index == -1 or index == 2:
            d = utils.get_persistent_data()
            if not d.get('disable_account_creation'):
                d['disable_account_creation'] = True
                utils.update_persistent_data(d)
                # TODO: this instruction is only useful for Sublime Text
                editor.message_dialog(
                    '''You can set up a Floobits account at any time under:\n\nTools -> Floobits -> Set up'''
                )
            cb(None)
            return

        agent = None
        if index == 0:
            agent = credentials.RequestCredentialsHandler()
        else:
            agent = account.CreateAccountHandler()

        agent.once('end', cb)

        try:
            reactor.reactor.connect(agent, host, G.DEFAULT_PORT, True)
        except Exception as e:
            print(str_e(e))
Ejemplo n.º 2
0
    def create_or_link_account(self, context, host, force, cb):
        if host != "floobits.com":
            self.link_account(context, host, cb)
            return
        disable_account_creation = utils.get_persistent_data().get("disable_account_creation")
        if disable_account_creation and not force:
            print(
                "We could not automatically create or link your floobits account. Please go to floobits.com and sign up to use this plugin."
            )
            return

        if not G.EXPERT_MODE:
            editor.message_dialog(
                "Thank you for installing the Floobits plugin!\n\nLet's set up your editor to work with Floobits."
            )

        choices = ["Sign in to Floobits", "Create a Floobits account", "Cancel (see https://floobits.com/help/floorc)"]

        (choice, index) = (
            yield self.user_select,
            context,
            "You need an account to use Floobits! Do you want to:",
            choices,
            None,
        )

        if index == -1 or index == 2:
            d = utils.get_persistent_data()
            if not d.get("disable_account_creation"):
                d["disable_account_creation"] = True
                utils.update_persistent_data(d)
                # TODO: this instruction is only useful for Sublime Text
                editor.message_dialog(
                    """You can set up a Floobits account at any time under\n\nTools -> Floobits -> Set up"""
                )
            cb(None)
            return

        agent = None
        if index == 0:
            agent = credentials.RequestCredentialsHandler()
        else:
            agent = account.CreateAccountHandler()

        agent.once("end", cb)

        try:
            reactor.reactor.connect(agent, host, G.DEFAULT_PORT, True)
        except Exception as e:
            print(str_e(e))
Ejemplo n.º 3
0
def add_workspace_to_persistent_json(owner, name, url, path):
    d = utils.get_persistent_data()
    workspaces = d['workspaces']
    if owner not in workspaces:
        workspaces[owner] = {}
    workspaces[owner][name] = {'url': url, 'path': path}
    utils.update_persistent_data(d)
Ejemplo n.º 4
0
def create_or_link_account():
    agent = None
    account = sublime.ok_cancel_dialog(
        'You need a Floobits account!\n\n'
        'Click "Open browser" if you have one or click "cancel" and we\'ll make it for you.',
        'Open browser')
    if account:
        token = binascii.b2a_hex(uuid.uuid4().bytes).decode('utf-8')
        agent = RequestCredentialsConnection(token)
    elif not utils.get_persistent_data().get('disable_account_creation'):
        agent = CreateAccountConnection()

    if not agent:
        sublime.error_message(
            'A configuration error occured earlier. Please go to floobits.com and sign up to use this plugin.\n\nWe\'re really sorry. This should never happen.'
        )
        return

    try:
        Listener.reset()
        G.AGENT = agent
        agent.connect()
    except Exception as e:
        print(e)
        tb = traceback.format_exc()
        print(tb)
Ejemplo n.º 5
0
def plugin_loaded():
    global called_plugin_loaded
    if called_plugin_loaded:
        return
    called_plugin_loaded = True
    print('Floobits: Called plugin_loaded.')

    utils.reload_settings()

    G.SOCK_SINGLE_READ = SOCK_SINGLE_READ

    # TODO: one day this can be removed (once all our users have updated)
    old_colab_dir = os.path.realpath(os.path.expanduser(os.path.join('~', '.floobits')))
    if os.path.isdir(old_colab_dir) and not os.path.exists(G.BASE_DIR):
        print('Renaming %s to %s' % (old_colab_dir, G.BASE_DIR))
        os.rename(old_colab_dir, G.BASE_DIR)
        os.symlink(G.BASE_DIR, old_colab_dir)

    try:
        utils.normalize_persistent_data()
    except Exception as e:
        print('Floobits: Error normalizing persistent data:', str_e(e))
        # Keep on truckin' I guess

    d = utils.get_persistent_data()
    G.AUTO_GENERATED_ACCOUNT = d.get('auto_generated_account', False)
    setup()
Ejemplo n.º 6
0
def plugin_loaded():
    global called_plugin_loaded
    if called_plugin_loaded:
        return
    called_plugin_loaded = True
    print('Floobits: Called plugin_loaded.')

    utils.reload_settings()

    # TODO: one day this can be removed (once all our users have updated)
    old_colab_dir = os.path.realpath(os.path.expanduser(os.path.join('~', '.floobits')))
    if os.path.isdir(old_colab_dir) and not os.path.exists(G.BASE_DIR):
        print('renaming %s to %s' % (old_colab_dir, G.BASE_DIR))
        os.rename(old_colab_dir, G.BASE_DIR)
        os.symlink(G.BASE_DIR, old_colab_dir)

    d = utils.get_persistent_data()
    G.AUTO_GENERATED_ACCOUNT = d.get('auto_generated_account', False)

    can_auth = (G.USERNAME or G.API_KEY) and G.SECRET
    # Sublime plugin API stuff can't be called right off the bat
    if not can_auth:
        utils.set_timeout(create_or_link_account, 1)

    utils.set_timeout(global_tick, 1)
Ejemplo n.º 7
0
def plugin_loaded():
    global called_plugin_loaded
    if called_plugin_loaded:
        return
    called_plugin_loaded = True
    print('Floobits: Called plugin_loaded.')

    if not os.path.exists(G.FLOORC_JSON_PATH):
        migrations.migrate_floorc()
    utils.reload_settings()

    # TODO: one day this can be removed (once all our users have updated)
    old_colab_dir = os.path.realpath(os.path.expanduser(os.path.join('~', '.floobits')))
    if os.path.isdir(old_colab_dir) and not os.path.exists(G.BASE_DIR):
        print('Renaming %s to %s' % (old_colab_dir, G.BASE_DIR))
        os.rename(old_colab_dir, G.BASE_DIR)
        os.symlink(G.BASE_DIR, old_colab_dir)

    try:
        utils.normalize_persistent_data()
    except Exception as e:
        print('Floobits: Error normalizing persistent data:', str_e(e))
        # Keep on truckin' I guess

    d = utils.get_persistent_data()
    G.AUTO_GENERATED_ACCOUNT = d.get('auto_generated_account', False)

    # Sublime plugin API stuff can't be called right off the bat
    if not utils.can_auth():
        utils.set_timeout(create_or_link_account, 1)

    utils.set_timeout(global_tick, 1)
Ejemplo n.º 8
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
Ejemplo n.º 9
0
def add_workspace_to_persistent_json(owner, name, url, path):
    d = utils.get_persistent_data()
    workspaces = d['workspaces']
    if owner not in workspaces:
        workspaces[owner] = {}
    workspaces[owner][name] = {'url': url, 'path': path}
    utils.update_persistent_data(d)
Ejemplo n.º 10
0
def plugin_loaded():
    global called_plugin_loaded
    if called_plugin_loaded:
        return
    called_plugin_loaded = True
    print('Floobits: Called plugin_loaded.')

    if not os.path.exists(G.FLOORC_JSON_PATH):
        migrations.migrate_floorc()
    utils.reload_settings()

    # TODO: one day this can be removed (once all our users have updated)
    old_colab_dir = os.path.realpath(
        os.path.expanduser(os.path.join('~', '.floobits')))
    if os.path.isdir(old_colab_dir) and not os.path.exists(G.BASE_DIR):
        print('Renaming %s to %s' % (old_colab_dir, G.BASE_DIR))
        os.rename(old_colab_dir, G.BASE_DIR)
        os.symlink(G.BASE_DIR, old_colab_dir)

    try:
        utils.normalize_persistent_data()
    except Exception as e:
        print('Floobits: Error normalizing persistent data:', str_e(e))
        # Keep on truckin' I guess

    d = utils.get_persistent_data()
    G.AUTO_GENERATED_ACCOUNT = d.get('auto_generated_account', False)

    # Sublime plugin API stuff can't be called right off the bat
    if not utils.can_auth():
        utils.set_timeout(create_or_link_account, 1)

    utils.set_timeout(global_tick, 1)
Ejemplo n.º 11
0
def plugin_loaded():
    global called_plugin_loaded
    if called_plugin_loaded:
        return
    called_plugin_loaded = True
    print('Floobits: Called plugin_loaded.')

    utils.reload_settings()

    G.SOCK_SINGLE_READ = SOCK_SINGLE_READ

    # TODO: one day this can be removed (once all our users have updated)
    old_colab_dir = os.path.realpath(
        os.path.expanduser(os.path.join('~', '.floobits')))
    if os.path.isdir(old_colab_dir) and not os.path.exists(G.BASE_DIR):
        print('Renaming %s to %s' % (old_colab_dir, G.BASE_DIR))
        os.rename(old_colab_dir, G.BASE_DIR)
        os.symlink(G.BASE_DIR, old_colab_dir)

    try:
        utils.normalize_persistent_data()
    except Exception as e:
        print('Floobits: Error normalizing persistent data:', str_e(e))
        # Keep on truckin' I guess

    d = utils.get_persistent_data()
    G.AUTO_GENERATED_ACCOUNT = d.get('auto_generated_account', False)
    setup()
Ejemplo n.º 12
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
Ejemplo n.º 13
0
    def _get_recent_workspaces(self):
        self.recent_workspaces = utils.get_persistent_data()['recent_workspaces']

        try:
            recent_workspaces = [x.get('url') for x in self.recent_workspaces if x.get('url') is not None]
        except Exception:
            pass
        return recent_workspaces
Ejemplo n.º 14
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
Ejemplo n.º 15
0
    def _get_recent_workspaces(self):
        self.persistent_data = utils.get_persistent_data()
        self.recent_workspaces = self.persistent_data['recent_workspaces']

        try:
            recent_workspaces = [x.get('url') for x in self.recent_workspaces if x.get('url') is not None]
        except Exception:
            pass
        return recent_workspaces
Ejemplo n.º 16
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()
 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))
Ejemplo n.º 18
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))
Ejemplo n.º 19
0
def update_recent_workspaces(workspace):
    d = utils.get_persistent_data()
    recent_workspaces = d.get('recent_workspaces', [])
    recent_workspaces.insert(0, workspace)
    recent_workspaces = recent_workspaces[:100]
    seen = set()
    new = []
    for r in recent_workspaces:
        string = json.dumps(r)
        if string not in seen:
            new.append(r)
            seen.add(string)
    d['recent_workspaces'] = new
    utils.update_persistent_data(d)
Ejemplo n.º 20
0
 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
Ejemplo n.º 21
0
def update_recent_workspaces(workspace):
    d = utils.get_persistent_data()
    recent_workspaces = d.get('recent_workspaces', [])
    recent_workspaces.insert(0, workspace)
    recent_workspaces = recent_workspaces[:100]
    seen = set()
    new = []
    for r in recent_workspaces:
        string = json.dumps(r)
        if string not in seen:
            new.append(r)
            seen.add(string)
    d['recent_workspaces'] = new
    utils.update_persistent_data(d)
Ejemplo n.º 22
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
Ejemplo n.º 23
0
def migrate_symlinks():
    data = {}
    old_path = os.path.join(G.COLAB_DIR, 'persistent.json')
    if not os.path.exists(old_path):
        return
    old_data = utils.get_persistent_data(old_path)
    data['workspaces'] = get_legacy_projects()
    data['recent_workspaces'] = old_data.get('recent_workspaces')
    utils.update_persistent_data(data)
    try:
        os.unlink(old_path)
        os.unlink(os.path.join(G.COLAB_DIR, 'msgs.floobits.log'))
    except Exception:
        pass
    print('migrated')
Ejemplo n.º 24
0
def migrate_symlinks():
    data = {}
    old_path = os.path.join(G.COLAB_DIR, 'persistent.json')
    if not os.path.exists(old_path):
        return
    old_data = utils.get_persistent_data(old_path)
    data['workspaces'] = get_legacy_projects()
    data['recent_workspaces'] = old_data.get('recent_workspaces')
    utils.update_persistent_data(data)
    try:
        os.unlink(old_path)
        os.unlink(os.path.join(G.COLAB_DIR, 'msgs.floobits.log'))
    except Exception:
        pass
    print('migrated')
Ejemplo n.º 25
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
Ejemplo n.º 26
0
    def handle(self, req):
        self.net_buf += req
        while True:
            before, sep, after = self.net_buf.partition('\n')
            if not sep:
                break
            self.net_buf = after
            try:
                data = json.loads(before)
            except Exception as e:
                msg.error('Unable to parse json:', e)
                msg.error('Data:', before)
                raise e
            if data['name'] == 'share_dir':
                utils.reload_settings()
                G.USERNAME = data['username']
                G.SECRET = data['secret']
                self.share_dir(data['dir_to_share'], data.get('perms'))
            elif data['name'] == 'join_workspace':
                utils.reload_settings()
                workspace = data['workspace']
                owner = data['workspace_owner']
                G.USERNAME = data['username']
                G.SECRET = data['secret']

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

                if G.PROJECT_PATH and os.path.isdir(G.PROJECT_PATH):
                    workspace_url = utils.to_workspace_url({'secure': True, 'owner': owner, 'workspace': workspace})
                    self.remote_connect(workspace_url)
                    continue

                G.PROJECT_PATH = '~/floobits/share/%s/%s' % (owner, workspace)
                self.get_input('Give me a directory to sync data to: ', G.PROJECT_PATH, self.join_workspace, owner, workspace)

            elif data['name'] == 'user_input':
                cb_id = int(data['id'])
                cb = self.user_inputs.get(cb_id)
                if cb is None:
                    msg.error('cb for input %s is none' % cb_id)
                    continue
                cb(data)
                del self.user_inputs[cb_id]
            else:
                self.agent.protocol.emacs_handle(data)
Ejemplo n.º 27
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
Ejemplo n.º 28
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 cb(index):
     if index == 0:
         token = binascii.b2a_hex(uuid.uuid4().bytes).decode('utf-8')
         agent = RequestCredentialsHandler(token)
     elif index == 1:
         agent = CreateAccountHandler()
     else:
         d = utils.get_persistent_data()
         if d.get('disable_account_creation'):
             return
         d['disable_account_creation'] = True
         utils.update_persistent_data(d)
         sublime.message_dialog('''You can set up a Floobits account at any time under\n\nTools -> Floobits -> Setup''')
     try:
         reactor.connect(agent, G.DEFAULT_HOST, G.DEFAULT_PORT, True)
     except Exception as e:
         print(str_e(e))
Ejemplo n.º 30
0
def create_or_link_account(force=False):
    disable_account_creation = utils.get_persistent_data().get(
        'disable_account_creation')
    if disable_account_creation and not force:
        print(
            'We could not automatically create or link your floobits account. Please go to floobits.com and sign up to use this plugin.'
        )
        return

    opts = [
        ['Use existing Floobits account.', '(opens web page)'],
        ['Create a new Floobits account.', ''],
        ['Cancel', ''],
    ]

    def cb(index):
        if index == 0:
            token = binascii.b2a_hex(uuid.uuid4().bytes).decode('utf-8')
            agent = RequestCredentialsHandler(token)
        elif index == 1:
            agent = CreateAccountHandler()
        else:
            d = utils.get_persistent_data()
            if d.get('disable_account_creation'):
                return
            d['disable_account_creation'] = True
            utils.update_persistent_data(d)
            sublime.message_dialog(
                '''You can set up a Floobits account at any time under\n\nTools -> Floobits -> Setup'''
            )
        try:
            reactor.connect(agent, G.DEFAULT_HOST, G.DEFAULT_PORT, True)
        except Exception as e:
            print(str_e(e))

    def get_workspace_window():
        w = sublime.active_window()
        if w is None:
            return utils.set_timeout(get_workspace_window, 50)
        sublime.message_dialog(
            'Thank you for installing the Floobits plugin!\n\nLet\'s set up your editor to work with Floobits.'
        )
        w.show_quick_panel(opts, cb)

    get_workspace_window()
Ejemplo n.º 31
0
 def cb(index):
     if index == 0:
         token = binascii.b2a_hex(uuid.uuid4().bytes).decode('utf-8')
         agent = RequestCredentialsHandler(token)
     elif index == 1:
         agent = CreateAccountHandler()
     else:
         d = utils.get_persistent_data()
         if d.get('disable_account_creation'):
             return
         d['disable_account_creation'] = True
         utils.update_persistent_data(d)
         sublime.message_dialog(
             '''You can set up a Floobits account at any time under\n\nTools -> Floobits -> Setup'''
         )
     try:
         reactor.connect(agent, G.DEFAULT_HOST, G.DEFAULT_PORT, True)
     except Exception as e:
         print(str_e(e))
Ejemplo n.º 32
0
 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
Ejemplo n.º 33
0
def create_or_link_account():
    agent = None
    account = sublime.ok_cancel_dialog('You need a Floobits account!\n\n'
                                       'Click "Open browser" if you have one or click "cancel" and we\'ll make it for you.',
                                       'Open browser')
    if account:
        token = binascii.b2a_hex(uuid.uuid4().bytes).decode('utf-8')
        agent = RequestCredentialsHandler(token)
    elif not utils.get_persistent_data().get('disable_account_creation'):
        agent = CreateAccountHandler()

    if not agent:
        sublime.error_message('A configuration error occured earlier. Please go to floobits.com and sign up to use this plugin.\n\nWe\'re really sorry. This should never happen.')
        return

    try:
        reactor.connect(agent, G.DEFAULT_HOST, G.DEFAULT_PORT, True)
    except Exception as e:
        print(e)
        tb = traceback.format_exc()
        print(tb)
Ejemplo n.º 34
0
def floobits_setup_credentials():
    prompt = 'You need a Floobits account! Do you have one? If no we will create one for you [y/n]. '
    d = vim_input(prompt, '')
    if d and (d != 'y' and d != 'n'):
        return floobits_setup_credentials()
    agent = None
    if d == 'y':
        msg.debug('You have an account.')
        token = binascii.b2a_hex(uuid.uuid4().bytes).decode('utf-8')
        agent = RequestCredentialsHandler(token)
    elif not utils.get_persistent_data().get('disable_account_creation'):
        agent = CreateAccountHandler()
    if not agent:
        msg.error('A configuration error occured earlier. Please go to floobits.com and sign up to use this plugin.\n\n'
                  'We\'re really sorry. This should never happen.')
        return
    try:
        reactor.connect(agent, G.DEFAULT_HOST, G.DEFAULT_PORT, True)
    except Exception as e:
        msg.error(str(e))
        msg.debug(traceback.format_exc())
Ejemplo n.º 35
0
def floobits_setup_credentials():
    prompt = 'You need a Floobits account! Do you have one? If no we will create one for you [y/n]. '
    d = vim_input(prompt, '')
    if d and (d != 'y' and d != 'n'):
        return floobits_setup_credentials()
    agent = None
    if d == 'y':
        msg.debug('You have an account.')
        token = binascii.b2a_hex(uuid.uuid4().bytes).decode('utf-8')
        agent = RequestCredentialsHandler(token)
    elif not utils.get_persistent_data().get('disable_account_creation'):
        agent = CreateAccountHandler()
    if not agent:
        msg.error(
            'A configuration error occured earlier. Please go to floobits.com and sign up to use this plugin.\n\n'
            'We\'re really sorry. This should never happen.')
        return
    try:
        reactor.connect(agent, G.DEFAULT_HOST, G.DEFAULT_PORT, True)
    except Exception as e:
        msg.error(str(e))
        msg.debug(traceback.format_exc())
def create_or_link_account(force=False):
    disable_account_creation = utils.get_persistent_data().get('disable_account_creation')
    if disable_account_creation and not force:
        print('We could not automatically create or link your floobits account. Please go to floobits.com and sign up to use this plugin.')
        return

    opts = [
        ['Use existing Floobits account.', '(opens web page)'],
        ['Create a new Floobits account.', ''],
        ['Cancel', ''],
    ]

    def cb(index):
        if index == 0:
            token = binascii.b2a_hex(uuid.uuid4().bytes).decode('utf-8')
            agent = RequestCredentialsHandler(token)
        elif index == 1:
            agent = CreateAccountHandler()
        else:
            d = utils.get_persistent_data()
            if d.get('disable_account_creation'):
                return
            d['disable_account_creation'] = True
            utils.update_persistent_data(d)
            sublime.message_dialog('''You can set up a Floobits account at any time under\n\nTools -> Floobits -> Setup''')
        try:
            reactor.connect(agent, G.DEFAULT_HOST, G.DEFAULT_PORT, True)
        except Exception as e:
            print(str_e(e))

    def get_workspace_window():
        w = sublime.active_window()
        if w is None:
            return utils.set_timeout(get_workspace_window, 50)
        sublime.message_dialog('Thank you for installing the Floobits plugin!\n\nLet\'s set up your editor to work with Floobits.')
        w.show_quick_panel(opts, cb)
    get_workspace_window()
Ejemplo n.º 37
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))
Ejemplo n.º 38
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))
Ejemplo n.º 39
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]))
Ejemplo n.º 40
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]))
Ejemplo n.º 41
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))
Ejemplo n.º 42
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]))
Ejemplo n.º 43
0
    def _on_room_info(self, data):
        self.joined_workspace = True
        self.workspace_info = data
        G.PERMS = data['perms']

        self.proto.reset_retries()

        if G.OUTBOUND_FILTERING:
            msg.error(
                'Detected outbound port blocking! See https://floobits.com/help/network for more info.'
            )

        read_only = False
        if 'patch' not in data['perms']:
            read_only = True
            no_perms_msg = '''You don't have permission to edit this workspace. All files will be read-only.'''
            msg.log('No patch permission. Setting buffers to read-only')
            if 'request_perm' in data['perms']:
                should_send = yield self.ok_cancel_dialog, no_perms_msg + '\nDo you want to request edit permission?'
                # TODO: wait for perms to be OK'd/denied before uploading or bailing
                if should_send:
                    self.send({
                        'name': 'request_perms',
                        'perms': ['edit_room']
                    })
            else:
                if G.EXPERT_MODE:
                    editor.status_message(no_perms_msg)
                else:
                    editor.error_message(no_perms_msg)

        floo_json = {
            'url':
            utils.to_workspace_url({
                'owner': self.owner,
                'workspace': self.workspace,
                'host': self.proto.host,
                'port': self.proto.port,
                'secure': self.proto.secure,
            })
        }
        utils.update_floo_file(os.path.join(G.PROJECT_PATH, '.floo'),
                               floo_json)
        utils.update_recent_workspaces(self.workspace_url)

        changed_bufs = []
        missing_bufs = []
        new_files = set()
        ig = ignore.create_ignore_tree(G.PROJECT_PATH)
        G.IGNORE = ig
        if not read_only:
            new_files = set([utils.to_rel_path(x) for x in ig.list_paths()])

        for buf_id, buf in data['bufs'].items():
            buf_id = int(buf_id)  # json keys must be strings
            buf_path = utils.get_full_path(buf['path'])
            new_dir = os.path.dirname(buf_path)
            utils.mkdir(new_dir)
            self.bufs[buf_id] = buf
            self.paths_to_ids[buf['path']] = buf_id

            view = self.get_view(buf_id)
            if view and not view.is_loading() and buf['encoding'] == 'utf8':
                view_text = view.get_text()
                view_md5 = hashlib.md5(view_text.encode('utf-8')).hexdigest()
                buf['buf'] = view_text
                buf['view'] = view
                G.VIEW_TO_HASH[view.native_id] = view_md5
                if view_md5 == buf['md5']:
                    msg.debug('md5 sum matches view. not getting buffer ',
                              buf['path'])
                else:
                    changed_bufs.append(buf)
                    buf['md5'] = view_md5
                continue

            try:
                if buf['encoding'] == 'utf8':
                    if io:
                        buf_fd = io.open(buf_path, 'Urt', encoding='utf8')
                        buf_buf = buf_fd.read()
                    else:
                        buf_fd = open(buf_path, 'rb')
                        buf_buf = buf_fd.read().decode('utf-8').replace(
                            '\r\n', '\n')
                    md5 = hashlib.md5(buf_buf.encode('utf-8')).hexdigest()
                else:
                    buf_fd = open(buf_path, 'rb')
                    buf_buf = buf_fd.read()
                    md5 = hashlib.md5(buf_buf).hexdigest()
                buf_fd.close()
                buf['buf'] = buf_buf
                if md5 == buf['md5']:
                    msg.debug('md5 sum matches. not getting buffer ',
                              buf['path'])
                else:
                    msg.debug('md5 differs. possibly getting buffer later ',
                              buf['path'])
                    changed_bufs.append(buf)
                    buf['md5'] = md5
            except Exception as e:
                msg.debug('Error calculating md5 for ', buf['path'], ', ',
                          str_e(e))
                missing_bufs.append(buf)

        ignored = []
        for p, buf_id in self.paths_to_ids.items():
            if p not in new_files:
                ignored.append(p)
            new_files.discard(p)

        if self.action == utils.JOIN_ACTION.UPLOAD:
            yield self._initial_upload, ig, missing_bufs, changed_bufs
            # TODO: maybe use org name here
            who = 'Your friends'
            anon_perms = G.AGENT.workspace_info.get('anon_perms')
            if 'get_buf' in anon_perms:
                who = 'Anyone'
            _msg = 'You are sharing:\n\n%s\n\n%s can join your workspace at:\n\n%s' % (
                G.PROJECT_PATH, who, G.AGENT.workspace_url)
            # Workaround for horrible Sublime Text bug
            utils.set_timeout(editor.message_dialog, 0, _msg)
        elif changed_bufs or missing_bufs or new_files:
            # TODO: handle readonly here
            if self.action == utils.JOIN_ACTION.PROMPT:
                stomp_local = yield self.stomp_prompt, changed_bufs, missing_bufs, list(
                    new_files), ignored
                if stomp_local not in [0, 1]:
                    self.stop()
                    return
            elif self.action == utils.JOIN_ACTION.DOWNLOAD:
                stomp_local = True
            else:
                # This should never happen
                assert False
                return

            if stomp_local:
                for buf in changed_bufs:
                    self.get_buf(buf['id'], buf.get('view'))
                    self.save_on_get_bufs.add(buf['id'])
                for buf in missing_bufs:
                    self.get_buf(buf['id'], buf.get('view'))
                    self.save_on_get_bufs.add(buf['id'])
            else:
                yield self._initial_upload, ig, missing_bufs, changed_bufs

        success_msg = '%s@%s/%s: Joined!' % (self.username, self.owner,
                                             self.workspace)
        msg.log(success_msg)
        editor.status_message(success_msg)

        data = utils.get_persistent_data()
        data['recent_workspaces'].insert(0, {"url": self.workspace_url})
        utils.update_persistent_data(data)
        utils.add_workspace_to_persistent_json(self.owner, self.workspace,
                                               self.workspace_url,
                                               G.PROJECT_PATH)

        temp_data = data.get('temp_data', {})
        hangout = temp_data.get('hangout', {})
        hangout_url = hangout.get('url')
        if hangout_url:
            self.prompt_join_hangout(hangout_url)

        self.emit("room_info")
Ejemplo n.º 44
0
    if not os.path.exists(old_path):
        return
    old_data = utils.get_persistent_data(old_path)
    data['workspaces'] = get_legacy_projects()
    data['recent_workspaces'] = old_data.get('recent_workspaces')
    utils.update_persistent_data(data)
    try:
        os.unlink(old_path)
        os.unlink(os.path.join(G.COLAB_DIR, 'msgs.floobits.log'))
    except Exception:
        pass
    print('migrated')

migrate_symlinks()

d = utils.get_persistent_data()
G.AUTO_GENERATED_ACCOUNT = d.get('auto_generated_account', False)


def get_active_window(cb):
    win = sublime.active_window()
    if not win:
        return utils.set_timeout(get_active_window, 50, cb)
    cb(win)


def create_or_link_account():
    agent = None
    account = sublime.ok_cancel_dialog('You need a Floobits account!\n\n'
                                       'Click "Open browser" if you have one or click "cancel" and we\'ll make it for you.',
                                       'Open browser')
Ejemplo n.º 45
0
    def _on_room_info(self, data):
        self.joined_workspace = True
        self.workspace_info = data
        G.PERMS = data['perms']

        self.proto.reset_retries()

        if G.OUTBOUND_FILTERING:
            msg.error('Detected outbound port blocking! See https://floobits.com/help/network for more info.')

        read_only = False
        if 'patch' not in data['perms']:
            read_only = True
            no_perms_msg = '''You don't have permission to edit this workspace. All files will be read-only.'''
            msg.log('No patch permission. Setting buffers to read-only')
            if 'request_perm' in data['perms']:
                should_send = yield self.ok_cancel_dialog, no_perms_msg + '\nDo you want to request edit permission?'
                # TODO: wait for perms to be OK'd/denied before uploading or bailing
                if should_send:
                    self.send({'name': 'request_perms', 'perms': ['edit_room']})
            else:
                if G.EXPERT_MODE:
                    editor.status_message(no_perms_msg)
                else:
                    editor.error_message(no_perms_msg)

        floo_json = {
            'url': utils.to_workspace_url({
                'owner': self.owner,
                'workspace': self.workspace,
                'host': self.proto.host,
                'port': self.proto.port,
                'secure': self.proto.secure,
            })
        }
        utils.update_floo_file(os.path.join(G.PROJECT_PATH, '.floo'), floo_json)
        utils.update_recent_workspaces(self.workspace_url)

        ig = ignore.create_ignore_tree(G.PROJECT_PATH)
        G.IGNORE = ig
        for buf_id, buf in data['bufs'].items():
            buf_id = int(buf_id)  # json keys must be strings
            self.bufs[buf_id] = buf
            self.paths_to_ids[buf['path']] = buf_id
        changed_bufs, missing_bufs, new_files = self._scan_dir(data['bufs'], ig, read_only)

        ignored = []
        for p, buf_id in self.paths_to_ids.items():
            if p not in new_files:
                ignored.append(p)
            new_files.discard(p)

        if self.action == utils.JOIN_ACTION.UPLOAD:
            yield self._initial_upload, ig, missing_bufs, changed_bufs
            # TODO: maybe use org name here
            who = 'Your friends'
            anon_perms = G.AGENT.workspace_info.get('anon_perms')
            if 'get_buf' in anon_perms:
                who = 'Anyone'
            _msg = 'You are sharing:\n\n%s\n\n%s can join your workspace at:\n\n%s' % (G.PROJECT_PATH, who, G.AGENT.workspace_url)
            # Workaround for horrible Sublime Text bug
            utils.set_timeout(editor.message_dialog, 0, _msg)
            # Don't auto-upload again on reconnect
            self.action = utils.JOIN_ACTION.PROMPT
        elif changed_bufs or missing_bufs or new_files:
            # TODO: handle readonly here
            if self.action == utils.JOIN_ACTION.PROMPT:
                stomp_local = yield self.stomp_prompt, changed_bufs, missing_bufs, list(new_files), ignored
                if stomp_local not in [0, 1]:
                    self.stop()
                    return
            elif self.action == utils.JOIN_ACTION.DOWNLOAD:
                stomp_local = True
            else:
                # This should never happen
                assert False
                return

            if stomp_local:
                for buf in changed_bufs:
                    self.get_buf(buf['id'], buf.get('view'))
                    self.save_on_get_bufs.add(buf['id'])
                for buf in missing_bufs:
                    self.get_buf(buf['id'], buf.get('view'))
                    self.save_on_get_bufs.add(buf['id'])
            else:
                yield self._initial_upload, ig, missing_bufs, changed_bufs

        success_msg = '%s@%s/%s: Joined!' % (self.username, self.owner, self.workspace)
        msg.log(success_msg)
        editor.status_message(success_msg)

        data = utils.get_persistent_data()
        data['recent_workspaces'].insert(0, {"url": self.workspace_url})
        utils.update_persistent_data(data)
        utils.add_workspace_to_persistent_json(self.owner, self.workspace, self.workspace_url, G.PROJECT_PATH)

        temp_data = data.get('temp_data', {})
        hangout = temp_data.get('hangout', {})
        hangout_url = hangout.get('url')
        if hangout_url:
            self.prompt_join_hangout(hangout_url)

        if data.get('repo_info'):
            msg.log('Repo info:', data.get('repo_info'))
            # TODO: check local repo info and update remote (or prompt?)
        else:
            repo_info = repo.get_info(self.workspace_url, G.PROJECT_PATH)
            if repo_info and 'repo' in G.PERMS:
                self.send({
                    'name': 'repo',
                    'action': 'set',
                    'data': repo_info,
                })

        self.emit("room_info")
Ejemplo n.º 46
0
    def _on_room_info(self, data):
        self.reset()
        self.joined_workspace = True
        self.workspace_info = data
        G.PERMS = data['perms']

        self.proto.reset_retries()

        if G.OUTBOUND_FILTERING:
            msg.error('Detected outbound port blocking! See https://floobits.com/help/network for more info.')

        read_only = False
        if 'patch' not in data['perms']:
            read_only = True
            no_perms_msg = '''You don't have permission to edit this workspace. All files will be read-only.'''
            msg.log('No patch permission. Setting buffers to read-only')
            if 'request_perm' in data['perms']:
                should_send = yield self.ok_cancel_dialog, no_perms_msg + '\nDo you want to request edit permission?'
                # TODO: wait for perms to be OK'd/denied before uploading or bailing
                if should_send:
                    self.send({'name': 'request_perms', 'perms': ['edit_room']})
            else:
                if G.EXPERT_MODE:
                    editor.status_message(no_perms_msg)
                else:
                    editor.error_message(no_perms_msg)

        floo_json = {
            'url': utils.to_workspace_url({
                'owner': self.owner,
                'workspace': self.workspace,
                'host': self.proto.host,
                'port': self.proto.port,
                'secure': self.proto.secure,
            })
        }
        utils.update_floo_file(os.path.join(G.PROJECT_PATH, '.floo'), floo_json)
        utils.update_recent_workspaces(self.workspace_url)

        changed_bufs = []
        missing_bufs = []
        new_files = set()
        ig = ignore.create_ignore_tree(G.PROJECT_PATH)
        G.IGNORE = ig
        if not read_only:
            new_files = set([utils.to_rel_path(x) for x in ig.list_paths()])

        for buf_id, buf in data['bufs'].items():
            buf_id = int(buf_id)  # json keys must be strings
            buf_path = utils.get_full_path(buf['path'])
            new_dir = os.path.dirname(buf_path)
            utils.mkdir(new_dir)
            self.bufs[buf_id] = buf
            self.paths_to_ids[buf['path']] = buf_id

            view = self.get_view(buf_id)
            if view and not view.is_loading() and buf['encoding'] == 'utf8':
                view_text = view.get_text()
                view_md5 = hashlib.md5(view_text.encode('utf-8')).hexdigest()
                buf['buf'] = view_text
                buf['view'] = view
                G.VIEW_TO_HASH[view.native_id] = view_md5
                if view_md5 == buf['md5']:
                    msg.debug('md5 sum matches view. not getting buffer ', buf['path'])
                else:
                    changed_bufs.append(buf)
                    buf['md5'] = view_md5
                continue

            try:
                if buf['encoding'] == 'utf8':
                    if io:
                        buf_fd = io.open(buf_path, 'Urt', encoding='utf8')
                        buf_buf = buf_fd.read()
                    else:
                        buf_fd = open(buf_path, 'rb')
                        buf_buf = buf_fd.read().decode('utf-8').replace('\r\n', '\n')
                    md5 = hashlib.md5(buf_buf.encode('utf-8')).hexdigest()
                else:
                    buf_fd = open(buf_path, 'rb')
                    buf_buf = buf_fd.read()
                    md5 = hashlib.md5(buf_buf).hexdigest()
                buf_fd.close()
                buf['buf'] = buf_buf
                if md5 == buf['md5']:
                    msg.debug('md5 sum matches. not getting buffer ', buf['path'])
                else:
                    msg.debug('md5 differs. possibly getting buffer later ', buf['path'])
                    changed_bufs.append(buf)
                    buf['md5'] = md5
            except Exception as e:
                msg.debug('Error calculating md5 for ', buf['path'], ', ', str_e(e))
                missing_bufs.append(buf)

        ignored = []
        for p, buf_id in self.paths_to_ids.items():
            if p not in new_files:
                ignored.append(p)
            new_files.discard(p)

        if self.action == utils.JOIN_ACTION.UPLOAD:
            yield self._initial_upload, ig, missing_bufs, changed_bufs
            # TODO: maybe use org name here
            who = 'Your friends'
            anon_perms = G.AGENT.workspace_info.get('anon_perms')
            if 'get_buf' in anon_perms:
                who = 'Anyone'
            _msg = 'You are sharing:\n\n%s\n\n%s can join your workspace at:\n\n%s' % (G.PROJECT_PATH, who, G.AGENT.workspace_url)
            # Workaround for horrible Sublime Text bug
            utils.set_timeout(editor.message_dialog, 0, _msg)
        elif changed_bufs or missing_bufs or new_files:
            # TODO: handle readonly here
            if self.action == utils.JOIN_ACTION.PROMPT:
                stomp_local = yield self.stomp_prompt, changed_bufs, missing_bufs, list(new_files), ignored
                if stomp_local not in [0, 1]:
                    self.stop()
                    return
            elif self.action == utils.JOIN_ACTION.DOWNLOAD:
                stomp_local = True
            else:
                # This should never happen
                assert False
                return

            if stomp_local:
                for buf in changed_bufs:
                    self.get_buf(buf['id'], buf.get('view'))
                    self.save_on_get_bufs.add(buf['id'])
                for buf in missing_bufs:
                    self.get_buf(buf['id'], buf.get('view'))
                    self.save_on_get_bufs.add(buf['id'])
            else:
                yield self._initial_upload, ig, missing_bufs, changed_bufs

        success_msg = 'Successfully joined workspace %s/%s' % (self.owner, self.workspace)
        msg.log(success_msg)
        editor.status_message(success_msg)

        data = utils.get_persistent_data()
        data['recent_workspaces'].insert(0, {"url": self.workspace_url})
        utils.update_persistent_data(data)
        utils.add_workspace_to_persistent_json(self.owner, self.workspace, self.workspace_url, G.PROJECT_PATH)

        temp_data = data.get('temp_data', {})
        hangout = temp_data.get('hangout', {})
        hangout_url = hangout.get('url')
        if hangout_url:
            self.prompt_join_hangout(hangout_url)

        self.emit("room_info")
Ejemplo n.º 47
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()
    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))
Ejemplo n.º 49
0
    def _on_room_info(self, data):
        self.joined_workspace = True
        self.workspace_info = data
        G.PERMS = data['perms']

        self.proto.reset_retries()

        if G.OUTBOUND_FILTERING:
            msg.error(
                'Detected outbound port blocking! See https://floobits.com/help/network for more info.'
            )

        read_only = False
        if 'patch' not in data['perms']:
            read_only = True
            no_perms_msg = '''You don't have permission to edit this workspace. All files will be read-only.'''
            msg.log('No patch permission. Setting buffers to read-only')
            if 'request_perm' in data['perms']:
                should_send = yield self.ok_cancel_dialog, no_perms_msg + '\nDo you want to request edit permission?'
                # TODO: wait for perms to be OK'd/denied before uploading or bailing
                if should_send:
                    self.send({
                        'name': 'request_perms',
                        'perms': ['edit_room']
                    })
            else:
                if G.EXPERT_MODE:
                    editor.status_message(no_perms_msg)
                else:
                    editor.error_message(no_perms_msg)

        floo_json = {
            'url':
            utils.to_workspace_url({
                'owner': self.owner,
                'workspace': self.workspace,
                'host': self.proto.host,
                'port': self.proto.port,
                'secure': self.proto.secure,
            })
        }
        utils.update_floo_file(os.path.join(G.PROJECT_PATH, '.floo'),
                               floo_json)
        utils.update_recent_workspaces(self.workspace_url)

        ig = ignore.create_ignore_tree(G.PROJECT_PATH)
        G.IGNORE = ig
        for buf_id, buf in data['bufs'].items():
            buf_id = int(buf_id)  # json keys must be strings
            self.bufs[buf_id] = buf
            self.paths_to_ids[buf['path']] = buf_id
        changed_bufs, missing_bufs, new_files = self._scan_dir(
            data['bufs'], ig, read_only)

        ignored = []
        for p, buf_id in self.paths_to_ids.items():
            if p not in new_files:
                ignored.append(p)
            new_files.discard(p)

        if self.action == utils.JOIN_ACTION.UPLOAD:
            yield self._initial_upload, ig, missing_bufs, changed_bufs
            # TODO: maybe use org name here
            who = 'Your friends'
            anon_perms = G.AGENT.workspace_info.get('anon_perms')
            if 'get_buf' in anon_perms:
                who = 'Anyone'
            _msg = 'You are sharing:\n\n%s\n\n%s can join your workspace at:\n\n%s' % (
                G.PROJECT_PATH, who, G.AGENT.workspace_url)
            # Workaround for horrible Sublime Text bug
            utils.set_timeout(editor.message_dialog, 0, _msg)
            # Don't auto-upload again on reconnect
            self.action = utils.JOIN_ACTION.PROMPT
        elif changed_bufs or missing_bufs or new_files:
            # TODO: handle readonly here
            if self.action == utils.JOIN_ACTION.PROMPT:
                stomp_local = yield self.stomp_prompt, changed_bufs, missing_bufs, list(
                    new_files), ignored
                if stomp_local not in [0, 1]:
                    self.stop()
                    return
            elif self.action == utils.JOIN_ACTION.DOWNLOAD:
                stomp_local = True
            else:
                # This should never happen
                assert False
                return

            if stomp_local:
                for buf in changed_bufs:
                    self.get_buf(buf['id'], buf.get('view'))
                    self.save_on_get_bufs.add(buf['id'])
                for buf in missing_bufs:
                    self.get_buf(buf['id'], buf.get('view'))
                    self.save_on_get_bufs.add(buf['id'])
            else:
                yield self._initial_upload, ig, missing_bufs, changed_bufs

        success_msg = '%s@%s/%s: Joined!' % (self.username, self.owner,
                                             self.workspace)
        msg.log(success_msg)
        editor.status_message(success_msg)

        data = utils.get_persistent_data()
        data['recent_workspaces'].insert(0, {"url": self.workspace_url})
        utils.update_persistent_data(data)
        utils.add_workspace_to_persistent_json(self.owner, self.workspace,
                                               self.workspace_url,
                                               G.PROJECT_PATH)

        temp_data = data.get('temp_data', {})
        hangout = temp_data.get('hangout', {})
        hangout_url = hangout.get('url')
        if hangout_url:
            self.prompt_join_hangout(hangout_url)

        if data.get('repo_info'):
            msg.log('Repo info:', data.get('repo_info'))
            # TODO: check local repo info and update remote (or prompt?)
        else:
            repo_info = repo.get_info(self.workspace_url, G.PROJECT_PATH)
            if repo_info and 'repo' in G.PERMS:
                self.send({
                    'name': 'repo',
                    'action': 'set',
                    'data': repo_info,
                })

        self.emit("room_info")
Ejemplo n.º 50
0
        return
    old_data = utils.get_persistent_data(old_path)
    data['workspaces'] = get_legacy_projects()
    data['recent_workspaces'] = old_data.get('recent_workspaces')
    utils.update_persistent_data(data)
    try:
        os.unlink(old_path)
        os.unlink(os.path.join(G.COLAB_DIR, 'msgs.floobits.log'))
    except Exception:
        pass
    print('migrated')


migrate_symlinks()

d = utils.get_persistent_data()
G.AUTO_GENERATED_ACCOUNT = d.get('auto_generated_account', False)


def get_active_window(cb):
    win = sublime.active_window()
    if not win:
        return utils.set_timeout(get_active_window, 50, cb)
    cb(win)


def create_or_link_account():
    agent = None
    account = sublime.ok_cancel_dialog(
        'You need a Floobits account!\n\n'
        'Click "Open browser" if you have one or click "cancel" and we\'ll make it for you.',
Ejemplo n.º 51
0
    def _on_room_info(self, data):
        self.reset()
        G.JOINED_WORKSPACE = True
        self.workspace_info = data
        G.PERMS = data['perms']

        if 'patch' not in data['perms']:
            msg.log('No patch permission. Setting buffers to read-only')
            should_send = yield self.ok_cancel_dialog, 'You don\'t have permission to edit this workspace. All files will be read-only.\n\nDo you want to request edit permission?'
            if should_send:
                self.send({'name': 'request_perms', 'perms': ['edit_room']})

        floo_json = {
            'url': utils.to_workspace_url({
                'owner': self.owner,
                'workspace': self.workspace,
                'host': self.proto.host,
                'port': self.proto.port,
                'secure': self.proto.secure,
            })
        }
        utils.update_floo_file(os.path.join(G.PROJECT_PATH, '.floo'), floo_json)

        changed_bufs = []
        missing_bufs = []
        for buf_id, buf in data['bufs'].items():
            buf_id = int(buf_id)  # json keys must be strings
            buf_path = utils.get_full_path(buf['path'])
            new_dir = os.path.dirname(buf_path)
            utils.mkdir(new_dir)
            self.bufs[buf_id] = buf
            self.paths_to_ids[buf['path']] = buf_id

            view = self.get_view(buf_id)
            if view and not view.is_loading() and buf['encoding'] == 'utf8':
                view_text = view.get_text()
                view_md5 = hashlib.md5(view_text.encode('utf-8')).hexdigest()
                if view_md5 == buf['md5']:
                    msg.debug('md5 sum matches view. not getting buffer %s' % buf['path'])
                    buf['buf'] = view_text
                    G.VIEW_TO_HASH[view.native_id] = view_md5
                elif self.should_get_bufs:
                    changed_bufs.append(buf_id)
            else:
                try:
                    buf_fd = open(buf_path, 'rb')
                    buf_buf = buf_fd.read()
                    md5 = hashlib.md5(buf_buf).hexdigest()
                    if md5 == buf['md5']:
                        msg.debug('md5 sum matches. not getting buffer %s' % buf['path'])
                        if buf['encoding'] == 'utf8':
                            buf_buf = buf_buf.decode('utf-8')
                        buf['buf'] = buf_buf
                    elif self.should_get_bufs:
                        changed_bufs.append(buf_id)
                except Exception as e:
                    msg.debug('Error calculating md5:', e)
                    missing_bufs.append(buf_id)

        if changed_bufs and self.should_get_bufs:
            if len(changed_bufs) > 4:
                prompt = '%s local files are different from the workspace. Overwrite your local files?' % len(changed_bufs)
            else:
                prompt = 'Overwrite the following local files?\n'
                for buf_id in changed_bufs:
                    prompt += '\n%s' % self.bufs[buf_id]['path']

            stomp_local = yield self.ok_cancel_dialog, prompt
            for buf_id in changed_bufs:
                if stomp_local:
                    self.get_buf(buf_id)
                    self.save_on_get_bufs.add(buf_id)
                else:
                    buf = self.bufs[buf_id]
                    # TODO: this is inefficient. we just read the file 20 lines ago
                    self.upload(utils.get_full_path(buf['path']))

        for buf_id in missing_bufs:
            self.get_buf(buf_id)

        success_msg = 'Successfully joined workspace %s/%s' % (self.owner, self.workspace)
        msg.log(success_msg)
        editor.status_message(success_msg)

        temp_data = data.get('temp_data', {})
        hangout = temp_data.get('hangout', {})
        hangout_url = hangout.get('url')
        if hangout_url:
            self.prompt_join_hangout(hangout_url)

        data = utils.get_persistent_data()
        data['recent_workspaces'].insert(0, {"url": self.workspace_url})
        utils.update_persistent_data(data)
        utils.add_workspace_to_persistent_json(self.owner, self.workspace, self.workspace_url, G.PROJECT_PATH)
        self.emit("room_info")
Ejemplo n.º 52
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):
            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]))
Ejemplo n.º 53
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 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))
    def _on_room_info(self, data):
        self.reset()
        G.JOINED_WORKSPACE = True
        self.workspace_info = data
        G.PERMS = data['perms']

        if 'patch' not in data['perms']:
            msg.log('No patch permission. Setting buffers to read-only')
            should_send = yield self.ok_cancel_dialog, '''You don't have permission to edit this workspace. All files will be read-only.
Do you want to request edit permission?'''
            if should_send:
                self.send({'name': 'request_perms', 'perms': ['edit_room']})

        floo_json = {
            'url': utils.to_workspace_url({
                'owner': self.owner,
                'workspace': self.workspace,
                'host': self.proto.host,
                'port': self.proto.port,
                'secure': self.proto.secure,
            })
        }
        utils.update_floo_file(os.path.join(G.PROJECT_PATH, '.floo'), floo_json)

        changed_bufs = []
        missing_bufs = []
        for buf_id, buf in data['bufs'].items():
            buf_id = int(buf_id)  # json keys must be strings
            buf_path = utils.get_full_path(buf['path'])
            new_dir = os.path.dirname(buf_path)
            utils.mkdir(new_dir)
            self.bufs[buf_id] = buf
            self.paths_to_ids[buf['path']] = buf_id

            view = self.get_view(buf_id)
            if view and not view.is_loading() and buf['encoding'] == 'utf8':
                view_text = view.get_text()
                view_md5 = hashlib.md5(view_text.encode('utf-8')).hexdigest()
                if view_md5 == buf['md5']:
                    msg.debug('md5 sum matches view. not getting buffer %s' % buf['path'])
                    buf['buf'] = view_text
                    G.VIEW_TO_HASH[view.native_id] = view_md5
                elif self.should_get_bufs:
                    changed_bufs.append(buf_id)
            else:
                try:
                    buf_fd = open(buf_path, 'rb')
                    buf_buf = buf_fd.read()
                    md5 = hashlib.md5(buf_buf).hexdigest()
                    if md5 == buf['md5']:
                        msg.debug('md5 sum matches. not getting buffer %s' % buf['path'])
                        if buf['encoding'] == 'utf8':
                            buf_buf = buf_buf.decode('utf-8')
                        buf['buf'] = buf_buf
                    elif self.should_get_bufs:
                        changed_bufs.append(buf_id)
                except Exception as e:
                    msg.debug('Error calculating md5:', e)
                    missing_bufs.append(buf_id)

        if changed_bufs and self.should_get_bufs:
            if len(changed_bufs) > 4:
                prompt = '%s local files are different from the workspace. Overwrite your local files?' % len(changed_bufs)
            else:
                prompt = 'Overwrite the following local files?\n'
                for buf_id in changed_bufs:
                    prompt += '\n%s' % self.bufs[buf_id]['path']

            stomp_local = yield self.ok_cancel_dialog, prompt
            for buf_id in changed_bufs:
                if stomp_local:
                    self.get_buf(buf_id)
                    self.save_on_get_bufs.add(buf_id)
                else:
                    buf = self.bufs[buf_id]
                    # TODO: this is inefficient. we just read the file 20 lines ago
                    self.upload(utils.get_full_path(buf['path']))

        for buf_id in missing_bufs:
            self.get_buf(buf_id)

        success_msg = 'Successfully joined workspace %s/%s' % (self.owner, self.workspace)
        msg.log(success_msg)
        editor.status_message(success_msg)

        temp_data = data.get('temp_data', {})
        hangout = temp_data.get('hangout', {})
        hangout_url = hangout.get('url')
        if hangout_url:
            self.prompt_join_hangout(hangout_url)

        data = utils.get_persistent_data()
        data['recent_workspaces'].insert(0, {"url": self.workspace_url})
        utils.update_persistent_data(data)
        utils.add_workspace_to_persistent_json(self.owner, self.workspace, self.workspace_url, G.PROJECT_PATH)
        self.emit("room_info")
Ejemplo n.º 55
0
    def _on_room_info(self, data):
        self.reset()
        self.joined_workspace = True
        self.workspace_info = data
        G.PERMS = data['perms']

        if 'patch' not in data['perms']:
            no_perms_msg = '''You don't have permission to edit this workspace. All files will be read-only.'''
            msg.log('No patch permission. Setting buffers to read-only')
            if 'request_perm' in data['perms']:
                should_send = yield self.ok_cancel_dialog, no_perms_msg + '\nDo you want to request edit permission?'
                if should_send:
                    self.send({
                        'name': 'request_perms',
                        'perms': ['edit_room']
                    })
            else:
                editor.error_message(no_perms_msg)

        floo_json = {
            'url':
            utils.to_workspace_url({
                'owner': self.owner,
                'workspace': self.workspace,
                'host': self.proto.host,
                'port': self.proto.port,
                'secure': self.proto.secure,
            })
        }
        utils.update_floo_file(os.path.join(G.PROJECT_PATH, '.floo'),
                               floo_json)

        changed_bufs = []
        missing_bufs = []
        for buf_id, buf in data['bufs'].items():
            buf_id = int(buf_id)  # json keys must be strings
            buf_path = utils.get_full_path(buf['path'])
            new_dir = os.path.dirname(buf_path)
            utils.mkdir(new_dir)
            self.bufs[buf_id] = buf
            self.paths_to_ids[buf['path']] = buf_id

            view = self.get_view(buf_id)
            if view and not view.is_loading() and buf['encoding'] == 'utf8':
                view_text = view.get_text()
                view_md5 = hashlib.md5(view_text.encode('utf-8')).hexdigest()
                buf['buf'] = view_text
                buf['view'] = view
                G.VIEW_TO_HASH[view.native_id] = view_md5
                if view_md5 == buf['md5']:
                    msg.debug('md5 sum matches view. not getting buffer %s' %
                              buf['path'])
                else:
                    changed_bufs.append(buf_id)
                    buf['md5'] = view_md5
            else:
                try:
                    if buf['encoding'] == "utf8":
                        if io:
                            buf_fd = io.open(buf_path, 'Urt', encoding='utf8')
                            buf_buf = buf_fd.read()
                        else:
                            buf_fd = open(buf_path, 'rb')
                            buf_buf = buf_fd.read().decode('utf-8').replace(
                                '\r\n', '\n')
                        md5 = hashlib.md5(buf_buf.encode('utf-8')).hexdigest()
                    else:
                        buf_fd = open(buf_path, 'rb')
                        buf_buf = buf_fd.read()
                        md5 = hashlib.md5(buf_buf).hexdigest()
                    buf_fd.close()
                    buf['buf'] = buf_buf
                    if md5 == buf['md5']:
                        msg.debug('md5 sum matches. not getting buffer %s' %
                                  buf['path'])
                    else:
                        msg.debug(
                            'md5 differs. possibly getting buffer later %s' %
                            buf['path'])
                        changed_bufs.append(buf_id)
                        buf['md5'] = md5
                except Exception as e:
                    msg.debug('Error calculating md5 for %s, %s' %
                              (buf['path'], e))
                    missing_bufs.append(buf_id)

        stomp_local = self.should_get_bufs
        if stomp_local and (changed_bufs or missing_bufs):
            changed = [self.bufs[buf_id] for buf_id in changed_bufs]
            missing = [self.bufs[buf_id] for buf_id in missing_bufs]
            choice = yield self.stomp_prompt, changed, missing
            if choice not in [0, 1]:
                self.stop()
                return
            stomp_local = bool(choice)

        for buf_id in changed_bufs:
            buf = self.bufs[buf_id]
            if stomp_local:
                self.get_buf(buf_id, buf.get('view'))
                self.save_on_get_bufs.add(buf_id)
            else:
                self._upload(utils.get_full_path(buf['path']), buf['buf'])

        for buf_id in missing_bufs:
            buf = self.bufs[buf_id]
            if stomp_local:
                self.get_buf(buf_id, buf.get('view'))
                self.save_on_get_bufs.add(buf_id)
            else:
                self.send({
                    'name': 'delete_buf',
                    'id': buf['id'],
                })

        success_msg = 'Successfully joined workspace %s/%s' % (self.owner,
                                                               self.workspace)
        msg.log(success_msg)
        editor.status_message(success_msg)

        temp_data = data.get('temp_data', {})
        hangout = temp_data.get('hangout', {})
        hangout_url = hangout.get('url')
        if hangout_url:
            self.prompt_join_hangout(hangout_url)

        data = utils.get_persistent_data()
        data['recent_workspaces'].insert(0, {"url": self.workspace_url})
        utils.update_persistent_data(data)
        utils.add_workspace_to_persistent_json(self.owner, self.workspace,
                                               self.workspace_url,
                                               G.PROJECT_PATH)
        self.emit("room_info")