Search in sources :

Example 1 with ClassDiscoveryCache

use of com.laytonsmith.PureUtilities.ClassLoading.ClassDiscoveryCache in project CommandHelper by EngineHub.

the class ExtensionManager method Cache.

public static void Cache(File extCache, Class... extraClasses) {
    // We will only cache on Windows, as Linux doesn't natively lock
    // files that are in use. Windows prevents any modification, making
    // it harder for server owners on Windows to update the jars.
    boolean onWindows = (OSUtils.GetOS() == OSUtils.OS.WINDOWS);
    if (!onWindows) {
        return;
    }
    // Create the directory if it doesn't exist.
    extCache.mkdirs();
    // cleanup wasn't successful on the last run.
    for (File f : extCache.listFiles()) {
        try {
            Files.delete(f.toPath());
        } catch (IOException ex) {
            Static.getLogger().log(Level.WARNING, "[CommandHelper] Could not delete loose file " + f.getAbsolutePath() + ": " + ex.getMessage());
        }
    }
    // The cache, cd and dcl here will just be thrown away.
    // They are only used here for the purposes of discovering what a given
    // jar has to offer.
    ClassDiscoveryCache cache = new ClassDiscoveryCache(CommandHelperFileLocations.getDefault().getCacheDirectory());
    cache.setLogger(Static.getLogger());
    DynamicClassLoader dcl = new DynamicClassLoader();
    ClassDiscovery cd = new ClassDiscovery();
    cd.setClassDiscoveryCache(cache);
    cd.addDiscoveryLocation(ClassDiscovery.GetClassContainer(ExtensionManager.class));
    for (Class klazz : extraClasses) {
        cd.addDiscoveryLocation(ClassDiscovery.GetClassContainer(klazz));
    }
    // Look in the given locations for jars, add them to our class discovery.
    List<File> toProcess = new ArrayList<>();
    for (File location : locations) {
        toProcess.addAll(getFiles(location));
    }
    // Load the files into the discovery mechanism.
    for (File file : toProcess) {
        if (!file.canRead()) {
            continue;
        }
        URL jar;
        try {
            jar = file.toURI().toURL();
        } catch (MalformedURLException ex) {
            Static.getLogger().log(Level.SEVERE, null, ex);
            continue;
        }
        dcl.addJar(jar);
        cd.addDiscoveryLocation(jar);
    }
    cd.setDefaultClassLoader(dcl);
    // Loop thru the found lifecycles, copy them to the cache using the name
    // given in the lifecycle. If more than one jar has the same internal
    // name, the filename will be given a number.
    Set<File> done = new HashSet<>();
    Map<String, Integer> namecount = new HashMap<>();
    // use their internal name.
    for (ClassMirror<? extends AbstractExtension> extmirror : cd.getClassesWithAnnotationThatExtend(MSExtension.class, AbstractExtension.class)) {
        if (extmirror.equals(new ClassMirror<>(AbstractExtension.class))) {
            continue;
        }
        AnnotationMirror plug = extmirror.getAnnotation(MSExtension.class);
        URL plugURL = extmirror.getContainer();
        // Get the internal name that this extension exposes.
        if (plugURL != null && plugURL.getPath().endsWith(".jar")) {
            File f;
            try {
                f = new File(URLDecoder.decode(plugURL.getFile(), "UTF8"));
            } catch (UnsupportedEncodingException ex) {
                Logger.getLogger(ExtensionManager.class.getName()).log(Level.SEVERE, null, ex);
                continue;
            }
            // Skip extensions that originate from commandhelpercore.
            if (plugURL.equals(ClassDiscovery.GetClassContainer(ExtensionManager.class))) {
                done.add(f);
                continue;
            }
            // Skip files already processed.
            if (done.contains(f)) {
                CHLog.GetLogger().Log(CHLog.Tags.EXTENSIONS, LogLevel.WARNING, f.getAbsolutePath() + " contains more than one extension" + " descriptor. Bug someone about it!", Target.UNKNOWN);
                continue;
            }
            done.add(f);
            String name = plug.getValue("value").toString();
            // lets track and rename them using a number scheme.
            if (namecount.containsKey(name.toLowerCase())) {
                int i = namecount.get(name.toLowerCase());
                name += "-" + i;
                namecount.put(name.toLowerCase(), i++);
                CHLog.GetLogger().Log(CHLog.Tags.EXTENSIONS, LogLevel.WARNING, f.getAbsolutePath() + " contains a duplicate internally" + " named extension (" + name + "). Bug someone" + " about it!", Target.UNKNOWN);
            } else {
                namecount.put(name.toLowerCase(), 1);
            }
            // Rename the jar to use the plugin's internal name and
            // copy it into the cache.
            File newFile = new File(extCache, name.toLowerCase() + ".jar");
            try {
                Files.copy(f.toPath(), newFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
            } catch (IOException ex) {
                Static.getLogger().log(Level.SEVERE, "Could not copy '" + f.getName() + "' to cache: " + ex.getMessage());
            }
        }
    }
    Set<ClassMirror<?>> classes = cd.getClassesWithAnnotation(api.class);
    // Now process @api annotated extensions, ignoring ones already processed.
    for (ClassMirror klass : classes) {
        URL plugURL = klass.getContainer();
        if (plugURL != null && plugURL.getPath().endsWith(".jar")) {
            File f;
            try {
                f = new File(URLDecoder.decode(plugURL.getFile(), "UTF8"));
            } catch (UnsupportedEncodingException ex) {
                Logger.getLogger(ExtensionManager.class.getName()).log(Level.SEVERE, null, ex);
                continue;
            }
            // Skip files already processed.
            if (done.contains(f)) {
                continue;
            }
            // No special processing needed.
            if (cd.doesClassExtend(klass, Event.class) || cd.doesClassExtend(klass, Function.class)) {
                // We're processing it here instead of above, complain about it.
                CHLog.GetLogger().Log(CHLog.Tags.EXTENSIONS, LogLevel.WARNING, f.getAbsolutePath() + " is an old-style extension!" + " Bug the author to update it to the new extension system!", Target.UNKNOWN);
                // Only process this file once.
                done.add(f);
                File newFile = new File(extCache, "oldstyle-" + f.getName());
                try {
                    Files.copy(f.toPath(), newFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
                } catch (IOException ex) {
                    Static.getLogger().log(Level.SEVERE, "Could not copy '" + f.getName() + "' to cache: " + ex.getMessage());
                }
            }
        }
    }
    // Shut down the original dcl to "unlock" the processed jars.
    // The cache and cd instances will just fall into oblivion.
    dcl.destroy();
    // Explicit call. Without this, jar files won't actually get unlocked on
    // Windows. Of course, this is hit and miss, but that's fine; we tried.
    System.gc();
}
Also used : DynamicClassLoader(com.laytonsmith.PureUtilities.ClassLoading.DynamicClassLoader) MalformedURLException(java.net.MalformedURLException) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) ClassMirror(com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.ClassMirror) URL(java.net.URL) CFunction(com.laytonsmith.core.constructs.CFunction) Function(com.laytonsmith.core.functions.Function) HashSet(java.util.HashSet) UnsupportedEncodingException(java.io.UnsupportedEncodingException) IOException(java.io.IOException) ClassDiscovery(com.laytonsmith.PureUtilities.ClassLoading.ClassDiscovery) AnnotationMirror(com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.AnnotationMirror) Event(com.laytonsmith.core.events.Event) File(java.io.File) ClassDiscoveryCache(com.laytonsmith.PureUtilities.ClassLoading.ClassDiscoveryCache)

Example 2 with ClassDiscoveryCache

use of com.laytonsmith.PureUtilities.ClassLoading.ClassDiscoveryCache in project CommandHelper by EngineHub.

the class CommandHelperPlugin method onLoad.

@Override
public void onLoad() {
    Implementation.setServerType(Implementation.Type.BUKKIT);
    CommandHelperFileLocations.setDefault(new CommandHelperFileLocations());
    CommandHelperFileLocations.getDefault().getCacheDirectory().mkdirs();
    CommandHelperFileLocations.getDefault().getPreferencesDirectory().mkdirs();
    UpgradeLog upgradeLog = new UpgradeLog(CommandHelperFileLocations.getDefault().getUpgradeLogFile());
    upgradeLog.addUpgradeTask(new UpgradeLog.UpgradeTask() {

        String version = null;

        @Override
        public boolean doRun() {
            try {
                version = "versionUpgrade-" + Main.loadSelfVersion();
                return !hasBreadcrumb(version);
            } catch (Exception ex) {
                Logger.getLogger(CommandHelperPlugin.class.getName()).log(Level.SEVERE, null, ex);
                return false;
            }
        }

        @Override
        public void run() {
            leaveBreadcrumb(version);
        }
    });
    upgradeLog.addUpgradeTask(new UpgradeLog.UpgradeTask() {

        File oldPreferences = new File(CommandHelperFileLocations.getDefault().getConfigDirectory(), "preferences.txt");

        @Override
        public boolean doRun() {
            return oldPreferences.exists() && !CommandHelperFileLocations.getDefault().getPreferencesFile().exists();
        }

        @Override
        public void run() {
            try {
                Prefs.init(oldPreferences);
                Prefs.SetColors();
                Logger.getLogger("Minecraft").log(Level.INFO, TermColors.YELLOW + "[" + Implementation.GetServerType().getBranding() + "] Old preferences.txt file detected. Moving preferences.txt to preferences.ini." + TermColors.reset());
                FileUtil.copy(oldPreferences, CommandHelperFileLocations.getDefault().getPreferencesFile(), true);
                oldPreferences.deleteOnExit();
            } catch (IOException ex) {
                Logger.getLogger(CommandHelperPlugin.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    });
    upgradeLog.addUpgradeTask(new UpgradeLog.UpgradeTask() {

        File cd = CommandHelperFileLocations.getDefault().getConfigDirectory();

        private final String breadcrumb = "move-preference-files-v1.0";

        @Override
        public boolean doRun() {
            return !hasBreadcrumb(breadcrumb) && new File(cd, "preferences.ini").exists();
        }

        @Override
        public void run() {
            // We need to move the following files:
            // 1. persistance.config to prefs/persistence.ini (note the correct spelling)
            // 2. preferences.ini to prefs/preferences.ini
            // 3. profiler.config to prefs/profiler.ini
            // 4. sql-profiles.xml to prefs/sql-profiles.xml
            // 5. We are not moving loggerPreferences.txt, instead just deleting it,
            // because the defaults have changed. Most people aren't using this feature
            // anyways. (The new one will write itself out upon installation.)
            // Other than the config/prefs directory, we are hardcoding all the values, so
            // we know they are correct (for old values). Any errors will be reported, but will not
            // stop the entire process.
            CommandHelperFileLocations p = CommandHelperFileLocations.getDefault();
            try {
                FileUtil.move(new File(cd, "persistance.config"), p.getPersistenceConfig());
            } catch (IOException ex) {
                Logger.getLogger(CommandHelperPlugin.class.getName()).log(Level.SEVERE, null, ex);
            }
            try {
                FileUtil.move(new File(cd, "preferences.ini"), p.getPreferencesFile());
            } catch (IOException ex) {
                Logger.getLogger(CommandHelperPlugin.class.getName()).log(Level.SEVERE, null, ex);
            }
            try {
                FileUtil.move(new File(cd, "profiler.config"), p.getProfilerConfigFile());
            } catch (IOException ex) {
                Logger.getLogger(CommandHelperPlugin.class.getName()).log(Level.SEVERE, null, ex);
            }
            try {
                FileUtil.move(new File(cd, "sql-profiles.xml"), p.getProfilesFile());
            } catch (IOException ex) {
                Logger.getLogger(CommandHelperPlugin.class.getName()).log(Level.SEVERE, null, ex);
            }
            new File(cd, "logs/debug/loggerPreferences.txt").delete();
            leaveBreadcrumb(breadcrumb);
            StreamUtils.GetSystemOut().println("CommandHelper: Your preferences files have all been relocated to " + p.getPreferencesDirectory());
            StreamUtils.GetSystemOut().println("CommandHelper: The loggerPreferences.txt file has been deleted and re-created, as the defaults have changed.");
        }
    });
    // Renames the sql-profiles.xml file to the new name.
    upgradeLog.addUpgradeTask(new UpgradeLog.UpgradeTask() {

        // This should never change
        private final File oldProfilesFile = new File(MethodScriptFileLocations.getDefault().getPreferencesDirectory(), "sql-profiles.xml");

        @Override
        public boolean doRun() {
            return oldProfilesFile.exists();
        }

        @Override
        public void run() {
            try {
                FileUtil.move(oldProfilesFile, MethodScriptFileLocations.getDefault().getProfilesFile());
                StreamUtils.GetSystemOut().println("CommandHelper: sql-profiles.xml has been renamed to " + MethodScriptFileLocations.getDefault().getProfilesFile().getName());
            } catch (IOException ex) {
                Logger.getLogger(CommandHelperPlugin.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    });
    try {
        upgradeLog.runTasks();
    } catch (IOException ex) {
        Logger.getLogger(CommandHelperPlugin.class.getName()).log(Level.SEVERE, null, ex);
    }
    try {
        Prefs.init(CommandHelperFileLocations.getDefault().getPreferencesFile());
    } catch (IOException ex) {
        Logger.getLogger(CommandHelperPlugin.class.getName()).log(Level.SEVERE, null, ex);
    }
    Prefs.SetColors();
    CHLog.initialize(CommandHelperFileLocations.getDefault().getConfigDirectory());
    Installer.Install(CommandHelperFileLocations.getDefault().getConfigDirectory());
    if (new SimpleVersion(System.getProperty("java.version")).lt(new SimpleVersion("1.8"))) {
        CHLog.GetLogger().w(CHLog.Tags.GENERAL, "You appear to be running a version of Java older than Java 8. You should have plans" + " to upgrade at some point, as " + Implementation.GetServerType().getBranding() + " may require it at some point.", Target.UNKNOWN);
    }
    self = this;
    ClassDiscoveryCache cdc = new ClassDiscoveryCache(CommandHelperFileLocations.getDefault().getCacheDirectory());
    cdc.setLogger(Logger.getLogger(CommandHelperPlugin.class.getName()));
    ClassDiscovery.getDefaultInstance().setClassDiscoveryCache(cdc);
    ClassDiscovery.getDefaultInstance().addDiscoveryLocation(ClassDiscovery.GetClassContainer(CommandHelperPlugin.class));
    StreamUtils.GetSystemOut().println("[CommandHelper] Running initial class discovery," + " this will probably take a few seconds...");
    StreamUtils.GetSystemOut().println("[CommandHelper] Loading extensions in the background...");
    loadingThread = new Thread("extensionloader") {

        @Override
        public void run() {
            ExtensionManager.AddDiscoveryLocation(CommandHelperFileLocations.getDefault().getExtensionsDirectory());
            if (OSUtils.GetOS() == OSUtils.OS.WINDOWS) {
                // Using StreamUtils.GetSystemOut() here instead of the logger as the logger doesn't
                // immediately print to the console.
                StreamUtils.GetSystemOut().println("[CommandHelper] Caching extensions...");
                ExtensionManager.Cache(CommandHelperFileLocations.getDefault().getExtensionCacheDirectory());
                StreamUtils.GetSystemOut().println("[CommandHelper] Extension caching complete.");
            }
            ExtensionManager.Initialize(ClassDiscovery.getDefaultInstance());
            StreamUtils.GetSystemOut().println("[CommandHelper] Extension loading complete.");
        }
    };
    loadingThread.start();
}
Also used : UpgradeLog(com.laytonsmith.core.UpgradeLog) SimpleVersion(com.laytonsmith.PureUtilities.SimpleVersion) IOException(java.io.IOException) File(java.io.File) InvocationTargetException(java.lang.reflect.InvocationTargetException) EventException(org.bukkit.event.EventException) IOException(java.io.IOException) ClassDiscoveryCache(com.laytonsmith.PureUtilities.ClassLoading.ClassDiscoveryCache)

Example 3 with ClassDiscoveryCache

use of com.laytonsmith.PureUtilities.ClassLoading.ClassDiscoveryCache in project CommandHelper by EngineHub.

the class ExtensionDocGen method generate.

public static void generate(File inputExtension, OutputStream outputStream) throws InstantiationException, IllegalAccessException, MalformedURLException, IOException {
    ClassDiscovery customDiscovery = new ClassDiscovery();
    ClassDiscoveryCache cache = new ClassDiscoveryCache(CommandHelperFileLocations.getDefault().getCacheDirectory());
    customDiscovery.setClassDiscoveryCache(cache);
    URL url = new URL("jar:" + inputExtension.toURI().toURL() + "!/");
    customDiscovery.addDiscoveryLocation(url);
    customDiscovery.setDefaultClassLoader(ExtensionDocGen.class.getClassLoader());
    StringBuilder fdocs = new StringBuilder();
    DynamicClassLoader classloader = new DynamicClassLoader();
    classloader.addJar(url);
    // functions
    HashMap<Class<?>, ArrayList<Class<? extends Function>>> functionMap = new HashMap<>();
    for (Class<? extends Function> cf : customDiscovery.loadClassesWithAnnotationThatExtend(api.class, Function.class, classloader, true)) {
        Class enclosing = cf.getEnclosingClass();
        if (functionMap.containsKey(enclosing)) {
            functionMap.get(enclosing).add(cf);
        } else {
            functionMap.put(enclosing, new ArrayList<Class<? extends Function>>());
            functionMap.get(enclosing).add(cf);
        }
    }
    ArrayList<Entry<Class<?>, ArrayList<Class<? extends Function>>>> functionEntryList = new ArrayList<>(functionMap.entrySet());
    Collections.sort(functionEntryList, new Comparator<Entry<Class<?>, ArrayList<Class<? extends Function>>>>() {

        @Override
        public int compare(Entry<Class<?>, ArrayList<Class<? extends Function>>> o1, Entry<Class<?>, ArrayList<Class<? extends Function>>> o2) {
            return o1.getKey().getName().compareTo(o2.getKey().getName());
        }
    });
    for (Entry<Class<?>, ArrayList<Class<? extends Function>>> e : functionEntryList) {
        Collections.sort(e.getValue(), new Comparator<Class<? extends Function>>() {

            @Override
            public int compare(Class<? extends Function> o1, Class<? extends Function> o2) {
                return o1.getName().compareTo(o2.getName());
            }
        });
    }
    if (!functionEntryList.isEmpty()) {
        fdocs.append("# Functions").append(nl);
    }
    for (Entry<Class<?>, ArrayList<Class<? extends Function>>> entry : functionEntryList) {
        Class enclosingClass = entry.getKey();
        String[] split = enclosingClass.getName().split("\\.");
        fdocs.append("## ").append(split[split.length - 1]).append(nl);
        try {
            Method docsMethod = enclosingClass.getMethod("docs", (Class[]) null);
            Object o = enclosingClass.newInstance();
            fdocs.append((String) docsMethod.invoke(o, (Object[]) null)).append(nl).append(nl);
        } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException exception) {
        }
        for (Class<? extends Function> cf : entry.getValue()) {
            Function f = cf.newInstance();
            if (f.appearInDocumentation()) {
                DocGen.DocInfo di = new DocGen.DocInfo(f.docs());
                String d = "### " + markdownEscape(di.ret) + " " + markdownEscape(f.getName()) + "(" + markdownEscape(di.originalArgs) + "):" + nl + convertWiki(di.topDesc != null ? di.topDesc : di.desc) + nl + convertWiki(di.extendedDesc != null ? nl + di.extendedDesc + nl : "");
                fdocs.append(d).append(nl);
            }
        }
    }
    // events
    HashMap<Class<?>, ArrayList<Class<? extends Event>>> eventMap = new HashMap<>();
    for (Class<? extends Event> ce : customDiscovery.loadClassesWithAnnotationThatExtend(api.class, Event.class, classloader, true)) {
        Class<?> enclosing = ce.getEnclosingClass();
        if (eventMap.containsKey(enclosing)) {
            eventMap.get(enclosing).add(ce);
        } else {
            eventMap.put(enclosing, new ArrayList<Class<? extends Event>>());
            eventMap.get(enclosing).add(ce);
        }
    }
    ArrayList<Entry<Class<?>, ArrayList<Class<? extends Event>>>> eventEntryList = new ArrayList<>(eventMap.entrySet());
    Collections.sort(eventEntryList, new Comparator<Entry<Class<?>, ArrayList<Class<? extends Event>>>>() {

        @Override
        public int compare(Entry<Class<?>, ArrayList<Class<? extends Event>>> o1, Entry<Class<?>, ArrayList<Class<? extends Event>>> o2) {
            return o1.getKey().getName().compareTo(o2.getKey().getName());
        }
    });
    for (Entry<Class<?>, ArrayList<Class<? extends Event>>> e : eventEntryList) {
        Collections.sort(e.getValue(), new Comparator<Class<? extends Event>>() {

            @Override
            public int compare(Class<? extends Event> o1, Class<? extends Event> o2) {
                return o1.getName().compareTo(o2.getName());
            }
        });
    }
    if (!eventEntryList.isEmpty()) {
        fdocs.append("# Events").append(nl);
    }
    for (Entry<Class<?>, ArrayList<Class<? extends Event>>> entry : eventEntryList) {
        Class enclosingClass = entry.getKey();
        String[] split = enclosingClass.getName().split("\\.");
        fdocs.append("## ").append(split[split.length - 1]).append(nl);
        try {
            Method docsMethod = enclosingClass.getMethod("docs", (Class[]) null);
            Object o = enclosingClass.newInstance();
            fdocs.append((String) docsMethod.invoke(o, (Object[]) null)).append(nl).append(nl);
        } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException exception) {
        }
        for (Class<? extends Event> ce : entry.getValue()) {
            Event e = ce.newInstance();
            Pattern p = Pattern.compile("\\{(.*?)\\} *?(.*?) *?\\{(.*?)\\} *?\\{(.*?)\\}");
            Matcher m = p.matcher(e.docs());
            if (m.find()) {
                String name = e.getName();
                String description = m.group(2).trim();
                String prefilter = DocGen.PrefilterData.Get(m.group(1).split("\\|"), DocGen.MarkupType.MARKDOWN);
                String eventData = DocGen.EventData.Get(m.group(3).split("\\|"), DocGen.MarkupType.MARKDOWN);
                String mutability = DocGen.MutabilityData.Get(m.group(4).split("\\|"), DocGen.MarkupType.MARKDOWN);
                // String manualTrigger = ManualTriggerData.Get(m.group(5).split("\\|"), DocGen.MarkupType.MARKDOWN);
                // String since = e.since().toString();
                fdocs.append("### ").append(markdownEscape(name)).append(nl);
                fdocs.append(description).append(nl);
                fdocs.append("#### Prefilters").append(nl).append(prefilter).append(nl);
                fdocs.append("#### Event Data").append(nl).append(eventData).append(nl);
                fdocs.append("#### Mutable Fields").append(nl).append(mutability).append(nl);
            }
        }
    }
    outputStream.write(fdocs.toString().getBytes("UTF-8"));
}
Also used : DynamicClassLoader(com.laytonsmith.PureUtilities.ClassLoading.DynamicClassLoader) HashMap(java.util.HashMap) Matcher(java.util.regex.Matcher) ArrayList(java.util.ArrayList) URL(java.net.URL) Function(com.laytonsmith.core.functions.Function) Entry(java.util.Map.Entry) Pattern(java.util.regex.Pattern) Method(java.lang.reflect.Method) ClassDiscovery(com.laytonsmith.PureUtilities.ClassLoading.ClassDiscovery) InvocationTargetException(java.lang.reflect.InvocationTargetException) Event(com.laytonsmith.core.events.Event) ClassDiscoveryCache(com.laytonsmith.PureUtilities.ClassLoading.ClassDiscoveryCache)

Example 4 with ClassDiscoveryCache

use of com.laytonsmith.PureUtilities.ClassLoading.ClassDiscoveryCache in project CommandHelper by EngineHub.

the class Main method main.

@SuppressWarnings("ResultOfObjectAllocationIgnored")
public static void main(String[] args) throws Exception {
    try {
        Implementation.setServerType(Implementation.Type.SHELL);
        CHLog.initialize(MethodScriptFileLocations.getDefault().getJarDirectory());
        Prefs.init(MethodScriptFileLocations.getDefault().getPreferencesFile());
        Prefs.SetColors();
        if (Prefs.UseColors()) {
            // Use jansi to enable output to color properly, even on windows.
            org.fusesource.jansi.AnsiConsole.systemInstall();
        }
        ClassDiscovery cd = ClassDiscovery.getDefaultInstance();
        cd.addDiscoveryLocation(ClassDiscovery.GetClassContainer(Main.class));
        ClassDiscoveryCache cdcCache = new ClassDiscoveryCache(MethodScriptFileLocations.getDefault().getCacheDirectory());
        cd.setClassDiscoveryCache(cdcCache);
        cd.addAllJarsInFolder(MethodScriptFileLocations.getDefault().getExtensionsDirectory());
        ExtensionManager.AddDiscoveryLocation(MethodScriptFileLocations.getDefault().getExtensionsDirectory());
        ExtensionManager.Cache(MethodScriptFileLocations.getDefault().getExtensionCacheDirectory());
        ExtensionManager.Initialize(cd);
        ExtensionManager.Startup();
        if (args.length == 0) {
            args = new String[] { "--help" };
        }
        // I'm not sure why this is in Main, but if this breaks something, it needs to be put back.
        // However, if it is put back, then it needs to be figured out why this causes the terminal
        // to lose focus on mac.
        // AnnotationChecks.checkForceImplementation();
        ArgumentParser mode;
        ArgumentParser.ArgumentParserResults parsedArgs;
        try {
            ArgumentSuite.ArgumentSuiteResults results = ARGUMENT_SUITE.match(args, "help");
            mode = results.getMode();
            parsedArgs = results.getResults();
        } catch (ArgumentParser.ResultUseException | ArgumentParser.ValidationException e) {
            StreamUtils.GetSystemOut().println(TermColors.RED + e.getMessage() + TermColors.RESET);
            mode = helpMode;
            parsedArgs = null;
        }
        if (mode == helpMode) {
            String modeForHelp = null;
            if (parsedArgs != null) {
                modeForHelp = parsedArgs.getStringArgument();
            }
            modeForHelp = ARGUMENT_SUITE.getModeFromAlias(modeForHelp);
            if (modeForHelp == null) {
                // Display the general help
                StreamUtils.GetSystemOut().println(ARGUMENT_SUITE.getBuiltDescription());
                System.exit(0);
                return;
            } else {
                // Display the help for this mode
                StreamUtils.GetSystemOut().println(ARGUMENT_SUITE.getModeFromName(modeForHelp).getBuiltDescription());
                return;
            }
        }
        // if it were, the help command would have run.
        assert parsedArgs != null;
        if (mode == managerMode) {
            Manager.start();
            System.exit(0);
        } else if (mode == coreFunctionsMode) {
            List<String> core = new ArrayList<>();
            for (api.Platforms platform : api.Platforms.values()) {
                for (FunctionBase f : FunctionList.getFunctionList(platform)) {
                    if (f.isCore()) {
                        core.add(f.getName());
                    }
                }
            }
            Collections.sort(core);
            StreamUtils.GetSystemOut().println(StringUtils.Join(core, ", "));
            System.exit(0);
        } else if (mode == interpreterMode) {
            new Interpreter(parsedArgs.getStringListArgument(), parsedArgs.getStringArgument("location-----"));
            System.exit(0);
        } else if (mode == installCmdlineMode) {
            Interpreter.install();
            System.exit(0);
        } else if (mode == uninstallCmdlineMode) {
            Interpreter.uninstall();
            System.exit(0);
        } else if (mode == docgenMode) {
            DocGenUI.main(args);
            System.exit(0);
        } else if (mode == mslpMode) {
            String mslp = parsedArgs.getStringArgument();
            if (mslp.isEmpty()) {
                StreamUtils.GetSystemOut().println("Usage: --mslp path/to/folder");
                System.exit(0);
            }
            MSLPMaker.start(mslp);
            System.exit(0);
        } else if (mode == versionMode) {
            StreamUtils.GetSystemOut().println("You are running " + Implementation.GetServerType().getBranding() + " version " + loadSelfVersion());
            System.exit(0);
        } else if (mode == copyrightMode) {
            StreamUtils.GetSystemOut().println("The MIT License (MIT)\n" + "\n" + "Copyright (c) 2012-2017 Methodscript Contributors\n" + "\n" + "Permission is hereby granted, free of charge, to any person obtaining a copy of \n" + "this software and associated documentation files (the \"Software\"), to deal in \n" + "the Software without restriction, including without limitation the rights to \n" + "use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of \n" + "the Software, and to permit persons to whom the Software is furnished to do so, \n" + "subject to the following conditions:\n" + "\n" + "The above copyright notice and this permission notice shall be included in all \n" + "copies or substantial portions of the Software.\n" + "\n" + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR \n" + "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS \n" + "FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR \n" + "COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER \n" + "IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN \n" + "CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.");
            System.exit(0);
        } else if (mode == printDBMode) {
            ConnectionMixinFactory.ConnectionMixinOptions options = new ConnectionMixinFactory.ConnectionMixinOptions();
            options.setWorkingDirectory(MethodScriptFileLocations.getDefault().getConfigDirectory());
            PersistenceNetwork pn = new PersistenceNetwork(MethodScriptFileLocations.getDefault().getPersistenceConfig(), new URI("sqlite://" + MethodScriptFileLocations.getDefault().getDefaultPersistenceDBFile().getCanonicalPath().replace('\\', '/')), options);
            Map<String[], String> values = pn.getNamespace(new String[] {});
            for (String[] s : values.keySet()) {
                StreamUtils.GetSystemOut().println(StringUtils.Join(s, ".") + "=" + values.get(s));
            }
            System.exit(0);
        } else if (mode == docsMode) {
            DocGen.MarkupType docs;
            try {
                docs = DocGen.MarkupType.valueOf(parsedArgs.getStringArgument().toUpperCase());
            } catch (IllegalArgumentException e) {
                StreamUtils.GetSystemOut().println("The type of documentation must be one of the following: " + StringUtils.Join(DocGen.MarkupType.values(), ", ", ", or "));
                System.exit(1);
                return;
            }
            // Documentation generator
            StreamUtils.GetSystemErr().print("Creating " + docs + " documentation...");
            DocGen.functions(docs, api.Platforms.INTERPRETER_JAVA, true);
            StreamUtils.GetSystemErr().println("Done.");
            System.exit(0);
        } else if (mode == examplesMode) {
            ExampleLocalPackageInstaller.run(MethodScriptFileLocations.getDefault().getJarDirectory(), parsedArgs.getStringArgument());
        } else if (mode == verifyMode) {
            String file = parsedArgs.getStringArgument();
            if ("".equals(file)) {
                StreamUtils.GetSystemErr().println("File parameter is required.");
                System.exit(1);
            }
            File f = new File(file);
            String script = FileUtil.read(f);
            try {
                try {
                    MethodScriptCompiler.compile(MethodScriptCompiler.lex(script, f, file.endsWith("ms")));
                } catch (ConfigCompileException ex) {
                    Set<ConfigCompileException> s = new HashSet<>(1);
                    s.add(ex);
                    throw new ConfigCompileGroupException(s);
                }
            } catch (ConfigCompileGroupException ex) {
                List<Map<String, Object>> err = new ArrayList<>();
                for (ConfigCompileException e : ex.getList()) {
                    Map<String, Object> error = new HashMap<>();
                    error.put("msg", e.getMessage());
                    error.put("file", e.getFile().getAbsolutePath());
                    error.put("line", e.getLineNum());
                    error.put("col", e.getColumn());
                    // TODO: Need to track target length for this
                    error.put("len", 0);
                    err.add(error);
                }
                String serr = JSONValue.toJSONString(err);
                StreamUtils.GetSystemOut().println(serr);
            }
        } else if (mode == apiMode) {
            String function = parsedArgs.getStringArgument();
            if ("".equals(function)) {
                StreamUtils.GetSystemErr().println("Usage: java -jar CommandHelper.jar --api <function name>");
                System.exit(1);
            }
            FunctionBase f;
            try {
                f = FunctionList.getFunction(function, Target.UNKNOWN);
            } catch (ConfigCompileException e) {
                StreamUtils.GetSystemErr().println("The function '" + function + "' was not found.");
                System.exit(1);
                throw new Error();
            }
            DocGen.DocInfo di = new DocGen.DocInfo(f.docs());
            String ret = di.ret.replaceAll("</?[a-z].*?>", "");
            String args2 = di.args.replaceAll("</?[a-z].*?>", "");
            String desc = (di.desc + (di.extendedDesc != null ? "\n\n" + di.extendedDesc : "")).replaceAll("</?[a-z].*?>", "");
            StreamUtils.GetSystemOut().println(StringUtils.Join(new String[] { function, "Returns " + ret, "Expects " + args2, desc }, " // "));
            System.exit(0);
        } else if (mode == syntaxMode) {
            // TODO: Maybe load extensions here?
            List<String> syntax = parsedArgs.getStringListArgument();
            String type = (syntax.size() >= 1 ? syntax.get(0) : null);
            String theme = (syntax.size() >= 2 ? syntax.get(1) : null);
            StreamUtils.GetSystemOut().println(SyntaxHighlighters.generate(type, theme));
            System.exit(0);
        } else if (mode == optimizerTestMode) {
            String path = parsedArgs.getStringArgument();
            File source = new File(path);
            String plain = FileUtil.read(source);
            Security.setSecurityEnabled(false);
            String optimized;
            try {
                try {
                    optimized = OptimizationUtilities.optimize(plain, source);
                } catch (ConfigCompileException ex) {
                    Set<ConfigCompileException> group = new HashSet<>();
                    group.add(ex);
                    throw new ConfigCompileGroupException(group);
                }
            } catch (ConfigCompileGroupException ex) {
                ConfigRuntimeException.HandleUncaughtException(ex, null);
                System.exit(1);
                return;
            }
            StreamUtils.GetSystemOut().println(optimized);
            System.exit(0);
        } else if (mode == cmdlineMode) {
            // We actually can't use the parsedArgs, because there may be cmdline switches in
            // the arguments that we want to ignore here, but otherwise pass through. parsedArgs
            // will prevent us from seeing those, however.
            List<String> allArgs = new ArrayList<>(Arrays.asList(args));
            // The 0th arg is the cmdline verb though, so remove that.
            allArgs.remove(0);
            if (allArgs.isEmpty()) {
                StreamUtils.GetSystemErr().println("Usage: path/to/file.ms [arg1 arg2]");
                System.exit(1);
            }
            String fileName = allArgs.get(0);
            allArgs.remove(0);
            try {
                Interpreter.startWithTTY(fileName, allArgs);
            } catch (Profiles.InvalidProfileException ex) {
                StreamUtils.GetSystemErr().println("Invalid profile file at " + MethodScriptFileLocations.getDefault().getProfilesFile() + ": " + ex.getMessage());
                System.exit(1);
            }
            StaticLayer.GetConvertor().runShutdownHooks();
            System.exit(0);
        } else if (mode == extensionDocsMode) {
            String inputJarS = parsedArgs.getStringArgument("input-jar");
            String outputFileS = parsedArgs.getStringArgument("output-file");
            if (inputJarS == null) {
                StreamUtils.GetSystemOut().println("Usage: --input-jar extension-docs path/to/extension.jar [--output-file path/to/output.md]\n\tIf the output is blank, it is printed to stdout.");
                System.exit(1);
            }
            File inputJar = new File(inputJarS);
            OutputStream outputFile = StreamUtils.GetSystemOut();
            if (outputFileS != null) {
                outputFile = new FileOutputStream(new File(outputFileS));
            }
            ExtensionDocGen.generate(inputJar, outputFile);
        } else if (mode == docExportMode) {
            String extensionDirS = parsedArgs.getStringArgument("extension-dir");
            String outputFileS = parsedArgs.getStringArgument("output-file");
            OutputStream outputFile = StreamUtils.GetSystemOut();
            if (outputFileS != null) {
                outputFile = new FileOutputStream(new File(outputFileS));
            }
            Implementation.forceServerType(Implementation.Type.BUKKIT);
            File extensionDir = new File(extensionDirS);
            if (extensionDir.exists()) {
                // to stderr.
                for (File f : extensionDir.listFiles()) {
                    if (f.getName().endsWith(".jar")) {
                        cd.addDiscoveryLocation(f.toURI().toURL());
                    }
                }
            } else {
                StreamUtils.GetSystemErr().println("Extension directory specificed doesn't exist: " + extensionDirS + ". Continuing anyways.");
            }
            new DocGenExportTool(cd, outputFile).export();
        } else if (mode == profilerSummaryMode) {
            String input = parsedArgs.getStringArgument();
            if ("".equals(input)) {
                StreamUtils.GetSystemErr().println(TermColors.RED + "No input file specified! Run `help profiler-summary' for usage." + TermColors.RESET);
                System.exit(1);
            }
            double ignorePercentage = parsedArgs.getNumberArgument("ignore-percentage");
            ProfilerSummary summary = new ProfilerSummary(new FileInputStream(input));
            try {
                summary.setIgnorePercentage(ignorePercentage);
            } catch (IllegalArgumentException ex) {
                StreamUtils.GetSystemErr().println(TermColors.RED + ex.getMessage() + TermColors.RESET);
                System.exit(1);
            }
            StreamUtils.GetSystemOut().println(summary.getAnalysis());
            System.exit(0);
        } else if (mode == rsaKeyGenMode) {
            String outputFileString = parsedArgs.getStringArgument('o');
            File privOutputFile = new File(outputFileString);
            File pubOutputFile = new File(outputFileString + ".pub");
            String label = parsedArgs.getStringArgument('l');
            if (privOutputFile.exists() || pubOutputFile.exists()) {
                StreamUtils.GetSystemErr().println("Either the public key or private key file already exists. This utility will not overwrite any existing files.");
                System.exit(1);
            }
            RSAEncrypt enc = RSAEncrypt.generateKey(label);
            FileUtil.write(enc.getPrivateKey(), privOutputFile);
            FileUtil.write(enc.getPublicKey(), pubOutputFile);
            System.exit(0);
        } else if (mode == pnViewerMode) {
            if (parsedArgs.isFlagSet("server")) {
                if (parsedArgs.getNumberArgument("port") == null) {
                    StreamUtils.GetSystemErr().println("When running as a server, port is required.");
                    System.exit(1);
                }
                int port = parsedArgs.getNumberArgument("port").intValue();
                if (port > 65535 || port < 1) {
                    StreamUtils.GetSystemErr().println("Port must be between 1 and 65535.");
                    System.exit(1);
                }
                String password = parsedArgs.getStringArgument("password");
                if ("".equals(password)) {
                    ConsoleReader reader = null;
                    try {
                        reader = new ConsoleReader();
                        reader.setExpandEvents(false);
                        Character cha = new Character((char) 0);
                        password = reader.readLine("Enter password: ", cha);
                    } finally {
                        if (reader != null) {
                            reader.shutdown();
                        }
                    }
                }
                if (password == null) {
                    StreamUtils.GetSystemErr().println("Warning! Running server with no password, anyone will be able to connect!");
                    password = "";
                }
                try {
                    PNViewer.startServer(port, password);
                } catch (IOException ex) {
                    StreamUtils.GetSystemErr().println(ex.getMessage());
                    System.exit(1);
                }
            } else {
                try {
                    PNViewer.main(parsedArgs.getStringListArgument().toArray(ArrayUtils.EMPTY_STRING_ARRAY));
                } catch (HeadlessException ex) {
                    StreamUtils.GetSystemErr().println("The Persistence Network Viewer may not be run from a headless environment.");
                    System.exit(1);
                }
            }
        } else if (mode == uiMode) {
            if (parsedArgs.isFlagSet("in-shell")) {
                // Actually launch the GUI
                UILauncher.main(args);
            } else {
                // Relaunch the jar in a new process with the --run flag set,
                // so that the process will be in its own subshell
                CommandExecutor ce = new CommandExecutor("java -jar " + ClassDiscovery.GetClassContainer(Main.class).getPath() + " " + StringUtils.Join(args, " ") + " --in-shell");
                ce.start();
                System.exit(0);
            }
        } else if (mode == siteDeploy) {
            boolean clearLocalCache = parsedArgs.isFlagSet("clear-local-cache");
            if (clearLocalCache) {
                PersistenceNetwork p = SiteDeploy.getPersistenceNetwork();
                if (p == null) {
                    System.out.println("Cannot get reference to persistence network");
                    System.exit(1);
                    return;
                }
                DaemonManager dm = new DaemonManager();
                p.clearKey(dm, new String[] { "site_deploy", "local_cache" });
                dm.waitForThreads();
                System.out.println("Local cache cleared");
                System.exit(0);
            }
            boolean generatePrefs = parsedArgs.isFlagSet("generate-prefs");
            boolean useLocalCache = parsedArgs.isFlagSet("use-local-cache");
            boolean doValidation = parsedArgs.isFlagSet("do-validation");
            String configString = parsedArgs.getStringArgument("config");
            if ("".equals(configString)) {
                System.err.println("Config file missing, check command and try again");
                System.exit(1);
            }
            File config = new File(configString);
            SiteDeploy.run(generatePrefs, useLocalCache, config, "", doValidation);
        } else if (mode == newMode) {
            String li = OSUtils.GetLineEnding();
            for (String file : parsedArgs.getStringListArgument()) {
                File f = new File(file);
                if (f.exists() && !parsedArgs.isFlagSet('f')) {
                    System.out.println(file + " already exists, refusing to create");
                    continue;
                }
                f.createNewFile();
                f.setExecutable(true);
                FileUtil.write("#!/usr/bin/env /usr/local/bin/mscript" + li + "<!" + li + "\tstrict;" + li + "\tname: " + f.getName() + ";" + li + "\tauthor: " + StaticLayer.GetConvertor().GetUser(null) + ";" + li + "\tcreated: " + new Scheduling.simple_date().exec(Target.UNKNOWN, null, new CString("yyyy-MM-dd", Target.UNKNOWN)).val() + ";" + li + "\tdescription: " + ";" + li + ">" + li + li, f, true);
            }
        } else {
            throw new Error("Should not have gotten here");
        }
    } catch (NoClassDefFoundError error) {
        StreamUtils.GetSystemErr().println(getNoClassDefFoundErrorMessage(error));
    }
}
Also used : DocGenExportTool(com.laytonsmith.tools.docgen.DocGenExportTool) OutputStream(java.io.OutputStream) FileOutputStream(java.io.FileOutputStream) ArrayList(java.util.ArrayList) CommandExecutor(com.laytonsmith.PureUtilities.CommandExecutor) CString(com.laytonsmith.core.constructs.CString) PersistenceNetwork(com.laytonsmith.persistence.PersistenceNetwork) ArgumentSuite(com.laytonsmith.PureUtilities.ArgumentSuite) ConnectionMixinFactory(com.laytonsmith.persistence.io.ConnectionMixinFactory) FunctionList(com.laytonsmith.core.functions.FunctionList) List(java.util.List) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) ProfilerSummary(com.laytonsmith.tools.ProfilerSummary) ClassDiscovery(com.laytonsmith.PureUtilities.ClassLoading.ClassDiscovery) FileInputStream(java.io.FileInputStream) FileOutputStream(java.io.FileOutputStream) Map(java.util.Map) HashMap(java.util.HashMap) File(java.io.File) ClassDiscoveryCache(com.laytonsmith.PureUtilities.ClassLoading.ClassDiscoveryCache) Set(java.util.Set) HashSet(java.util.HashSet) HeadlessException(java.awt.HeadlessException) FunctionBase(com.laytonsmith.core.functions.FunctionBase) DocGen(com.laytonsmith.tools.docgen.DocGen) ExtensionDocGen(com.laytonsmith.tools.docgen.ExtensionDocGen) ArgumentParser(com.laytonsmith.PureUtilities.ArgumentParser) URI(java.net.URI) ConfigCompileException(com.laytonsmith.core.exceptions.ConfigCompileException) CString(com.laytonsmith.core.constructs.CString) Interpreter(com.laytonsmith.tools.Interpreter) ConsoleReader(jline.console.ConsoleReader) DaemonManager(com.laytonsmith.PureUtilities.DaemonManager) RSAEncrypt(com.laytonsmith.PureUtilities.Common.RSAEncrypt) IOException(java.io.IOException) ConfigCompileGroupException(com.laytonsmith.core.exceptions.ConfigCompileGroupException)

Aggregations

ClassDiscoveryCache (com.laytonsmith.PureUtilities.ClassLoading.ClassDiscoveryCache)4 ClassDiscovery (com.laytonsmith.PureUtilities.ClassLoading.ClassDiscovery)3 File (java.io.File)3 IOException (java.io.IOException)3 ArrayList (java.util.ArrayList)3 HashMap (java.util.HashMap)3 DynamicClassLoader (com.laytonsmith.PureUtilities.ClassLoading.DynamicClassLoader)2 Event (com.laytonsmith.core.events.Event)2 Function (com.laytonsmith.core.functions.Function)2 InvocationTargetException (java.lang.reflect.InvocationTargetException)2 URL (java.net.URL)2 HashSet (java.util.HashSet)2 ArgumentParser (com.laytonsmith.PureUtilities.ArgumentParser)1 ArgumentSuite (com.laytonsmith.PureUtilities.ArgumentSuite)1 AnnotationMirror (com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.AnnotationMirror)1 ClassMirror (com.laytonsmith.PureUtilities.ClassLoading.ClassMirror.ClassMirror)1 CommandExecutor (com.laytonsmith.PureUtilities.CommandExecutor)1 RSAEncrypt (com.laytonsmith.PureUtilities.Common.RSAEncrypt)1 DaemonManager (com.laytonsmith.PureUtilities.DaemonManager)1 SimpleVersion (com.laytonsmith.PureUtilities.SimpleVersion)1