diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b26060e --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +#IDE +.idea/ +*.iml +/.settings +/bin +/.classpath +/.project + +#Gradle +build/ +.gradle diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..7d65bf1 --- /dev/null +++ b/build.gradle @@ -0,0 +1,22 @@ +apply plugin: 'java' + +sourceCompatibility = '1.8' +targetCompatibility = '1.8' +compileJava.options.encoding = 'UTF-8' +version = '1.0' + +repositories { + mavenCentral() +} + +dependencies { + compile 'commons-io:commons-io:2.4' + compile 'net.sf.jopt-simple:jopt-simple:4.5' +} + +jar { + from configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } + manifest { + attributes("Main-Class": "org.ultramine.bootstrap.Main") + } +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..3c7abdf --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.jar Binary files differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..eb67457 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Thu Apr 24 12:13:23 VLAT 2014 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=http\://services.gradle.org/distributions/gradle-2.10-all.zip diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..91a7e26 --- /dev/null +++ b/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..8a0b282 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..5390861 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'ultramine_bootstrap' + diff --git a/src/main/java/org/ultramine/bootstrap/Constants.java b/src/main/java/org/ultramine/bootstrap/Constants.java new file mode 100644 index 0000000..fb0da10 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/Constants.java @@ -0,0 +1,8 @@ +package org.ultramine.bootstrap; + +public class Constants +{ + public static final String UM_REPO = "http://maven.ultramine.ru"; + public static final String UM_CORE_GROUP = "org.ultramine.core"; + public static final String UM_CORE_NAME = "ultramine_core-1.7.10-server"; +} diff --git a/src/main/java/org/ultramine/bootstrap/Main.java b/src/main/java/org/ultramine/bootstrap/Main.java new file mode 100644 index 0000000..a0d69b3 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/Main.java @@ -0,0 +1,135 @@ +package org.ultramine.bootstrap; + +import joptsimple.OptionParser; +import joptsimple.OptionSet; +import joptsimple.OptionSpec; +import org.ultramine.bootstrap.maven.MavenDependency; +import org.ultramine.bootstrap.exceptions.ApplicationErrorException; +import org.ultramine.bootstrap.task.DependencyResolver; +import org.ultramine.bootstrap.task.ScriptCreator; +import org.ultramine.bootstrap.util.I18n; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.Locale; +import java.util.Set; + +public class Main +{ + public static void main(String[] args) + { + System.out.println(I18n.tlt("stage.start")); + OptionParser opt = new OptionParser(); + opt.accepts("help", "Show the help").forHelp(); +// opt.acceptsAll(Arrays.asList("v", "minecraft"), "Version of minecraft (1.7.10)") +// .withRequiredArg() +// .ofType(String.class) +// .defaultsTo("1.7.10") +// .describedAs("version"); + OptionSpec optLang = opt.accepts("lang", "Language") + .withRequiredArg() + .ofType(String.class) + .defaultsTo(Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry()) + .describedAs("lang"); + opt.accepts("stacktrace", "Print detailed stacktrace on application error"); + OptionSpec optDir = opt.accepts("dir", "Server directory") + .withRequiredArg() + .ofType(File.class) + .defaultsTo(new File(".")) + .describedAs("file"); +// opt.accepts("addliburl", "Add extra libs by URL") +// .withRequiredArg() +// .ofType(URL.class) +// .describedAs("lib url"); + OptionSpec optAddLib = opt.accepts("addlib", "Add extra libs from maven repo (gradle format)") + .withRequiredArg() + .ofType(String.class) + .describedAs("maven lib"); + OptionSpec optAddRepo = opt.accepts("addrepo", "Add extra maven repository URL") + .withRequiredArg() + .ofType(URL.class) + .describedAs("repo URL"); + opt.accepts("install", "Install ultramine server"); + opt.accepts("update", "Update ultramine server"); + opt.accepts("forge", "Make forge-compatible directory mappings"); + opt.accepts("beta", "Use beta channel"); + OptionSpec optVersion = opt.accepts("version", "ultramine core version") + .withRequiredArg() + .ofType(String.class) + .describedAs("version"); + + OptionSpec optXMX = opt.accepts("xmx", "Max heap size for server (-Xmx)") + .withRequiredArg() + .ofType(String.class) + .defaultsTo("2048m") + .describedAs("max memory"); + OptionSpec optXMS = opt.accepts("xms", "Start heap size for server (-Xms)") + .withRequiredArg() + .ofType(String.class) + .defaultsTo("2048m") + .describedAs("start memory"); + + OptionSpec optTerminal = opt.accepts("terminal", "Terminal (console) mode") + .withRequiredArg() + .ofType(String.class) + .defaultsTo("jline") + .describedAs("jline/ansi/default/raw"); + + OptionSet options; + + try { + options = opt.parse(args); + } catch (joptsimple.OptionException e) { + throw new RuntimeException("Fail to parse command line", e); + } + + I18n.select(optLang.value(options)); + + if (options.has("help")) { + try { + opt.printHelpOn(System.out); + System.exit(0); + } catch (IOException e) { + throw new RuntimeException("Fail print help", e); + } + } + + try + { + File dir = optDir.value(options); + Set deps = DependencyResolver.load( + dir, + optVersion.value(options), + options.has("install") || options.has("update"), + options.has("beta"), + optAddRepo.values(options), + optAddLib.values(options) + ); + ScriptCreator.create( + dir, + deps, + optXMX.value(options), + optXMS.value(options), + optTerminal.value(options), + options.has("forge") + ); + System.out.println(I18n.tlt("stage.finished")); + } + catch(ApplicationErrorException e) + { + System.err.println(e.getTranslatedMessage()); + if(options.has("stacktrace")) + e.printStackTrace(); + else + System.err.println(I18n.tlt("hint.stacktrace")); + System.exit(1); + } + catch(RuntimeException e) + { + e.printStackTrace(); + } + + System.exit(0); + } +} diff --git a/src/main/java/org/ultramine/bootstrap/UMCoreVersionsRetriever.java b/src/main/java/org/ultramine/bootstrap/UMCoreVersionsRetriever.java new file mode 100644 index 0000000..4f44a30 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/UMCoreVersionsRetriever.java @@ -0,0 +1,33 @@ +package org.ultramine.bootstrap; + +import org.ultramine.bootstrap.maven.MavenMetadata; +import org.ultramine.bootstrap.versioning.DefaultArtifactVersion; + +import java.util.ArrayList; +import java.util.List; + +public class UMCoreVersionsRetriever +{ + private final List betaVersions; + private final List stableVersions; + + public UMCoreVersionsRetriever() + { + List versions = MavenMetadata.loadFromProject(Constants.UM_REPO, Constants.UM_CORE_GROUP, Constants.UM_CORE_NAME).getVersions(); + + betaVersions = new ArrayList<>(versions.size()); + stableVersions = new ArrayList<>(versions.size()); + for(DefaultArtifactVersion version : versions) + (version.getLabel().contains("beta") ? betaVersions : stableVersions).add(version); + } + + public List getBetaVersions() + { + return betaVersions; + } + + public List getStableVersions() + { + return stableVersions; + } +} diff --git a/src/main/java/org/ultramine/bootstrap/deps/AbstractDownloadable.java b/src/main/java/org/ultramine/bootstrap/deps/AbstractDownloadable.java new file mode 100644 index 0000000..a08aaf5 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/deps/AbstractDownloadable.java @@ -0,0 +1,65 @@ +package org.ultramine.bootstrap.deps; + +import org.apache.commons.io.IOUtils; +import org.ultramine.bootstrap.deps.IDownloadable; +import org.ultramine.bootstrap.util.HashUtil; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.MessageDigest; + +public abstract class AbstractDownloadable implements IDownloadable +{ + protected File outputDir; + protected File checkSumsDir; + + public void setOutputDir(File outputDir) + { + this.outputDir = outputDir; + } + + public File getOutputDir() + { + return this.outputDir; + } + + public void setCheckSumsDir(File checkSumsDir) + { + this.checkSumsDir = checkSumsDir; + } + + protected static String copyAndDigest(InputStream in, OutputStream out) throws IOException + { + MessageDigest digest = HashUtil.getSHA1(); + byte[] buffer = new byte[0x10000]; + try + { + for(int read = in.read(buffer); read > 0; read = in.read(buffer)) + { + digest.update(buffer, 0, read); + out.write(buffer, 0, read); + } + } + finally + { + IOUtils.closeQuietly(in); + IOUtils.closeQuietly(out); + } + + return HashUtil.byteArray2Hex(digest.digest()); + } + + protected static void ensureFileWritable(File target) + { + if(target.getParentFile() != null && !target.getParentFile().isDirectory()) + { + if(!target.getParentFile().mkdirs() && !target.getParentFile().isDirectory()) + throw new RuntimeException("Could not create directory " + target.getParentFile()); + } + + if(target.isFile() && !target.canWrite()) + throw new RuntimeException("Do not have write permissions for " + target + " - aborting!"); + } +} diff --git a/src/main/java/org/ultramine/bootstrap/deps/IDependency.java b/src/main/java/org/ultramine/bootstrap/deps/IDependency.java new file mode 100644 index 0000000..fa6c035 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/deps/IDependency.java @@ -0,0 +1,5 @@ +package org.ultramine.bootstrap.deps; + +public interface IDependency +{ +} diff --git a/src/main/java/org/ultramine/bootstrap/deps/IDownloadable.java b/src/main/java/org/ultramine/bootstrap/deps/IDownloadable.java new file mode 100644 index 0000000..6ab6631 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/deps/IDownloadable.java @@ -0,0 +1,15 @@ +package org.ultramine.bootstrap.deps; + +import java.io.File; +import java.io.IOException; + +public interface IDownloadable +{ + void setOutputDir(File outputDir); + + File getOutputDir(); + + void setCheckSumsDir(File checkSumsDir); + + void download() throws IOException; +} diff --git a/src/main/java/org/ultramine/bootstrap/deps/IRepository.java b/src/main/java/org/ultramine/bootstrap/deps/IRepository.java new file mode 100644 index 0000000..ee3abb0 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/deps/IRepository.java @@ -0,0 +1,24 @@ +package org.ultramine.bootstrap.deps; + +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.io.InputStream; + +public interface IRepository +{ + InputStream resolve(String path) throws IOException; + + default String resolveCheckSum(String path) throws IOException + { + InputStream inp = resolve(path + ".sha1"); + if(inp == null) + inp = resolve(path + ".sha"); + if(inp == null) + return null; + String sum = IOUtils.toString(inp).trim(); + if(sum.length() > 40) + sum = sum.substring(0, 40); + return sum; + } +} diff --git a/src/main/java/org/ultramine/bootstrap/exceptions/ApplicationErrorException.java b/src/main/java/org/ultramine/bootstrap/exceptions/ApplicationErrorException.java new file mode 100644 index 0000000..51c14a8 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/exceptions/ApplicationErrorException.java @@ -0,0 +1,24 @@ +package org.ultramine.bootstrap.exceptions; + +public class ApplicationErrorException extends TranslatableMessageException +{ + public ApplicationErrorException(String format) + { + super(format); + } + + public ApplicationErrorException(String format, Object... args) + { + super(format, args); + } + + public ApplicationErrorException(Throwable cause, String format) + { + super(cause, format); + } + + public ApplicationErrorException(Throwable cause, String format, Object... args) + { + super(cause, format, args); + } +} diff --git a/src/main/java/org/ultramine/bootstrap/exceptions/TranslatableMessageException.java b/src/main/java/org/ultramine/bootstrap/exceptions/TranslatableMessageException.java new file mode 100644 index 0000000..13b4133 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/exceptions/TranslatableMessageException.java @@ -0,0 +1,40 @@ +package org.ultramine.bootstrap.exceptions; + +import org.ultramine.bootstrap.util.I18n; + +public class TranslatableMessageException extends RuntimeException +{ + private final String format; + private Object[] args; + + public TranslatableMessageException(String format) + { + super(I18n.tlt(format)); + this.format = format; + } + + public TranslatableMessageException(String format, Object... args) + { + super(I18n.tlt(format, args)); + this.format = format; + this.args = args; + } + + public TranslatableMessageException(Throwable cause, String format) + { + super(I18n.tlt(format), cause); + this.format = format; + } + + public TranslatableMessageException(Throwable cause, String format, Object... args) + { + super(I18n.tlt(format, args), cause); + this.format = format; + this.args = args; + } + + public String getTranslatedMessage() + { + return args == null ? I18n.tlt(format) : I18n.tlt(format, args); + } +} diff --git a/src/main/java/org/ultramine/bootstrap/maven/MavenDependency.java b/src/main/java/org/ultramine/bootstrap/maven/MavenDependency.java new file mode 100644 index 0000000..480fec1 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/maven/MavenDependency.java @@ -0,0 +1,108 @@ +package org.ultramine.bootstrap.maven; + +import org.ultramine.bootstrap.deps.IDependency; +import org.ultramine.bootstrap.deps.IRepository; +import org.ultramine.bootstrap.deps.IDownloadable; + +import java.util.List; +import java.util.Objects; + +public class MavenDependency implements IDependency +{ + public final String group; + public final String artifactName; + public final String version; + + public MavenDependency(String group, String artifactName, String version) + { + this.group = Objects.requireNonNull(group); + this.artifactName = Objects.requireNonNull(artifactName); + this.version = Objects.requireNonNull(version); + } + + public MavenDependency(String name) + { + String[] parts = name.split(":", 3); + this.group = parts[0]; + this.artifactName = parts[1]; + this.version = parts[2]; + } + + public String getGroup() + { + return group; + } + + public String getArtifactName() + { + return artifactName; + } + + public String getVersion() + { + return version; + } + + public String getArtifactBaseDir() + { + return group.replace('.', '/') + "/" + artifactName + "/" + version; + } + + public String getArtifactFilename(String classifier, String extension) + { + return artifactName + "-" + version + (classifier == null || classifier.isEmpty() ? "" : "-" + classifier) + "." + extension; + } + + public String getArtifactPath() + { + return getArtifactPath(null); + } + + public String getArtifactPath(String classifier) + { + return getArtifactBaseDir() + "/" + getArtifactFilename(classifier); + } + + public String getArtifactPath(String classifier, String extension) + { + return getArtifactBaseDir() + "/" + getArtifactFilename(classifier, extension); + } + + public String getArtifactFilename() + { + return getArtifactFilename(null); + } + + public String getArtifactFilename(String classifier) + { + return getArtifactFilename(classifier, "jar"); + } + + public IDownloadable resolve(List repositories) + { + return new MavenDownloadable(repositories, this); + } + + @Override + public boolean equals(Object o) + { + if(this == o) return true; + if(o == null || getClass() != o.getClass()) return false; + MavenDependency that = (MavenDependency) o; + return Objects.equals(group, that.group) && + Objects.equals(artifactName, that.artifactName) && + Objects.equals(version, that.version); + } + + @Override + public int hashCode() + { + return Objects.hash(group, artifactName, version); + } + + @Override + public String toString() + { + return group+':'+ artifactName +':'+version; + } +} diff --git a/src/main/java/org/ultramine/bootstrap/maven/MavenDownloadable.java b/src/main/java/org/ultramine/bootstrap/maven/MavenDownloadable.java new file mode 100644 index 0000000..215a8f0 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/maven/MavenDownloadable.java @@ -0,0 +1,78 @@ +package org.ultramine.bootstrap.maven; + +import org.apache.commons.io.FileUtils; +import org.ultramine.bootstrap.deps.IRepository; +import org.ultramine.bootstrap.deps.AbstractDownloadable; +import org.ultramine.bootstrap.exceptions.ApplicationErrorException; +import org.ultramine.bootstrap.util.HashUtil; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.ConnectException; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; +import java.util.List; + +public class MavenDownloadable extends AbstractDownloadable +{ + private final List repositories; + private final MavenDependency dependency; + + public MavenDownloadable(List repositories, MavenDependency dependency) + { + this.repositories = repositories; + this.dependency = dependency; + } + + @Override + public void download() throws IOException + { + String artifactName = dependency.getArtifactFilename(); + File output = new File(outputDir, artifactName); + File checkSumFile = new File(checkSumsDir, artifactName+".sha1"); + if(output.isFile() && checkSumFile.isFile()) + { + if(HashUtil.sha1Str(output).equals(FileUtils.readFileToString(checkSumFile))) + return; + } + ensureFileWritable(output); + ensureFileWritable(checkSumFile); + String path = dependency.getArtifactPath(); + for(IRepository repo : repositories) + if(tryDownload(output, checkSumFile, path, repo)) + return; + throw new FileNotFoundException("Maven dependency not found in any repositories: "+dependency); + } + + private boolean tryDownload(File output, File checkSumFile, String path, IRepository repo) throws IOException + { + try + { + InputStream resolved = repo.resolve(path); + if(resolved == null) + return false; + System.out.println("Downloading " + dependency.getArtifactName() + " from " + repo + "/" + path); + String computedCheckSum = copyAndDigest(resolved, new FileOutputStream(output)); + String loadedCheckSum = repo.resolveCheckSum(path); + if(loadedCheckSum != null && !loadedCheckSum.equals(computedCheckSum)) + throw new RuntimeException("CheckSums failed for " + dependency + "("+computedCheckSum + " != " + loadedCheckSum + ")"); + FileUtils.writeStringToFile(checkSumFile, computedCheckSum); + return true; + } catch (UnknownHostException e) + { + throw new ApplicationErrorException(e, "error.unavailable.host", e.getMessage()); + } catch (SocketTimeoutException | ConnectException e) + { + throw new ApplicationErrorException(e, "error.unavailable.maven", repo.toString()); + } + } + + @Override + public String toString() + { + return dependency.toString(); + } +} diff --git a/src/main/java/org/ultramine/bootstrap/maven/MavenLocalRepository.java b/src/main/java/org/ultramine/bootstrap/maven/MavenLocalRepository.java new file mode 100644 index 0000000..20f0ba2 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/maven/MavenLocalRepository.java @@ -0,0 +1,33 @@ +package org.ultramine.bootstrap.maven; + +import org.ultramine.bootstrap.deps.IRepository; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class MavenLocalRepository implements IRepository +{ + private final File directory; + + public MavenLocalRepository(File directory) + { + this.directory = directory; + } + + @Override + public InputStream resolve(String path) throws IOException + { + File file = new File(directory, path.replace("/", File.separator)); + if(!file.isFile()) + return null; + return new FileInputStream(file); + } + + @Override + public String toString() + { + return directory.getAbsolutePath(); + } +} diff --git a/src/main/java/org/ultramine/bootstrap/maven/MavenMetadata.java b/src/main/java/org/ultramine/bootstrap/maven/MavenMetadata.java new file mode 100644 index 0000000..ffb590e --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/maven/MavenMetadata.java @@ -0,0 +1,58 @@ +package org.ultramine.bootstrap.maven; + +import org.ultramine.bootstrap.exceptions.ApplicationErrorException; +import org.ultramine.bootstrap.versioning.DefaultArtifactVersion; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; + +import javax.xml.parsers.DocumentBuilderFactory; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class MavenMetadata +{ + private final List versions; + + private MavenMetadata(String xmlUrl) + { + Document doc; + try + { + doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(xmlUrl); + } + catch (Exception e) + { + throw new ApplicationErrorException(e, "error.mavenmetadata", xmlUrl); + } + NodeList listNodes = doc.getElementsByTagName("version"); + + versions = new ArrayList<>(listNodes.getLength()); + for(int i = 0, s = listNodes.getLength(); i < s; i++) + { + String version = listNodes.item(i).getTextContent(); + versions.add(new DefaultArtifactVersion(version, version)); + } + Collections.sort(versions); + } + + public List getVersions() + { + return versions; + } + + public static MavenMetadata loadFromXML(String xmlUrl) + { + return new MavenMetadata(xmlUrl); + } + + public static MavenMetadata loadFromProject(String projectUrl) + { + return loadFromXML(projectUrl + (projectUrl.endsWith("/") ? "" : "/") + "maven-metadata.xml"); + } + + public static MavenMetadata loadFromProject(String repoUrl, String group, String project) + { + return loadFromProject(repoUrl + "/" + group.replace('.', '/') + "/" + project); + } +} diff --git a/src/main/java/org/ultramine/bootstrap/maven/MavenRemoteRepository.java b/src/main/java/org/ultramine/bootstrap/maven/MavenRemoteRepository.java new file mode 100644 index 0000000..f04f602 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/maven/MavenRemoteRepository.java @@ -0,0 +1,52 @@ +package org.ultramine.bootstrap.maven; + +import org.ultramine.bootstrap.deps.IRepository; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +public class MavenRemoteRepository implements IRepository +{ + private final String url; + + public MavenRemoteRepository(String url) + { + this.url = url; + } + + public String getURL() + { + return url; + } + + @Override + public InputStream resolve(String path) throws IOException + { + HttpURLConnection conn = makeConnection(new URL(getURL() + "/" + path)); + int status = conn.getResponseCode(); + if(status / 100 != 2) + return null; + return conn.getInputStream(); + } + + protected HttpURLConnection makeConnection(URL url) throws IOException + { + HttpURLConnection connection = (HttpURLConnection)url.openConnection(); + connection.setUseCaches(false); + connection.setDefaultUseCaches(false); + connection.setRequestProperty("Cache-Control", "no-store,max-age=0,no-cache"); + connection.setRequestProperty("Expires", "0"); + connection.setRequestProperty("Pragma", "no-cache"); + connection.setConnectTimeout(5000); + connection.setReadTimeout(30000); + return connection; + } + + @Override + public String toString() + { + return url; + } +} diff --git a/src/main/java/org/ultramine/bootstrap/maven/ProjectObjectModel.java b/src/main/java/org/ultramine/bootstrap/maven/ProjectObjectModel.java new file mode 100644 index 0000000..b9cc9ea --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/maven/ProjectObjectModel.java @@ -0,0 +1,69 @@ +package org.ultramine.bootstrap.maven; + +import org.ultramine.bootstrap.exceptions.ApplicationErrorException; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import javax.xml.parsers.DocumentBuilderFactory; +import java.util.ArrayList; +import java.util.List; + +public class ProjectObjectModel +{ + private final List runtimeDependencies; + + private ProjectObjectModel(String pomUrl) + { + Document doc; + try + { + doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(pomUrl); + } + catch (Exception e) + { + throw new ApplicationErrorException(e, "error.pom", pomUrl); + } + NodeList listNodes = doc.getElementsByTagName("dependency"); + + runtimeDependencies = new ArrayList<>(listNodes.getLength()); + for(int i = 0, s = listNodes.getLength(); i < s; i++) + { + NodeList dependency = listNodes.item(i).getChildNodes(); + String group = null; + String artifact = null; + String version = null; + String scope = null; + for(int i1 = 0, s1 = dependency.getLength(); i1 < s1; i1++) + { + Node nd = dependency.item(i1); + String name = nd.getNodeName(); + String val = nd.getTextContent(); + switch(name) + { + case "groupId": group = val; break; + case "artifactId": artifact = val; break; + case "version": version = val; break; + case "scope": scope = val; break; + } + } + if("runtime".equals(scope) || "compile".equals(scope)) + runtimeDependencies.add(new MavenDependency(group, artifact, version)); + } + } + + public List getRuntimeDependencies() + { + return runtimeDependencies; + } + + public static ProjectObjectModel loadFromXML(String pomUrl) + { + return new ProjectObjectModel(pomUrl); + } + + public static ProjectObjectModel loadFromArtifact(String repoUrl, String group, String project, String version) + { + return loadFromXML(repoUrl + "/" + group.replace('.', '/') + "/" + project + "/" + version + "/" + project + "-" + version + ".pom"); + } +} diff --git a/src/main/java/org/ultramine/bootstrap/task/DependencyResolver.java b/src/main/java/org/ultramine/bootstrap/task/DependencyResolver.java new file mode 100644 index 0000000..bbf444a --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/task/DependencyResolver.java @@ -0,0 +1,164 @@ +package org.ultramine.bootstrap.task; + +import org.apache.commons.io.FileUtils; +import org.ultramine.bootstrap.Constants; +import org.ultramine.bootstrap.util.I18n; +import org.ultramine.bootstrap.UMCoreVersionsRetriever; +import org.ultramine.bootstrap.util.UmSslUtil; +import org.ultramine.bootstrap.deps.IRepository; +import org.ultramine.bootstrap.maven.MavenDependency; +import org.ultramine.bootstrap.maven.MavenLocalRepository; +import org.ultramine.bootstrap.maven.MavenRemoteRepository; +import org.ultramine.bootstrap.deps.IDownloadable; +import org.ultramine.bootstrap.exceptions.ApplicationErrorException; +import org.ultramine.bootstrap.maven.ProjectObjectModel; +import org.ultramine.bootstrap.versioning.DefaultArtifactVersion; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class DependencyResolver +{ + public static Set load(File dir, String selVersion, boolean update, boolean beta, List extraRepos, List extraLibs) + { + UmSslUtil.checkOrInstall(); + File libraryDir = new File(dir, "libraries"); + File checkSumsDir = new File(libraryDir, "checksums"); + + List repositories = new ArrayList<>(); + addMavenLocalIfExists(repositories, findMavenLocal()); + addMavenLocalIfExists(repositories, findMinecraftLibs()); + repositories.addAll(Arrays.asList( + new MavenRemoteRepository("https://repo1.maven.org/maven2"), + new MavenRemoteRepository("https://oss.sonatype.org/content/repositories/snapshots"), + new MavenRemoteRepository("http://files.minecraftforge.net/maven"), + new MavenRemoteRepository("https://libraries.minecraft.net"), + new MavenRemoteRepository("http"+(UmSslUtil.isUseHttps() ? "s" : "")+"://maven.ultramine.ru") + )); + + for(URL url : extraRepos) + try { + repositories.add(url.getProtocol().equals("file") ? new MavenLocalRepository(new File(url.toURI())) : new MavenRemoteRepository(url.toString())); + } catch(URISyntaxException e) { + throw new ApplicationErrorException(e, "error.addrepo.file", url.toString()); + } + + System.out.println(I18n.tlt("stage.versions")); + String targetVersion = selVersion; + if(targetVersion == null) + { + List versions = null; + if(!update) + versions = retrieveLocalVersions(dir); + if(versions == null || versions.size() == 0) + { + UMCoreVersionsRetriever retr = new UMCoreVersionsRetriever(); + versions = beta ? retr.getBetaVersions() : retr.getStableVersions(); + } + + targetVersion = versions.get(versions.size()-1).getLabel(); + } + + MavenDependency umCoreDep = new MavenDependency(Constants.UM_CORE_GROUP, Constants.UM_CORE_NAME, targetVersion); + File umCoreFile = new File(dir, umCoreDep.getArtifactFilename()); + + Set dependencies = new HashSet<>(); + dependencies.addAll(ProjectObjectModel.loadFromArtifact(Constants.UM_REPO, Constants.UM_CORE_GROUP, Constants.UM_CORE_NAME, targetVersion) + .getRuntimeDependencies()); + dependencies.addAll(extraLibs.stream().map(MavenDependency::new).collect(Collectors.toList())); + + + List toDownload = dependencies.stream().map(d -> d.resolve(repositories)).collect(Collectors.toList()); + IDownloadable umCoreDownloadable = umCoreDep.resolve(repositories); + umCoreDownloadable.setOutputDir(dir); + toDownload.add(umCoreDownloadable); + System.out.println(I18n.tlt("stage.downloading")); + toDownload.parallelStream().forEach(d -> { + try + { + d.setCheckSumsDir(checkSumsDir); + if(d.getOutputDir() == null) + d.setOutputDir(libraryDir); + d.download(); + } catch (IOException e) { + throw new ApplicationErrorException(e, "error.download.dependency", d.toString(), e.toString()); + } + }); + + try + { + File symlink = new File(dir, Constants.UM_CORE_NAME+"-latest.jar"); + if(symlink.exists()) + FileUtils.forceDelete(symlink); + try { + Files.createSymbolicLink(new File(dir, Constants.UM_CORE_NAME + "-latest.jar").toPath(), umCoreFile.toPath()); + } catch(IOException e) { + FileUtils.copyFile(umCoreFile, symlink); + } + } + catch(IOException e) + { + throw new ApplicationErrorException(e, "error.write.file", Constants.UM_CORE_NAME+"-latest.jar", e.getMessage()); + } + + return dependencies; + } + + private static List retrieveLocalVersions(File dir) + { + return Stream.of(dir.list((d, name) -> name.startsWith(Constants.UM_CORE_NAME))) + .map(s -> s.substring(Constants.UM_CORE_NAME.length()+1, s.length()-4)) + .map(s -> new DefaultArtifactVersion(s, s)).sorted().collect(Collectors.toList()); + } + + private static void addMavenLocalIfExists(List list, File repo) + { + if(repo != null && repo.exists()) + list.add(new MavenLocalRepository(repo)); + } + + private static File findMavenLocal() + { + String home = System.getProperty("user.home"); + if(home != null) + return new File(home, ".m2"+File.separator+"repository"); + return null; + } + + private static File findMinecraftLibs() + { + return getFromAppdata(".minecraft"+File.separator+"libraries"); + } + + private static File getFromAppdata(String name) + { + String osName = System.getProperty("os.name").toLowerCase(); + String home = System.getProperty("user.home", "."); + File dir; + if(osName.contains("linux") || osName.contains("unix")) + dir = new File(home, name); + else if(osName.contains("win")) + { + String appdata = System.getenv("APPDATA"); + if(appdata != null) + dir = new File(appdata, name); + else + dir = new File(home, name); + } + else if(osName.contains("mac")) + dir = new File(home, "Library/Application Support/" + name); + else + dir = new File(home, name); + return dir; + } +} diff --git a/src/main/java/org/ultramine/bootstrap/task/ScriptCreator.java b/src/main/java/org/ultramine/bootstrap/task/ScriptCreator.java new file mode 100644 index 0000000..1d0a12c --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/task/ScriptCreator.java @@ -0,0 +1,139 @@ +package org.ultramine.bootstrap.task; + +import org.apache.commons.io.FileUtils; +import org.ultramine.bootstrap.Constants; +import org.ultramine.bootstrap.util.I18n; +import org.ultramine.bootstrap.maven.MavenDependency; +import org.ultramine.bootstrap.exceptions.ApplicationErrorException; +import org.ultramine.bootstrap.util.Resources; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Properties; +import java.util.Set; + +public class ScriptCreator +{ + public static void create(File dir, Set dependencies, String parXmx, String parXms, String parTerminal, boolean forge) + { + System.out.println(I18n.tlt("stage.scripts")); + long xmx = resolveMemory(parXmx); + long xms = resolveMemory(parXms); + long xmn = Math.min(xmx / 4, 1024L*1024*1024); + if(xms > xmx) + xms = xmx; + if(xmx < 32*1024*1024) + throw new ApplicationErrorException("Maximum heap size (-Xmx) is too low: %s", parXmx); + + boolean win = System.getProperty("os.name").toLowerCase().contains("win"); + try(BufferedWriter writer = new BufferedWriter(new FileWriter( + new File(dir, "ultramine_server_run_line."+(win ? "bat" : "sh"))))) + { + if(!win) + { + writer.write("#!/bin/sh"); + writer.newLine(); + } + writer.write(Resources.getAsString("/assets/script/java_command_line.txt") + .replace("{xms}", formatMemory(xmx)) + .replace("{xmx}", formatMemory(xms)) + .replace("{xmn}", formatMemory(xmn)) + + .replace("{terminal}", parTerminal) + + .replace("{vanilla_dir}", forge ? "." : "storage") + .replace("{worlds_dir}", forge ? "." : "worlds") + + .replace("{classpath}", buildClassPath(dependencies)) + .replace('\\', win ? '^' : '\\') + .replace("#", win ? "::" : "#") +// .replace("<", win ? "%=" : "`#") +// .replace(">", win ? "=%" : "`") + ); + writer.newLine(); + } + catch(IOException e) + { + throw new ApplicationErrorException(e, "error.write.file", "ultramine_server_run_line."+(win ? "bat" : "sh"), e.getMessage()); + } + + try + { + FileUtils.writeStringToFile(new File(dir, "start."+(win ? "bat" : "sh")), + Resources.getAsString("/assets/script/"+(win ? "windows/start.bat" : "shell/start.sh"))); + } + catch(IOException e) + { + throw new ApplicationErrorException(e, "error.write.file", "start."+(win ? "bat" : "sh"), e.getMessage()); + } + + if(forge) + { + try + { + File serverYml = new File(dir, "settings"+File.separator+"server.yml"); + if(!serverYml.exists()) + { + String confStr = Resources.getAsString("/assets/server.yml"); + confStr = confStr.replace("{split-world-dirs}", "false"); + Properties defs = new Properties(); + defs.load(Resources.getAsStream("/assets/server.properties")); + Properties props = new Properties(defs); + File propsFile = new File(dir, "server.properties"); + if(propsFile.exists()) + try(FileInputStream inp = new FileInputStream(propsFile)) { + props.load(inp); + } + for(Object key : defs.keySet()) + confStr = confStr.replace("{"+key+"}", props.getProperty(key.toString())); + FileUtils.writeStringToFile(serverYml, confStr); + } + } + catch(IOException e) + { + throw new ApplicationErrorException(e, "error.write.file", "settings/server.yml", e.getMessage()); + } + } + } + + /** @return number in bytes */ + private static long resolveMemory(String s) + { + try + { + return Long.parseLong(s); + } + catch (NumberFormatException e1) + { + long val = Long.parseLong(s.substring(0, s.length() - 1)); + char mod = Character.toLowerCase(s.charAt(s.length()-1)); + if(mod != 'k' && mod != 'm' && mod != 'g') + throw new IllegalArgumentException(s); + return val * (mod == 'k' ? 1024 : mod == 'm' ? 1024*1024 : 1024*1024*1024); + } + } + + private static String formatMemory(long bytes) + { + return (bytes / (1024*1024)) + "m"; + } + + private static String buildClassPath(Set dependencies) + { + StringBuilder sb = new StringBuilder(); + String separator = System.getProperty("path.separator"); + + sb.append(Constants.UM_CORE_NAME+"-latest.jar"); + for(MavenDependency dep : dependencies) + { + sb.append(separator); + sb.append("libraries/"); + sb.append(dep.getArtifactFilename()); + } + + return sb.toString(); + } +} diff --git a/src/main/java/org/ultramine/bootstrap/util/HashUtil.java b/src/main/java/org/ultramine/bootstrap/util/HashUtil.java new file mode 100644 index 0000000..8a1b966 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/util/HashUtil.java @@ -0,0 +1,68 @@ +package org.ultramine.bootstrap.util; + +import org.apache.commons.io.IOUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class HashUtil +{ + private static final char[] CHARS = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + + public static MessageDigest getSHA1() + { + try + { + return MessageDigest.getInstance("SHA-1"); + } + catch(NoSuchAlgorithmException e) + { + throw new RuntimeException("SHA-1 not found", e); + } + } + + public static String sha1Str(File file) + { + return byteArray2Hex(calculateHash(getSHA1(), file)); + } + + public static byte[] calculateHash(MessageDigest alg, File file) + { + DigestInputStream dis = null; + try + { + dis = new DigestInputStream(new FileInputStream(file), alg); + + byte[] buff = new byte[4096]; + do {} while(dis.read(buff) != -1); + + return alg.digest(); + } + catch(IOException e) + { + alg.reset(); + return new byte[0]; + } + finally + { + IOUtils.closeQuietly(dis); + } + } + + public static String byteArray2Hex(byte[] hash) + { + StringBuilder sb = new StringBuilder(hash.length*2); + for(int i = 0; i < hash.length; i++) + { + byte b = hash[i]; + sb.append(CHARS[(b & 0xff) >> 4]); + sb.append(CHARS[b & 15]); + } + + return sb.toString(); + } +} diff --git a/src/main/java/org/ultramine/bootstrap/util/I18n.java b/src/main/java/org/ultramine/bootstrap/util/I18n.java new file mode 100644 index 0000000..5e73754 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/util/I18n.java @@ -0,0 +1,46 @@ +package org.ultramine.bootstrap.util; + +import org.ultramine.bootstrap.util.Resources; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +public class I18n +{ + private static final Properties enUs = loadLang("en_US"); + private static Properties selected = enUs; + + public static void select(String locale) + { + Properties props = locale.equals("en_US") ? enUs : loadLang(locale); + selected = props != null ? props : enUs; + } + + private static Properties loadLang(String locale) + { + InputStream inp = Resources.getAsStream("/assets/lang/"+locale+".lang"); + if(inp == null) + return null; + try + { + Properties props = enUs != null ? new Properties(enUs) : new Properties(); + props.load(inp); + return props; + } + catch(IOException e) + { + throw new RuntimeException(e); + } + } + + public static String tlt(String key) + { + return selected.getProperty(key, key); + } + + public static String tlt(String key, Object... args) + { + return String.format(tlt(key), args); + } +} diff --git a/src/main/java/org/ultramine/bootstrap/util/Resources.java b/src/main/java/org/ultramine/bootstrap/util/Resources.java new file mode 100644 index 0000000..f859002 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/util/Resources.java @@ -0,0 +1,34 @@ +package org.ultramine.bootstrap.util; + +import org.apache.commons.io.Charsets; +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.io.InputStream; + +public class Resources +{ + public static InputStream getAsStream(String path) + { + return Resources.class.getResourceAsStream(path); + } + + public static String getAsString(String path) + { + InputStream is = getAsStream(path); + if(is == null) + throw new RuntimeException("Requested resource not found: " + path); + try + { + return IOUtils.toString(is, Charsets.UTF_8); + } + catch(IOException e) + { + throw new RuntimeException("Failed to load resource: " + path, e); + } + finally + { + IOUtils.closeQuietly(is); + } + } +} diff --git a/src/main/java/org/ultramine/bootstrap/util/UmSslUtil.java b/src/main/java/org/ultramine/bootstrap/util/UmSslUtil.java new file mode 100644 index 0000000..49ed417 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/util/UmSslUtil.java @@ -0,0 +1,72 @@ +package org.ultramine.bootstrap.util; + +import org.ultramine.bootstrap.util.Resources; + +import java.io.BufferedInputStream; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.KeyStore; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; + +public class UmSslUtil +{ + private static boolean useHttps = true; + + public static boolean isUseHttps() + { + return useHttps; + } + + public static void checkOrInstall() + { + //TODO connection caching issues +// try +// { +// new URL("https://maven.ultramine.ru").openConnection().getInputStream().close(); +// } +// catch (SSLHandshakeException e) +// { + installDSTRootCA(); +// } +// catch(IOException e) +// { +// throw new ApplicationErrorException(e, "error.unavailable.maven", "maven.ultramine.ru"); +// } + } + + private static void installDSTRootCA() + { + try + { + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + Path ksPath = Paths.get(System.getProperty("java.home"), + "lib", "security", "cacerts"); + keyStore.load(Files.newInputStream(ksPath), + "changeit".toCharArray()); + + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + try(InputStream caInput = new BufferedInputStream( Resources.getAsStream("/assets/crt/DSTRootCAX3.pem"))) + { + Certificate crt = cf.generateCertificate(caInput); + keyStore.setCertificateEntry("DSTRootCAX3", crt); + } + + TrustManagerFactory tmf = TrustManagerFactory + .getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(keyStore); + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, tmf.getTrustManagers(), null); + SSLContext.setDefault(sslContext); + } + catch (Throwable e) + { + useHttps = false; + } + } +} diff --git a/src/main/java/org/ultramine/bootstrap/versioning/ArtifactVersion.java b/src/main/java/org/ultramine/bootstrap/versioning/ArtifactVersion.java new file mode 100644 index 0000000..7ef90f8 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/versioning/ArtifactVersion.java @@ -0,0 +1,50 @@ +/* + * Forge Mod Loader + * Copyright (c) 2012-2013 cpw. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser Public License v2.1 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * + * Contributors: + * cpw - implementation + */ + +package org.ultramine.bootstrap.versioning; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/** + * Describes an artifactName version in terms of its components, converts it to/from a string and + * compares two versions. + * + * @author Brett Porter + */ +public interface ArtifactVersion + extends Comparable +{ + String getLabel(); + + String getVersionString(); + + boolean containsVersion(ArtifactVersion source); + + String getRangeString(); +} \ No newline at end of file diff --git a/src/main/java/org/ultramine/bootstrap/versioning/ComparableVersion.java b/src/main/java/org/ultramine/bootstrap/versioning/ComparableVersion.java new file mode 100644 index 0000000..587edf2 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/versioning/ComparableVersion.java @@ -0,0 +1,500 @@ +/* + * Forge Mod Loader + * Copyright (c) 2012-2013 cpw. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser Public License v2.1 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * + * Contributors: + * cpw - implementation + */ + +package org.ultramine.bootstrap.versioning; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Locale; +import java.util.Properties; +import java.util.Stack; + +/** + * Generic implementation of version comparison. + * + *

