Upgrade gadgets when they change
This adds a --upgrade option to install_gadget.py and makes VimspectorUpdate only update things which have changed. To do this, we record the gadget spec in a manfiest file and compare it with the current spec when in upgrade mode. 'Changed' in this case means that the gadget spec has changed from the last time the installer was run. It does _not_ actually check the presence of the gadget.
This commit is contained in:
parent
56418e3233
commit
f9d20b9537
5 changed files with 162 additions and 70 deletions
|
|
@ -234,8 +234,7 @@ GADGETS = {
|
|||
},
|
||||
'macos': {
|
||||
'file_name': 'netcoredbg-osx-master.tar.gz',
|
||||
'checksum':
|
||||
'c1dc6ed58c3f5b0473cfb4985a96552999360ceb9795e42d9c9be64af054f821',
|
||||
'checksum': '',
|
||||
},
|
||||
'linux': {
|
||||
'file_name': 'netcoredbg-linux-master.tar.gz',
|
||||
|
|
@ -385,7 +384,7 @@ GADGETS = {
|
|||
'enabled': False,
|
||||
'repo': {
|
||||
'url': 'https://github.com/microsoft/vscode-node-debug2',
|
||||
'ref': 'v1.42.0',
|
||||
'ref': 'v1.42.5'
|
||||
},
|
||||
'do': lambda name, root, gadget: installer.InstallNodeDebug( name,
|
||||
root,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,11 @@ def GetGadgetDir( vimspector_base ):
|
|||
return os.path.join( os.path.abspath( vimspector_base ), 'gadgets', GetOS() )
|
||||
|
||||
|
||||
def GetManifestFile( vimspector_base ):
|
||||
return os.path.join( GetGadgetDir( vimspector_base ),
|
||||
'.gadgets.manifest.json' )
|
||||
|
||||
|
||||
def GetGadgetConfigFile( vimspector_base ):
|
||||
return os.path.join( GetGadgetDir( vimspector_base ), '.gadgets.json' )
|
||||
|
||||
|
|
|
|||
|
|
@ -162,6 +162,7 @@ def RunUpdate( api_prefix, leave_open, *args ):
|
|||
insatller_args.extend( FindGadgetForAdapter( adapter_name ) )
|
||||
|
||||
if insatller_args:
|
||||
insatller_args.append( '--upgrade' )
|
||||
RunInstaller( api_prefix, leave_open, *insatller_args )
|
||||
|
||||
|
||||
|
|
@ -217,6 +218,91 @@ def FindGadgetForAdapter( adapter_name ):
|
|||
return candidates
|
||||
|
||||
|
||||
class Manifest:
|
||||
manifest: dict
|
||||
|
||||
def __init__( self ):
|
||||
self.manifest = {}
|
||||
self.Read()
|
||||
|
||||
def Read( self ):
|
||||
try:
|
||||
with open( install.GetManifestFile( options.vimspector_base ), 'r' ) as f:
|
||||
self.manifest = json.load( f )
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def Write( self ):
|
||||
with open( install.GetManifestFile( options.vimspector_base ), 'w' ) as f:
|
||||
json.dump( self.manifest, f )
|
||||
|
||||
|
||||
def Clear( self, name: str ):
|
||||
try:
|
||||
del self.manifest[ name ]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
def Update( self, name: str, gadget_spec: dict ):
|
||||
self.manifest[ name ] = gadget_spec
|
||||
|
||||
|
||||
def RequiresUpdate( self, name: str, gadget_spec: dict ):
|
||||
try:
|
||||
current_spec = self.manifest[ name ]
|
||||
except KeyError:
|
||||
# It's new.
|
||||
return True
|
||||
|
||||
# If anything changed in the spec, update
|
||||
if not current_spec == gadget_spec:
|
||||
return True
|
||||
|
||||
# Always update if the version string is 'master'. Probably a git repo
|
||||
# that pulls master (which tbh we shouldn't have)
|
||||
if current_spec.get( 'version' ) in ( 'master', '' ):
|
||||
return True
|
||||
if current_spec.get( 'repo', {} ).get( 'ref' ) == 'master':
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def ReadAdapters( read_existing = True ):
|
||||
all_adapters = {}
|
||||
if read_existing:
|
||||
try:
|
||||
with open( install.GetGadgetConfigFile( options.vimspector_base ),
|
||||
'r' ) as f:
|
||||
all_adapters = json.load( f ).get( 'adapters', {} )
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
# Include "built-in" adapter for multi-session mode
|
||||
all_adapters.update( {
|
||||
'multi-session': {
|
||||
'port': '${port}',
|
||||
'host': '${host}'
|
||||
},
|
||||
} )
|
||||
|
||||
return all_adapters
|
||||
|
||||
|
||||
def WriteAdapters( all_adapters, to_file=None ):
|
||||
adapter_config = json.dumps ( { 'adapters': all_adapters },
|
||||
indent=2,
|
||||
sort_keys=True )
|
||||
|
||||
if to_file:
|
||||
to_file.write( adapter_config )
|
||||
else:
|
||||
with open( install.GetGadgetConfigFile( options.vimspector_base ),
|
||||
'w' ) as f:
|
||||
f.write( adapter_config )
|
||||
|
||||
|
||||
def InstallGeneric( name, root, gadget ):
|
||||
extension = os.path.join( root, 'extension' )
|
||||
for f in gadget.get( 'make_executable', [] ):
|
||||
|
|
@ -300,52 +386,57 @@ def InstallTclProDebug( name, root, gadget ):
|
|||
|
||||
|
||||
def InstallNodeDebug( name, root, gadget ):
|
||||
node_version = subprocess.check_output( [ 'node', '--version' ],
|
||||
universal_newlines=True ).strip()
|
||||
Print( "Node.js version: {}".format( node_version ) )
|
||||
if list( map( int, node_version[ 1: ].split( '.' ) ) ) >= [ 12, 0, 0 ]:
|
||||
Print( "Can't install vscode-debug-node2:" )
|
||||
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 "
|
||||
"we know, there isn't a pre-built independent package." )
|
||||
Print( "My advice is to install nvm, then do:" )
|
||||
Print( " $ nvm install --lts 10" )
|
||||
Print( " $ nvm use --lts 10" )
|
||||
Print( " $ ./install_gadget.py --enable-node ..." )
|
||||
raise RuntimeError( 'Node 10 is required to install node debugger (sadly)' )
|
||||
|
||||
with CurrentWorkingDir( root ):
|
||||
CheckCall( [ 'npm', 'install' ] )
|
||||
CheckCall( [ 'npm', 'run', 'build' ] )
|
||||
MakeSymlink( name, root )
|
||||
|
||||
|
||||
def InstallGagdet( name, gadget, succeeded, failed, all_adapters ):
|
||||
def InstallGagdet( name: str,
|
||||
gadget: dict,
|
||||
manifest: Manifest,
|
||||
succeeded: list,
|
||||
failed: list,
|
||||
all_adapters: dict ):
|
||||
|
||||
try:
|
||||
print( f"Installing {name}..." )
|
||||
v = {}
|
||||
v.update( gadget.get( 'all', {} ) )
|
||||
v.update( gadget.get( install.GetOS(), {} ) )
|
||||
# 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 v:
|
||||
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,
|
||||
v[ 'version' ] )
|
||||
spec[ 'version' ] )
|
||||
|
||||
url = string.Template( gadget[ 'download' ][ 'url' ] ).substitute( v )
|
||||
url = string.Template( gadget[ 'download' ][ 'url' ] ).substitute( spec )
|
||||
|
||||
file_path = DownloadFileTo(
|
||||
url,
|
||||
destination,
|
||||
file_name = gadget[ 'download' ].get( 'target' ),
|
||||
checksum = v.get( 'checksum' ),
|
||||
checksum = spec.get( 'checksum' ),
|
||||
check_certificate = not options.no_check_certificate )
|
||||
|
||||
root = os.path.join( destination, 'root' )
|
||||
|
|
@ -354,8 +445,15 @@ def InstallGagdet( name, gadget, succeeded, failed, all_adapters ):
|
|||
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 )
|
||||
url = string.Template( gadget[ 'repo' ][ 'url' ] ).substitute( spec )
|
||||
ref = string.Template( gadget[ 'repo' ][ 'ref' ] ).substitute( spec )
|
||||
|
||||
print( f"Installing {name}@{gadget[ 'repo' ][ '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 ),
|
||||
|
|
@ -365,15 +463,12 @@ def InstallGagdet( name, gadget, succeeded, failed, all_adapters ):
|
|||
root = destination
|
||||
|
||||
if 'do' in gadget:
|
||||
gadget[ 'do' ]( name, root, v )
|
||||
gadget[ 'do' ]( name, root, spec )
|
||||
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', {} ) )
|
||||
InstallGeneric( name, root, spec )
|
||||
|
||||
save_adapters()
|
||||
manifest.Update( name, spec )
|
||||
succeeded.append( name )
|
||||
print( f" - Done installing {name}" )
|
||||
except Exception as e:
|
||||
|
|
@ -383,40 +478,6 @@ def InstallGagdet( name, gadget, succeeded, failed, all_adapters ):
|
|||
print( f" - FAILED installing {name}: {e}".format( name, e ) )
|
||||
|
||||
|
||||
def ReadAdapters( read_existing = True ):
|
||||
all_adapters = {}
|
||||
if read_existing:
|
||||
try:
|
||||
with open( install.GetGadgetConfigFile( options.vimspector_base ),
|
||||
'r' ) as f:
|
||||
all_adapters = json.load( f ).get( 'adapters', {} )
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
# Include "built-in" adapter for multi-session mode
|
||||
all_adapters.update( {
|
||||
'multi-session': {
|
||||
'port': '${port}',
|
||||
'host': '${host}'
|
||||
},
|
||||
} )
|
||||
|
||||
return all_adapters
|
||||
|
||||
|
||||
def WriteAdapters( all_adapters, to_file=None ):
|
||||
adapter_config = json.dumps ( { 'adapters': all_adapters },
|
||||
indent=2,
|
||||
sort_keys=True )
|
||||
|
||||
if to_file:
|
||||
to_file.write( adapter_config )
|
||||
else:
|
||||
with open( install.GetGadgetConfigFile( options.vimspector_base ),
|
||||
'w' ) as f:
|
||||
f.write( adapter_config )
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def CurrentWorkingDir( d ):
|
||||
cur_d = os.getcwd()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue