def testCanIncreaseId(self):
     rm = RequestIdManager()
     _id1 = rm.new_id(self.view, None)
     _id2 = rm.new_id(self.view, None)
     _id3 = rm.new_id(self.view, None)
     self.assertEqual(_id1, '0')
     self.assertEqual(_id2, '1')
     self.assertEqual(_id3, '2')
 def testCanIncreaseId(self):
     rm = RequestIdManager()
     _id1 = rm.new_id(self.view, None)
     _id2 = rm.new_id(self.view, None)
     _id3 = rm.new_id(self.view, None)
     self.assertEqual(_id1, '0')
     self.assertEqual(_id2, '1')
     self.assertEqual(_id3, '2')
Exemple #3
0
 def __init__(self):
     self.roots = []
     self.priority_files = []
     self.requests = RequestsQueue('requests')
     self.responses = AnalyzerQueue('responses')
     self.request_ids = RequestIdManager()
Exemple #4
0
class AnalysisServer(object):
    MAX_ID = 9999999

    _request_id_lock = threading.Lock()
    _op_lock = threading.Lock()
    _write_lock = threading.Lock()

    _request_id = -1

    server = None

    def __init__(self):
        self.roots = []
        self.priority_files = []
        self.requests = RequestsQueue('requests')
        self.responses = AnalyzerQueue('responses')
        self.request_ids = RequestIdManager()

    @property
    def stdout(self):
        return AnalysisServer.server.proc.stdout

    @property
    def stdin(self):
        return AnalysisServer.server.proc.stdin

    def get_request_id(self, view, response_type):
        return self.request_ids.new_id(view, response_type)

    @staticmethod
    def ping():
        try:
            return AnalysisServer.server.is_running
        except AttributeError:
            return

    def start_handlers(self):
        reqh = RequestHandler(self)
        reqh.daemon = True
        reqh.start()

        resh = ResponseHandler(self)
        resh.daemon = True
        resh.start()

    @property
    def proc(self):
        return AnalysisServer.server

    def add_root(self, view, path):
        """
        Adds `path` to the monitored roots if it is unknown.

        If a `pubspec.yaml` is found in the path, its parent is monitored.
        Otherwise the passed-in directory name is monitored.

        @path
          Can be a directory or a file path.
        """

        if not path:
            _logger.debug('not a valid path: %s', path)
            return

        new_root_path = find_pubspec_path(path)
        if not new_root_path:
            # It seems we're not in a pub package, so we're probably looking
            # at a loose .dart file.
            new_root_path = os.path.dirname(path)
            _logger.debug('did not find pubspec.yaml in path: %s', path)
            _logger.debug('set root to: %s', new_root_path)

        with AnalysisServer._op_lock:
            if new_root_path not in self.roots:
                _logger.debug('adding new root: %s', new_root_path)
                self.roots.append(new_root_path)
                self.send_set_roots(view, self.roots)
                return

        _logger.debug('root already known: %s', new_root_path)

    def start(self):
        if AnalysisServer.ping():
            _logger.info('AnalysisServer is already running')
            return

        self.send_get_version()

        sdk = SDK()

        _logger.info('starting AnalysisServer')

        AnalysisServer.server = PipeServer([
            sdk.path_to_dart,
            sdk.path_to_analysis_snapshot,
            '--sdk={0}'.format(sdk.path),
            '--file-read-mode normalize-eol-always',
        ])

        def do_start():
            try:
                AnalysisServer.server.start(working_dir=sdk.path)
                self.start_handlers()
                self.start_stdout_watcher()
            except Exception as e:
                _logger.error('could not start server properly')
                _logger.error(e)
                return

        threading.Thread(target=do_start).start()

    def start_stdout_watcher(self):
        sdk = SDK()
        t = StdoutWatcher(self, sdk.path)
        # Thread dies with the main thread.
        t.daemon = True
        t.start()

    def stop(self):
        req = requests.shut_down(str(AnalysisServer.MAX_ID + 100))
        self.requests.put(req, priority=TaskPriority.HIGHEST, block=False)
        self.requests.put({'_internal': _SIGNAL_STOP}, block=False)
        self.responses.put({'_internal': _SIGNAL_STOP}, block=False)
        # self.server.stop()

    def write(self, data):
        with AnalysisServer._write_lock:
            data = (json.dumps(data) + '\n').encode('utf-8')
            _logger.debug('writing to stdin: %s', data)
            self.stdin.write(data)
            self.stdin.flush()

    def send_set_roots(self, view, included=[], excluded=[]):
        included = [f for f in included if not self.should_ignore_file(f)]

        if not (included or excluded):
            return

        req = AnalysisSetAnalysisRootsParams(included, excluded)
        _logger.info('sending set_roots request')
        self.requests.put(req.to_request(
            self.get_request_id(view, AnalysisSetAnalysisRootsResult)),
                          block=False)

    def send_get_version(self, view=None):
        view = get_active_view()
        req = ServerGetVersionParams().to_request(
            self.get_request_id(view, ServerGetVersionResult))
        _logger.info('sending get version request')
        self.requests.put(req, block=False)

    def send_add_content(self, view):
        if self.should_ignore_file(view.file_name()):
            return

        content = view.substr(sublime.Region(0, view.size()))
        req = AnalysisUpdateContentParams(
            {view.file_name(): AddContentOverlay(content)})
        _logger.info('sending update content request - add')
        # track this type of req as it may expire
        # TODO: when this file is saved, we must remove the overlays.
        self.requests.put(req.to_request(
            self.get_request_id(view, AnalysisUpdateContentResult)),
                          view=view,
                          priority=TaskPriority.HIGH,
                          block=False)

    def send_remove_content(self, view):
        if self.should_ignore_file(view.file_name()):
            return

        req = AnalysisUpdateContentParams(
            {view.file_name(): RemoveContentOverlay()})
        _logger.info('sending update content request - delete')
        self.requests.put(req.to_request(
            self.get_request_id(view, AnalysisUpdateContentResult)),
                          view=view,
                          priority=TaskPriority.HIGH,
                          block=False)

    def send_set_priority_files(self, view, files):
        if files == self.priority_files:
            return

        definite_files = [f for f in files if not self.should_ignore_file(f)]
        if not definite_files:
            return

        req = AnalysisSetPriorityFilesParams(definite_files)
        self.requests.put(req.to_request(
            self.get_request_id(view, AnalysisSetPriorityFilesResult)),
                          priority=TaskPriority.HIGH,
                          block=False)

        req2 = AnalysisSetSubscriptionsParams(
            {AnalysisService.NAVIGATION: definite_files})
        self.requests.put(req2.to_request(
            self.get_request_id(view, ServerSetSubscriptionsResult)),
                          priority=TaskPriority.HIGH,
                          block=False)

    def send_get_suggestions(self, view, file, offset):
        new_id = self.get_request_id(view, CompletionGetSuggestionsResult)

        with editor_context.autocomplete_context as actx:
            actx.invalidate()
            actx.request_id = new_id

        req = CompletionGetSuggestionsParams(file, offset)
        req = req.to_request(new_id)

        self.requests.put(req, priority=TaskPriority.HIGH, block=False)

    def send_format_file(self, view):
        new_id = self.get_request_id(view, EditFormatResult)

        if not view.file_name():
            _logger.info(
                "aborting sending request for formatting - no file name")
            return

        r0 = None
        try:
            r0 = view.sel()[0]
        except IndexError:
            r0 = sublime.Region(0)

        # TODO: Implement lineLength parameter.
        req = EditFormatParams(view.file_name(), r0.begin(), r0.size())
        req = req.to_request(new_id)

        _logger.info("now sending request for formatting")
        self.requests.put(req, priority=TaskPriority.HIGH, block=False)

    def should_ignore_file(self, path):
        project = DartProject.from_path(path)
        is_a_third_party_file = (project and is_path_under(
            project.path_to_packages, path))

        if is_a_third_party_file:
            return True

        sdk = SDK()
        return is_path_under(sdk.path, path)
 def testValidateCanFail(self):
     rm = RequestIdManager()
     _id = rm.new_id(self.view, int)
     self.assertFalse(rm.validate(self.view, {'id': '1'}))
 def testValidationCanSucceed(self):
     rm = RequestIdManager()
     _id = rm.new_id(self.view, int)
     self.assertTrue(rm.validate(self.view, {'id': '0'}))
 def testCanRetrieveResponseType(self):
     rm = RequestIdManager()
     _id = rm.new_id(self.view, int)
     self.assertEqual(rm.get_response_type(self.view, '0'), int)
 def testIdsWrapAround(self):
     rm = RequestIdManager()
     rm._id = 1 << 10
     _id = rm.new_id(self.view, None)
     self.assertEqual(_id, '0')
 def testValidateCanFail(self):
     rm = RequestIdManager()
     _id = rm.new_id(self.view, int)
     self.assertFalse(rm.validate(self.view, {'id': '1'}))
 def testValidationCanSucceed(self):
     rm = RequestIdManager()
     _id = rm.new_id(self.view, int)
     self.assertTrue(rm.validate(self.view, {'id': '0'}))
 def testCanRetrieveResponseType(self):
     rm = RequestIdManager()
     _id = rm.new_id(self.view, int)
     self.assertEqual(rm.get_response_type(self.view, '0'), int)
 def testIdsWrapAround(self):
     rm = RequestIdManager()
     rm._id = 1 << 10
     _id = rm.new_id(self.view, None)
     self.assertEqual(_id, '0')
 def __init__(self):
     self.roots = []
     self.priority_files = []
     self.requests = RequestsQueue('requests')
     self.responses = AnalyzerQueue('responses')
     self.request_ids = RequestIdManager()
class AnalysisServer(object):
    MAX_ID = 9999999

    _request_id_lock = threading.Lock()
    _op_lock = threading.Lock()
    _write_lock = threading.Lock()

    _request_id = -1

    server = None

    def __init__(self):
        self.roots = []
        self.priority_files = []
        self.requests = RequestsQueue('requests')
        self.responses = AnalyzerQueue('responses')
        self.request_ids = RequestIdManager()

    @property
    def stdout(self):
        return AnalysisServer.server.proc.stdout

    @property
    def stdin(self):
        return AnalysisServer.server.proc.stdin

    def get_request_id(self, view, response_type):
        return self.request_ids.new_id(view, response_type)

    @staticmethod
    def ping():
        try:
            return AnalysisServer.server.is_running
        except AttributeError:
            return

    def start_handlers(self):
        reqh = RequestHandler(self)
        reqh.daemon = True
        reqh.start()

        resh = ResponseHandler(self)
        resh.daemon = True
        resh.start()

    @property
    def proc(self):
        return AnalysisServer.server

    def add_root(self, view, path):
        """
        Adds `path` to the monitored roots if it is unknown.

        If a `pubspec.yaml` is found in the path, its parent is monitored.
        Otherwise the passed-in directory name is monitored.

        @path
          Can be a directory or a file path.
        """

        if not path:
            _logger.debug('not a valid path: %s', path)
            return

        new_root_path = find_pubspec_path(path)
        if not new_root_path:
            # It seems we're not in a pub package, so we're probably looking
            # at a loose .dart file.
            new_root_path = os.path.dirname(path)
            _logger.debug('did not find pubspec.yaml in path: %s', path)
            _logger.debug('set root to: %s', new_root_path)

        with AnalysisServer._op_lock:
            if new_root_path not in self.roots:
                _logger.debug('adding new root: %s', new_root_path)
                self.roots.append(new_root_path)
                self.send_set_roots(view, self.roots)
                return

        _logger.debug('root already known: %s', new_root_path)

    def start(self):
        if AnalysisServer.ping():
            _logger.info('AnalysisServer is already running')
            return

        self.send_get_version()

        sdk = SDK()

        _logger.info('starting AnalysisServer')

        AnalysisServer.server = PipeServer([sdk.path_to_dart,
                sdk.path_to_analysis_snapshot,
               '--sdk={0}'.format(sdk.path),
               '--file-read-mode normalize-eol-always',
               ])

        def do_start():
            try:
                AnalysisServer.server.start(working_dir=sdk.path)
                self.start_handlers()
                self.start_stdout_watcher()
            except Exception as e:
                _logger.error('could not start server properly')
                _logger.error(e)
                return

        threading.Thread(target=do_start).start()

    def start_stdout_watcher(self):
        sdk = SDK()
        t = StdoutWatcher(self, sdk.path)
        # Thread dies with the main thread.
        t.daemon = True
        t.start()

    def stop(self):
        req = requests.shut_down(str(AnalysisServer.MAX_ID + 100))
        self.requests.put(req, priority=TaskPriority.HIGHEST, block=False)
        self.requests.put({'_internal': _SIGNAL_STOP}, block=False)
        self.responses.put({'_internal': _SIGNAL_STOP}, block=False)
        # self.server.stop()

    def write(self, data):
        with AnalysisServer._write_lock:
            data = (json.dumps(data) + '\n').encode('utf-8')
            _logger.debug('writing to stdin: %s', data)
            self.stdin.write(data)
            self.stdin.flush()

    def send_set_roots(self, view, included=[], excluded=[]):
        included = [f for f in included if not self.should_ignore_file(f)]

        if not (included or excluded):
            return

        req = AnalysisSetAnalysisRootsParams(included, excluded)
        _logger.info('sending set_roots request')
        self.requests.put(req.to_request(self.get_request_id(view,
                AnalysisSetAnalysisRootsResult)), block=False)

    def send_get_version(self, view=None):
        view = get_active_view()
        req = ServerGetVersionParams().to_request(
                self.get_request_id(view, ServerGetVersionResult))
        _logger.info('sending get version request')
        self.requests.put(req, block=False)

    def send_add_content(self, view):
        if self.should_ignore_file(view.file_name()):
            return

        content = view.substr(sublime.Region(0, view.size()))
        req = AnalysisUpdateContentParams({view.file_name(): AddContentOverlay(content)})
        _logger.info('sending update content request - add')
        # track this type of req as it may expire
        # TODO: when this file is saved, we must remove the overlays.
        self.requests.put(req.to_request(self.get_request_id(view, AnalysisUpdateContentResult)),
                          view=view,
                          priority=TaskPriority.HIGH,
                          block=False)

    def send_remove_content(self, view):
        if self.should_ignore_file(view.file_name()):
            return

        req = AnalysisUpdateContentParams({view.file_name(): RemoveContentOverlay()})
        _logger.info('sending update content request - delete')
        self.requests.put(req.to_request(self.get_request_id(view, AnalysisUpdateContentResult)),
                view=view,
                priority=TaskPriority.HIGH,
                block=False)

    def send_set_priority_files(self, view, files):
        if files == self.priority_files:
            return

        definite_files = [f for f in files if not self.should_ignore_file(f)]
        if not definite_files:
            return

        req = AnalysisSetPriorityFilesParams(definite_files)
        self.requests.put(req.to_request(self.get_request_id(view, AnalysisSetPriorityFilesResult)),
                priority=TaskPriority.HIGH, block=False)

        req2 = AnalysisSetSubscriptionsParams({AnalysisService.NAVIGATION: definite_files})
        self.requests.put(req2.to_request(self.get_request_id(view,
                ServerSetSubscriptionsResult)),
                priority=TaskPriority.HIGH,
                block=False)

    def send_get_suggestions(self, view, file, offset):
        new_id = self.get_request_id(view, CompletionGetSuggestionsResult)

        with editor_context.autocomplete_context as actx:
            actx.invalidate()
            actx.request_id = new_id

        req = CompletionGetSuggestionsParams(file, offset)
        req = req.to_request(new_id)

        self.requests.put(req, priority=TaskPriority.HIGH, block=False)

    def send_format_file(self, view):
        new_id = self.get_request_id(view, EditFormatResult)

        if not view.file_name():
            _logger.info("aborting sending request for formatting - no file name")
            return

        r0 = None
        try:
            r0 = view.sel()[0]
        except IndexError:
            r0 = sublime.Region(0)

        # TODO: Implement lineLength parameter.
        req = EditFormatParams(view.file_name(), r0.begin(), r0.size())
        req = req.to_request(new_id)

        _logger.info("now sending request for formatting")
        self.requests.put(req, priority=TaskPriority.HIGH, block=False)

    def should_ignore_file(self, path):
        project = DartProject.from_path(path)
        is_a_third_party_file = (project and is_path_under(project.path_to_packages, path))

        if is_a_third_party_file:
            return True

        sdk = SDK()
        return is_path_under(sdk.path, path)