Prettify the output with some syntax and quiet option

This commit is contained in:
Ben Jackson 2020-07-22 14:40:23 +01:00
commit 000f7a9232
8 changed files with 146 additions and 78 deletions

View file

@ -268,13 +268,16 @@ There are a few ways to do this:
* Using `:VimspectorInstall <adapter> <args...>` (use TAB `wildmenu` to see the * Using `:VimspectorInstall <adapter> <args...>` (use TAB `wildmenu` to see the
options, also accepts any `install_gadget.py` option) options, also accepts any `install_gadget.py` option)
* Using `python3 install_gadget.py <args>` (use `--help` to see all options) * Alternatively, using `python3 install_gadget.py <args>` (use `--help` to see
all options)
* When attempting to launch a debug configuration, if the configured adapter * When attempting to launch a debug configuration, if the configured adapter
can't be found, vimspector might suggest installing one. can't be found, vimspector might suggest installing one.
* Use `:VimspectorUpdate` to install the latest supported versions of the
gadgets.
Here's a demo: Here's a demo of doing somee installs and an upgrade:
[![asciicast](https://asciinema.org/a/M3kShmfAZ8I5YewTCCKezzrr9.svg)](https://asciinema.org/a/M3kShmfAZ8I5YewTCCKezzrr9) [![asciicast](https://asciinema.org/a/Hfu4ZvuyTZun8THNen9FQbTay.svg)](https://asciinema.org/a/Hfu4ZvuyTZun8THNen9FQbTay)
Both `install_gadget.py` and `:VimspectorInstall` do the same set of things, Both `install_gadget.py` and `:VimspectorInstall` do the same set of things,
though the default behaviours are slightly different. For supported languages, though the default behaviours are slightly different. For supported languages,
@ -305,10 +308,6 @@ To install the tested debug adapter for a language, run:
`"VimspectorInstall` runs `install_gadget.py` in the background with some of `"VimspectorInstall` runs `install_gadget.py` in the background with some of
the options defaulted. the options defaulted.
Here's a demo:
[![asciicast](https://asciinema.org/a/mJQmMAuQG4rOp5DWq1IhDvQty.svg)](https://asciinema.org/a/mJQmMAuQG4rOp5DWq1IhDvQty)
By default `install_gadget.py` will overwrite your `.gadgets.json` with the set By default `install_gadget.py` will overwrite your `.gadgets.json` with the set
of adapters just installed, whereas `:VimspectorInstall` will _update_ it, of adapters just installed, whereas `:VimspectorInstall` will _update_ it,
overwriting only newly changed or installed adapters. overwriting only newly changed or installed adapters.

View file

@ -256,7 +256,7 @@ function! vimspector#CompleteInstall( ArgLead, CmdLine, CursorPos ) abort
\ . ')' ) \ . ')' )
endfunction endfunction
function! vimspector#Update() abort function! vimspector#Update( ... ) abort
if !s:enabled if !s:enabled
return return
endif endif
@ -264,9 +264,20 @@ function! vimspector#Update() abort
let prefix = vimspector#internal#state#GetAPIPrefix() let prefix = vimspector#internal#state#GetAPIPrefix()
py3 __import__( 'vimspector', py3 __import__( 'vimspector',
\ fromlist = [ 'installer' ] ).installer.RunUpdate( \ fromlist = [ 'installer' ] ).installer.RunUpdate(
\ vim.eval( 'prefix' ) ) \ vim.eval( 'prefix' ),
\ *vim.eval( 'a:000' ) )
endfunction endfunction
function! vimspector#AbortInstall() abort
if !s:enabled
return
endif
let prefix = vimspector#internal#state#GetAPIPrefix()
py3 __import__( 'vimspector', fromlist = [ 'installer' ] ).installer.Abort()
endfunction
" Boilerplate {{{ " Boilerplate {{{
let &cpoptions=s:save_cpo let &cpoptions=s:save_cpo
unlet s:save_cpo unlet s:save_cpo

View file

@ -69,6 +69,14 @@ parser.add_argument( '--force-all',
action = 'store_true', action = 'store_true',
help = 'Enable all unsupported completers' ) help = 'Enable all unsupported completers' )
parser.add_argument( '--quiet',
action = 'store_true',
help = 'Suppress installation output' )
parser.add_argument( '--verbose',
action = 'store_true',
help = 'Force installation output' )
parser.add_argument( '--basedir', parser.add_argument( '--basedir',
action = 'store', action = 'store',
help = 'Advanced option. ' help = 'Advanced option. '
@ -145,6 +153,7 @@ if args.basedir:
install.MakeInstallDirs( vimspector_base ) install.MakeInstallDirs( vimspector_base )
installer.Configure( vimspector_base = vimspector_base, installer.Configure( vimspector_base = vimspector_base,
quiet = args.quiet and not args.verbose,
no_check_certificate = args.no_check_certificate ) no_check_certificate = args.no_check_certificate )
if args.force_all and not args.all: if args.force_all and not args.all:
@ -202,8 +211,11 @@ if args.basedir:
"let g:vimspector_base_dir='" + vimspector_base + "'" ) "let g:vimspector_base_dir='" + vimspector_base + "'" )
if succeeded: if succeeded:
print( "The following adapters were installed successfully: {}".format( print( "Done. The following adapters were installed successfully:\n - {}".format(
','.join( succeeded ) ) ) '\n - '.join( succeeded ) ) )
if failed: if failed:
sys.exit( 'Failed to install adapters: {}'.format( ','.join( failed ) ) ) sys.exit( 'Failed to install adapters:\n * {}{}'.format(
'\n * '.join( failed ),
"\nRe-run with --verbose for more info on failures"
if args.quiet and not args.verbose else '' ) )

View file

@ -102,9 +102,12 @@ command! -bar
command! -bar -nargs=* -complete=custom,vimspector#CompleteInstall command! -bar -nargs=* -complete=custom,vimspector#CompleteInstall
\ VimspectorInstall \ VimspectorInstall
\ call vimspector#Install( <f-args> ) \ call vimspector#Install( <f-args> )
command! -bar -nargs=0 command! -bar -nargs=*
\ VimspectorUpdate \ VimspectorUpdate
\ call vimspector#Update() \ call vimspector#Update( <f-args> )
command! -bar -nargs=*
\ VimspectorAbortInstall
\ call vimspector#AbortInstall( <f-args> )

View file

@ -44,6 +44,7 @@ OUTPUT_VIEW = None
class Options: class Options:
vimspector_base = None vimspector_base = None
no_check_certificate = False no_check_certificate = False
quiet = False
options = Options() options = Options()
@ -54,6 +55,23 @@ def Configure( **kwargs ):
setattr( options, k, v ) setattr( options, k, v )
def Print( *args, **kwargs ):
if not options.quiet:
print( *args, **kwargs )
def CheckCall( *args, **kwargs ):
if options.quiet:
out = subprocess.PIPE
else:
out = sys.stdout
kwargs[ 'stdout' ] = out
kwargs[ 'stderr' ] = subprocess.STDOUT
subprocess.check_call( *args, **kwargs )
def PathToAnyWorkingPython3(): def PathToAnyWorkingPython3():
# We can't rely on sys.executable because it's usually 'vim' (fixme, not with # We can't rely on sys.executable because it's usually 'vim' (fixme, not with
# neovim?) # neovim?)
@ -91,9 +109,7 @@ def RunInstaller( api_prefix, *args, **kwargs ):
vimspector_base_dir = utils.GetVimspectorBase() vimspector_base_dir = utils.GetVimspectorBase()
global OUTPUT_VIEW global OUTPUT_VIEW
if OUTPUT_VIEW: _ResetInstaller()
OUTPUT_VIEW.Reset()
OUTPUT_VIEW = None
with utils.RestoreCurrentWindow(): with utils.RestoreCurrentWindow():
vim.command( f'botright { settings.Int( "bottombar_height", 10 ) }new' ) vim.command( f'botright { settings.Int( "bottombar_height", 10 ) }new' )
@ -104,6 +120,7 @@ def RunInstaller( api_prefix, *args, **kwargs ):
PathToAnyWorkingPython3(), PathToAnyWorkingPython3(),
'-u', '-u',
os.path.join( vimspector_home, 'install_gadget.py' ), os.path.join( vimspector_home, 'install_gadget.py' ),
'--quiet',
'--update-gadget-config', '--update-gadget-config',
] ]
if not vimspector_base_dir == vimspector_home: if not vimspector_base_dir == vimspector_home:
@ -112,10 +129,7 @@ def RunInstaller( api_prefix, *args, **kwargs ):
def handler( exit_code ): def handler( exit_code ):
if exit_code == 0: if exit_code == 0:
global OUTPUT_VIEW _ResetInstaller()
if OUTPUT_VIEW:
OUTPUT_VIEW.Reset()
OUTPUT_VIEW = None
utils.UserMessage( "Vimspector gadget installation complete!" ) utils.UserMessage( "Vimspector gadget installation complete!" )
vim.command( 'silent doautocmd User VimspectorInstallSuccess' ) vim.command( 'silent doautocmd User VimspectorInstallSuccess' )
if 'then' in kwargs: if 'then' in kwargs:
@ -128,21 +142,37 @@ def RunInstaller( api_prefix, *args, **kwargs ):
OUTPUT_VIEW.RunJobWithOutput( 'Installer', OUTPUT_VIEW.RunJobWithOutput( 'Installer',
cmd, cmd,
completion_handler = handler ) completion_handler = handler,
syntax = 'vimspector-installer' )
OUTPUT_VIEW.ShowOutput( 'Installer' ) OUTPUT_VIEW.ShowOutput( 'Installer' )
def RunUpdate( api_prefix ): def RunUpdate( api_prefix, *args ):
from vimspector import utils from vimspector import utils
Configure( vimspector_base = utils.GetVimspectorBase() ) Configure( vimspector_base = utils.GetVimspectorBase() )
args = list( args )
current_adapters = ReadAdapters( read_existing = True ) current_adapters = ReadAdapters( read_existing = True )
adapters = []
for adapter_name in current_adapters.keys(): for adapter_name in current_adapters.keys():
adapters.extend( FindGadgetForAdapter( adapter_name ) ) args.extend( FindGadgetForAdapter( adapter_name ) )
if adapters: if args:
RunInstaller( api_prefix, *adapters ) RunInstaller( api_prefix, *args )
def _ResetInstaller():
global OUTPUT_VIEW
if OUTPUT_VIEW:
OUTPUT_VIEW.Reset()
OUTPUT_VIEW = None
def Abort():
_ResetInstaller()
from vimspector import utils
utils.UserMessage( 'Vimspector installation aborted',
persist = True,
error = True )
def GadgetListToInstallerArgs( *gadget_list ): def GadgetListToInstallerArgs( *gadget_list ):
@ -222,7 +252,7 @@ def InstallDebugpy( name, root, gadget ):
root = os.path.join( root, 'debugpy-{}'.format( gadget[ 'version' ] ) ) root = os.path.join( root, 'debugpy-{}'.format( gadget[ 'version' ] ) )
os.chdir( root ) os.chdir( root )
try: try:
subprocess.check_call( [ sys.executable, 'setup.py', 'build' ] ) CheckCall( [ sys.executable, 'setup.py', 'build' ] )
finally: finally:
os.chdir( wd ) os.chdir( wd )
@ -258,8 +288,8 @@ def InstallTclProDebug( name, root, gadget ):
with CurrentWorkingDir( os.path.join( root, 'lib', 'tclparser' ) ): with CurrentWorkingDir( os.path.join( root, 'lib', 'tclparser' ) ):
subprocess.check_call( configure ) CheckCall( configure )
subprocess.check_call( [ 'make' ] ) CheckCall( [ 'make' ] )
MakeSymlink( name, root ) MakeSymlink( name, root )
@ -267,26 +297,27 @@ def InstallTclProDebug( name, root, gadget ):
def InstallNodeDebug( name, root, gadget ): def InstallNodeDebug( name, root, gadget ):
node_version = subprocess.check_output( [ 'node', '--version' ], node_version = subprocess.check_output( [ 'node', '--version' ],
universal_newlines=True ).strip() universal_newlines=True ).strip()
print( "Node.js version: {}".format( node_version ) ) Print( "Node.js version: {}".format( node_version ) )
if list( map( int, node_version[ 1: ].split( '.' ) ) ) >= [ 12, 0, 0 ]: if list( map( int, node_version[ 1: ].split( '.' ) ) ) >= [ 12, 0, 0 ]:
print( "Can't install vscode-debug-node2:" ) Print( "Can't install vscode-debug-node2:" )
print( "Sorry, you appear to be running node 12 or later. That's not " Print( "Sorry, you appear to be running node 12 or later. That's not "
"compatible with the build system for this extension, and as far as " "compatible with the build system for this extension, and as far as "
"we know, there isn't a pre-built independent package." ) "we know, there isn't a pre-built independent package." )
print( "My advice is to install nvm, then do:" ) Print( "My advice is to install nvm, then do:" )
print( " $ nvm install --lts 10" ) Print( " $ nvm install --lts 10" )
print( " $ nvm use --lts 10" ) Print( " $ nvm use --lts 10" )
print( " $ ./install_gadget.py --enable-node ..." ) Print( " $ ./install_gadget.py --enable-node ..." )
raise RuntimeError( 'Invalid node environent for node debugger' ) raise RuntimeError( 'Node 10 is required to install node debugger (sadly)' )
with CurrentWorkingDir( root ): with CurrentWorkingDir( root ):
subprocess.check_call( [ 'npm', 'install' ] ) CheckCall( [ 'npm', 'install' ] )
subprocess.check_call( [ 'npm', 'run', 'build' ] ) CheckCall( [ 'npm', 'run', 'build' ] )
MakeSymlink( name, root ) MakeSymlink( name, root )
def InstallGagdet( name, gadget, succeeded, failed, all_adapters ): def InstallGagdet( name, gadget, succeeded, failed, all_adapters ):
try: try:
print( f"Installing {name}..." )
v = {} v = {}
v.update( gadget.get( 'all', {} ) ) v.update( gadget.get( 'all', {} ) )
v.update( gadget.get( install.GetOS(), {} ) ) v.update( gadget.get( install.GetOS(), {} ) )
@ -339,11 +370,12 @@ def InstallGagdet( name, gadget, succeeded, failed, all_adapters ):
all_adapters.update( gadget.get( 'adapters', {} ) ) all_adapters.update( gadget.get( 'adapters', {} ) )
succeeded.append( name ) succeeded.append( name )
print( "Done installing {}".format( name ) ) print( f" - Done installing {name}" )
except Exception as e: except Exception as e:
traceback.print_exc() if not options.quiet:
traceback.print_exc()
failed.append( name ) failed.append( name )
print( "FAILED installing {}: {}".format( name, e ) ) print( f" - FAILED installing {name}: {e}".format( name, e ) )
def ReadAdapters( read_existing = True ): def ReadAdapters( read_existing = True ):
@ -392,7 +424,7 @@ def CurrentWorkingDir( d ):
def MakeExecutable( file_path ): def MakeExecutable( file_path ):
# TODO: import stat and use them by _just_ adding the X bit. # TODO: import stat and use them by _just_ adding the X bit.
print( 'Making executable: {}'.format( file_path ) ) Print( 'Making executable: {}'.format( file_path ) )
os.chmod( file_path, 0o755 ) os.chmod( file_path, 0o755 )
@ -409,7 +441,7 @@ def WithRetry( f ):
return f( *args, **kwargs ) return f( *args, **kwargs )
except Exception as e: except Exception as e:
thrown = e thrown = e
print( "Failed - {}, will retry in {} seconds".format( e, timeout ) ) Print( "Failed - {}, will retry in {} seconds".format( e, timeout ) )
time.sleep( timeout ) time.sleep( timeout )
raise thrown raise thrown
@ -437,13 +469,13 @@ def DownloadFileTo( url,
if os.path.exists( file_path ): if os.path.exists( file_path ):
if checksum: if checksum:
if ValidateCheckSumSHA256( file_path, checksum ): if ValidateCheckSumSHA256( file_path, checksum ):
print( "Checksum matches for {}, using it".format( file_path ) ) Print( "Checksum matches for {}, using it".format( file_path ) )
return file_path return file_path
else: else:
print( "Checksum doesn't match for {}, removing it".format( Print( "Checksum doesn't match for {}, removing it".format(
file_path ) ) file_path ) )
print( "Removing existing {}".format( file_path ) ) Print( "Removing existing {}".format( file_path ) )
os.remove( file_path ) os.remove( file_path )
r = request.Request( url, headers = { 'User-Agent': 'Vimspector' } ) r = request.Request( url, headers = { 'User-Agent': 'Vimspector' } )
@ -470,7 +502,7 @@ def DownloadFileTo( url,
GetChecksumSHA254( file_path ), GetChecksumSHA254( file_path ),
checksum ) ) checksum ) )
else: else:
print( "Checksum for {}: {}".format( file_path, Print( "Checksum for {}: {}".format( file_path,
GetChecksumSHA254( file_path ) ) ) GetChecksumSHA254( file_path ) ) )
return file_path return file_path
@ -488,7 +520,7 @@ def ValidateCheckSumSHA256( file_path, checksum ):
def RemoveIfExists( destination ): def RemoveIfExists( destination ):
if os.path.islink( destination ): if os.path.islink( destination ):
print( "Removing file {}".format( destination ) ) Print( "Removing file {}".format( destination ) )
os.remove( destination ) os.remove( destination )
return return
@ -499,21 +531,21 @@ def RemoveIfExists( destination ):
return "{}.{}".format( destination, N ) return "{}.{}".format( destination, N )
while os.path.isdir( BackupDir() ): while os.path.isdir( BackupDir() ):
print( "Removing old dir {}".format( BackupDir() ) ) Print( "Removing old dir {}".format( BackupDir() ) )
try: try:
shutil.rmtree( BackupDir() ) shutil.rmtree( BackupDir() )
print ( "OK, removed it" ) Print ( "OK, removed it" )
break break
except OSError: except OSError:
print ( "FAILED" ) Print ( "FAILED" )
N = N + 1 N = N + 1
if os.path.exists( destination ): if os.path.exists( destination ):
print( "Removing dir {}".format( destination ) ) Print( "Removing dir {}".format( destination ) )
try: try:
shutil.rmtree( destination ) shutil.rmtree( destination )
except OSError: except OSError:
print( "FAILED, moving {} to dir {}".format( destination, BackupDir() ) ) Print( "FAILED, moving {} to dir {}".format( destination, BackupDir() ) )
os.rename( destination, BackupDir() ) os.rename( destination, BackupDir() )
@ -534,7 +566,7 @@ class ModePreservingZipFile( zipfile.ZipFile ):
def ExtractZipTo( file_path, destination, format ): def ExtractZipTo( file_path, destination, format ):
print( "Extracting {} to {}".format( file_path, destination ) ) Print( "Extracting {} to {}".format( file_path, destination ) )
RemoveIfExists( destination ) RemoveIfExists( destination )
if format == 'zip': if format == 'zip':
@ -556,7 +588,7 @@ def ExtractZipTo( file_path, destination, format ):
# windows-generated tar files # windows-generated tar files
os.makedirs( destination ) os.makedirs( destination )
with CurrentWorkingDir( destination ): with CurrentWorkingDir( destination ):
subprocess.check_call( [ 'tar', 'zxvf', file_path ] ) CheckCall( [ 'tar', 'zxvf', file_path ] )
def MakeExtensionSymlink( name, root ): def MakeExtensionSymlink( name, root ):
@ -580,12 +612,7 @@ def MakeSymlink( link, pointing_to, in_folder = None ):
link_path = os.path.abspath( link_path ) link_path = os.path.abspath( link_path )
if os.path.isdir( link_path ): if os.path.isdir( link_path ):
os.rmdir( link_path ) os.rmdir( link_path )
subprocess.check_call( [ 'cmd.exe', CheckCall( [ 'cmd.exe', '/c', 'mklink', '/J', link_path, pointing_to ] )
'/c',
'mklink',
'/J',
link_path,
pointing_to ] )
else: else:
os.symlink( pointing_to_relative, link_path ) os.symlink( pointing_to_relative, link_path )
@ -593,13 +620,10 @@ def MakeSymlink( link, pointing_to, in_folder = None ):
def CloneRepoTo( url, ref, destination ): def CloneRepoTo( url, ref, destination ):
RemoveIfExists( destination ) RemoveIfExists( destination )
git_in_repo = [ 'git', '-C', destination ] git_in_repo = [ 'git', '-C', destination ]
subprocess.check_call( [ 'git', 'clone', url, destination ] ) CheckCall( [ 'git', 'clone', url, destination ] )
subprocess.check_call( git_in_repo + [ 'checkout', ref ] ) CheckCall( git_in_repo + [ 'checkout', ref ] )
subprocess.check_call( git_in_repo + [ 'submodule', 'sync', '--recursive' ] ) CheckCall( git_in_repo + [ 'submodule', 'sync', '--recursive' ] )
subprocess.check_call( git_in_repo + [ 'submodule', CheckCall( git_in_repo + [ 'submodule', 'update', '--init', '--recursive' ] )
'update',
'--init',
'--recursive' ] )
def AbortIfSUperUser( force_sudo ): def AbortIfSUperUser( force_sudo ):
@ -613,4 +637,5 @@ def AbortIfSUperUser( force_sudo ):
print( "*** RUNNING AS SUPER USER DUE TO force_sudo! " print( "*** RUNNING AS SUPER USER DUE TO force_sudo! "
" All bets are off. ***" ) " All bets are off. ***" )
else: else:
sys.exit( "This script should *not* be run as super user. Aborting." ) raise RuntimeError(
"This script should *not* be run as super user. Aborting." )

View file

@ -25,6 +25,7 @@ class TabBuffer( object ):
self.index = index self.index = index
self.flag = False self.flag = False
self.is_job = False self.is_job = False
self.syntax = None
BUFFER_MAP = { BUFFER_MAP = {
@ -135,17 +136,16 @@ class OutputView( object ):
self._RenderWinBar( category ) self._RenderWinBar( category )
def RunJobWithOutput( self, category, cmd, completion_handler = None ): def RunJobWithOutput( self, category, cmd, **kwargs ):
self._CreateBuffer( category, self._CreateBuffer( category, cmd = cmd, **kwargs )
cmd = cmd,
completion_handler = completion_handler )
def _CreateBuffer( self, def _CreateBuffer( self,
category, category,
file_name = None, file_name = None,
cmd = None, cmd = None,
completion_handler = None ): completion_handler = None,
syntax = None ):
if file_name is not None: if file_name is not None:
assert cmd is None assert cmd is None
if install.GetOS() == "windows": if install.GetOS() == "windows":
@ -182,6 +182,12 @@ class OutputView( object ):
self._RenderWinBar( category ) self._RenderWinBar( category )
self._buffers[ category ].syntax = utils.SetSyntax(
self._buffers[ category ].syntax,
syntax,
self._buffers[ category ].buf )
def _RenderWinBar( self, category ): def _RenderWinBar( self, category ):
if not self._window.valid: if not self._window.valid:
return return

View file

@ -621,8 +621,7 @@ def SetSyntax( current_syntax, syntax, *args ):
# doesn't actually trigger the Syntax autocommand, and i'm not sure that # doesn't actually trigger the Syntax autocommand, and i'm not sure that
# 'doautocmd Syntax' is the right solution or not # 'doautocmd Syntax' is the right solution or not
for buf in args: for buf in args:
with AnyWindowForBuffer( buf ): Call( 'setbufvar', buf.number, '&syntax', syntax )
vim.command( 'set syntax={}'.format( Escape( syntax ) ) )
return syntax return syntax

View file

@ -0,0 +1,13 @@
if exists( 'b:current_syntax' )
finish
endif
let b:current_syntax = 'vimspector-installer'
syn keyword VimspectorInstalling Installing
syn keyword VimspectorDone Done
syn keyword VimspectorError Failed FAILED
hi default link VimspectorInstalling Constant
hi default link VimspectorDone DiffAdd
hi default link VimspectorError WarningMsg