def InstallGagdet(name, gadget, succeeded, failed, all_adapters): try: print(f"Installing {name}...") v = {} v.update(gadget.get('all', {})) v.update(gadget.get(install.GetOS(), {})) if 'download' in gadget: if 'file_name' not in v: raise RuntimeError("Unsupported OS {} for gadget {}".format( install.GetOS(), name)) destination = os.path.join( install.GetGadgetDir(options.vimspector_base), 'download', name, v['version']) url = string.Template(gadget['download']['url']).substitute(v) file_path = DownloadFileTo( url, destination, file_name=gadget['download'].get('target'), checksum=v.get('checksum'), check_certificate=not options.no_check_certificate) root = os.path.join(destination, 'root') ExtractZipTo(file_path, root, format=gadget['download'].get('format', 'zip')) elif 'repo' in gadget: url = string.Template(gadget['repo']['url']).substitute(v) ref = string.Template(gadget['repo']['ref']).substitute(v) destination = os.path.join( install.GetGadgetDir(options.vimspector_base), 'download', name) CloneRepoTo(url, ref, destination) root = destination if 'do' in gadget: gadget['do'](name, root, v) else: InstallGeneric(name, root, v) # Allow per-OS adapter overrides. v already did that for us... all_adapters.update(v.get('adapters', {})) # Add any other "all" adapters all_adapters.update(gadget.get('adapters', {})) succeeded.append(name) print(f" - Done installing {name}") except Exception as e: if not options.quiet: traceback.print_exc() failed.append(name) print(f" - FAILED installing {name}: {e}".format(name, e))
def __init__(self, api_prefix): self._logger = logging.getLogger(__name__) utils.SetUpLogging(self._logger) self._api_prefix = api_prefix self._logger.info("**** INITIALISING NEW VIMSPECTOR SESSION ****") self._logger.info("API is: {}".format(api_prefix)) self._logger.info('VIMSPECTOR_HOME = %s', VIMSPECTOR_HOME) self._logger.info('gadgetDir = %s', install.GetGadgetDir(VIMSPECTOR_HOME)) self._uiTab = None self._logView = None self._stackTraceView = None self._variablesView = None self._outputView = None self._breakpoints = breakpoints.ProjectBreakpoints() self._splash_screen = None self._remote_term = None self._run_on_server_exit = None self._configuration = None self._adapter = None self._ResetServerState()
def SetUpDebugpy(wait=False, port=5678): sys.path.insert( 1, os.path.join(install.GetGadgetDir(utils.GetVimspectorBase()), 'debugpy', 'build', 'lib')) import debugpy exe = sys.executable try: # debugpy uses sys.executable (which is `vim`, so we hack it) sys.executable = installer.PathToAnyWorkingPython3() debugpy.listen(port) finally: sys.executable = exe if wait: debugpy.wait_for_client()
def __init__(self): self._logger = logging.getLogger(__name__) utils.SetUpLogging(self._logger) self._logger.info('VIMSPECTOR_HOME = %s', VIMSPECTOR_HOME) self._logger.info( 'gadgetDir = %s', install.GetGadgetDir(VIMSPECTOR_HOME, install.GetOS())) self._uiTab = None self._stackTraceView = None self._variablesView = None self._outputView = None self._breakpoints = breakpoints.ProjectBreakpoints() self._run_on_server_exit = None self._ResetServerState()
def MakeSymlink(link, pointing_to, in_folder=None): if not in_folder: in_folder = install.GetGadgetDir(options.vimspector_base) RemoveIfExists(os.path.join(in_folder, link)) in_folder = os.path.abspath(in_folder) pointing_to_relative = os.path.relpath(os.path.abspath(pointing_to), in_folder) link_path = os.path.join(in_folder, link) if install.GetOS() == 'windows': # While symlinks do exist on Windows, they require elevated privileges, so # let's use a directory junction which is all we need. link_path = os.path.abspath(link_path) if os.path.isdir(link_path): os.rmdir(link_path) CheckCall(['cmd.exe', '/c', 'mklink', '/J', link_path, pointing_to]) else: os.symlink(pointing_to_relative, link_path)
def Start(self, launch_variables=None): # We mutate launch_variables, so don't mutate the default argument. # https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments if launch_variables is None: launch_variables = {} self._logger.info("User requested start debug session with %s", launch_variables) self._configuration = None self._adapter = None current_file = utils.GetBufferFilepath(vim.current.buffer) filetypes = utils.GetBufferFiletypes(vim.current.buffer) configurations = {} adapters = {} glob.glob(install.GetGadgetDir(VIMSPECTOR_HOME, install.GetOS())) for gadget_config_file in PathsToAllGadgetConfigs( VIMSPECTOR_HOME, current_file): self._logger.debug(f'Reading gadget config: {gadget_config_file}') if not gadget_config_file or not os.path.exists( gadget_config_file): continue with open(gadget_config_file, 'r') as f: adapters.update(json.load(f).get('adapters') or {}) for launch_config_file in PathsToAllConfigFiles( VIMSPECTOR_HOME, current_file, filetypes): self._logger.debug( f'Reading configurations from: {launch_config_file}') if not launch_config_file or not os.path.exists( launch_config_file): continue with open(launch_config_file, 'r') as f: database = json.load(f) adapters.update(database.get('adapters') or {}) configurations.update(database.get('configurations' or {})) if not configurations: utils.UserMessage('Unable to find any debug configurations. ' 'You need to tell vimspector how to launch your ' 'application.') return if 'configuration' in launch_variables: configuration_name = launch_variables.pop('configuration') elif len(configurations) == 1: configuration_name = next(iter(configurations.keys())) else: configuration_name = utils.SelectFromList( 'Which launch configuration?', sorted(configurations.keys())) if not configuration_name or configuration_name not in configurations: return if launch_config_file: self._workspace_root = os.path.dirname(launch_config_file) else: self._workspace_root = os.path.dirname(current_file) configuration = configurations[configuration_name] adapter = configuration.get('adapter') if isinstance(adapter, str): adapter = adapters.get(adapter) # TODO: Do we want some form of persistence ? e.g. self._staticVariables, # set from an api call like SetLaunchParam( 'var', 'value' ), perhaps also a # way to load .vimspector.local.json which just sets variables # # Additional vars as defined by VSCode: # # ${workspaceFolder} - the path of the folder opened in VS Code # ${workspaceFolderBasename} - the name of the folder opened in VS Code # without any slashes (/) # ${file} - the current opened file # ${relativeFile} - the current opened file relative to workspaceFolder # ${fileBasename} - the current opened file's basename # ${fileBasenameNoExtension} - the current opened file's basename with no # file extension # ${fileDirname} - the current opened file's dirname # ${fileExtname} - the current opened file's extension # ${cwd} - the task runner's current working directory on startup # ${lineNumber} - the current selected line number in the active file # ${selectedText} - the current selected text in the active file # ${execPath} - the path to the running VS Code executable def relpath(p, relative_to): if not p: return '' return os.path.relpath(p, relative_to) def splitext(p): if not p: return ['', ''] return os.path.splitext(p) self._variables = { 'dollar': '$', # HACK. Hote '$$' also works. 'workspaceRoot': self._workspace_root, 'workspaceFolder': self._workspace_root, 'gadgetDir': install.GetGadgetDir(VIMSPECTOR_HOME, install.GetOS()), 'file': current_file, 'relativeFile': relpath(current_file, self._workspace_root), 'fileBasename': os.path.basename(current_file), 'fileBasenameNoExtension': splitext(os.path.basename(current_file))[0], 'fileDirname': os.path.dirname(current_file), 'fileExtname': splitext(os.path.basename(current_file))[1], # NOTE: this is the window-local cwd for the current window, *not* Vim's # working directory. 'cwd': os.getcwd(), } # Pretend that vars passed to the launch command were typed in by the user # (they may have been in theory) USER_CHOICES.update(launch_variables) self._variables.update(launch_variables) self._variables.update( utils.ParseVariables(adapter.get('variables', {}), self._variables, USER_CHOICES)) self._variables.update( utils.ParseVariables(configuration.get('variables', {}), self._variables, USER_CHOICES)) utils.ExpandReferencesInDict(configuration, self._variables, USER_CHOICES) utils.ExpandReferencesInDict(adapter, self._variables, USER_CHOICES) if not adapter: utils.UserMessage( 'No adapter configured for {}'.format(configuration_name), persist=True) return self._StartWithConfiguration(configuration, adapter)
gadget['do'](name, root, v) else: installer.MakeExtensionSymlink(vimspector_base, name, root) all_adapters.update(gadget.get('adapters', {})) print("Done installing {}".format(name)) except Exception as e: traceback.print_exc() failed.append(name) print("FAILED installing {}: {}".format(name, e)) vimspector_base = os.path.dirname(__file__) OS = install.GetOS() gadget_dir = install.GetGadgetDir(vimspector_base, OS) print('OS = ' + OS) print('gadget_dir = ' + gadget_dir) parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, description='Install DAP Servers for use with Vimspector.', epilog=""" If you're not sure, normally --all is enough to get started. Custom server definitions can be defined in JSON files, allowing installation of arbitrary servers packaged in one of the ways that this installer understands. The format of the file can be found on the Vimspector reference guide:
def Start(self, launch_variables=None): # We mutate launch_variables, so don't mutate the default argument. # https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments if launch_variables is None: launch_variables = {} self._logger.info("User requested start debug session with %s", launch_variables) self._configuration = None self._adapter = None current_file = utils.GetBufferFilepath(vim.current.buffer) filetypes = utils.GetBufferFiletypes(vim.current.buffer) configurations = {} adapters = {} glob.glob(install.GetGadgetDir(VIMSPECTOR_HOME)) for gadget_config_file in PathsToAllGadgetConfigs( VIMSPECTOR_HOME, current_file): self._logger.debug(f'Reading gadget config: {gadget_config_file}') if not gadget_config_file or not os.path.exists( gadget_config_file): continue with open(gadget_config_file, 'r') as f: a = json.loads(minify(f.read())).get('adapters') or {} adapters.update(a) for launch_config_file in PathsToAllConfigFiles( VIMSPECTOR_HOME, current_file, filetypes): self._logger.debug( f'Reading configurations from: {launch_config_file}') if not launch_config_file or not os.path.exists( launch_config_file): continue with open(launch_config_file, 'r') as f: database = json.loads(minify(f.read())) adapters.update(database.get('adapters') or {}) configurations.update(database.get('configurations' or {})) if not configurations: utils.UserMessage('Unable to find any debug configurations. ' 'You need to tell vimspector how to launch your ' 'application.') return if 'configuration' in launch_variables: configuration_name = launch_variables.pop('configuration') elif (len(configurations) == 1 and next(iter(configurations.values())).get("autoselect", True)): configuration_name = next(iter(configurations.keys())) else: # Find a single configuration with 'default' True and autoselect not False defaults = { n: c for n, c in configurations.items() if c.get('default', False) is True and c.get('autoselect', True) is not False } if len(defaults) == 1: configuration_name = next(iter(defaults.keys())) else: configuration_name = utils.SelectFromList( 'Which launch configuration?', sorted(configurations.keys())) if not configuration_name or configuration_name not in configurations: return if launch_config_file: self._workspace_root = os.path.dirname(launch_config_file) else: self._workspace_root = os.path.dirname(current_file) configuration = configurations[configuration_name] adapter = configuration.get('adapter') if isinstance(adapter, str): adapter_dict = adapters.get(adapter) if adapter_dict is None: suggested_gadgets = installer.FindGadgetForAdapter(adapter) if suggested_gadgets: response = utils.AskForInput( f"The specified adapter '{adapter}' is not " "installed. Would you like to install the following gadgets? ", ' '.join(suggested_gadgets)) if response: new_launch_variables = dict(launch_variables) new_launch_variables[ 'configuration'] = configuration_name installer.RunInstaller( self._api_prefix, False, # Don't leave open *shlex.split(response), then=lambda: self.Start(new_launch_variables)) return elif response is None: return utils.UserMessage( f"The specified adapter '{adapter}' is not " "available. Did you forget to run " "'install_gadget.py'?", persist=True, error=True) return adapter = adapter_dict # Additional vars as defined by VSCode: # # ${workspaceFolder} - the path of the folder opened in VS Code # ${workspaceFolderBasename} - the name of the folder opened in VS Code # without any slashes (/) # ${file} - the current opened file # ${relativeFile} - the current opened file relative to workspaceFolder # ${fileBasename} - the current opened file's basename # ${fileBasenameNoExtension} - the current opened file's basename with no # file extension # ${fileDirname} - the current opened file's dirname # ${fileExtname} - the current opened file's extension # ${cwd} - the task runner's current working directory on startup # ${lineNumber} - the current selected line number in the active file # ${selectedText} - the current selected text in the active file # ${execPath} - the path to the running VS Code executable def relpath(p, relative_to): if not p: return '' return os.path.relpath(p, relative_to) def splitext(p): if not p: return ['', ''] return os.path.splitext(p) variables = { 'dollar': '$', # HACK. Hote '$$' also works. 'workspaceRoot': self._workspace_root, 'workspaceFolder': self._workspace_root, 'gadgetDir': install.GetGadgetDir(VIMSPECTOR_HOME), 'file': current_file, } calculus = { 'relativeFile': lambda: relpath(current_file, self._workspace_root), 'fileBasename': lambda: os.path.basename(current_file), 'fileBasenameNoExtension': lambda: splitext(os.path.basename(current_file))[0], 'fileDirname': lambda: os.path.dirname(current_file), 'fileExtname': lambda: splitext(os.path.basename(current_file))[1], # NOTE: this is the window-local cwd for the current window, *not* Vim's # working directory. 'cwd': os.getcwd, 'unusedLocalPort': utils.GetUnusedLocalPort, } # Pretend that vars passed to the launch command were typed in by the user # (they may have been in theory) USER_CHOICES.update(launch_variables) variables.update(launch_variables) try: variables.update( utils.ParseVariables(adapter.get('variables', {}), variables, calculus, USER_CHOICES)) variables.update( utils.ParseVariables(configuration.get('variables', {}), variables, calculus, USER_CHOICES)) utils.ExpandReferencesInDict(configuration, variables, calculus, USER_CHOICES) utils.ExpandReferencesInDict(adapter, variables, calculus, USER_CHOICES) except KeyboardInterrupt: self._Reset() return if not adapter: utils.UserMessage( 'No adapter configured for {}'.format(configuration_name), persist=True) return self._StartWithConfiguration(configuration, adapter)
def InstallGagdet(name: str, gadget: dict, manifest: Manifest, succeeded: list, failed: list, all_adapters: dict): try: # Spec is an os-specific definition of the gadget spec = {} spec.update(gadget.get('all', {})) spec.update(gadget.get(install.GetOS(), {})) def save_adapters(): # allow per-os adapter overrides. v already did that for us... all_adapters.update(spec.get('adapters', {})) # add any other "all" adapters all_adapters.update(gadget.get('adapters', {})) if 'download' in gadget: if 'file_name' not in spec: raise RuntimeError("Unsupported OS {} for gadget {}".format( install.GetOS(), name)) print(f"Installing {name}@{spec[ 'version' ]}...") spec['download'] = gadget['download'] if not manifest.RequiresUpdate(name, spec): save_adapters() print(" - Skip - up to date") return destination = os.path.join( install.GetGadgetDir(options.vimspector_base), 'download', name, spec['version']) url = string.Template(gadget['download']['url']).substitute(spec) file_path = DownloadFileTo( url, destination, file_name=gadget['download'].get('target'), checksum=spec.get('checksum'), check_certificate=not options.no_check_certificate) root = os.path.join(destination, 'root') ExtractZipTo(file_path, root, format=gadget['download'].get('format', 'zip')) elif 'repo' in gadget: url = string.Template(gadget['repo']['url']).substitute(spec) ref = string.Template(gadget['repo']['ref']).substitute(spec) print(f"Installing {name}@{ref}...") spec['repo'] = gadget['repo'] if not manifest.RequiresUpdate(name, spec): save_adapters() print(" - Skip - up to date") return destination = os.path.join( install.GetGadgetDir(options.vimspector_base), 'download', name) CloneRepoTo(url, ref, destination) root = destination if 'do' in gadget: gadget['do'](name, root, spec) else: InstallGeneric(name, root, spec) save_adapters() manifest.Update(name, spec) succeeded.append(name) print(f" - Done installing {name}") except Exception as e: if not options.quiet: traceback.print_exc() failed.append(name) print(f" - FAILED installing {name}: {e}".format(name, e))
def MakeSymlink(in_folder, link, pointing_to): RemoveIfExists(os.path.join(in_folder, link)) in_folder = os.path.abspath(in_folder) pointing_to = os.path.relpath(os.path.abspath(pointing_to), in_folder) os.symlink(pointing_to, os.path.join(in_folder, link)) def CloneRepoTo(url, ref, destination): RemoveIfExists(destination) subprocess.check_call(['git', 'clone', url, destination]) subprocess.check_call(['git', '-C', destination, 'checkout', ref]) OS = install.GetOS() gadget_dir = install.GetGadgetDir(os.path.dirname(__file__), OS) print('OS = ' + OS) print('gadget_dir = ' + gadget_dir) parser = argparse.ArgumentParser() parser.add_argument('--all', action='store_true', help='Enable all completers') done_languages = set() for name, gadget in GADGETS.items(): lang = gadget['language'] if lang in done_languages: continue done_languages.add(lang) if not gadget.get('enabled', True):
def Start(self, launch_variables={}): self._configuration = None self._adapter = None launch_config_file = utils.PathToConfigFile('.vimspector.json') if not launch_config_file: utils.UserMessage( 'Unable to find .vimspector.json. You need to tell ' 'vimspector how to launch your application') return with open(launch_config_file, 'r') as f: database = json.load(f) configurations = database.get('configurations') adapters = {} for gadget_config_file in [ install.GetGadgetConfigFile(VIMSPECTOR_HOME), utils.PathToConfigFile('.gadgets.json') ]: if gadget_config_file and os.path.exists(gadget_config_file): with open(gadget_config_file, 'r') as f: adapters.update(json.load(f).get('adapters') or {}) adapters.update(database.get('adapters') or {}) if len(configurations) == 1: configuration_name = next(iter(configurations.keys())) else: configuration_name = utils.SelectFromList( 'Which launch configuration?', sorted(list(configurations.keys()))) if not configuration_name or configuration_name not in configurations: return self._workspace_root = os.path.dirname(launch_config_file) configuration = configurations[configuration_name] adapter = configuration.get('adapter') if isinstance(adapter, str): adapter = adapters.get(adapter) # TODO: Do we want some form of persistence ? e.g. self._staticVariables, # set from an api call like SetLaunchParam( 'var', 'value' ), perhaps also a # way to load .vimspector.local.json which just sets variables self._variables = { 'dollar': '$', # HACK. Hote '$$' also works. 'workspaceRoot': self._workspace_root, 'gadgetDir': install.GetGadgetDir(VIMSPECTOR_HOME, install.GetOS()) } self._variables.update( utils.ParseVariables(adapter.get('variables', {}))) self._variables.update( utils.ParseVariables(configuration.get('variables', {}))) self._variables.update(launch_variables) utils.ExpandReferencesInDict(configuration, self._variables) utils.ExpandReferencesInDict(adapter, self._variables) if not adapter: utils.UserMessage( 'No adapter configured for {}'.format(configuration_name), persist=True) return self._StartWithConfiguration(configuration, adapter)
def MakeExtensionSymlink( vimspector_base, name, root ): MakeSymlink( install.GetGadgetDir( vimspector_base, install.GetOS() ), name, os.path.join( root, 'extension' ) ),
def Start( self, launch_variables = {} ): self._logger.info( "User requested start debug session with %s", launch_variables ) self._configuration = None self._adapter = None launch_config_file = utils.PathToConfigFile( '.vimspector.json' ) if not launch_config_file: utils.UserMessage( 'Unable to find .vimspector.json. You need to tell ' 'vimspector how to launch your application' ) return with open( launch_config_file, 'r' ) as f: database = json.load( f ) configurations = database.get( 'configurations' ) adapters = {} for gadget_config_file in [ install.GetGadgetConfigFile( VIMSPECTOR_HOME ), utils.PathToConfigFile( '.gadgets.json' ) ]: if gadget_config_file and os.path.exists( gadget_config_file ): with open( gadget_config_file, 'r' ) as f: adapters.update( json.load( f ).get( 'adapters' ) or {} ) adapters.update( database.get( 'adapters' ) or {} ) if len( configurations ) == 1: configuration_name = next( iter( configurations.keys() ) ) else: configuration_name = utils.SelectFromList( 'Which launch configuration?', sorted( list( configurations.keys() ) ) ) if not configuration_name or configuration_name not in configurations: return self._workspace_root = os.path.dirname( launch_config_file ) configuration = configurations[ configuration_name ] adapter = configuration.get( 'adapter' ) if isinstance( adapter, str ): adapter = adapters.get( adapter ) # TODO: Do we want some form of persistence ? e.g. self._staticVariables, # set from an api call like SetLaunchParam( 'var', 'value' ), perhaps also a # way to load .vimspector.local.json which just sets variables # # Additional vars as defined by VSCode: # # ${workspaceFolder} - the path of the folder opened in VS Code # ${workspaceFolderBasename} - the name of the folder opened in VS Code # without any slashes (/) # ${file} - the current opened file # ${relativeFile} - the current opened file relative to workspaceFolder # ${fileBasename} - the current opened file's basename # ${fileBasenameNoExtension} - the current opened file's basename with no # file extension # ${fileDirname} - the current opened file's dirname # ${fileExtname} - the current opened file's extension # ${cwd} - the task runner's current working directory on startup # ${lineNumber} - the current selected line number in the active file # ${selectedText} - the current selected text in the active file # ${execPath} - the path to the running VS Code executable current_file = utils.GetBufferFilepath( vim.current.buffer ) self._variables = { 'dollar': '$', # HACK. Hote '$$' also works. 'workspaceRoot': self._workspace_root, 'workspaceFolder': self._workspace_root, 'gadgetDir': install.GetGadgetDir( VIMSPECTOR_HOME, install.GetOS() ), 'file': current_file, 'relativeFile': os.path.relpath( current_file, self._workspace_root ), 'fileBasename': os.path.basename( current_file ), 'fileBasenameNoExtension': os.path.splitext( os.path.basename( current_file ) )[ 0 ], 'fileDirname': os.path.dirname( current_file ), 'fileExtname': os.path.splitext( os.path.basename( current_file ) )[ 1 ], 'cwd': os.getcwd(), } self._variables.update( utils.ParseVariables( adapter.get( 'variables', {} ), self._variables ) ) self._variables.update( utils.ParseVariables( configuration.get( 'variables', {} ), self._variables ) ) self._variables.update( launch_variables ) utils.ExpandReferencesInDict( configuration, self._variables ) utils.ExpandReferencesInDict( adapter, self._variables ) if not adapter: utils.UserMessage( 'No adapter configured for {}'.format( configuration_name ), persist=True ) return self._StartWithConfiguration( configuration, adapter )