Features: + *

    + *
  • mixing of '-' (dash) and '.' (dot) separators,
  • + *
  • transition between characters and digits also constitutes a separator: + * 1.0alpha1 => [1, 0, alpha, 1]
  • + *
  • unlimited number of version components,
  • + *
  • version components in the text can be digits or strings,
  • + *
  • strings are checked for well-known qualifiers and the qualifier ordering is used for version ordering. + * Well-known qualifiers (case insensitive) are:
      + *
    • snapshot
    • + *
    • alpha or a
    • + *
    • beta or b
    • + *
    • milestone or m
    • + *
    • rc or cr
    • + *
    • (the empty string) or ga or final
    • + *
    • sp
    • + *
    + * Unknown qualifiers are considered after known qualifiers, with lexical order (always case insensitive), + *
  • + *
  • a dash usually precedes a qualifier, and is always less important than something preceded with a dot.
  • + *

+ * + * @see "Versioning" on Maven Wiki + * @author Kenney Westerhof + * @author Hervé Boutemy + */ +public class ComparableVersion + implements Comparable +{ + private String value; + + private String canonical; + + private ListItem items; + + private interface Item + { + final int INTEGER_ITEM = 0; + final int STRING_ITEM = 1; + final int LIST_ITEM = 2; + + int compareTo(Item item); + + int getType(); + + boolean isNull(); + } + + /** + * Represents a numeric item in the version item list. + */ + private static class IntegerItem + implements Item + { + private static final BigInteger BigInteger_ZERO = new BigInteger( "0" ); + + private final BigInteger value; + + public static final IntegerItem ZERO = new IntegerItem(); + + private IntegerItem() + { + this.value = BigInteger_ZERO; + } + + public IntegerItem( String str ) + { + this.value = new BigInteger( str ); + } + + @Override + public int getType() + { + return INTEGER_ITEM; + } + + @Override + public boolean isNull() + { + return BigInteger_ZERO.equals( value ); + } + + @Override + public int compareTo( Item item ) + { + if ( item == null ) + { + return BigInteger_ZERO.equals( value ) ? 0 : 1; // 1.0 == 1, 1.1 > 1 + } + + switch ( item.getType() ) + { + case INTEGER_ITEM: + return value.compareTo( ( (IntegerItem) item ).value ); + + case STRING_ITEM: + return 1; // 1.1 > 1-sp + + case LIST_ITEM: + return 1; // 1.1 > 1-1 + + default: + throw new RuntimeException( "invalid item: " + item.getClass() ); + } + } + + @Override + public String toString() + { + return value.toString(); + } + } + + /** + * Represents a string in the version item list, usually a qualifier. + */ + private static class StringItem + implements Item + { + private static final String[] QUALIFIERS = { "alpha", "beta", "milestone", "rc", "snapshot", "", "sp" }; + + private static final List _QUALIFIERS = Arrays.asList( QUALIFIERS ); + + private static final Properties ALIASES = new Properties(); + static + { + ALIASES.put( "ga", "" ); + ALIASES.put( "final", "" ); + ALIASES.put( "cr", "rc" ); + } + + /** + * A comparable value for the empty-string qualifier. This one is used to determine if a given qualifier makes + * the version older than one without a qualifier, or more recent. + */ + private static final String RELEASE_VERSION_INDEX = String.valueOf( _QUALIFIERS.indexOf( "" ) ); + + private String value; + + public StringItem( String value, boolean followedByDigit ) + { + if ( followedByDigit && value.length() == 1 ) + { + // a1 = alpha-1, b1 = beta-1, m1 = milestone-1 + switch ( value.charAt( 0 ) ) + { + case 'a': + value = "alpha"; + break; + case 'b': + value = "beta"; + break; + case 'm': + value = "milestone"; + break; + } + } + this.value = ALIASES.getProperty( value , value ); + } + + @Override + public int getType() + { + return STRING_ITEM; + } + + @Override + public boolean isNull() + { + return ( comparableQualifier( value ).compareTo( RELEASE_VERSION_INDEX ) == 0 ); + } + + /** + * Returns a comparable value for a qualifier. + * + * This method takes into account the ordering of known qualifiers then unknown qualifiers with lexical ordering. + * + * just returning an Integer with the index here is faster, but requires a lot of if/then/else to check for -1 + * or QUALIFIERS.size and then resort to lexical ordering. Most comparisons are decided by the first character, + * so this is still fast. If more characters are needed then it requires a lexical sort anyway. + * + * @param qualifier + * @return an equivalent value that can be used with lexical comparison + */ + public static String comparableQualifier( String qualifier ) + { + int i = _QUALIFIERS.indexOf( qualifier ); + + return i == -1 ? ( _QUALIFIERS.size() + "-" + qualifier ) : String.valueOf( i ); + } + + @Override + public int compareTo( Item item ) + { + if ( item == null ) + { + // 1-rc < 1, 1-ga > 1 + return comparableQualifier( value ).compareTo( RELEASE_VERSION_INDEX ); + } + switch ( item.getType() ) + { + case INTEGER_ITEM: + return -1; // 1.any < 1.1 ? + + case STRING_ITEM: + return comparableQualifier( value ).compareTo( comparableQualifier( ( (StringItem) item ).value ) ); + + case LIST_ITEM: + return -1; // 1.any < 1-1 + + default: + throw new RuntimeException( "invalid item: " + item.getClass() ); + } + } + + @Override + public String toString() + { + return value; + } + } + + /** + * Represents a version list item. This class is used both for the global item list and for sub-lists (which start + * with '-(number)' in the version specification). + */ + private static class ListItem + extends ArrayList + implements Item + { + /** + * + */ + private static final long serialVersionUID = 1L; + + @Override + public int getType() + { + return LIST_ITEM; + } + + @Override + public boolean isNull() + { + return ( size() == 0 ); + } + + void normalize() + { + for( ListIterator iterator = listIterator( size() ); iterator.hasPrevious(); ) + { + Item item = iterator.previous(); + if ( item.isNull() ) + { + iterator.remove(); // remove null trailing items: 0, "", empty list + } + else + { + break; + } + } + } + + @Override + public int compareTo( Item item ) + { + if ( item == null ) + { + if ( size() == 0 ) + { + return 0; // 1-0 = 1- (normalize) = 1 + } + Item first = get( 0 ); + return first.compareTo( null ); + } + switch ( item.getType() ) + { + case INTEGER_ITEM: + return -1; // 1-1 < 1.0.x + + case STRING_ITEM: + return 1; // 1-1 > 1-sp + + case LIST_ITEM: + Iterator left = iterator(); + Iterator right = ( (ListItem) item ).iterator(); + + while ( left.hasNext() || right.hasNext() ) + { + Item l = left.hasNext() ? left.next() : null; + Item r = right.hasNext() ? right.next() : null; + + // if this is shorter, then invert the compare and mul with -1 + int result = l == null ? -1 * r.compareTo( l ) : l.compareTo( r ); + + if ( result != 0 ) + { + return result; + } + } + + return 0; + + default: + throw new RuntimeException( "invalid item: " + item.getClass() ); + } + } + + @Override + public String toString() + { + StringBuilder buffer = new StringBuilder( "(" ); + for( Iterator iter = iterator(); iter.hasNext(); ) + { + buffer.append( iter.next() ); + if ( iter.hasNext() ) + { + buffer.append( ',' ); + } + } + buffer.append( ')' ); + return buffer.toString(); + } + } + + public ComparableVersion( String version ) + { + parseVersion( version ); + } + + public final void parseVersion( String version ) + { + this.value = version; + + items = new ListItem(); + + version = version.toLowerCase( Locale.ENGLISH ); + + ListItem list = items; + + Stack stack = new Stack(); + stack.push( list ); + + boolean isDigit = false; + + int startIndex = 0; + + for ( int i = 0; i < version.length(); i++ ) + { + char c = version.charAt( i ); + + if ( c == '.' ) + { + if ( i == startIndex ) + { + list.add( IntegerItem.ZERO ); + } + else + { + list.add( parseItem( isDigit, version.substring( startIndex, i ) ) ); + } + startIndex = i + 1; + } + else if ( c == '-' ) + { + if ( i == startIndex ) + { + list.add( IntegerItem.ZERO ); + } + else + { + list.add( parseItem( isDigit, version.substring( startIndex, i ) ) ); + } + startIndex = i + 1; + + if ( isDigit ) + { + list.normalize(); // 1.0-* = 1-* + + if ( ( i + 1 < version.length() ) && Character.isDigit( version.charAt( i + 1 ) ) ) + { + // new ListItem only if previous were digits and new char is a digit, + // ie need to differentiate only 1.1 from 1-1 + list.add( list = new ListItem() ); + + stack.push( list ); + } + } + } + else if ( Character.isDigit( c ) ) + { + if ( !isDigit && i > startIndex ) + { + list.add( new StringItem( version.substring( startIndex, i ), true ) ); + startIndex = i; + } + + isDigit = true; + } + else + { + if ( isDigit && i > startIndex ) + { + list.add( parseItem( true, version.substring( startIndex, i ) ) ); + startIndex = i; + } + + isDigit = false; + } + } + + if ( version.length() > startIndex ) + { + list.add( parseItem( isDigit, version.substring( startIndex ) ) ); + } + + while ( !stack.isEmpty() ) + { + list = (ListItem) stack.pop(); + list.normalize(); + } + + canonical = items.toString(); + } + + private static Item parseItem( boolean isDigit, String buf ) + { + return isDigit ? new IntegerItem( buf ) : new StringItem( buf, false ); + } + + @Override + public int compareTo( ComparableVersion o ) + { + return items.compareTo( o.items ); + } + + @Override + public String toString() + { + return value; + } + + @Override + public boolean equals( Object o ) + { + return ( o instanceof ComparableVersion ) && canonical.equals( ( (ComparableVersion) o ).canonical ); + } + + @Override + public int hashCode() + { + return canonical.hashCode(); + } +} \ No newline at end of file diff --git a/src/main/java/org/ultramine/bootstrap/versioning/DefaultArtifactVersion.java b/src/main/java/org/ultramine/bootstrap/versioning/DefaultArtifactVersion.java new file mode 100644 index 0000000..ded634a --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/versioning/DefaultArtifactVersion.java @@ -0,0 +1,105 @@ +/* + * Forge Mod Loader + * Copyright (c) 2012-2013 cpw. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser Public License v2.1 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * + * Contributors: + * cpw - implementation + */ + +package org.ultramine.bootstrap.versioning; + +public class DefaultArtifactVersion implements ArtifactVersion +{ + private ComparableVersion comparableVersion; + private String label; + private boolean unbounded; + private VersionRange range; + + public DefaultArtifactVersion(String versionNumber) + { + comparableVersion = new ComparableVersion(versionNumber); + range = VersionRange.createFromVersion(versionNumber, this); + } + + public DefaultArtifactVersion(String label, VersionRange range) + { + this.label = label; + this.range = range; + } + public DefaultArtifactVersion(String label, String version) + { + this(version); + this.label = label; + } + + public DefaultArtifactVersion(String string, boolean unbounded) + { + this.label = string; + this.unbounded = true; + } + + @Override + public boolean equals(Object obj) + { + return ((DefaultArtifactVersion)obj).containsVersion(this); + } + + @Override + public int compareTo(ArtifactVersion o) + { + return unbounded ? 0 : this.comparableVersion.compareTo(((DefaultArtifactVersion)o).comparableVersion); + } + + @Override + public String getLabel() + { + return label; + } + + @Override + public boolean containsVersion(ArtifactVersion source) + { + if (!source.getLabel().equals(getLabel())) + { + return false; + } + if (unbounded) + { + return true; + } + if (range != null) + { + return range.containsVersion(source); + } + else + { + return false; + } + } + + @Override + public String getVersionString() + { + return comparableVersion == null ? "unknown" : comparableVersion.toString(); + } + + @Override + public String getRangeString() + { + return range == null ? "any" : range.toString(); + } + @Override + public String toString() + { + return label == null ? comparableVersion.toString() : label + ( unbounded ? "" : "@" + range); + } + + public VersionRange getRange() + { + return range; + } +} \ No newline at end of file diff --git a/src/main/java/org/ultramine/bootstrap/versioning/InvalidVersionSpecificationException.java b/src/main/java/org/ultramine/bootstrap/versioning/InvalidVersionSpecificationException.java new file mode 100644 index 0000000..333fd70 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/versioning/InvalidVersionSpecificationException.java @@ -0,0 +1,47 @@ +/* + * Forge Mod Loader + * Copyright (c) 2012-2013 cpw. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser Public License v2.1 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * + * Contributors: + * cpw - implementation + */ + +package org.ultramine.bootstrap.versioning; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/** + * Occurs when a version is invalid. + * + * @author Brett Porter + */ +public class InvalidVersionSpecificationException extends Exception +{ + private static final long serialVersionUID = 1L; + + public InvalidVersionSpecificationException( String message ) + { + super( message ); + } +} \ No newline at end of file diff --git a/src/main/java/org/ultramine/bootstrap/versioning/Restriction.java b/src/main/java/org/ultramine/bootstrap/versioning/Restriction.java new file mode 100644 index 0000000..0baf78e --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/versioning/Restriction.java @@ -0,0 +1,212 @@ +/* + * Forge Mod Loader + * Copyright (c) 2012-2013 cpw. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser Public License v2.1 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * + * Contributors: + * cpw - implementation + */ + +package org.ultramine.bootstrap.versioning; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/** + * Describes a restriction in versioning. + * + * @author Brett Porter + */ +public class Restriction +{ + private final ArtifactVersion lowerBound; + + private final boolean lowerBoundInclusive; + + private final ArtifactVersion upperBound; + + private final boolean upperBoundInclusive; + + public static final Restriction EVERYTHING = new Restriction( null, false, null, false ); + + public Restriction( ArtifactVersion lowerBound, boolean lowerBoundInclusive, ArtifactVersion upperBound, + boolean upperBoundInclusive ) + { + this.lowerBound = lowerBound; + this.lowerBoundInclusive = lowerBoundInclusive; + this.upperBound = upperBound; + this.upperBoundInclusive = upperBoundInclusive; + } + + public ArtifactVersion getLowerBound() + { + return lowerBound; + } + + public boolean isLowerBoundInclusive() + { + return lowerBoundInclusive; + } + + public ArtifactVersion getUpperBound() + { + return upperBound; + } + + public boolean isUpperBoundInclusive() + { + return upperBoundInclusive; + } + + public boolean containsVersion( ArtifactVersion version ) + { + if ( lowerBound != null ) + { + int comparison = lowerBound.compareTo( version ); + + if ( ( comparison == 0 ) && !lowerBoundInclusive ) + { + return false; + } + if ( comparison > 0 ) + { + return false; + } + } + if ( upperBound != null ) + { + int comparison = upperBound.compareTo( version ); + + if ( ( comparison == 0 ) && !upperBoundInclusive ) + { + return false; + } + if ( comparison < 0 ) + { + return false; + } + } + + return true; + } + + @Override + public int hashCode() + { + int result = 13; + + if ( lowerBound == null ) + { + result += 1; + } + else + { + result += lowerBound.hashCode(); + } + + result *= lowerBoundInclusive ? 1 : 2; + + if ( upperBound == null ) + { + result -= 3; + } + else + { + result -= upperBound.hashCode(); + } + + result *= upperBoundInclusive ? 2 : 3; + + return result; + } + + @Override + public boolean equals( Object other ) + { + if ( this == other ) + { + return true; + } + + if ( !( other instanceof Restriction ) ) + { + return false; + } + + Restriction restriction = (Restriction) other; + if ( lowerBound != null ) + { + if ( !lowerBound.equals( restriction.lowerBound ) ) + { + return false; + } + } + else if ( restriction.lowerBound != null ) + { + return false; + } + + if ( lowerBoundInclusive != restriction.lowerBoundInclusive ) + { + return false; + } + + if ( upperBound != null ) + { + if ( !upperBound.equals( restriction.upperBound ) ) + { + return false; + } + } + else if ( restriction.upperBound != null ) + { + return false; + } + + if ( upperBoundInclusive != restriction.upperBoundInclusive ) + { + return false; + } + + return true; + } + + @Override + public String toString() + { + StringBuilder buf = new StringBuilder(); + + buf.append( isLowerBoundInclusive() ? "[" : "(" ); + if ( getLowerBound() != null ) + { + buf.append( getLowerBound().toString() ); + } + buf.append( "," ); + if ( getUpperBound() != null ) + { + buf.append( getUpperBound().toString() ); + } + buf.append( isUpperBoundInclusive() ? "]" : ")" ); + + return buf.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/org/ultramine/bootstrap/versioning/VersionParser.java b/src/main/java/org/ultramine/bootstrap/versioning/VersionParser.java new file mode 100644 index 0000000..81d24e2 --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/versioning/VersionParser.java @@ -0,0 +1,66 @@ +/* + * Forge Mod Loader + * Copyright (c) 2012-2013 cpw. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser Public License v2.1 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * + * Contributors: + * cpw - implementation + */ + +package org.ultramine.bootstrap.versioning; + +import java.util.Arrays; +import java.util.List; + +/** + * Parses version strings according to the specification here: + * http://docs.codehaus.org/display/MAVEN/Versioning + * and allows for comparison of versions based on that document. + * Bounded version specifications are defined as + * http://maven.apache.org/plugins/maven-enforcer-plugin/rules/versionRanges.html + * + * Borrows heavily from maven version range management code + * + * @author cpw + * + */ +public class VersionParser +{ + public static ArtifactVersion parseVersionReference(String labelledRef) + { + if (labelledRef == null || labelledRef.isEmpty()) + { + throw new RuntimeException(String.format("Empty reference %s", labelledRef)); + } + List parts = Arrays.asList(labelledRef.split("@")); + if (parts.size()>2) + { + throw new RuntimeException(String.format("Invalid versioned reference %s", labelledRef)); + } + if (parts.size()==1) + { + return new DefaultArtifactVersion(parts.get(0), true); + } + return new DefaultArtifactVersion(parts.get(0),parseRange(parts.get(1))); + } + + public static boolean satisfies(ArtifactVersion target, ArtifactVersion source) + { + return target.containsVersion(source); + } + + public static VersionRange parseRange(String range) + { + try + { + return VersionRange.createFromVersionSpec(range); + } + catch (InvalidVersionSpecificationException e) + { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/ultramine/bootstrap/versioning/VersionRange.java b/src/main/java/org/ultramine/bootstrap/versioning/VersionRange.java new file mode 100644 index 0000000..8d0a34c --- /dev/null +++ b/src/main/java/org/ultramine/bootstrap/versioning/VersionRange.java @@ -0,0 +1,575 @@ +/* + * Forge Mod Loader + * Copyright (c) 2012-2013 cpw. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser Public License v2.1 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * + * Contributors: + * cpw - implementation + */ + +package org.ultramine.bootstrap.versioning; +/* + * Modifications by cpw under LGPL 2.1 or later + */ + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Construct a version range from a specification. + * + * @author Brett Porter + */ +public class VersionRange +{ + private final ArtifactVersion recommendedVersion; + + private final List restrictions; + + private VersionRange( ArtifactVersion recommendedVersion, + List restrictions ) + { + this.recommendedVersion = recommendedVersion; + this.restrictions = restrictions; + } + + public ArtifactVersion getRecommendedVersion() + { + return recommendedVersion; + } + + public List getRestrictions() + { + return restrictions; + } + + public VersionRange cloneOf() + { + List copiedRestrictions = null; + + if ( restrictions != null ) + { + copiedRestrictions = new ArrayList(); + + if ( !restrictions.isEmpty() ) + { + copiedRestrictions.addAll( restrictions ); + } + } + + return new VersionRange( recommendedVersion, copiedRestrictions ); + } + + /** + * Factory method, for custom versioning schemes + * @param version version + * @param restrictions restriction list + * @return a new version range + */ + public static VersionRange newRange(ArtifactVersion version, List restrictions) + { + return new VersionRange(version, restrictions); + } + /** + * Create a version range from a string representation + *

+ * Some spec examples are + *

    + *
  • 1.0 Version 1.0
  • + *
  • [1.0,2.0) Versions 1.0 (included) to 2.0 (not included)
  • + *
  • [1.0,2.0] Versions 1.0 to 2.0 (both included)
  • + *
  • [1.5,) Versions 1.5 and higher
  • + *
  • (,1.0],[1.2,) Versions up to 1.0 (included) and 1.2 or higher
  • + *
+ * + * @param spec string representation of a version or version range + * @return a new {@link VersionRange} object that represents the spec + * @throws InvalidVersionSpecificationException + * + */ + public static VersionRange createFromVersionSpec( String spec ) + throws InvalidVersionSpecificationException + { + if ( spec == null ) + { + return null; + } + + List restrictions = new ArrayList(); + String process = spec; + ArtifactVersion version = null; + ArtifactVersion upperBound = null; + ArtifactVersion lowerBound = null; + + while ( process.startsWith( "[" ) || process.startsWith( "(" ) ) + { + int index1 = process.indexOf( ")" ); + int index2 = process.indexOf( "]" ); + + int index = index2; + if ( index2 < 0 || index1 < index2 ) + { + if ( index1 >= 0 ) + { + index = index1; + } + } + + if ( index < 0 ) + { + throw new InvalidVersionSpecificationException( "Unbounded range: " + spec ); + } + + Restriction restriction = parseRestriction( process.substring( 0, index + 1 ) ); + if ( lowerBound == null ) + { + lowerBound = restriction.getLowerBound(); + } + if ( upperBound != null ) + { + if ( restriction.getLowerBound() == null || restriction.getLowerBound().compareTo( upperBound ) < 0 ) + { + throw new InvalidVersionSpecificationException( "Ranges overlap: " + spec ); + } + } + restrictions.add( restriction ); + upperBound = restriction.getUpperBound(); + + process = process.substring( index + 1 ).trim(); + + if ( process.length() > 0 && process.startsWith( "," ) ) + { + process = process.substring( 1 ).trim(); + } + } + + if ( process.length() > 0 ) + { + if ( restrictions.size() > 0 ) + { + throw new InvalidVersionSpecificationException( + "Only fully-qualified sets allowed in multiple set scenario: " + spec ); + } + else + { + version = new DefaultArtifactVersion( process ); + restrictions.add( Restriction.EVERYTHING ); + } + } + + return new VersionRange( version, restrictions ); + } + + private static Restriction parseRestriction( String spec ) + throws InvalidVersionSpecificationException + { + boolean lowerBoundInclusive = spec.startsWith( "[" ); + boolean upperBoundInclusive = spec.endsWith( "]" ); + + String process = spec.substring( 1, spec.length() - 1 ).trim(); + + Restriction restriction; + + int index = process.indexOf( "," ); + + if ( index < 0 ) + { + if ( !lowerBoundInclusive || !upperBoundInclusive ) + { + throw new InvalidVersionSpecificationException( "Single version must be surrounded by []: " + spec ); + } + + ArtifactVersion version = new DefaultArtifactVersion( process ); + + restriction = new Restriction( version, lowerBoundInclusive, version, upperBoundInclusive ); + } + else + { + String lowerBound = process.substring( 0, index ).trim(); + String upperBound = process.substring( index + 1 ).trim(); + if ( lowerBound.equals( upperBound ) ) + { + throw new InvalidVersionSpecificationException( "Range cannot have identical boundaries: " + spec ); + } + + ArtifactVersion lowerVersion = null; + if ( lowerBound.length() > 0 ) + { + lowerVersion = new DefaultArtifactVersion( lowerBound ); + } + ArtifactVersion upperVersion = null; + if ( upperBound.length() > 0 ) + { + upperVersion = new DefaultArtifactVersion( upperBound ); + } + + if ( upperVersion != null && lowerVersion != null && upperVersion.compareTo( lowerVersion ) < 0 ) + { + throw new InvalidVersionSpecificationException( "Range defies version ordering: " + spec ); + } + + restriction = new Restriction( lowerVersion, lowerBoundInclusive, upperVersion, upperBoundInclusive ); + } + + return restriction; + } + + public static VersionRange createFromVersion( String version , ArtifactVersion existing) + { + List restrictions = Collections.emptyList(); + if (existing == null) + { + existing = new DefaultArtifactVersion( version ); + } + return new VersionRange(existing , restrictions ); + } + + /** + * Creates and returns a new VersionRange that is a restriction of this + * version range and the specified version range. + *

+ * Note: Precedence is given to the recommended version from this version range over the + * recommended version from the specified version range. + *

+ * + * @param restriction the VersionRange that will be used to restrict this version + * range. + * @return the VersionRange that is a restriction of this version range and the + * specified version range. + *

+ * The restrictions of the returned version range will be an intersection of the restrictions + * of this version range and the specified version range if both version ranges have + * restrictions. Otherwise, the restrictions on the returned range will be empty. + *

+ *

+ * The recommended version of the returned version range will be the recommended version of + * this version range, provided that ranges falls within the intersected restrictions. If + * the restrictions are empty, this version range's recommended version is used if it is not + * null. If it is null, the specified version range's recommended + * version is used (provided it is non-null). If no recommended version can be + * obtained, the returned version range's recommended version is set to null. + *

+ * @throws NullPointerException if the specified VersionRange is + * null. + */ + public VersionRange restrict( VersionRange restriction ) + { + List r1 = this.restrictions; + List r2 = restriction.restrictions; + List restrictions; + + if ( r1.isEmpty() || r2.isEmpty() ) + { + restrictions = Collections.emptyList(); + } + else + { + restrictions = intersection( r1, r2 ); + } + + ArtifactVersion version = null; + if ( restrictions.size() > 0 ) + { + for ( Restriction r : restrictions ) + { + if ( recommendedVersion != null && r.containsVersion( recommendedVersion ) ) + { + // if we find the original, use that + version = recommendedVersion; + break; + } + else if ( version == null && restriction.getRecommendedVersion() != null + && r.containsVersion( restriction.getRecommendedVersion() ) ) + { + // use this if we can, but prefer the original if possible + version = restriction.getRecommendedVersion(); + } + } + } + // Either the original or the specified version ranges have no restrictions + else if ( recommendedVersion != null ) + { + // Use the original recommended version since it exists + version = recommendedVersion; + } + else if ( restriction.recommendedVersion != null ) + { + // Use the recommended version from the specified VersionRange since there is no + // original recommended version + version = restriction.recommendedVersion; + } +/* TODO: should throw this immediately, but need artifactName + else + { + throw new OverConstrainedVersionException( "Restricting incompatible version ranges" ); + } +*/ + + return new VersionRange( version, restrictions ); + } + + private List intersection( List r1, List r2 ) + { + List restrictions = new ArrayList( r1.size() + r2.size() ); + Iterator i1 = r1.iterator(); + Iterator i2 = r2.iterator(); + Restriction res1 = i1.next(); + Restriction res2 = i2.next(); + + boolean done = false; + while ( !done ) + { + if ( res1.getLowerBound() == null || res2.getUpperBound() == null + || res1.getLowerBound().compareTo( res2.getUpperBound() ) <= 0 ) + { + if ( res1.getUpperBound() == null || res2.getLowerBound() == null + || res1.getUpperBound().compareTo( res2.getLowerBound() ) >= 0 ) + { + ArtifactVersion lower; + ArtifactVersion upper; + boolean lowerInclusive; + boolean upperInclusive; + + // overlaps + if ( res1.getLowerBound() == null ) + { + lower = res2.getLowerBound(); + lowerInclusive = res2.isLowerBoundInclusive(); + } + else if ( res2.getLowerBound() == null ) + { + lower = res1.getLowerBound(); + lowerInclusive = res1.isLowerBoundInclusive(); + } + else + { + int comparison = res1.getLowerBound().compareTo( res2.getLowerBound() ); + if ( comparison < 0 ) + { + lower = res2.getLowerBound(); + lowerInclusive = res2.isLowerBoundInclusive(); + } + else if ( comparison == 0 ) + { + lower = res1.getLowerBound(); + lowerInclusive = res1.isLowerBoundInclusive() && res2.isLowerBoundInclusive(); + } + else + { + lower = res1.getLowerBound(); + lowerInclusive = res1.isLowerBoundInclusive(); + } + } + + if ( res1.getUpperBound() == null ) + { + upper = res2.getUpperBound(); + upperInclusive = res2.isUpperBoundInclusive(); + } + else if ( res2.getUpperBound() == null ) + { + upper = res1.getUpperBound(); + upperInclusive = res1.isUpperBoundInclusive(); + } + else + { + int comparison = res1.getUpperBound().compareTo( res2.getUpperBound() ); + if ( comparison < 0 ) + { + upper = res1.getUpperBound(); + upperInclusive = res1.isUpperBoundInclusive(); + } + else if ( comparison == 0 ) + { + upper = res1.getUpperBound(); + upperInclusive = res1.isUpperBoundInclusive() && res2.isUpperBoundInclusive(); + } + else + { + upper = res2.getUpperBound(); + upperInclusive = res2.isUpperBoundInclusive(); + } + } + + // don't add if they are equal and one is not inclusive + if ( lower == null || upper == null || lower.compareTo( upper ) != 0 ) + { + restrictions.add( new Restriction( lower, lowerInclusive, upper, upperInclusive ) ); + } + else if ( lowerInclusive && upperInclusive ) + { + restrictions.add( new Restriction( lower, lowerInclusive, upper, upperInclusive ) ); + } + + //noinspection ObjectEquality + if ( upper == res2.getUpperBound() ) + { + // advance res2 + if ( i2.hasNext() ) + { + res2 = i2.next(); + } + else + { + done = true; + } + } + else + { + // advance res1 + if ( i1.hasNext() ) + { + res1 = i1.next(); + } + else + { + done = true; + } + } + } + else + { + // move on to next in r1 + if ( i1.hasNext() ) + { + res1 = i1.next(); + } + else + { + done = true; + } + } + } + else + { + // move on to next in r2 + if ( i2.hasNext() ) + { + res2 = i2.next(); + } + else + { + done = true; + } + } + } + + return restrictions; + } + + @Override + public String toString() + { + if ( recommendedVersion != null ) + { + return recommendedVersion.getVersionString(); + } + else + { + return restrictions.stream().map(Restriction::toString).collect(Collectors.joining(",")); + } + } + + public ArtifactVersion matchVersion( List versions ) + { + // TODO: could be more efficient by sorting the list and then moving along the restrictions in order? + + ArtifactVersion matched = null; + for ( ArtifactVersion version : versions ) + { + if ( containsVersion( version ) ) + { + // valid - check if it is greater than the currently matched version + if ( matched == null || version.compareTo( matched ) > 0 ) + { + matched = version; + } + } + } + return matched; + } + + public boolean containsVersion( ArtifactVersion version ) + { + for ( Restriction restriction : restrictions ) + { + if ( restriction.containsVersion( version ) ) + { + return true; + } + } + return false; + } + + public boolean hasRestrictions() + { + return !restrictions.isEmpty() && recommendedVersion == null; + } + + @Override + public boolean equals( Object obj ) + { + if ( this == obj ) + { + return true; + } + if ( !( obj instanceof VersionRange ) ) + { + return false; + } + VersionRange other = (VersionRange) obj; + + boolean equals = + recommendedVersion == other.recommendedVersion + || ( ( recommendedVersion != null ) && recommendedVersion.equals( other.recommendedVersion ) ); + equals &= + restrictions == other.restrictions + || ( ( restrictions != null ) && restrictions.equals( other.restrictions ) ); + return equals; + } + + @Override + public int hashCode() + { + int hash = 7; + hash = 31 * hash + ( recommendedVersion == null ? 0 : recommendedVersion.hashCode() ); + hash = 31 * hash + ( restrictions == null ? 0 : restrictions.hashCode() ); + return hash; + } + + public boolean isUnboundedAbove() + { + return restrictions.size() == 1 && restrictions.get(0).getUpperBound() == null && !restrictions.get(0).isUpperBoundInclusive(); + } + + public String getLowerBoundString() + { + return restrictions.size() == 1 ? restrictions.get(0).getLowerBound().getVersionString() : ""; + } + +} \ No newline at end of file diff --git a/src/main/resources/assets/crt/DSTRootCAX3.pem b/src/main/resources/assets/crt/DSTRootCAX3.pem new file mode 100644 index 0000000..b2e43c9 --- /dev/null +++ b/src/main/resources/assets/crt/DSTRootCAX3.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow +PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD +Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O +rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq +OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b +xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw +7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD +aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG +SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 +ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr +AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz +R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 +JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo +Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- diff --git a/src/main/resources/assets/lang/en_US.lang b/src/main/resources/assets/lang/en_US.lang new file mode 100644 index 0000000..7a3630d --- /dev/null +++ b/src/main/resources/assets/lang/en_US.lang @@ -0,0 +1,15 @@ +stage.start=Bootstrap for UltraMine Core 1.7.10 +stage.versions=Retrieving versions +stage.downloading=Checking & downloading dependencies +stage.scripts=Creating scripts +stage.finished=Bootstrap finished. Run ./start.sh (or start.bat) to run ultramine server + +error.mavenmetadata=Failed to retriever maven metadata from %s +error.pom=Failed to retriever pom xml from %s +error.addrepo.file=Failed to add repository: path is corrupted: %s +error.unavailable.host=Failed to resolve hostname (%s); check your network connection +error.unavailable.maven=Maven server (%s) is currently unavailable; check your network connection +error.download.dependency=Failed to download dependency: %s (%s) +error.write.file=Error write file %s: %s + +hint.stacktrace=Run with --stacktrace for more information diff --git a/src/main/resources/assets/lang/ru_RU.lang b/src/main/resources/assets/lang/ru_RU.lang new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/main/resources/assets/lang/ru_RU.lang diff --git a/src/main/resources/assets/script/java_command_line.txt b/src/main/resources/assets/script/java_command_line.txt new file mode 100644 index 0000000..ced75b2 --- /dev/null +++ b/src/main/resources/assets/script/java_command_line.txt @@ -0,0 +1,16 @@ +# Use start.sh to start minecraft server, don't use this file + +java \ +-Xms{xms} \ +-Xmx{xmx} \ +-Xmn{xmn} \ +-XX:+UseParallelGC \ +-XX:+UseTLAB \ +-XX:+AggressiveOpts \ +-XX:+UseFastEmptyMethods \ +-XX:+UseFastAccessorMethods \ +-Dfile.encoding=utf8 \ +-Dorg.ultramine.terminal={terminal} \ +-Dorg.ultramine.dirs.vanilla={vanilla_dir} \ +-Dorg.ultramine.dirs.worlds={worlds_dir} \ +-cp "{classpath}" cpw.mods.fml.relauncher.ServerLaunchWrapper \ No newline at end of file diff --git a/src/main/resources/assets/script/shell/start.sh b/src/main/resources/assets/script/shell/start.sh new file mode 100644 index 0000000..e4f222a --- /dev/null +++ b/src/main/resources/assets/script/shell/start.sh @@ -0,0 +1,7 @@ +#!/bin/bash +while : +do + ./ultramine_server_run_line.sh + echo "waiting before restarting" + sleep 10 +done \ No newline at end of file diff --git a/src/main/resources/assets/script/windows/start.bat b/src/main/resources/assets/script/windows/start.bat new file mode 100644 index 0000000..3bd412c --- /dev/null +++ b/src/main/resources/assets/script/windows/start.bat @@ -0,0 +1,5 @@ +:loop +ultramine_server_run_line.bat +echo waiting before restarting +timeout 10 +goto loop \ No newline at end of file diff --git a/src/main/resources/assets/server.properties b/src/main/resources/assets/server.properties new file mode 100644 index 0000000..181cad3 --- /dev/null +++ b/src/main/resources/assets/server.properties @@ -0,0 +1,34 @@ +#Minecraft server properties +#http://server.properties/owner.html +generator-settings= +op-permission-level=4 +allow-nether=true +level-name=world +enable-query=false +query-port=25565 +allow-flight=false +announce-player-achievements=true +server-port=25565 +level-type=DEFAULT +enable-rcon=false +rcon-port=25565 +level-seed= +force-gamemode=false +server-ip= +max-build-height=256 +spawn-npcs=true +white-list=false +spawn-animals=true +snooper-enabled=true +online-mode=true +resource-pack= +pvp=true +difficulty=1 +enable-command-block=false +gamemode=0 +player-idle-timeout=0 +max-players=20 +spawn-monsters=true +generate-structures=true +view-distance=10 +motd=A Minecraft Server \ No newline at end of file diff --git a/src/main/resources/assets/server.yml b/src/main/resources/assets/server.yml new file mode 100644 index 0000000..11d34d1 --- /dev/null +++ b/src/main/resources/assets/server.yml @@ -0,0 +1,72 @@ +listen: + minecraft: + serverIP: '{server-ip}' + port: {server-port} + query: + enabled: {enable-query} + port: {query-port} + rcon: + enabled: {enable-rcon} + port: {rcon-port} + password: '' + whitelist: null +settings: + authorization: + onlineMode: {online-mode} + player: + playerIdleTimeout: {player-idle-timeout} + gamemode: 0 + maxPlayers: {max-players} + forceGamemode: false + whiteList: {white-list} + other: + snooperEnabled: {snooper-enabled} + hardcore: false + resourcePack: '' + enableCommandBlock: {enable-command-block} + splitWorldDirs: {split-world-dirs} + recipeCacheEnabled: true + spawnLocations: + firstSpawn: spawn + deathSpawn: spawn + respawnOnBed: true + teleportation: + cooldown: 60 + delay: 5 + interWorldHome: true + interWorldWarp: true + messages: + announcePlayerAchievements: {announce-player-achievements} + motd: {motd} + watchdogThread: + timeout: 120 + restart: true + inSQLServerStorage: + enabled: false + database: global + tablePrefix: mc_ + security: + allowFlight: false + checkBreakSpeed: true +tools: + autobroadcast: + enabled: false + intervalSeconds: 600 + messages: [] + showAllMessages: false + autoDebugInfo: + enabled: false + intervalSeconds: 600 + autobackup: + enabled: false + interval: 60 + maxBackups: 10 + maxDirSize: 50000 + worlds: null + notifyPlayers: true + warpProtection: [] + economy: + startBalance: 30.0 +databases: {} +vanilla: + unresolved: {}