cli: switch to click
This commit is contained in:
parent
55c5bc489c
commit
1bea5f5a6d
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
*.swp
|
*.swp
|
||||||
Pipfile.lock
|
Pipfile.lock
|
||||||
|
build
|
||||||
|
3
Pipfile
3
Pipfile
@ -6,6 +6,9 @@ name = "pypi"
|
|||||||
[packages]
|
[packages]
|
||||||
pyyaml = "*"
|
pyyaml = "*"
|
||||||
semantic-version = "*"
|
semantic-version = "*"
|
||||||
|
click = "*"
|
||||||
|
minecraft-package-manager = {editable = true, path = "."}
|
||||||
|
columnar = "*"
|
||||||
|
|
||||||
[dev-packages]
|
[dev-packages]
|
||||||
|
|
||||||
|
@ -9,4 +9,4 @@ name = "minecraft-package-manager"
|
|||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
mpm = "mpm.main:main"
|
mpm = "mpm.commands:mpm"
|
||||||
|
16
src/mpm/commands/__init__.py
Normal file
16
src/mpm/commands/__init__.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
from . import server, repo, config
|
||||||
|
from mpm.config import Config
|
||||||
|
import click
|
||||||
|
|
||||||
|
@click.group()
|
||||||
|
@click.option("--config", type=click.Path(readable=True, writable=False,
|
||||||
|
dir_okay=False))
|
||||||
|
@click.pass_context
|
||||||
|
def mpm(ctx, config):
|
||||||
|
ctx.ensure_object(dict)
|
||||||
|
ctx.obj['config'] = Config(config)
|
||||||
|
pass
|
||||||
|
|
||||||
|
mpm.add_command(config.config)
|
||||||
|
mpm.add_command(server.server)
|
||||||
|
mpm.add_command(repo.repo)
|
14
src/mpm/commands/config.py
Normal file
14
src/mpm/commands/config.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import click
|
||||||
|
import sys
|
||||||
|
import yaml
|
||||||
|
from mpm.config import Dumper
|
||||||
|
|
||||||
|
@click.group(help='Configure MPM')
|
||||||
|
def config():
|
||||||
|
pass
|
||||||
|
|
||||||
|
@config.command(help='Show the current configuration')
|
||||||
|
@click.pass_context
|
||||||
|
def show(ctx):
|
||||||
|
sys.stdout.write("# {}\n".format(ctx.obj['config'].path))
|
||||||
|
yaml.dump(ctx.obj['config'].config, sys.stdout, Dumper=Dumper)
|
77
src/mpm/commands/repo.py
Normal file
77
src/mpm/commands/repo.py
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import click
|
||||||
|
import os
|
||||||
|
from mpm.model import Plugin
|
||||||
|
from mpm.config import RepoParamType
|
||||||
|
import pathlib
|
||||||
|
from columnar import columnar
|
||||||
|
|
||||||
|
@click.group(help='Add and import plugins to repositories')
|
||||||
|
def repo():
|
||||||
|
pass
|
||||||
|
|
||||||
|
@repo.command('list', help='List configured repositories')
|
||||||
|
@click.pass_context
|
||||||
|
def list_(ctx):
|
||||||
|
for repo in ctx.obj['config'].repositories():
|
||||||
|
click.echo("{} ({})".format(click.style(repo.name,bold=True), repo.path))
|
||||||
|
rows = []
|
||||||
|
for plugin in sorted(repo.plugins()):
|
||||||
|
rows.append([
|
||||||
|
click.style(plugin.name, fg='green'),
|
||||||
|
click.style(plugin.version, fg='yellow')
|
||||||
|
])
|
||||||
|
if len(rows) > 0:
|
||||||
|
click.echo(columnar(rows, ['Plugin', 'Version'], no_borders=True))
|
||||||
|
else:
|
||||||
|
click.echo("No plugins found.")
|
||||||
|
for badFile in sorted(repo.badFiles()):
|
||||||
|
click.echo('\tWARNING: Unknown file {}'.format(badFile))
|
||||||
|
|
||||||
|
@repo.command(help='Add a new repository')
|
||||||
|
@click.pass_context
|
||||||
|
@click.argument("name")
|
||||||
|
@click.argument("path", type=click.Path(path_type=pathlib.Path))
|
||||||
|
def add(ctx, name, path):
|
||||||
|
path.mkdir(parents=True, exist_ok=True)
|
||||||
|
ctx.obj['config'].add_repository(name, path)
|
||||||
|
ctx.obj['config'].save()
|
||||||
|
click.echo("Added repository {} from {}".format(name, path))
|
||||||
|
|
||||||
|
@repo.command('import', help='Import a plugin to a repository')
|
||||||
|
@click.argument('repo', type=RepoParamType())
|
||||||
|
@click.argument('paths', type=click.Path(exists=True, readable=True,
|
||||||
|
path_type=pathlib.Path), nargs=-1)
|
||||||
|
def import_(repo, paths):
|
||||||
|
plugins = []
|
||||||
|
searchPaths = list(paths)
|
||||||
|
for path in searchPaths:
|
||||||
|
try:
|
||||||
|
if path.is_dir():
|
||||||
|
searchPaths += list(path.glob("*"))
|
||||||
|
continue
|
||||||
|
except PermissionError:
|
||||||
|
click.echo("Cannot read {}".format(path))
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
plugins.append(Plugin(path))
|
||||||
|
except:
|
||||||
|
click.echo("Bad plugin filename {}".format(path))
|
||||||
|
|
||||||
|
if len(plugins) == 0:
|
||||||
|
click.echo("No plugins found.")
|
||||||
|
return
|
||||||
|
|
||||||
|
click.echo('Found the following plugins:')
|
||||||
|
for plugin in plugins:
|
||||||
|
click.echo("\t{} {}".format(click.style(plugin.name, fg='green'),
|
||||||
|
click.style(plugin.version, fg='yellow')))
|
||||||
|
click.echo("Import plugins into {} ({})? [y/N] ".format(repo.name,
|
||||||
|
repo.path), nl=False)
|
||||||
|
answer = click.getchar().lower()
|
||||||
|
if answer == "y":
|
||||||
|
with click.progressbar(plugins, label='Importing') as bar:
|
||||||
|
for plugin in bar:
|
||||||
|
repo.importPlugin(plugin)
|
||||||
|
click.echo("Imported!")
|
||||||
|
else:
|
||||||
|
click.echo("Cancelled.")
|
150
src/mpm/commands/server.py
Normal file
150
src/mpm/commands/server.py
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
import click
|
||||||
|
from mpm.model import *
|
||||||
|
import pathlib
|
||||||
|
from mpm.config import ServerParamType
|
||||||
|
|
||||||
|
@click.group(help='Add, remove, and synchronize Servers')
|
||||||
|
def server():
|
||||||
|
pass
|
||||||
|
|
||||||
|
@server.command(help='Add a new server')
|
||||||
|
@click.pass_context
|
||||||
|
@click.argument('name')
|
||||||
|
@click.argument('path', type=click.Path(dir_okay=True, exists=True))
|
||||||
|
def add(ctx, name, path):
|
||||||
|
ctx.obj['config'].add_server(name, path)
|
||||||
|
ctx.obj['config'].save()
|
||||||
|
click.echo("Added server {} in {}".format(name, path))
|
||||||
|
|
||||||
|
@server.command('list', help='List configured servers')
|
||||||
|
@click.pass_context
|
||||||
|
def list_(ctx):
|
||||||
|
for server in ctx.obj['config'].servers():
|
||||||
|
click.echo('{} ({}):'.format(server.name, server.path))
|
||||||
|
serverPath = pathlib.Path(server.path)
|
||||||
|
if not serverPath.exists():
|
||||||
|
click.echo(click.style("\tServer path does not exist", fg='red'))
|
||||||
|
continue
|
||||||
|
pluginPath = pathlib.Path(server.path+'/plugins')
|
||||||
|
if not pluginPath.exists():
|
||||||
|
click.echo(click.style("\tServer plugin directory does not exist", fg='red'))
|
||||||
|
continue
|
||||||
|
outdatedLinks = []
|
||||||
|
missing = []
|
||||||
|
installed = []
|
||||||
|
unmanaged = []
|
||||||
|
conflicts = []
|
||||||
|
for state in sorted(server.pluginStates(ctx.obj['config'].repositories())):
|
||||||
|
if isinstance(state, OutdatedSymlink):
|
||||||
|
outdatedLinks.append(state)
|
||||||
|
elif isinstance(state, Installed):
|
||||||
|
installed.append(state)
|
||||||
|
elif isinstance(state, MissingVersions):
|
||||||
|
missing.append(state)
|
||||||
|
elif isinstance(state, UnmanagedFile):
|
||||||
|
unmanaged.append(state)
|
||||||
|
elif isinstance(state, SymlinkConflict):
|
||||||
|
conflicts.append(state)
|
||||||
|
|
||||||
|
click.echo("Installed plugins:")
|
||||||
|
for state in sorted(installed):
|
||||||
|
click.echo("\t{} {}: {}".format(state.plugin.name, state.plugin.versionSpec, state.currentVersion))
|
||||||
|
click.echo("Oudated symlinks:")
|
||||||
|
for state in sorted(outdatedLinks):
|
||||||
|
click.echo("\t{} {}: Current: {} Wanted: {}".format(state.plugin.name, state.plugin.versionSpec, state.currentVersion, state.wantedVersion))
|
||||||
|
click.echo("Missing plugins:")
|
||||||
|
for state in sorted(missing):
|
||||||
|
click.echo("\t{}: {}".format(state.plugin.name, state.plugin.versionSpec))
|
||||||
|
click.echo("Unmanaged files:")
|
||||||
|
for state in sorted(unmanaged):
|
||||||
|
click.echo("\t{}".format(state.filename))
|
||||||
|
click.echo("Symlink Conflicts:")
|
||||||
|
for state in sorted(conflicts):
|
||||||
|
click.echo("\t{}.jar".format(state.plugin.name))
|
||||||
|
|
||||||
|
@server.command(help='Add a plugin to a server')
|
||||||
|
@click.pass_context
|
||||||
|
@click.argument('server', type=ServerParamType())
|
||||||
|
@click.argument('plugins', nargs=-1)
|
||||||
|
def add_plugin(ctx, server, plugins):
|
||||||
|
pluginQueue = []
|
||||||
|
for pluginSpec in plugins:
|
||||||
|
if os.path.exists(pluginSpec):
|
||||||
|
plugin = Plugin(pluginSpec)
|
||||||
|
pluginSpec = PluginSpec(plugin.name, str(plugin.version))
|
||||||
|
else:
|
||||||
|
allVersions = []
|
||||||
|
for repo in ctx.obj['config'].repositories():
|
||||||
|
allVersions += repo.versionsForPlugin(pluginSpec)
|
||||||
|
pluginSpec = PluginSpec(pluginSpec, list(reversed(sorted(allVersions)))[0])
|
||||||
|
|
||||||
|
pluginQueue.append(pluginSpec)
|
||||||
|
|
||||||
|
click.echo("Resolved plugin list:")
|
||||||
|
for pluginSpec in pluginQueue:
|
||||||
|
click.echo("\t{} {}".format(click.style(pluginSpec.name, fg='green'),
|
||||||
|
click.style(pluginSpec.versionSpec,
|
||||||
|
fg='yellow')))
|
||||||
|
click.echo("Add these plugins to server {}? [y/N] ".format(server.name),
|
||||||
|
nl=False)
|
||||||
|
answer = click.getchar().lower()
|
||||||
|
if answer == "y":
|
||||||
|
for pluginSpec in pluginQueue:
|
||||||
|
try:
|
||||||
|
server.add_plugin(pluginSpec)
|
||||||
|
except KeyError:
|
||||||
|
click.echo("{} already added!".format(pluginSpec))
|
||||||
|
ctx.obj['config'].update_server(server.name, server.config)
|
||||||
|
ctx.obj['config'].save()
|
||||||
|
click.echo("Added!")
|
||||||
|
else:
|
||||||
|
click.echo("Cancelled.")
|
||||||
|
|
||||||
|
|
||||||
|
@server.command(help="Synchronize a server's plugins")
|
||||||
|
@click.pass_context
|
||||||
|
def sync(ctx):
|
||||||
|
for server in ctx.obj['config'].servers():
|
||||||
|
click.echo('{} ({}):'.format(server.name, server.path))
|
||||||
|
outdatedLinks = []
|
||||||
|
available = []
|
||||||
|
missing = []
|
||||||
|
for state in sorted(server.pluginStates(ctx.obj['config'].repositories())):
|
||||||
|
if isinstance(state, OutdatedSymlink):
|
||||||
|
outdatedLinks.append(state)
|
||||||
|
elif isinstance(state, Available):
|
||||||
|
available.append(state)
|
||||||
|
elif isinstance(state, MissingVersions):
|
||||||
|
missing.append(state)
|
||||||
|
|
||||||
|
click.echo("Plugins to update:")
|
||||||
|
for state in sorted(outdatedLinks):
|
||||||
|
click.echo("\t{} {}: Current: {} Wanted: {}".format(state.plugin.name, state.plugin.versionSpec, state.currentVersion, state.wantedVersion))
|
||||||
|
click.echo("New plugins to install:")
|
||||||
|
for state in sorted(available):
|
||||||
|
click.echo("\t{}: {}".format(state.plugin.name, state.plugin.version))
|
||||||
|
click.echo("Missing plugins:")
|
||||||
|
for state in sorted(missing):
|
||||||
|
click.echo("\t{} {}".format(click.style(state.plugin.name, fg='red'),
|
||||||
|
click.style(state.plugin.versionSpec,
|
||||||
|
fg='yellow')))
|
||||||
|
if len(outdatedLinks) > 0 or len(available) > 0:
|
||||||
|
click.echo("Apply changes? [y/N]", nl=False)
|
||||||
|
answer = click.getchar().lower()
|
||||||
|
if answer == "y":
|
||||||
|
with click.progressbar(length=len(available)+len(outdatedLinks),
|
||||||
|
label='Synchronizing') as bar:
|
||||||
|
i = 0
|
||||||
|
for state in available:
|
||||||
|
server.installVersion(state.plugin)
|
||||||
|
server.updateSymlinkForPlugin(state.plugin, state.plugin.version)
|
||||||
|
i += 1
|
||||||
|
bar.update(i)
|
||||||
|
for state in outdatedLinks:
|
||||||
|
server.updateSymlinkForPlugin(state.plugin, state.wantedVersion)
|
||||||
|
i += 1
|
||||||
|
bar.update(i)
|
||||||
|
else:
|
||||||
|
click.echo("Not applying changes.")
|
||||||
|
else:
|
||||||
|
click.echo("No changes to apply.")
|
85
src/mpm/config.py
Normal file
85
src/mpm/config.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import os
|
||||||
|
import yaml
|
||||||
|
import click
|
||||||
|
from mpm.repo import Repo
|
||||||
|
from mpm.server import Server
|
||||||
|
from mpm.model import *
|
||||||
|
|
||||||
|
try:
|
||||||
|
from yaml import CLoader as Loader, CDumper as Dumper
|
||||||
|
except ImportError:
|
||||||
|
from yaml import Loader, Dumper
|
||||||
|
|
||||||
|
DEFAULT_CONFIG = """
|
||||||
|
repositories: {}
|
||||||
|
servers: {}
|
||||||
|
"""
|
||||||
|
|
||||||
|
class RepoParamType(click.ParamType):
|
||||||
|
name = "repo-name"
|
||||||
|
|
||||||
|
def convert(self, value, param, ctx):
|
||||||
|
if isinstance(value, Repo):
|
||||||
|
return value
|
||||||
|
return ctx.obj['config'].repository(value)
|
||||||
|
|
||||||
|
class ServerParamType(click.ParamType):
|
||||||
|
name = "server-name"
|
||||||
|
|
||||||
|
def convert(self, value, param, ctx):
|
||||||
|
if isinstance(value, Repo):
|
||||||
|
return value
|
||||||
|
return ctx.obj['config'].server(value)
|
||||||
|
|
||||||
|
class Config():
|
||||||
|
|
||||||
|
def __init__(self, path):
|
||||||
|
if path is None:
|
||||||
|
path = os.path.expanduser('~/mpm.yaml')
|
||||||
|
self.path = path
|
||||||
|
with open(path, 'r') as fd:
|
||||||
|
self.yaml = yaml.load(fd, Loader=Loader)
|
||||||
|
self.config = yaml.load(DEFAULT_CONFIG, Loader=Loader)
|
||||||
|
if isinstance(self.yaml, dict):
|
||||||
|
self.config.update(self.yaml)
|
||||||
|
|
||||||
|
def repository(self, name):
|
||||||
|
return Repo(name, self.config['repositories'][name])
|
||||||
|
|
||||||
|
def repositories(self):
|
||||||
|
return [Repo(name, c) for (name, c) in self.config['repositories'].items()]
|
||||||
|
|
||||||
|
def update_repository(self, name, config):
|
||||||
|
self.config['repositories'][name] = config
|
||||||
|
|
||||||
|
def add_repository(self, name, path):
|
||||||
|
if name in self.config['repositories']:
|
||||||
|
raise ValueError('Repository already exists')
|
||||||
|
|
||||||
|
self.update_repository(name, {
|
||||||
|
'path': str(path)
|
||||||
|
})
|
||||||
|
|
||||||
|
def servers(self):
|
||||||
|
return [Server(name, c) for (name, c) in self.config['servers'].items()]
|
||||||
|
|
||||||
|
def server(self, name):
|
||||||
|
return Server(name, self.config['servers'][name])
|
||||||
|
|
||||||
|
def update_server(self, server, config):
|
||||||
|
self.config['servers'][server] = config
|
||||||
|
|
||||||
|
def add_server(self, name, path):
|
||||||
|
if name in self.config['servers']:
|
||||||
|
raise ValueError("Server already exists")
|
||||||
|
|
||||||
|
self.update_server(name, {
|
||||||
|
'path': path,
|
||||||
|
'plugins': [],
|
||||||
|
'inherit': []
|
||||||
|
})
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
stream = open(self.path, 'w')
|
||||||
|
yaml.dump(self.config, stream, Dumper=Dumper)
|
||||||
|
stream.close()
|
267
src/mpm/main.py
267
src/mpm/main.py
@ -1,267 +0,0 @@
|
|||||||
#!/bin/env python
|
|
||||||
import argparse
|
|
||||||
import pathlib
|
|
||||||
import sys
|
|
||||||
import yaml
|
|
||||||
import os
|
|
||||||
|
|
||||||
from mpm.repo import Repo
|
|
||||||
from mpm.server import Server
|
|
||||||
from mpm.model import *
|
|
||||||
|
|
||||||
try:
|
|
||||||
from yaml import CLoader as Loader, CDumper as Dumper
|
|
||||||
except ImportError:
|
|
||||||
from yaml import Loader, Dumper
|
|
||||||
|
|
||||||
DEFAULT_CONFIG = """
|
|
||||||
repositories: {}
|
|
||||||
servers: {}
|
|
||||||
"""
|
|
||||||
|
|
||||||
class Config():
|
|
||||||
|
|
||||||
def __init__(self, path):
|
|
||||||
if path is None:
|
|
||||||
path = os.path.expanduser('~/mpm.yaml')
|
|
||||||
self.path = path
|
|
||||||
with open(path, 'r') as fd:
|
|
||||||
self.yaml = yaml.load(fd, Loader=Loader)
|
|
||||||
self.config = yaml.load(DEFAULT_CONFIG, Loader=Loader)
|
|
||||||
if isinstance(self.yaml, dict):
|
|
||||||
self.config.update(self.yaml)
|
|
||||||
|
|
||||||
def repository(self, name):
|
|
||||||
return Repo(name, self.config['repositories'][name])
|
|
||||||
|
|
||||||
def repositories(self):
|
|
||||||
return [Repo(name, c) for (name, c) in self.config['repositories'].items()]
|
|
||||||
|
|
||||||
def update_repository(self, name, config):
|
|
||||||
self.config['repositories'][name] = config
|
|
||||||
|
|
||||||
def add_repository(self, name, path):
|
|
||||||
if name in self.config['repositories']:
|
|
||||||
raise ValueError('Repository already exists')
|
|
||||||
|
|
||||||
self.update_repository(name, {
|
|
||||||
'path': path
|
|
||||||
})
|
|
||||||
|
|
||||||
def servers(self):
|
|
||||||
return [Server(name, c) for (name, c) in self.config['servers'].items()]
|
|
||||||
|
|
||||||
def server(self, name):
|
|
||||||
return Server(name, self.config['servers'][name])
|
|
||||||
|
|
||||||
def update_server(self, server, config):
|
|
||||||
self.config['servers'][server] = config
|
|
||||||
|
|
||||||
def add_server(self, name, path):
|
|
||||||
if name in self.config['servers']:
|
|
||||||
raise ValueError("Server already exists")
|
|
||||||
|
|
||||||
self.update_server(name, {
|
|
||||||
'path': path,
|
|
||||||
'plugins': [],
|
|
||||||
'inherit': []
|
|
||||||
})
|
|
||||||
|
|
||||||
def save(self):
|
|
||||||
stream = open(self.path, 'w')
|
|
||||||
yaml.dump(self.config, stream, Dumper=Dumper)
|
|
||||||
stream.close()
|
|
||||||
|
|
||||||
def do_repo_add(args, config):
|
|
||||||
if not os.path.exists(args.path):
|
|
||||||
os.makedirs(args.path)
|
|
||||||
config.add_repository(args.name, args.path)
|
|
||||||
config.save()
|
|
||||||
print("Added repository {}".format(args.path))
|
|
||||||
|
|
||||||
def do_repo_list(args, config):
|
|
||||||
for repo in config.repositories():
|
|
||||||
print("{} ({})".format(repo.name, repo.path))
|
|
||||||
for plugin in sorted(repo.plugins()):
|
|
||||||
print('\t', plugin.name, '\t', plugin.version)
|
|
||||||
for badFile in sorted(repo.badFiles()):
|
|
||||||
print('\tWARNING: Unknown file', badFile)
|
|
||||||
|
|
||||||
def do_repo_import(args, config):
|
|
||||||
repo = config.repository(args.name)
|
|
||||||
plugins = []
|
|
||||||
for path in args.path:
|
|
||||||
try:
|
|
||||||
plugins.append(Plugin(path))
|
|
||||||
except:
|
|
||||||
print("Bad plugin filename {}".format(path))
|
|
||||||
|
|
||||||
if len(plugins) == 0:
|
|
||||||
print("No plugins found.")
|
|
||||||
|
|
||||||
print('Found the following plugins:')
|
|
||||||
for plugin in plugins:
|
|
||||||
print("\t{} {}".format(plugin.name, plugin.version))
|
|
||||||
print("Import plugins into {}? [y/N]".format(repo.name))
|
|
||||||
answer = input().lower()
|
|
||||||
if answer == "y":
|
|
||||||
for plugin in plugins:
|
|
||||||
repo.importPlugin(plugin)
|
|
||||||
print("Imported!")
|
|
||||||
else:
|
|
||||||
print("Cancelled.")
|
|
||||||
|
|
||||||
def do_server_add(args, config):
|
|
||||||
config.add_server(args.name, args.path)
|
|
||||||
config.save()
|
|
||||||
print("Added server {} in {}".format(args.name, args.path))
|
|
||||||
|
|
||||||
def do_server_list(args, config):
|
|
||||||
for server in config.servers():
|
|
||||||
print('{} ({}):'.format(server.name, server.path))
|
|
||||||
outdatedLinks = []
|
|
||||||
missing = []
|
|
||||||
installed = []
|
|
||||||
unmanaged = []
|
|
||||||
conflicts = []
|
|
||||||
for state in sorted(server.pluginStates(config.repositories())):
|
|
||||||
if isinstance(state, OutdatedSymlink):
|
|
||||||
outdatedLinks.append(state)
|
|
||||||
elif isinstance(state, Installed):
|
|
||||||
installed.append(state)
|
|
||||||
elif isinstance(state, MissingVersions):
|
|
||||||
missing.append(state)
|
|
||||||
elif isinstance(state, UnmanagedFile):
|
|
||||||
unmanaged.append(state)
|
|
||||||
elif isinstance(state, SymlinkConflict):
|
|
||||||
conflicts.append(state)
|
|
||||||
|
|
||||||
print("Installed plugins:")
|
|
||||||
for state in sorted(installed):
|
|
||||||
print("\t{} {}: {}".format(state.plugin.name, state.plugin.versionSpec, state.currentVersion))
|
|
||||||
print("Oudated symlinks:")
|
|
||||||
for state in sorted(outdatedLinks):
|
|
||||||
print("\t{} {}: Current: {} Wanted: {}".format(state.plugin.name, state.plugin.versionSpec, state.currentVersion, state.wantedVersion))
|
|
||||||
print("Missing plugins:")
|
|
||||||
for state in sorted(missing):
|
|
||||||
print("\t{}: {}".format(state.plugin.name, state.plugin.versionSpec))
|
|
||||||
print("Unmanaged files:")
|
|
||||||
for state in sorted(unmanaged):
|
|
||||||
print("\t{}".format(state.filename))
|
|
||||||
print("Symlink Conflicts:")
|
|
||||||
for state in sorted(conflicts):
|
|
||||||
print("\t{}.jar".format(state.plugin.name))
|
|
||||||
|
|
||||||
def do_server_add_plugin(args, config):
|
|
||||||
server = config.server(args.server)
|
|
||||||
plugins = []
|
|
||||||
for pluginSpec in args.plugin:
|
|
||||||
|
|
||||||
if os.path.exists(pluginSpec):
|
|
||||||
plugin = Plugin(pluginSpec)
|
|
||||||
pluginSpec = PluginSpec(plugin.name, str(plugin.version))
|
|
||||||
else:
|
|
||||||
allVersions = []
|
|
||||||
for repo in config.repositories():
|
|
||||||
allVersions += repo.versionsForPlugin(pluginSpec)
|
|
||||||
pluginSpec = PluginSpec(pluginSpec, list(reversed(sorted(allVersions)))[0])
|
|
||||||
|
|
||||||
plugins.append(pluginSpec)
|
|
||||||
|
|
||||||
print("Added {} to {}".format(pluginSpec, server.name))
|
|
||||||
for pluginSpec in plugins:
|
|
||||||
print("\t{} {}".format(pluginSpec.name, pluginSpec.versionSpec))
|
|
||||||
print("Add these plugins to server {}? [y/N]".format(server.name))
|
|
||||||
answer = input().lower()
|
|
||||||
if answer == "y":
|
|
||||||
for pluginSpec in plugins:
|
|
||||||
server.add_plugin(pluginSpec)
|
|
||||||
config.update_server(server.name, server.config)
|
|
||||||
config.save()
|
|
||||||
print("Added!")
|
|
||||||
else:
|
|
||||||
print("Cancelled.")
|
|
||||||
|
|
||||||
def do_server_sync(args, config):
|
|
||||||
for server in config.servers():
|
|
||||||
print('{} ({}):'.format(server.name, server.path))
|
|
||||||
outdatedLinks = []
|
|
||||||
available = []
|
|
||||||
for state in sorted(server.pluginStates(config.repositories())):
|
|
||||||
if isinstance(state, OutdatedSymlink):
|
|
||||||
outdatedLinks.append(state)
|
|
||||||
elif isinstance(state, Available):
|
|
||||||
available.append(state)
|
|
||||||
|
|
||||||
print("Plugins to update:")
|
|
||||||
for state in sorted(outdatedLinks):
|
|
||||||
print("\t{} {}: Current: {} Wanted: {}".format(state.plugin.name, state.plugin.versionSpec, state.currentVersion, state.wantedVersion))
|
|
||||||
print("New plugins to install:")
|
|
||||||
for state in sorted(available):
|
|
||||||
print("\t{}: {}".format(state.plugin.name, state.plugin.version))
|
|
||||||
|
|
||||||
if len(outdatedLinks) > 0 or len(available) > 0:
|
|
||||||
print("Apply changes? [y/N]")
|
|
||||||
answer = input().lower()
|
|
||||||
if answer == "y":
|
|
||||||
for state in available:
|
|
||||||
server.installVersion(state.plugin)
|
|
||||||
server.updateSymlinkForPlugin(state.plugin, state.plugin.version)
|
|
||||||
print("Installed {} {}".format(state.plugin.name, state.plugin.version))
|
|
||||||
for state in outdatedLinks:
|
|
||||||
server.updateSymlinkForPlugin(state.plugin, state.wantedVersion)
|
|
||||||
print("Updated {} to {}".format(state.plugin.name, state.wantedVersion))
|
|
||||||
else:
|
|
||||||
print("Not applying changes.")
|
|
||||||
else:
|
|
||||||
print("No changes to apply.")
|
|
||||||
|
|
||||||
def main():
|
|
||||||
parser = argparse.ArgumentParser(description='Paper Plugin Sync')
|
|
||||||
parser.add_argument('--config', dest='config_path', type=Config)
|
|
||||||
subparsers = parser.add_subparsers()
|
|
||||||
repos = subparsers.add_parser('repo')
|
|
||||||
repo_sub = repos.add_subparsers()
|
|
||||||
|
|
||||||
repo_add = repo_sub.add_parser('add')
|
|
||||||
repo_add.add_argument('name', help='Name of the repository')
|
|
||||||
repo_add.add_argument('path', help='Where to add a repository or create a new one')
|
|
||||||
repo_add.set_defaults(func=do_repo_add)
|
|
||||||
|
|
||||||
repo_list = repo_sub.add_parser('list')
|
|
||||||
repo_list.set_defaults(func=do_repo_list)
|
|
||||||
|
|
||||||
repo_import = repo_sub.add_parser('import')
|
|
||||||
repo_import.add_argument('name', help='Name of the repository')
|
|
||||||
repo_import.add_argument('path', nargs="+", help='Path of the plugin to import')
|
|
||||||
repo_import.set_defaults(func=do_repo_import)
|
|
||||||
|
|
||||||
servers = subparsers.add_parser('server')
|
|
||||||
server_sub = servers.add_subparsers()
|
|
||||||
server_add = server_sub.add_parser('add')
|
|
||||||
server_add.add_argument('name', help='Name for the server')
|
|
||||||
server_add.add_argument('path', help='Path to your server\'s root directory')
|
|
||||||
server_add.set_defaults(func=do_server_add)
|
|
||||||
|
|
||||||
server_list = server_sub.add_parser('list')
|
|
||||||
server_list.set_defaults(func=do_server_list)
|
|
||||||
|
|
||||||
server_add_plugin = server_sub.add_parser('add-plugin')
|
|
||||||
server_add_plugin.add_argument('server', help='Name of server to modify')
|
|
||||||
server_add_plugin.add_argument('plugin', nargs='+', help='Plugin file or spec to install')
|
|
||||||
server_add_plugin.set_defaults(func=do_server_add_plugin)
|
|
||||||
|
|
||||||
server_sync = server_sub.add_parser('sync')
|
|
||||||
server_sync.set_defaults(func=do_server_sync)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
config = Config(args.config_path)
|
|
||||||
|
|
||||||
if 'func' not in args:
|
|
||||||
parser.print_usage()
|
|
||||||
else:
|
|
||||||
args.func(args, config)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,73 +0,0 @@
|
|||||||
#!/bin/env python
|
|
||||||
import yaml
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
from model import *
|
|
||||||
|
|
||||||
try:
|
|
||||||
from yaml import CLoader as Loader, CDumper as Dumper
|
|
||||||
except ImportError:
|
|
||||||
from yaml import Loader, Dumper
|
|
||||||
|
|
||||||
conf = yaml.load(open('plugins.yml', 'r'), Loader=Loader)
|
|
||||||
|
|
||||||
for (serverName,server) in conf['servers'].items():
|
|
||||||
changeset = []
|
|
||||||
if len(sys.argv) > 1 and serverName not in sys.argv[1:]:
|
|
||||||
continue
|
|
||||||
if 'pluginPath' not in server:
|
|
||||||
continue
|
|
||||||
if not os.path.exists(server['pluginPath']):
|
|
||||||
print("Missing plugin path for {}: {}".format(serverName, server['pluginPath']))
|
|
||||||
else:
|
|
||||||
print("=== Updating server {}".format(serverName))
|
|
||||||
pluginSpecs = {}
|
|
||||||
for inherited in server.get('inherit', ()):
|
|
||||||
for inheritedPlugin in conf['servers'][inherited]['plugins']:
|
|
||||||
pluginSpecs[inheritedPlugin['name']] = PluginSpec(inheritedPlugin['name'], str(inheritedPlugin.get('version', '*')))
|
|
||||||
|
|
||||||
for pluginConf in server.get('plugins', ()):
|
|
||||||
pluginSpecs[pluginConf['name']] = PluginSpec(pluginConf['name'], str(pluginConf.get('version', '*')))
|
|
||||||
|
|
||||||
repo = Repo(server['pluginPath'], pluginSpecs.values())
|
|
||||||
outdatedLinks = []
|
|
||||||
missing = []
|
|
||||||
installed = []
|
|
||||||
unmanaged = []
|
|
||||||
conflicts = []
|
|
||||||
for state in repo.pluginStates():
|
|
||||||
if isinstance(state, OutdatedSymlink):
|
|
||||||
outdatedLinks.append(state)
|
|
||||||
elif isinstance(state, Installed):
|
|
||||||
installed.append(state)
|
|
||||||
elif isinstance(state, MissingVersions):
|
|
||||||
missing.append(state)
|
|
||||||
elif isinstance(state, UnmanagedFile):
|
|
||||||
unmanaged.append(state)
|
|
||||||
elif isinstance(state, SymlinkConflict):
|
|
||||||
conflicts.append(state)
|
|
||||||
|
|
||||||
print("Installed plugins:")
|
|
||||||
for state in sorted(installed):
|
|
||||||
print("\t{} {}: {}".format(state.plugin.name, state.plugin.versionSpec, state.currentVersion))
|
|
||||||
print("Oudated symlinks:")
|
|
||||||
for state in sorted(outdatedLinks):
|
|
||||||
print("\t{} {}: Current: {} Wanted: {}".format(state.plugin.name, state.plugin.versionSpec, state.currentVersion, state.wantedVersion))
|
|
||||||
print("Missing plugins:")
|
|
||||||
for state in sorted(missing):
|
|
||||||
print("\t{}: {}".format(state.plugin.name, state.plugin.versionSpec))
|
|
||||||
print("Unmanaged files:")
|
|
||||||
for state in sorted(unmanaged):
|
|
||||||
print("\t{}".format(state.filename))
|
|
||||||
print("Symlink Conflicts:")
|
|
||||||
for state in sorted(conflicts):
|
|
||||||
print("\t{}.jar".format(state.plugin.name))
|
|
||||||
|
|
||||||
if len(outdatedLinks) > 0:
|
|
||||||
print("Apply changes? [y/N]")
|
|
||||||
answer = input().lower()
|
|
||||||
if answer == "y":
|
|
||||||
for state in outdatedLinks:
|
|
||||||
repo.updateSymlinkForPlugin(state.plugin, state.wantedVersion)
|
|
||||||
else:
|
|
||||||
print("Not applying changes.")
|
|
@ -1,5 +1,6 @@
|
|||||||
from mpm.model import *
|
from mpm.model import *
|
||||||
import shutil
|
import shutil
|
||||||
|
import pathlib
|
||||||
|
|
||||||
class Server:
|
class Server:
|
||||||
def __init__(self, name, config):
|
def __init__(self, name, config):
|
||||||
@ -70,17 +71,18 @@ class Server:
|
|||||||
return pluginSemver
|
return pluginSemver
|
||||||
|
|
||||||
def versionsForPlugin(self, pluginName, repos):
|
def versionsForPlugin(self, pluginName, repos):
|
||||||
plugins = os.listdir(os.path.join(self.pluginPath, 'versions'))
|
if os.path.exists(os.path.join(self.pluginPath, 'versions')):
|
||||||
for pluginJar in plugins:
|
plugins = os.listdir(os.path.join(self.pluginPath, 'versions'))
|
||||||
if pluginJar.startswith(pluginName):
|
for pluginJar in plugins:
|
||||||
prefix = pluginName + '-'
|
if pluginJar.startswith(pluginName):
|
||||||
suffix = '.jar'
|
prefix = pluginName + '-'
|
||||||
jarVersion = pluginJar[len(prefix):len(pluginJar)-len(suffix)]
|
suffix = '.jar'
|
||||||
try:
|
jarVersion = pluginJar[len(prefix):len(pluginJar)-len(suffix)]
|
||||||
pluginSemver = Version.coerce(jarVersion)
|
try:
|
||||||
except ValueError:
|
pluginSemver = Version.coerce(jarVersion)
|
||||||
pluginSemver = jarVersion
|
except ValueError:
|
||||||
yield pluginSemver
|
pluginSemver = jarVersion
|
||||||
|
yield pluginSemver
|
||||||
|
|
||||||
def updateSymlinkForPlugin(self, plugin, version):
|
def updateSymlinkForPlugin(self, plugin, version):
|
||||||
pluginFilename = os.path.join(self.pluginPath, 'versions/{}-{}.jar'.format(plugin.name, version))
|
pluginFilename = os.path.join(self.pluginPath, 'versions/{}-{}.jar'.format(plugin.name, version))
|
||||||
@ -92,5 +94,7 @@ class Server:
|
|||||||
os.symlink(linkDst, pluginSymlink)
|
os.symlink(linkDst, pluginSymlink)
|
||||||
|
|
||||||
def installVersion(self, plugin):
|
def installVersion(self, plugin):
|
||||||
|
if not os.path.exists(os.path.join(self.pluginPath, 'versions')):
|
||||||
|
os.path.mkdir(os.path.join(self.pluginPath, 'versions'))
|
||||||
dest = os.path.join(self.pluginPath, 'versions/{}-{}.jar'.format(plugin.name, plugin.version))
|
dest = os.path.join(self.pluginPath, 'versions/{}-{}.jar'.format(plugin.name, plugin.version))
|
||||||
shutil.copyfile(plugin.path, dest)
|
shutil.copyfile(plugin.path, dest)
|
||||||
|
Loading…
Reference in New Issue
Block a user