Merge pull request #116 from puremourning/filetype-configs
Support per-filetype global launch configurations, and support trivial custom gadget installation
This commit is contained in:
commit
866e6fe9b1
8 changed files with 419 additions and 405 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -16,3 +16,4 @@ README.md.toc.*
|
||||||
*.vimspector.log
|
*.vimspector.log
|
||||||
support/test/csharp/*.exe*
|
support/test/csharp/*.exe*
|
||||||
.neomake.log
|
.neomake.log
|
||||||
|
configurations/
|
||||||
|
|
|
||||||
139
.vimspector.json
139
.vimspector.json
|
|
@ -1,139 +0,0 @@
|
||||||
{
|
|
||||||
"adapters": {
|
|
||||||
"lldb-mi": {
|
|
||||||
"name": "lldb-mi",
|
|
||||||
"command": [
|
|
||||||
"node",
|
|
||||||
"$HOME/.vscode/extensions/webfreak.debug-0.22.0/out/src/lldb.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"cppdbg": {
|
|
||||||
"name": "cppdbg",
|
|
||||||
"command": [ "$HOME/.vscode/extensions/ms-vscode.cpptools-0.20.1/debugAdapters/OpenDebugAD7" ],
|
|
||||||
"attach": {
|
|
||||||
"pidProperty": "processId",
|
|
||||||
"pidSelect": "ask"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"python": {
|
|
||||||
"name": "python",
|
|
||||||
"command": [
|
|
||||||
"node",
|
|
||||||
"$HOME/.vscode/extensions/ms-python.python-2018.4.0/out/client/debugger/Main.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"bashdb": {
|
|
||||||
"name": "bashdb",
|
|
||||||
"command": [
|
|
||||||
"node",
|
|
||||||
"$HOME/.vscode/extensions/rogalmic.bash-debug-0.2.0/out/bashDebug.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"lldb": {
|
|
||||||
"name": "lldb",
|
|
||||||
"command": [
|
|
||||||
"lldb",
|
|
||||||
"-b",
|
|
||||||
"-O",
|
|
||||||
"command script import '$HOME/.vscode/extensions/vadimcn.vscode-lldb-0.8.7/adapter'",
|
|
||||||
"-O",
|
|
||||||
"script adapter.main.run_stdio_session()"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"configurations": {
|
|
||||||
"simple_c_program - lldb-mi Launch": {
|
|
||||||
"adapter": "lldb-mi",
|
|
||||||
"configuration": {
|
|
||||||
"request": "launch",
|
|
||||||
"target": "support/test/cpp/simple_c_program/test",
|
|
||||||
"args": [],
|
|
||||||
"cwd": ".",
|
|
||||||
"lldbmipath": "$HOME/.vscode/extensions/ms-vscode.cpptools-0.20.1/debugAdapters/lldb/bin/lldb-mi",
|
|
||||||
"trace": true,
|
|
||||||
"logFilePath": "$HOME/.vimspector.protocol.log"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"simple_c_progra - ms Launch": {
|
|
||||||
"adapter": "cppdbg",
|
|
||||||
"configuration": {
|
|
||||||
"name": "ms Launch",
|
|
||||||
"type": "cppdbg",
|
|
||||||
"request": "launch",
|
|
||||||
"program": "${workspaceRoot}/support/test/cpp/simple_c_program/test",
|
|
||||||
"args": [],
|
|
||||||
"cwd": "$HOME",
|
|
||||||
"environment": [],
|
|
||||||
"externalConsole": true,
|
|
||||||
"MIMode": "lldb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"simple_python - launch": {
|
|
||||||
"adapter": "python",
|
|
||||||
"configuration": {
|
|
||||||
"name": "Python: Current File",
|
|
||||||
"type": "python",
|
|
||||||
"request": "launch",
|
|
||||||
"cwd": "${workspaceRoot}/support/test/python/simple_python",
|
|
||||||
"stopOnEntry": true,
|
|
||||||
"console": "externalTerminal",
|
|
||||||
"debugOptions": [],
|
|
||||||
"program": "${workspaceRoot}/support/test/python/simple_python/main.py"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"simple_c_program - MS Attach": {
|
|
||||||
"adapter": "cppdbg",
|
|
||||||
"configuration": {
|
|
||||||
"name": "(lldb) Attach",
|
|
||||||
"type": "cppdbg",
|
|
||||||
"request": "attach",
|
|
||||||
"program": "${workspaceRoot}/support/test/cpp/simple_c_program/test",
|
|
||||||
"MIMode": "lldb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"bashdb": {
|
|
||||||
"adapter": "bashdb",
|
|
||||||
"configuration": {
|
|
||||||
"type": "bashdb",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "Bash-Debug (simplest configuration)",
|
|
||||||
"program": "$HOME/.vim/bundle/YouCompleteMe/install.sh",
|
|
||||||
"args": [],
|
|
||||||
"cwd": "$HOME/.vim/bundle/YouCompleteMe",
|
|
||||||
"pathBash": "bash",
|
|
||||||
"pathBashdb": "bashdb",
|
|
||||||
"pathCat": "cat",
|
|
||||||
"pathMkfifo": "mkfifo",
|
|
||||||
"pathPkill": "pkill",
|
|
||||||
"showDebugOutput": true,
|
|
||||||
"trace": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lldb launch": {
|
|
||||||
"adapter": "lldb",
|
|
||||||
"configuration": {
|
|
||||||
"type": "lldb",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "LLDB: Launch",
|
|
||||||
"program": "$HOME/Development/vim/src/vim",
|
|
||||||
"args": [],
|
|
||||||
"cwd": "$HOME/Development/vim"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"racerd": {
|
|
||||||
"adapter": "lldb",
|
|
||||||
"configuration": {
|
|
||||||
"type": "lldb",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "LLDB: Launch",
|
|
||||||
"program": "$HOME/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/racerd/target/debug/racerd",
|
|
||||||
"args": [
|
|
||||||
"serve",
|
|
||||||
"--port=12345",
|
|
||||||
"--secret-file=secretfile"
|
|
||||||
],
|
|
||||||
"cwd": "$HOME/.vim/bundle/YouCompleteMe/third_party/ycmd"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -18,31 +18,24 @@
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
if sys.version_info.major < 3:
|
if sys.version_info.major < 3:
|
||||||
exit( "Sorry, you need to be running this script with python3 or later" )
|
sys.exit( "You need to run this with python 3. Your version is " +
|
||||||
|
'.'.join( map( str, sys.version_info[ :3 ] ) ) )
|
||||||
|
|
||||||
from urllib import request
|
|
||||||
import argparse
|
import argparse
|
||||||
import contextlib
|
|
||||||
import os
|
import os
|
||||||
import string
|
import string
|
||||||
import zipfile
|
|
||||||
import gzip
|
|
||||||
import shutil
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import traceback
|
import traceback
|
||||||
import tarfile
|
|
||||||
import hashlib
|
|
||||||
import json
|
import json
|
||||||
import functools
|
import functools
|
||||||
import time
|
import operator
|
||||||
import ssl
|
import glob
|
||||||
import io
|
|
||||||
|
|
||||||
# Include vimspector source, for utils
|
# Include vimspector source, for utils
|
||||||
sys.path.insert( 1, os.path.join( os.path.dirname( __file__ ),
|
sys.path.insert( 1, os.path.join( os.path.dirname( __file__ ),
|
||||||
'python3' ) )
|
'python3' ) )
|
||||||
|
|
||||||
from vimspector import install
|
from vimspector import install, installer
|
||||||
|
|
||||||
GADGETS = {
|
GADGETS = {
|
||||||
'vscode-cpptools': {
|
'vscode-cpptools': {
|
||||||
|
|
@ -200,13 +193,14 @@ GADGETS = {
|
||||||
},
|
},
|
||||||
'macos': {
|
'macos': {
|
||||||
'file_name': 'netcoredbg-osx-master.tar.gz',
|
'file_name': 'netcoredbg-osx-master.tar.gz',
|
||||||
'checksum': '',
|
'checksum':
|
||||||
|
'c1dc6ed58c3f5b0473cfb4985a96552999360ceb9795e42d9c9be64af054f821',
|
||||||
},
|
},
|
||||||
'linux': {
|
'linux': {
|
||||||
'file_name': 'netcoredbg-linux-master.tar.gz',
|
'file_name': 'netcoredbg-linux-master.tar.gz',
|
||||||
'checksum': '',
|
'checksum': '',
|
||||||
},
|
},
|
||||||
'do': lambda name, root, gadget: MakeSymlink(
|
'do': lambda name, root, gadget: installer.MakeSymlink(
|
||||||
gadget_dir,
|
gadget_dir,
|
||||||
name,
|
name,
|
||||||
os.path.join( root, 'netcoredbg' ) ),
|
os.path.join( root, 'netcoredbg' ) ),
|
||||||
|
|
@ -345,7 +339,7 @@ GADGETS = {
|
||||||
'enabled': False,
|
'enabled': False,
|
||||||
'repo': {
|
'repo': {
|
||||||
'url': 'https://github.com/microsoft/vscode-node-debug2',
|
'url': 'https://github.com/microsoft/vscode-node-debug2',
|
||||||
'ref': 'v1.39.1',
|
'ref': 'v1.42.0',
|
||||||
},
|
},
|
||||||
'do': lambda name, root, gadget: InstallNodeDebug( name, root, gadget ),
|
'do': lambda name, root, gadget: InstallNodeDebug( name, root, gadget ),
|
||||||
'adapters': {
|
'adapters': {
|
||||||
|
|
@ -389,29 +383,15 @@ GADGETS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
|
||||||
def CurrentWorkingDir( d ):
|
|
||||||
cur_d = os.getcwd()
|
|
||||||
try:
|
|
||||||
os.chdir( d )
|
|
||||||
yield
|
|
||||||
finally:
|
|
||||||
os.chdir( cur_d )
|
|
||||||
|
|
||||||
|
|
||||||
def MakeExecutable( file_path ):
|
|
||||||
# TODO: import stat and use them by _just_ adding the X bit.
|
|
||||||
print( 'Making executable: {}'.format( file_path ) )
|
|
||||||
os.chmod( file_path, 0o755 )
|
|
||||||
|
|
||||||
|
|
||||||
def InstallCppTools( name, root, gadget ):
|
def InstallCppTools( name, root, gadget ):
|
||||||
extension = os.path.join( root, 'extension' )
|
extension = os.path.join( root, 'extension' )
|
||||||
|
|
||||||
# It's hilarious, but the execute bits aren't set in the vsix. So they
|
# It's hilarious, but the execute bits aren't set in the vsix. So they
|
||||||
# actually have javascript code which does this. It's just a horrible horrible
|
# actually have javascript code which does this. It's just a horrible horrible
|
||||||
# hack that really is not funny.
|
# hack that really is not funny.
|
||||||
MakeExecutable( os.path.join( extension, 'debugAdapters', 'OpenDebugAD7' ) )
|
installer.MakeExecutable( os.path.join( extension,
|
||||||
|
'debugAdapters',
|
||||||
|
'OpenDebugAD7' ) )
|
||||||
with open( os.path.join( extension, 'package.json' ) ) as f:
|
with open( os.path.join( extension, 'package.json' ) ) as f:
|
||||||
package = json.load( f )
|
package = json.load( f )
|
||||||
runtime_dependencies = package[ 'runtimeDependencies' ]
|
runtime_dependencies = package[ 'runtimeDependencies' ]
|
||||||
|
|
@ -419,14 +399,17 @@ def InstallCppTools( name, root, gadget ):
|
||||||
for binary in dependency.get( 'binaries' ):
|
for binary in dependency.get( 'binaries' ):
|
||||||
file_path = os.path.abspath( os.path.join( extension, binary ) )
|
file_path = os.path.abspath( os.path.join( extension, binary ) )
|
||||||
if os.path.exists( file_path ):
|
if os.path.exists( file_path ):
|
||||||
MakeExecutable( os.path.join( extension, binary ) )
|
installer.MakeExecutable( os.path.join( extension, binary ) )
|
||||||
|
|
||||||
MakeExtensionSymlink( name, root )
|
installer.MakeExtensionSymlink( vimspector_base, name, root )
|
||||||
|
|
||||||
|
|
||||||
def InstallBashDebug( name, root, gadget ):
|
def InstallBashDebug( name, root, gadget ):
|
||||||
MakeExecutable( os.path.join( root, 'extension', 'bashdb_dir', 'bashdb' ) )
|
installer.MakeExecutable( os.path.join( root,
|
||||||
MakeExtensionSymlink( name, root )
|
'extension',
|
||||||
|
'bashdb_dir',
|
||||||
|
'bashdb' ) )
|
||||||
|
installer.MakeExtensionSymlink( vimspector_base, name, root )
|
||||||
|
|
||||||
|
|
||||||
def InstallDebugpy( name, root, gadget ):
|
def InstallDebugpy( name, root, gadget ):
|
||||||
|
|
@ -438,7 +421,7 @@ def InstallDebugpy( name, root, gadget ):
|
||||||
finally:
|
finally:
|
||||||
os.chdir( wd )
|
os.chdir( wd )
|
||||||
|
|
||||||
MakeSymlink( gadget_dir, name, root )
|
installer.MakeSymlink( gadget_dir, name, root )
|
||||||
|
|
||||||
|
|
||||||
def InstallTclProDebug( name, root, gadget ):
|
def InstallTclProDebug( name, root, gadget ):
|
||||||
|
|
@ -469,11 +452,11 @@ def InstallTclProDebug( name, root, gadget ):
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
with CurrentWorkingDir( os.path.join( root, 'lib', 'tclparser' ) ):
|
with installer.CurrentWorkingDir( os.path.join( root, 'lib', 'tclparser' ) ):
|
||||||
subprocess.check_call( configure )
|
subprocess.check_call( configure )
|
||||||
subprocess.check_call( [ 'make' ] )
|
subprocess.check_call( [ 'make' ] )
|
||||||
|
|
||||||
MakeSymlink( gadget_dir, name, root )
|
installer.MakeSymlink( gadget_dir, name, root )
|
||||||
|
|
||||||
|
|
||||||
def InstallNodeDebug( name, root, gadget ):
|
def InstallNodeDebug( name, root, gadget ):
|
||||||
|
|
@ -491,185 +474,82 @@ def InstallNodeDebug( name, root, gadget ):
|
||||||
print( " $ ./install_gadget.py --enable-node ..." )
|
print( " $ ./install_gadget.py --enable-node ..." )
|
||||||
raise RuntimeError( 'Invalid node environent for node debugger' )
|
raise RuntimeError( 'Invalid node environent for node debugger' )
|
||||||
|
|
||||||
with CurrentWorkingDir( root ):
|
with installer.CurrentWorkingDir( root ):
|
||||||
subprocess.check_call( [ 'npm', 'install' ] )
|
subprocess.check_call( [ 'npm', 'install' ] )
|
||||||
subprocess.check_call( [ 'npm', 'run', 'build' ] )
|
subprocess.check_call( [ 'npm', 'run', 'build' ] )
|
||||||
MakeSymlink( gadget_dir, name, root )
|
installer.MakeSymlink( gadget_dir, name, root )
|
||||||
|
|
||||||
|
|
||||||
def WithRetry( f ):
|
def InstallGagdet( name, gadget, failed, all_adapters ):
|
||||||
retries = 5
|
try:
|
||||||
timeout = 1 # seconds
|
v = {}
|
||||||
|
v.update( gadget.get( 'all', {} ) )
|
||||||
|
v.update( gadget.get( OS, {} ) )
|
||||||
|
|
||||||
@functools.wraps( f )
|
if 'download' in gadget:
|
||||||
def wrapper( *args, **kwargs ):
|
if 'file_name' not in v:
|
||||||
thrown = None
|
raise RuntimeError( "Unsupported OS {} for gadget {}".format( OS,
|
||||||
for _ in range( retries ):
|
name ) )
|
||||||
try:
|
|
||||||
return f( *args, **kwargs )
|
|
||||||
except Exception as e:
|
|
||||||
thrown = e
|
|
||||||
print( "Failed - {}, will retry in {} seconds".format( e, timeout ) )
|
|
||||||
time.sleep( timeout )
|
|
||||||
raise thrown
|
|
||||||
|
|
||||||
return wrapper
|
destination = os.path.join( gadget_dir, 'download', name, v[ 'version' ] )
|
||||||
|
|
||||||
|
url = string.Template( gadget[ 'download' ][ 'url' ] ).substitute( v )
|
||||||
|
|
||||||
@WithRetry
|
file_path = installer.DownloadFileTo(
|
||||||
def UrlOpen( *args, **kwargs ):
|
url,
|
||||||
return request.urlopen( *args, **kwargs )
|
destination,
|
||||||
|
file_name = gadget[ 'download' ].get( 'target' ),
|
||||||
|
checksum = v.get( 'checksum' ),
|
||||||
|
check_certificate = not args.no_check_certificate )
|
||||||
|
|
||||||
|
root = os.path.join( destination, 'root' )
|
||||||
|
installer.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 )
|
||||||
|
|
||||||
def DownloadFileTo( url,
|
destination = os.path.join( gadget_dir, 'download', name )
|
||||||
destination,
|
installer.CloneRepoTo( url, ref, destination )
|
||||||
file_name = None,
|
root = destination
|
||||||
checksum = None,
|
|
||||||
sslcheck = True ):
|
|
||||||
if not file_name:
|
|
||||||
file_name = url.split( '/' )[ -1 ]
|
|
||||||
|
|
||||||
file_path = os.path.abspath( os.path.join( destination, file_name ) )
|
if 'do' in gadget:
|
||||||
|
gadget[ 'do' ]( name, root, v )
|
||||||
if not os.path.isdir( destination ):
|
|
||||||
os.makedirs( destination )
|
|
||||||
|
|
||||||
if os.path.exists( file_path ):
|
|
||||||
if checksum:
|
|
||||||
if ValidateCheckSumSHA256( file_path, checksum ):
|
|
||||||
print( "Checksum matches for {}, using it".format( file_path ) )
|
|
||||||
return file_path
|
|
||||||
else:
|
|
||||||
print( "Checksum doesn't match for {}, removing it".format(
|
|
||||||
file_path ) )
|
|
||||||
|
|
||||||
print( "Removing existing {}".format( file_path ) )
|
|
||||||
os.remove( file_path )
|
|
||||||
|
|
||||||
r = request.Request( url, headers = { 'User-Agent': 'Vimspector' } )
|
|
||||||
|
|
||||||
print( "Downloading {} to {}/{}".format( url, destination, file_name ) )
|
|
||||||
|
|
||||||
if not sslcheck:
|
|
||||||
context = ssl.create_default_context()
|
|
||||||
context.check_hostname = False
|
|
||||||
context.verify_mode = ssl.CERT_NONE
|
|
||||||
kwargs = { "context": context }
|
|
||||||
else:
|
|
||||||
kwargs = {}
|
|
||||||
|
|
||||||
with contextlib.closing( UrlOpen( r, **kwargs ) ) as u:
|
|
||||||
with open( file_path, 'wb' ) as f:
|
|
||||||
f.write( u.read() )
|
|
||||||
|
|
||||||
if checksum:
|
|
||||||
if not ValidateCheckSumSHA256( file_path, checksum ):
|
|
||||||
raise RuntimeError(
|
|
||||||
'Checksum for {} ({}) does not match expected {}'.format(
|
|
||||||
file_path,
|
|
||||||
GetChecksumSHA254( file_path ),
|
|
||||||
checksum ) )
|
|
||||||
else:
|
|
||||||
print( "Checksum for {}: {}".format( file_path,
|
|
||||||
GetChecksumSHA254( file_path ) ) )
|
|
||||||
|
|
||||||
return file_path
|
|
||||||
|
|
||||||
|
|
||||||
def GetChecksumSHA254( file_path ):
|
|
||||||
with open( file_path, 'rb' ) as existing_file:
|
|
||||||
return hashlib.sha256( existing_file.read() ).hexdigest()
|
|
||||||
|
|
||||||
|
|
||||||
def ValidateCheckSumSHA256( file_path, checksum ):
|
|
||||||
existing_sha256 = GetChecksumSHA254( file_path )
|
|
||||||
return existing_sha256 == checksum
|
|
||||||
|
|
||||||
|
|
||||||
def RemoveIfExists( destination ):
|
|
||||||
if os.path.exists( destination ) or os.path.islink( destination ):
|
|
||||||
if os.path.islink( destination ):
|
|
||||||
print( "Removing file {}".format( destination ) )
|
|
||||||
os.remove( destination )
|
|
||||||
else:
|
else:
|
||||||
print( "Removing dir {}".format( destination ) )
|
installer.MakeExtensionSymlink( vimspector_base, name, root )
|
||||||
shutil.rmtree( destination )
|
|
||||||
|
all_adapters.update( gadget.get( 'adapters', {} ) )
|
||||||
|
|
||||||
# Python's ZipFile module strips execute bits from files, for no good reason
|
print( "Done installing {}".format( name ) )
|
||||||
# other than crappy code. Let's do it's job for it.
|
except Exception as e:
|
||||||
class ModePreservingZipFile( zipfile.ZipFile ):
|
traceback.print_exc()
|
||||||
def extract( self, member, path = None, pwd = None ):
|
failed.append( name )
|
||||||
if not isinstance( member, zipfile.ZipInfo ):
|
print( "FAILED installing {}: {}".format( name, e ) )
|
||||||
member = self.getinfo( member )
|
|
||||||
|
|
||||||
if path is None:
|
|
||||||
path = os.getcwd()
|
|
||||||
|
|
||||||
ret_val = self._extract_member( member, path, pwd )
|
|
||||||
attr = member.external_attr >> 16
|
|
||||||
os.chmod( ret_val, attr )
|
|
||||||
return ret_val
|
|
||||||
|
|
||||||
|
|
||||||
def ExtractZipTo( file_path, destination, format ):
|
|
||||||
print( "Extracting {} to {}".format( file_path, destination ) )
|
|
||||||
RemoveIfExists( destination )
|
|
||||||
|
|
||||||
if format == 'zip':
|
|
||||||
with ModePreservingZipFile( file_path ) as f:
|
|
||||||
f.extractall( path = destination )
|
|
||||||
elif format == 'zip.gz':
|
|
||||||
with gzip.open( file_path, 'rb' ) as f:
|
|
||||||
file_contents = f.read()
|
|
||||||
|
|
||||||
with ModePreservingZipFile( io.BytesIO( file_contents ) ) as f:
|
|
||||||
f.extractall( path = destination )
|
|
||||||
|
|
||||||
elif format == 'tar':
|
|
||||||
try:
|
|
||||||
with tarfile.open( file_path ) as f:
|
|
||||||
f.extractall( path = destination )
|
|
||||||
except Exception:
|
|
||||||
# There seems to a bug in python's tarfile that means it can't read some
|
|
||||||
# windows-generated tar files
|
|
||||||
os.makedirs( destination )
|
|
||||||
with CurrentWorkingDir( destination ):
|
|
||||||
subprocess.check_call( [ 'tar', 'zxvf', file_path ] )
|
|
||||||
|
|
||||||
|
|
||||||
def MakeExtensionSymlink( name, root ):
|
|
||||||
MakeSymlink( gadget_dir, name, os.path.join( root, 'extension' ) ),
|
|
||||||
|
|
||||||
|
|
||||||
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 )
|
|
||||||
git_in_repo = [ 'git', '-C', destination ]
|
|
||||||
subprocess.check_call( [ 'git', 'clone', url, destination ] )
|
|
||||||
subprocess.check_call( git_in_repo + [ 'checkout', ref ] )
|
|
||||||
subprocess.check_call( git_in_repo + [ 'submodule', 'sync', '--recursive' ] )
|
|
||||||
subprocess.check_call( git_in_repo + [ 'submodule',
|
|
||||||
'update',
|
|
||||||
'--init',
|
|
||||||
'--recursive' ] )
|
|
||||||
|
|
||||||
|
|
||||||
|
vimspector_base = os.path.dirname( __file__ )
|
||||||
OS = install.GetOS()
|
OS = install.GetOS()
|
||||||
gadget_dir = install.GetGadgetDir( os.path.dirname( __file__ ), OS )
|
gadget_dir = install.GetGadgetDir( vimspector_base, OS )
|
||||||
|
|
||||||
print( 'OS = ' + OS )
|
print( 'OS = ' + OS )
|
||||||
print( 'gadget_dir = ' + gadget_dir )
|
print( 'gadget_dir = ' + gadget_dir )
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser(
|
||||||
|
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:
|
||||||
|
https://puremourning.github.io/vimspector
|
||||||
|
"""
|
||||||
|
)
|
||||||
parser.add_argument( '--all',
|
parser.add_argument( '--all',
|
||||||
action = 'store_true',
|
action = 'store_true',
|
||||||
help = 'Enable all supported completers' )
|
help = 'Enable all supported completers' )
|
||||||
|
|
@ -682,6 +562,15 @@ parser.add_argument( '--no-gadget-config',
|
||||||
action = 'store_true',
|
action = 'store_true',
|
||||||
help = "Don't write the .gagets.json, just install" )
|
help = "Don't write the .gagets.json, just install" )
|
||||||
|
|
||||||
|
parser.add_argument( '--enable-custom',
|
||||||
|
dest='custom_gadget_file',
|
||||||
|
action='append',
|
||||||
|
nargs='*',
|
||||||
|
default = [],
|
||||||
|
help = 'Read custom gadget from supplied file. This '
|
||||||
|
'can be supplied multiple times and each time '
|
||||||
|
'multiple files can be passed.' )
|
||||||
|
|
||||||
done_languages = set()
|
done_languages = set()
|
||||||
for name, gadget in GADGETS.items():
|
for name, gadget in GADGETS.items():
|
||||||
lang = gadget[ 'language' ]
|
lang = gadget[ 'language' ]
|
||||||
|
|
@ -722,6 +611,18 @@ args = parser.parse_args()
|
||||||
if args.force_all and not args.all:
|
if args.force_all and not args.all:
|
||||||
args.all = True
|
args.all = True
|
||||||
|
|
||||||
|
CUSTOM_GADGETS = {}
|
||||||
|
custom_files = glob.glob( os.path.join( vimspector_base,
|
||||||
|
'gadgets',
|
||||||
|
'custom',
|
||||||
|
'*.json' ) )
|
||||||
|
for custom_file_name in functools.reduce( operator.add,
|
||||||
|
args.custom_gadget_file,
|
||||||
|
custom_files ):
|
||||||
|
with open( custom_file_name, 'r' ) as custom_file:
|
||||||
|
CUSTOM_GADGETS.update( json.load( custom_file ) )
|
||||||
|
|
||||||
|
|
||||||
failed = []
|
failed = []
|
||||||
all_adapters = {}
|
all_adapters = {}
|
||||||
for name, gadget in GADGETS.items():
|
for name, gadget in GADGETS.items():
|
||||||
|
|
@ -735,53 +636,14 @@ for name, gadget in GADGETS.items():
|
||||||
if getattr( args, 'disable_' + gadget[ 'language' ] ):
|
if getattr( args, 'disable_' + gadget[ 'language' ] ):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
InstallGagdet( name,
|
||||||
v = {}
|
gadget,
|
||||||
v.update( gadget.get( 'all', {} ) )
|
failed,
|
||||||
v.update( gadget.get( OS, {} ) )
|
all_adapters )
|
||||||
|
|
||||||
if 'download' in gadget:
|
|
||||||
if 'file_name' not in v:
|
|
||||||
raise RuntimeError( "Unsupported OS {} for gadget {}".format( OS,
|
|
||||||
name ) )
|
|
||||||
|
|
||||||
destination = os.path.join( gadget_dir, 'download', name, v[ 'version' ] )
|
|
||||||
|
|
||||||
url = string.Template( gadget[ 'download' ][ 'url' ] ).substitute( v )
|
|
||||||
verify_cert_off = args.no_check_certificate
|
|
||||||
|
|
||||||
file_path = DownloadFileTo(
|
|
||||||
url,
|
|
||||||
destination,
|
|
||||||
file_name = gadget[ 'download' ].get( 'target' ),
|
|
||||||
checksum = v.get( 'checksum' ),
|
|
||||||
sslcheck = not verify_cert_off )
|
|
||||||
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( gadget_dir, 'download', name )
|
|
||||||
CloneRepoTo( url, ref, destination )
|
|
||||||
root = destination
|
|
||||||
|
|
||||||
if 'do' in gadget:
|
|
||||||
gadget[ 'do' ]( name, root, v )
|
|
||||||
else:
|
|
||||||
MakeExtensionSymlink( name, root )
|
|
||||||
|
|
||||||
all_adapters.update( gadget.get( 'adapters', {} ) )
|
|
||||||
|
|
||||||
|
|
||||||
print( "Done installing {}".format( name ) )
|
for name, gadget in CUSTOM_GADGETS.items():
|
||||||
except Exception as e:
|
InstallGagdet( name, gadget, failed, all_adapters )
|
||||||
traceback.print_exc()
|
|
||||||
failed.append( name )
|
|
||||||
print( "FAILED installing {}: {}".format( name, e ) )
|
|
||||||
|
|
||||||
|
|
||||||
adapter_config = json.dumps ( { 'adapters': all_adapters },
|
adapter_config = json.dumps ( { 'adapters': all_adapters },
|
||||||
indent=2,
|
indent=2,
|
||||||
|
|
@ -792,8 +654,7 @@ if args.no_gadget_config:
|
||||||
print( "Would write the following gadgets: " )
|
print( "Would write the following gadgets: " )
|
||||||
print( adapter_config )
|
print( adapter_config )
|
||||||
else:
|
else:
|
||||||
with open( install.GetGadgetConfigFile( os.path.dirname( __file__ ) ),
|
with open( install.GetGadgetConfigFile( vimspector_base ), 'w' ) as f:
|
||||||
'w' ) as f:
|
|
||||||
f.write( adapter_config )
|
f.write( adapter_config )
|
||||||
|
|
||||||
if failed:
|
if failed:
|
||||||
|
|
|
||||||
|
|
@ -72,38 +72,49 @@ class DebugSession( object ):
|
||||||
self._on_init_complete_handlers = []
|
self._on_init_complete_handlers = []
|
||||||
self._server_capabilities = {}
|
self._server_capabilities = {}
|
||||||
|
|
||||||
def Start( self, launch_variables = {} ):
|
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",
|
self._logger.info( "User requested start debug session with %s",
|
||||||
launch_variables )
|
launch_variables )
|
||||||
self._configuration = None
|
self._configuration = None
|
||||||
self._adapter = None
|
self._adapter = None
|
||||||
|
|
||||||
current_file = utils.GetBufferFilepath( vim.current.buffer )
|
current_file = utils.GetBufferFilepath( vim.current.buffer )
|
||||||
|
filetypes = utils.GetBufferFiletypes( vim.current.buffer )
|
||||||
launch_config_file = utils.PathToConfigFile(
|
configurations = {}
|
||||||
'.vimspector.json',
|
|
||||||
os.path.dirname( current_file ) )
|
|
||||||
|
|
||||||
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 = {}
|
adapters = {}
|
||||||
|
|
||||||
glob.glob( install.GetGadgetDir( VIMSPECTOR_HOME, install.GetOS() ) )
|
glob.glob( install.GetGadgetDir( VIMSPECTOR_HOME, install.GetOS() ) )
|
||||||
for gadget_config_file in PathsToAllGadgetConfigs( VIMSPECTOR_HOME,
|
for gadget_config_file in PathsToAllGadgetConfigs( VIMSPECTOR_HOME,
|
||||||
current_file ):
|
current_file ):
|
||||||
self._logger.debug( f'Reading gadget config: {gadget_config_file}' )
|
self._logger.debug( f'Reading gadget config: {gadget_config_file}' )
|
||||||
if gadget_config_file and os.path.exists( gadget_config_file ):
|
if not gadget_config_file or not os.path.exists( gadget_config_file ):
|
||||||
with open( gadget_config_file, 'r' ) as f:
|
continue
|
||||||
adapters.update( json.load( f ).get( 'adapters' ) or {} )
|
|
||||||
|
|
||||||
adapters.update( database.get( 'adapters' ) or {} )
|
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:
|
if 'configuration' in launch_variables:
|
||||||
configuration_name = launch_variables.pop( 'configuration' )
|
configuration_name = launch_variables.pop( 'configuration' )
|
||||||
|
|
@ -117,7 +128,10 @@ class DebugSession( object ):
|
||||||
if not configuration_name or configuration_name not in configurations:
|
if not configuration_name or configuration_name not in configurations:
|
||||||
return
|
return
|
||||||
|
|
||||||
self._workspace_root = os.path.dirname( launch_config_file )
|
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 ]
|
configuration = configurations[ configuration_name ]
|
||||||
adapter = configuration.get( 'adapter' )
|
adapter = configuration.get( 'adapter' )
|
||||||
|
|
@ -936,3 +950,18 @@ def PathsToAllGadgetConfigs( vimspector_base, current_file ):
|
||||||
|
|
||||||
yield utils.PathToConfigFile( '.gadgets.json',
|
yield utils.PathToConfigFile( '.gadgets.json',
|
||||||
os.path.dirname( current_file ) )
|
os.path.dirname( current_file ) )
|
||||||
|
|
||||||
|
|
||||||
|
def PathsToAllConfigFiles( vimspector_base, current_file, filetypes ):
|
||||||
|
for ft in filetypes:
|
||||||
|
for p in sorted( glob.glob(
|
||||||
|
os.path.join( install.GetConfigDirForFiletype( vimspector_base, ft ),
|
||||||
|
'*.json' ) ) ):
|
||||||
|
yield p
|
||||||
|
|
||||||
|
for ft in filetypes:
|
||||||
|
yield utils.PathToConfigFile( f'.vimspector.{ft}.json',
|
||||||
|
os.path.dirname( current_file ) )
|
||||||
|
|
||||||
|
yield utils.PathToConfigFile( '.vimspector.json',
|
||||||
|
os.path.dirname( current_file ) )
|
||||||
|
|
|
||||||
|
|
@ -38,3 +38,13 @@ def GetGadgetConfigFile( vimspector_base ):
|
||||||
def GetGadgetConfigDir( vimspector_base ):
|
def GetGadgetConfigDir( vimspector_base ):
|
||||||
return os.path.join( GetGadgetDir( vimspector_base, GetOS() ),
|
return os.path.join( GetGadgetDir( vimspector_base, GetOS() ),
|
||||||
'.gadgets.d' )
|
'.gadgets.d' )
|
||||||
|
|
||||||
|
|
||||||
|
def GetConfigDirForFiletype( vimspector_base, filetype ):
|
||||||
|
if not filetype:
|
||||||
|
filetype = 'default'
|
||||||
|
|
||||||
|
return os.path.join( os.path.abspath( vimspector_base ),
|
||||||
|
'configurations',
|
||||||
|
GetOS(),
|
||||||
|
filetype )
|
||||||
|
|
|
||||||
218
python3/vimspector/installer.py
Normal file
218
python3/vimspector/installer.py
Normal file
|
|
@ -0,0 +1,218 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# vimspector - A multi-language debugging system for Vim
|
||||||
|
# Copyright 2019 Ben Jackson
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
from urllib import request
|
||||||
|
import io
|
||||||
|
import contextlib
|
||||||
|
import zipfile
|
||||||
|
import gzip
|
||||||
|
import shutil
|
||||||
|
import tarfile
|
||||||
|
import hashlib
|
||||||
|
import time
|
||||||
|
import ssl
|
||||||
|
import subprocess
|
||||||
|
import functools
|
||||||
|
import os
|
||||||
|
|
||||||
|
from vimspector import install
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def CurrentWorkingDir( d ):
|
||||||
|
cur_d = os.getcwd()
|
||||||
|
try:
|
||||||
|
os.chdir( d )
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
os.chdir( cur_d )
|
||||||
|
|
||||||
|
|
||||||
|
def MakeExecutable( file_path ):
|
||||||
|
# TODO: import stat and use them by _just_ adding the X bit.
|
||||||
|
print( 'Making executable: {}'.format( file_path ) )
|
||||||
|
os.chmod( file_path, 0o755 )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def WithRetry( f ):
|
||||||
|
retries = 5
|
||||||
|
timeout = 1 # seconds
|
||||||
|
|
||||||
|
@functools.wraps( f )
|
||||||
|
def wrapper( *args, **kwargs ):
|
||||||
|
thrown = None
|
||||||
|
for _ in range( retries ):
|
||||||
|
try:
|
||||||
|
return f( *args, **kwargs )
|
||||||
|
except Exception as e:
|
||||||
|
thrown = e
|
||||||
|
print( "Failed - {}, will retry in {} seconds".format( e, timeout ) )
|
||||||
|
time.sleep( timeout )
|
||||||
|
raise thrown
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
@WithRetry
|
||||||
|
def UrlOpen( *args, **kwargs ):
|
||||||
|
return request.urlopen( *args, **kwargs )
|
||||||
|
|
||||||
|
|
||||||
|
def DownloadFileTo( url,
|
||||||
|
destination,
|
||||||
|
file_name = None,
|
||||||
|
checksum = None,
|
||||||
|
check_certificate = True ):
|
||||||
|
if not file_name:
|
||||||
|
file_name = url.split( '/' )[ -1 ]
|
||||||
|
|
||||||
|
file_path = os.path.abspath( os.path.join( destination, file_name ) )
|
||||||
|
|
||||||
|
if not os.path.isdir( destination ):
|
||||||
|
os.makedirs( destination )
|
||||||
|
|
||||||
|
if os.path.exists( file_path ):
|
||||||
|
if checksum:
|
||||||
|
if ValidateCheckSumSHA256( file_path, checksum ):
|
||||||
|
print( "Checksum matches for {}, using it".format( file_path ) )
|
||||||
|
return file_path
|
||||||
|
else:
|
||||||
|
print( "Checksum doesn't match for {}, removing it".format(
|
||||||
|
file_path ) )
|
||||||
|
|
||||||
|
print( "Removing existing {}".format( file_path ) )
|
||||||
|
os.remove( file_path )
|
||||||
|
|
||||||
|
r = request.Request( url, headers = { 'User-Agent': 'Vimspector' } )
|
||||||
|
|
||||||
|
print( "Downloading {} to {}/{}".format( url, destination, file_name ) )
|
||||||
|
|
||||||
|
if not check_certificate:
|
||||||
|
context = ssl.create_default_context()
|
||||||
|
context.check_hostname = False
|
||||||
|
context.verify_mode = ssl.CERT_NONE
|
||||||
|
kwargs = { "context": context }
|
||||||
|
else:
|
||||||
|
kwargs = {}
|
||||||
|
|
||||||
|
with contextlib.closing( UrlOpen( r, **kwargs ) ) as u:
|
||||||
|
with open( file_path, 'wb' ) as f:
|
||||||
|
f.write( u.read() )
|
||||||
|
|
||||||
|
if checksum:
|
||||||
|
if not ValidateCheckSumSHA256( file_path, checksum ):
|
||||||
|
raise RuntimeError(
|
||||||
|
'Checksum for {} ({}) does not match expected {}'.format(
|
||||||
|
file_path,
|
||||||
|
GetChecksumSHA254( file_path ),
|
||||||
|
checksum ) )
|
||||||
|
else:
|
||||||
|
print( "Checksum for {}: {}".format( file_path,
|
||||||
|
GetChecksumSHA254( file_path ) ) )
|
||||||
|
|
||||||
|
return file_path
|
||||||
|
|
||||||
|
|
||||||
|
def GetChecksumSHA254( file_path ):
|
||||||
|
with open( file_path, 'rb' ) as existing_file:
|
||||||
|
return hashlib.sha256( existing_file.read() ).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def ValidateCheckSumSHA256( file_path, checksum ):
|
||||||
|
existing_sha256 = GetChecksumSHA254( file_path )
|
||||||
|
return existing_sha256 == checksum
|
||||||
|
|
||||||
|
|
||||||
|
def RemoveIfExists( destination ):
|
||||||
|
if os.path.exists( destination ) or os.path.islink( destination ):
|
||||||
|
if os.path.islink( destination ):
|
||||||
|
print( "Removing file {}".format( destination ) )
|
||||||
|
os.remove( destination )
|
||||||
|
else:
|
||||||
|
print( "Removing dir {}".format( destination ) )
|
||||||
|
shutil.rmtree( destination )
|
||||||
|
|
||||||
|
|
||||||
|
# Python's ZipFile module strips execute bits from files, for no good reason
|
||||||
|
# other than crappy code. Let's do it's job for it.
|
||||||
|
class ModePreservingZipFile( zipfile.ZipFile ):
|
||||||
|
def extract( self, member, path = None, pwd = None ):
|
||||||
|
if not isinstance( member, zipfile.ZipInfo ):
|
||||||
|
member = self.getinfo( member )
|
||||||
|
|
||||||
|
if path is None:
|
||||||
|
path = os.getcwd()
|
||||||
|
|
||||||
|
ret_val = self._extract_member( member, path, pwd )
|
||||||
|
attr = member.external_attr >> 16
|
||||||
|
os.chmod( ret_val, attr )
|
||||||
|
return ret_val
|
||||||
|
|
||||||
|
|
||||||
|
def ExtractZipTo( file_path, destination, format ):
|
||||||
|
print( "Extracting {} to {}".format( file_path, destination ) )
|
||||||
|
RemoveIfExists( destination )
|
||||||
|
|
||||||
|
if format == 'zip':
|
||||||
|
with ModePreservingZipFile( file_path ) as f:
|
||||||
|
f.extractall( path = destination )
|
||||||
|
elif format == 'zip.gz':
|
||||||
|
with gzip.open( file_path, 'rb' ) as f:
|
||||||
|
file_contents = f.read()
|
||||||
|
|
||||||
|
with ModePreservingZipFile( io.BytesIO( file_contents ) ) as f:
|
||||||
|
f.extractall( path = destination )
|
||||||
|
|
||||||
|
elif format == 'tar':
|
||||||
|
try:
|
||||||
|
with tarfile.open( file_path ) as f:
|
||||||
|
f.extractall( path = destination )
|
||||||
|
except Exception:
|
||||||
|
# There seems to a bug in python's tarfile that means it can't read some
|
||||||
|
# windows-generated tar files
|
||||||
|
os.makedirs( destination )
|
||||||
|
with CurrentWorkingDir( destination ):
|
||||||
|
subprocess.check_call( [ 'tar', 'zxvf', file_path ] )
|
||||||
|
|
||||||
|
|
||||||
|
def MakeExtensionSymlink( vimspector_base, name, root ):
|
||||||
|
MakeSymlink( install.GetGadgetDir( vimspector_base,
|
||||||
|
install.GetOS() ),
|
||||||
|
name,
|
||||||
|
os.path.join( root, 'extension' ) ),
|
||||||
|
|
||||||
|
|
||||||
|
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 )
|
||||||
|
git_in_repo = [ 'git', '-C', destination ]
|
||||||
|
subprocess.check_call( [ 'git', 'clone', url, destination ] )
|
||||||
|
subprocess.check_call( git_in_repo + [ 'checkout', ref ] )
|
||||||
|
subprocess.check_call( git_in_repo + [ 'submodule', 'sync', '--recursive' ] )
|
||||||
|
subprocess.check_call( git_in_repo + [ 'submodule',
|
||||||
|
'update',
|
||||||
|
'--init',
|
||||||
|
'--recursive' ] )
|
||||||
|
|
@ -515,3 +515,8 @@ def SetSyntax( current_syntax, syntax, *args ):
|
||||||
vim.command( 'set syntax={}'.format( Escape( syntax ) ) )
|
vim.command( 'set syntax={}'.format( Escape( syntax ) ) )
|
||||||
|
|
||||||
return syntax
|
return syntax
|
||||||
|
|
||||||
|
|
||||||
|
def GetBufferFiletypes( buf ):
|
||||||
|
ft = ToUnicode( vim.eval( f"getbufvar( {buf.number}, '&ft' )" ) )
|
||||||
|
return ft.split( '.' )
|
||||||
|
|
|
||||||
29
support/test/python/no_conf/main.py
Executable file
29
support/test/python/no_conf/main.py
Executable file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
|
||||||
|
class TestClass( object ):
|
||||||
|
def __init__( self, value ):
|
||||||
|
self._var = value
|
||||||
|
try:
|
||||||
|
self.DoSomething()
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def DoSomething( self ):
|
||||||
|
for i in range( 0, 100 ):
|
||||||
|
if i < self._var:
|
||||||
|
print( '{0} is less than the value'.format( i ) )
|
||||||
|
else:
|
||||||
|
print( '{0} might be more'.format( i ) )
|
||||||
|
|
||||||
|
raise ValueError( 'Done' )
|
||||||
|
|
||||||
|
|
||||||
|
def Main():
|
||||||
|
t = TestClass( 18 )
|
||||||
|
|
||||||
|
t._var = 99
|
||||||
|
t.DoSomething()
|
||||||
|
|
||||||
|
|
||||||
|
Main()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue