Multitool - An implementation and feature discussion.

MacOS first impressions, version 48
1: The installer installs, but the app will not run from the Applications Directory. It errors out because it is not signed. This will be a problem for most Mac users who are not devs and are not willing to bypass security.
2: Once that is resolved, the app does nothing (because it writes stuff to the console and quits).
3: Going to the directory and opening the app allows me to eventually get to the jar, which I can run from Terminal.

terminal output:

Bash:
 $ java -jar multitool-48.jar
Current working directory: /Applications/multitool.app/Contents/app
Path to local Java: /Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home/bin/java
Local Java version: 21
Preferred Java version: 21

ToolData for multitool
currentVersion=48
latestVersion=48
downloadURL=https://github.com/kolmafia/multitool/releases/download/r48/multitool-48.jar
needToDownload=false
localJars=[multitool-48.jar]
latestJarFile=/Applications/multitool.app/Contents/app/multitool-48.jar
localModificationFound=false

ToolData for kolmafia
currentVersion=0
latestVersion=28355
downloadURL=https://github.com/kolmafia/kolmafia/releases/download/r28355/kolmafia-28355.jar
needToDownload=true
localJars=[]
latestJarFile=/Applications/multitool.app/Contents/app
localModificationFound=false
 
error in run command for MacOS:

1: needs error handling if java isn't found. It's enclosing the executable in double quotes, which makes it not found.
2: also, don't do that. But do pre-process and replace spaces with %20 . Also, maybe some of our ".." resistant code from the scripts directory...
3: Please do not download the jar into the app directory on a Mac. The security infrastructure will plotz. It will become an issue down the road.

Bash:
mcroft@MacBook-Pro app % java -jar multitool-48.jar run
Current working directory: /Applications/multitool.app/Contents/app
Path to local Java: /Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home/bin/java
Local Java version: 21
Preferred Java version: 21

ToolData for multitool
currentVersion=48
latestVersion=48
downloadURL=https://github.com/kolmafia/multitool/releases/download/r48/multitool-48.jar
needToDownload=false
localJars=[multitool-48.jar]
latestJarFile=/Applications/multitool.app/Contents/app/multitool-48.jar
localModificationFound=false

ToolData for kolmafia
currentVersion=28355
latestVersion=28355
downloadURL=https://github.com/kolmafia/kolmafia/releases/download/r28355/kolmafia-28355.jar
needToDownload=false
localJars=[kolmafia-28355.jar]
latestJarFile=/Applications/multitool.app/Contents/app/kolmafia-28355.jar
localModificationFound=false

"/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home/bin/java" -jar /Applications/multitool.app/Contents/app/kolmafia-28355.jar
Exception in thread "main" java.lang.RuntimeException: java.io.IOException: Cannot run program ""/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home/bin/java"": error=2, No such file or directory
    at com.github.multitool.Multitool.main(Multitool.java:41)
Caused by: java.io.IOException: Cannot run program ""/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home/bin/java"": error=2, No such file or directory
    at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1170)
    at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1089)
    at java.base/java.lang.Runtime.exec(Runtime.java:681)
    at java.base/java.lang.Runtime.exec(Runtime.java:491)
    at java.base/java.lang.Runtime.exec(Runtime.java:366)
    at com.github.multitool.Multitool.startSecondJVM(Multitool.java:132)
    at com.github.multitool.Multitool.main(Multitool.java:39)
Caused by: java.io.IOException: error=2, No such file or directory
    at java.base/java.lang.ProcessImpl.forkAndExec(Native Method)
    at java.base/java.lang.ProcessImpl.<init>(ProcessImpl.java:295)
    at java.base/java.lang.ProcessImpl.start(ProcessImpl.java:225)
    at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1126)
    ... 6 more
mcroft@MacBook-Pro app % /Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home/bin/java -jar /Applications/multitool.app/Contents/app/kolmafia-28355.jar

KoLmafia r28355
Build main-27db087 21.0.6 (Eclipse Adoptium 21.0.6+7-LTS) Linux amd64 6.8.0-1021-azure

Currently Running on Mac OS X
Local Directory is /Users/mcroft/Library/Application Support/KoLmafia
Using Java 21.0.5

2025-02-16 01:04:42.266 java[53830:3105636] +[IMKClient subclass]: chose IMKClient_Modern
2025-02-16 01:04:42.266 java[53830:3105636] +[IMKInputSession subclass]: chose IMKInputSession_Modern
 
Welcome back.

We are in phase zero of a three phase approach:
  • Make it work some of the time.
  • Make it work more of the time and do so robustly and more efficiently
  • Make it do more.
My first comment is that the entire implementation as it currently exists depends upon the ability of the user to download a jar file into the directory that contains (or will contain) and will be the home directory for KoLmafia when running. If that is a problem for Mac users then I am going to push Mac support to phase 1.

There is also an assumption that the user has successfully run a jar file on their system previously or that they will ask for help from people and not expect it from a tool that they cannot run :)

Since there is a goal to run on an ancient JVM I have tended to avoid any thing that involves a third party dependency for obvious reasons. LOG4J and various JSON parsers are consequently not the first choice for implementation.

More later but some of your concerns are on the road map.

Thank you.
 
LOG4J and various JSON parsers are consequently not the first choice for implementation.
I'm inclined to agree, although maybe for slightly different reasons.

One, I think JSON is overkill for what we need.

Two, I would prefer to keep our external dependencies to a minimum. log4j in particular burned the entire industry quite badly a few years back, so I'm starting from a point of high skepticism of that specific dependency.

I would rather parse preferredJava directly from https://raw.githubusercontent.com/kolmafia/kolmafia/refs/heads/main/gradle.properties under the assumption that said file will not change drastically.
 
The jar works great on the Mac. (with exceptions as noted). It's the DMG that could be turned off. It can be brought back at an appropriate time, if it's useful. Most of the online stack overflow kind of help suggests switching to PKG from DMG.

The DMG target creates a disk image with the app and a link to the default /Applications folder, with an indicator that you should put the app there. That's not what we want at all, in part because the app image on the dmg is not set up properly.

It wouldn't be wrong to have the Multi-tool jar in the Applications directory, pulling down the jar to the same location. But if the jar is inside the app, then it looks to the security system like a self-modifying app and that is sus.

So as long as we do less, we're going to be OK...
 
OK.

The DMG, exe and the *nix package are code build artifacts that mafia created so I got them when I stole as much as I could from mafia. Given that my initial use case was always "download a jar and run it from a command line I wondered about the other packaging and whether it was needed. I made a half-hearted attempt to rip them out but the effect was the jar file was not built on GitHub nor treated as a release artifact. I probably need to circle back and figure that out or get some help.

Your comments about Mac file system quirks made sense and I am in the process of pushing code that works on Windows and should work better on a Mac. No promises but at least I am trying.

Right now it will run the latest version of KoLmafia it found at startup but does not update that there is a newer version downloaded. I can shuffle things to fix that but that might not happen today.

I am thinking about how to control things. Command line arguments or a preferences type file are somewhat easy to code but if the world is going to demand buttons on a GUI anyway then I might as well suck it up and do that now. Stand by.
 
On the Mac, the "home" directory for KoLmafia is ~/Library/Application Support/KoLmafia.
That is where DEBUG files go.
Subdirectories of that are data/, sessions/, /relay, and all the others.

That has literally nothing to do with where the .jar file is run from.
The user can put it wherever they want that they have write-access to.
I mean, I have a source code repository, cloned from github, at ~/root/src/kolmafia, I build from there and gradlew puts the jar in dist, and I just do java -jar dist/KoLmafia-XXXXX.jar.

I would find it really weird to put executable jar files under ~/Library/...

I don't know where other Mac users download into.
FWIW, Safari has a place on Settings/General to specify "File download location".
I bet Chrome does too.
The default seems to be ~/Downloads
 
The premise is that the user explicitly downloads and places multitool in the directory that already contains the mafia jar or the directory that the user wants to contain the mafia jar. If that is not possible or is nonsensical then I am prepared to say "then please don't use it yet" until I understand the problem and ways to fix it.

I note there may be some confusion because KoLmafia creates a dmg file (and others) so multitool created them as well. That is somewhere between ill-advised and WRONG and making it so the only artifact is multitool's jar file is on a ToDo list.

That said the launcher portion of multitool needs to establish the same run time environment that KolMafia would have is the user launched it without multitool. That may be harder than it looks, especially on a Mac. Luckily the launcher is not my immediate priority.

Thank you
 
On the Mac, the "home" directory for KoLmafia is ~/Library/Application Support/KoLmafia.
That is where DEBUG files go.
Subdirectories of that are data/, sessions/, /relay, and all the others.

That has literally nothing to do with where the .jar file is run from.
The user can put it wherever they want that they have write-access to.
I mean, I have a source code repository, cloned from github, at ~/root/src/kolmafia, I build from there and gradlew puts the jar in dist, and I just do java -jar dist/KoLmafia-XXXXX.jar.

I would find it really weird to put executable jar files under ~/Library/...

I don't know where other Mac users download into.
FWIW, Safari has a place on Settings/General to specify "File download location".
I bet Chrome does too.
The default seems to be ~/Downloads

Exactly. The downside is that some users regularly empty out ~/Downloads. (Not me. My oldest files in ~/Downloads can now vote.). Some commercial maintenance apps recommend it.

But if we're installing something, the default location is either in /Applications or ~/Applications if we want to install it for a single user.

We can figure it out when we are planning beyond phase 0.
 
I've slowed down but I am adding logging so there will be some record from a time when Multitool is not launched from the command line. I want to implement a user controlled purge option and be smart enough to not delete a running jar file. The only artifact created is a jar file which eliminates several other issues. I still need some live testing that shows it runs under a very old version of java and the GitHub project needs to be tweaked so that protection and collaboration are the same as for KoLmafia. I am having a hard time imagining a meaningful test suite but I wo think it would be neat to have coverage over 90%.

My excuse for this update, however is the following code which is currently called in KoLmafia main()

Code:
private static class UpdateCheckRunnable implements Runnable {
    @Override
    public void run() {
      // TODO: Check for new version on jenkins\github after migration is complete. See revision
      // history for old release update check.
    }
  }

Code looks to have been removed in 2021. It seems quite reasonable to restore this check in 2025. I'm not sure what it used to do but all it needs to go is get and compare a version number. But if it is going that it can also check the Java version required to run any update to KoLmafia that the user does not have.

So the version nag is probably not needed in it's proposed form and some multitool functionality could be redundant.

Food for thought.
 
Back
Top