diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3df98b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.swp +Pipfile.lock diff --git a/README.md b/README.md index 2546d78..80be4e4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Minecraft Plugin Sync +# Minecraft Plugin Manager mpm is a tool used to maintain the various servers and their plugins on play.malloc.gg. @@ -22,16 +22,24 @@ be able to work in other systems where: - You're trying to upgrade a network to a new minecraft release but can't bring all the servers and their plugins along at the same time +## Installation + + # pip install . ## Usage -To use, you'll need to create a `plugins.yml` file, using the same structure as -the one in this repository. Then, create a versions/ directory Inside each -server's plugins/ directory. For example, if your server.jar lives at -`/srv/minecraft/server/`, you'll create -`/srv/minecraft/server/plugins/versions/`. Plugin files are not automatically -synchronized between each server's versions directory, though this would be the -next direction for this tool to go. Versions are managed using simple symlinks, +- Create a new plugin repository: `mpm repo add` +- List repositories: `mpm repo list` +- Import a package to a repository: `mpm repo import` + +- Add a server to mpm: `mpm server add` +- List your servers: `mpm server list` +- Add a plugin to a server: `mpm server add-plugin` +- Commit your changes: `mpm server sync` + +Documentation is scarce. Sorry about that. Pull requests and wiki editors appreciated. + +Versions are managed using simple symlinks, and they require that the actual .jar files use Semver naming. Any deviation from Semver can result in some really goofy behavior, but for the most part, the majority of plugins available on spigot.org include a compatible string in the @@ -45,8 +53,7 @@ for good measure if you run into this. ## Known Bugs -- Sometimes you'll end up with a mismatch between where the symlink goes and the - version'd filename, usually when you've got a version that goes beyond the - traditional $MAJOR.$MINOR.$PATCH tuple. Just rename your files, I guess. +- Bad documentation +- 'mpm' is not an uncommon name Maybe you'll find this useful too. Batteries not included. diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..3004cd9 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,12 @@ +[build-system] +requires = ["setuptools", "wheel", "setuptools-pipfile"] +build-backend = "setuptools.build_meta" + +[tool.setuptools-pipfile] + +[project] +name = "minecraft-package-manager" +version = "0.0.1" + +[project.scripts] +mpm = "mpm.main:main" diff --git a/src/mpm/__init__.py b/src/mpm/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/main.py b/src/mpm/main.py similarity index 98% rename from main.py rename to src/mpm/main.py index c601326..43b689d 100755 --- a/main.py +++ b/src/mpm/main.py @@ -5,9 +5,9 @@ import sys import yaml import os -from repo import Repo -from server import Server -from model import * +from mpm.repo import Repo +from mpm.server import Server +from mpm.model import * try: from yaml import CLoader as Loader, CDumper as Dumper @@ -23,7 +23,7 @@ class Config(): def __init__(self, path): if path is None: - path = './mpm.yaml' + path = os.path.expanduser('~/mpm.yaml') self.path = path with open(path, 'r') as fd: self.yaml = yaml.load(fd, Loader=Loader) diff --git a/model.py b/src/mpm/model.py similarity index 94% rename from model.py rename to src/mpm/model.py index c9ee5a0..907484b 100644 --- a/model.py +++ b/src/mpm/model.py @@ -3,8 +3,6 @@ from functools import total_ordering import os import re -#version_pattern = re.compile('^(?P.*)-(?P[^-]+)(?P-[^-]+)?\.jar$') -version_pattern = re.compile('^(?P.*)-(?P[^-]+(?:-[^-]+)?)\.jar$') version_pattern = re.compile('^(?P.+)-(?P(?:\.?\d+)+).+jar$') @total_ordering diff --git a/src/mpm/plugin-sync.py b/src/mpm/plugin-sync.py new file mode 100755 index 0000000..484e7f8 --- /dev/null +++ b/src/mpm/plugin-sync.py @@ -0,0 +1,73 @@ +#!/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.") diff --git a/repo.py b/src/mpm/repo.py similarity index 99% rename from repo.py rename to src/mpm/repo.py index 5141a37..d719cfe 100644 --- a/repo.py +++ b/src/mpm/repo.py @@ -1,5 +1,5 @@ import os -from model import * +from mpm.model import * import shutil class Repo: diff --git a/server.py b/src/mpm/server.py similarity index 99% rename from server.py rename to src/mpm/server.py index 3d03528..972e857 100644 --- a/server.py +++ b/src/mpm/server.py @@ -1,4 +1,4 @@ -from model import * +from mpm.model import * import shutil class Server: