server: add a command to lock current versions
This commit is contained in:
parent
df4a4e3e1d
commit
5e7c703cca
@ -17,6 +17,62 @@ def add(ctx, name, path):
|
|||||||
ctx.obj['config'].save()
|
ctx.obj['config'].save()
|
||||||
click.echo("Added server {} in {}".format(name, path))
|
click.echo("Added server {} in {}".format(name, path))
|
||||||
|
|
||||||
|
@server.command(help="Save a server's current plugin list to mpm.yaml")
|
||||||
|
@click.pass_context
|
||||||
|
@click.argument('servers', type=ServerParamType(), nargs=-1)
|
||||||
|
def lock(ctx, servers):
|
||||||
|
config = ctx.obj['config']
|
||||||
|
if len(servers) == 0:
|
||||||
|
servers = config.servers()
|
||||||
|
validRepos = []
|
||||||
|
for repo in ctx.obj['config'].repositories():
|
||||||
|
if not repo.exists():
|
||||||
|
click.echo("Missing repository: '{}' not found at {}".format(repo.name, repo.path))
|
||||||
|
else:
|
||||||
|
validRepos.append(repo)
|
||||||
|
for server in servers:
|
||||||
|
click.echo('{} ({}):'.format(server.name, server.path))
|
||||||
|
savedPlugins = []
|
||||||
|
changedPlugins = []
|
||||||
|
for state in server.pluginStates(validRepos):
|
||||||
|
if isinstance(state, Installed):
|
||||||
|
savedPlugins.append(state)
|
||||||
|
elif isinstance(state, Outdated):
|
||||||
|
changedPlugins.append(state)
|
||||||
|
elif isinstance(state, MissingVersions):
|
||||||
|
changedPlugins.append(state)
|
||||||
|
rows = []
|
||||||
|
for state in savedPlugins:
|
||||||
|
newSpec = PluginSpec(state.plugin.name,
|
||||||
|
state.currentVersion.version)
|
||||||
|
if newSpec == state.plugin:
|
||||||
|
continue
|
||||||
|
rows.append([
|
||||||
|
state.plugin.name,
|
||||||
|
click.style('{} -> {}'.format(state.plugin.versionSpec,
|
||||||
|
state.currentVersion.version), fg='green'),
|
||||||
|
state.currentVersion.version
|
||||||
|
])
|
||||||
|
server.set_plugin_version(state.plugin.name, state.currentVersion.version)
|
||||||
|
for state in changedPlugins:
|
||||||
|
if state.currentVersion is not None:
|
||||||
|
rows.append([
|
||||||
|
click.style(state.plugin.name, fg='yellow'),
|
||||||
|
click.style('{} -> {}'.format(state.plugin.versionSpec,
|
||||||
|
state.currentVersion.version),
|
||||||
|
fg='yellow'),
|
||||||
|
state.currentVersion.version
|
||||||
|
])
|
||||||
|
server.set_plugin_version(state.plugin.name, state.currentVersion.version)
|
||||||
|
if len(rows) > 0:
|
||||||
|
click.echo(columnar(rows, ['Plugin', 'Wanted', 'Installed'],
|
||||||
|
no_borders=True))
|
||||||
|
config.update_server(server.name, server.config)
|
||||||
|
click.echo("Apply changes? [y/N]", nl=False)
|
||||||
|
answer = click.getchar().lower()
|
||||||
|
if answer == "y":
|
||||||
|
config.save()
|
||||||
|
|
||||||
@server.command('list', help='List configured servers')
|
@server.command('list', help='List configured servers')
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
@click.argument('servers', type=ServerParamType(), nargs=-1)
|
@click.argument('servers', type=ServerParamType(), nargs=-1)
|
||||||
@ -62,9 +118,9 @@ def list_(ctx, servers):
|
|||||||
curStr = click.style(str(state.currentVersion.version), fg='yellow')
|
curStr = click.style(str(state.currentVersion.version), fg='yellow')
|
||||||
rows.append([
|
rows.append([
|
||||||
state.plugin.name,
|
state.plugin.name,
|
||||||
click.style(str(state.wantedVersion), fg='green'),
|
click.style(str(state.plugin.versionSpec), fg='green'),
|
||||||
curStr,
|
curStr,
|
||||||
click.style(str(state.plugin.version), fg='green')
|
click.style(str(state.wantedVersion), fg='green')
|
||||||
])
|
])
|
||||||
for state in sorted(missing):
|
for state in sorted(missing):
|
||||||
rows.append([
|
rows.append([
|
||||||
@ -161,9 +217,9 @@ def sync(ctx, servers):
|
|||||||
curStr = click.style(str(state.currentVersion.version), fg='yellow')
|
curStr = click.style(str(state.currentVersion.version), fg='yellow')
|
||||||
rows.append([
|
rows.append([
|
||||||
state.plugin.name,
|
state.plugin.name,
|
||||||
click.style(str(state.wantedVersion), fg='green'),
|
click.style(str(state.plugin.versionSpec), fg='green'),
|
||||||
curStr,
|
curStr,
|
||||||
click.style(str(state.plugin.version), fg='green')
|
click.style(str(state.wantedVersion.version), fg='green')
|
||||||
])
|
])
|
||||||
|
|
||||||
click.echo("Missing plugins:")
|
click.echo("Missing plugins:")
|
||||||
|
@ -7,20 +7,28 @@ version_pattern = re.compile('^(?P<name>.+)-(?P<version>(?:\.?\d+)+).+jar$')
|
|||||||
|
|
||||||
@total_ordering
|
@total_ordering
|
||||||
class Plugin:
|
class Plugin:
|
||||||
def __init__(self, path):
|
def __init__(self, path, forceName=None, forceVersion=None):
|
||||||
self.path = path
|
self.path = path
|
||||||
pluginName = os.path.basename(path)
|
pluginName = os.path.basename(path)
|
||||||
pluginMatches = version_pattern.match(pluginName)
|
|
||||||
|
|
||||||
if pluginMatches is None:
|
if forceVersion is None:
|
||||||
raise ValueError("Cannot derive plugin name from '{}'".format(path))
|
pluginMatches = version_pattern.match(pluginName)
|
||||||
|
|
||||||
self.name = pluginMatches['name']
|
if pluginMatches is None:
|
||||||
|
raise ValueError("Cannot derive plugin name from '{}'".format(path))
|
||||||
|
|
||||||
try:
|
if forceName is None:
|
||||||
self.version = Version.coerce(pluginMatches['version'])
|
self.name = pluginMatches['name']
|
||||||
except ValueError:
|
else:
|
||||||
raise ValueError("Cannot derive semver from '{}'".format(path))
|
self.name = forceName
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.version = Version.coerce(pluginMatches['version'])
|
||||||
|
except ValueError:
|
||||||
|
raise ValueError("Cannot derive semver from '{}'".format(path))
|
||||||
|
else:
|
||||||
|
self.version = forceVersion
|
||||||
|
self.name = forceName
|
||||||
|
|
||||||
def normalizedFilename(self):
|
def normalizedFilename(self):
|
||||||
return "{}-{}.jar".format(self.name, self.version)
|
return "{}-{}.jar".format(self.name, self.version)
|
||||||
@ -98,19 +106,10 @@ class Outdated(PluginState):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'Outdated({})'.format(self.plugin)
|
return 'Outdated({})'.format(self.plugin)
|
||||||
|
|
||||||
class SymlinkConflict(PluginState):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class MissingVersions(PluginState):
|
class MissingVersions(PluginState):
|
||||||
pass
|
def __init__(self, plugin, currentVersion):
|
||||||
|
super().__init__(plugin)
|
||||||
class Available(PluginState):
|
self.currentVersion = currentVersion
|
||||||
def __init__(self, repoPlugin, wantedVersion):
|
|
||||||
super().__init__(repoPlugin)
|
|
||||||
self.wantedVersion = wantedVersion
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return 'Available({})'.format(self.plugin)
|
|
||||||
|
|
||||||
class Installed(PluginState):
|
class Installed(PluginState):
|
||||||
def __init__(self, plugin, currentVersion):
|
def __init__(self, plugin, currentVersion):
|
||||||
|
@ -2,6 +2,7 @@ from mpm.model import *
|
|||||||
import shutil
|
import shutil
|
||||||
import pathlib
|
import pathlib
|
||||||
import logging
|
import logging
|
||||||
|
import hashlib
|
||||||
import os
|
import os
|
||||||
import semantic_version
|
import semantic_version
|
||||||
|
|
||||||
@ -26,13 +27,18 @@ class Server:
|
|||||||
raise KeyError("Cannot add plugin multiple times.")
|
raise KeyError("Cannot add plugin multiple times.")
|
||||||
self.config['plugins'].append({'name': pluginSpec.name, 'version': str(pluginSpec.versionSpec)})
|
self.config['plugins'].append({'name': pluginSpec.name, 'version': str(pluginSpec.versionSpec)})
|
||||||
|
|
||||||
|
def set_plugin_version(self, pluginName, versionSpec):
|
||||||
|
for plugin in self.config['plugins']:
|
||||||
|
if plugin['name'] == pluginName:
|
||||||
|
plugin['version'] = str(versionSpec)
|
||||||
|
|
||||||
def pluginStates(self, repos):
|
def pluginStates(self, repos):
|
||||||
managedPluginFilenames = []
|
managedPluginFilenames = []
|
||||||
for plugin in self.plugins():
|
for plugin in self.plugins():
|
||||||
logger.debug("Checking %r", plugin)
|
logger.debug("Checking %r", plugin)
|
||||||
compatibleVersions = []
|
compatibleVersions = []
|
||||||
|
|
||||||
currentVersion = self.currentVersionForPlugin(plugin.name)
|
currentVersion = self.currentVersionForPlugin(plugin.name, repos)
|
||||||
logger.debug('Current version: %s', currentVersion)
|
logger.debug('Current version: %s', currentVersion)
|
||||||
if currentVersion is not None:
|
if currentVersion is not None:
|
||||||
if plugin.versionSpec.match(currentVersion.version):
|
if plugin.versionSpec.match(currentVersion.version):
|
||||||
@ -48,7 +54,7 @@ class Server:
|
|||||||
compatibleVersions.append(repoPlugin)
|
compatibleVersions.append(repoPlugin)
|
||||||
if len(compatibleVersions) == 0:
|
if len(compatibleVersions) == 0:
|
||||||
logger.debug('No compatible versions found for %s', plugin)
|
logger.debug('No compatible versions found for %s', plugin)
|
||||||
yield MissingVersions(plugin)
|
yield MissingVersions(plugin, currentVersion)
|
||||||
else:
|
else:
|
||||||
preferredVersion = list(reversed(sorted(compatibleVersions)))[0]
|
preferredVersion = list(reversed(sorted(compatibleVersions)))[0]
|
||||||
logger.debug('Wanted %r, found %r', plugin, preferredVersion)
|
logger.debug('Wanted %r, found %r', plugin, preferredVersion)
|
||||||
@ -57,7 +63,7 @@ class Server:
|
|||||||
yield Installed(plugin, currentVersion)
|
yield Installed(plugin, currentVersion)
|
||||||
else:
|
else:
|
||||||
logger.debug("Update available: %r -> %r", plugin, preferredVersion)
|
logger.debug("Update available: %r -> %r", plugin, preferredVersion)
|
||||||
yield Outdated(preferredVersion, currentVersion, plugin.versionSpec)
|
yield Outdated(plugin, currentVersion, preferredVersion)
|
||||||
|
|
||||||
otherPlugins = os.listdir(self.pluginPath)
|
otherPlugins = os.listdir(self.pluginPath)
|
||||||
for pluginFile in otherPlugins:
|
for pluginFile in otherPlugins:
|
||||||
@ -65,19 +71,39 @@ class Server:
|
|||||||
logger.debug("Unmanaged file: %s", pluginFile)
|
logger.debug("Unmanaged file: %s", pluginFile)
|
||||||
yield UnmanagedFile(pluginFile)
|
yield UnmanagedFile(pluginFile)
|
||||||
|
|
||||||
def currentVersionForPlugin(self, pluginName):
|
def currentVersionForPlugin(self, pluginName, repos=[]):
|
||||||
plugins = os.listdir(self.pluginPath)
|
plugins = os.listdir(self.pluginPath)
|
||||||
for pluginJar in plugins:
|
for pluginJar in plugins:
|
||||||
if pluginJar.startswith(pluginName) and pluginJar.endswith(".jar"):
|
if pluginJar.startswith(pluginName) and pluginJar.endswith(".jar"):
|
||||||
try:
|
if pluginJar == pluginName + ".jar":
|
||||||
return Plugin(os.path.join(self.pluginPath, pluginJar))
|
logger.debug("Running checksum search to find version of %s", pluginJar)
|
||||||
except ValueError:
|
pluginPath = os.path.join(self.pluginPath, pluginJar)
|
||||||
continue
|
with open(pluginPath, 'rb') as fd:
|
||||||
|
installedHash = hashlib.file_digest(fd, 'sha256')
|
||||||
|
pluginName = pluginJar.split('.jar')[0]
|
||||||
|
defaultVersion = semantic_version.Version("0.0.0")
|
||||||
|
for repo in repos:
|
||||||
|
for plugin in repo.plugins():
|
||||||
|
if plugin.name == pluginName:
|
||||||
|
with open(plugin.path, 'rb') as fd:
|
||||||
|
foundHash = hashlib.file_digest(fd, 'sha256')
|
||||||
|
if foundHash.hexdigest() == installedHash.hexdigest():
|
||||||
|
return Plugin(pluginPath,
|
||||||
|
forceName=pluginName,
|
||||||
|
forceVersion = plugin.version)
|
||||||
|
return Plugin(pluginPath,
|
||||||
|
forceName=pluginName,
|
||||||
|
forceVersion=defaultVersion)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
return Plugin(os.path.join(self.pluginPath, pluginJar))
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
|
||||||
def syncToVersion(self, plugin):
|
def syncToVersion(self, plugin, repos=[]):
|
||||||
dest = os.path.join(self.pluginPath, plugin.normalizedFilename())
|
dest = os.path.join(self.pluginPath, plugin.normalizedFilename())
|
||||||
logger.debug("Syncing %s to %s", dest, plugin)
|
logger.debug("Syncing %s to %s", dest, plugin)
|
||||||
current = self.currentVersionForPlugin(plugin.name)
|
current = self.currentVersionForPlugin(plugin.name, repos)
|
||||||
if current is not None:
|
if current is not None:
|
||||||
logger.debug("Removing current version %r", current)
|
logger.debug("Removing current version %r", current)
|
||||||
current.unlink()
|
current.unlink()
|
||||||
|
Loading…
Reference in New Issue
Block a user