timeseries / qstudio

qStudio - Free SQL Analysis Tool
https://www.timestored.com/qstudio/
Apache License 2.0
543 stars 23 forks source link

Workaround: Create double-clickable app for macOS #93

Open richb-hanover opened 1 week ago

richb-hanover commented 1 week ago

In #74, I describe a problem with double-clicking the qstudio.jar file in macOS. (The problem was that qStudio couldn't find the PATH to prqlc.) Here's a workaround.

This script update-jar-with-path.sh reads a qstudio.jar from the current directory and creates qstudio_app that can be double-clicked. That new binary also seems to set the PATH properly so that prqlc can be executed without error.

The downside of this approach is that it opens a new Terminal window for each instance.

Update: I don't know if this is a good idea for the qStudio project. I only document it here so that I remember how to do it, and that others in the same boat might benefit.

#!/bin/sh

# Make double-clickable `qstudio_app` for macOS

# Inspired by Apple StackExchange, https://apple.stackexchange.com/posts/65136/revisions
# Perfected by ChatGPT

# Usage: 
# 1. Drag the current version of the qstudio.jar into this directory
# 2. Run this script - sh ./update-jar-with-path.sh
# 3. Resulting "qstudio_app" is double-clickable and has the right path

# Why does this work in the first place? 
# Well, a .jar is just a .zip archive which gets unpacked and executed
# by java. And the zip format allows to prepend additional stuff in 
# front of the actual archive. Any zip unarchiver skips this part 
# until it finds the start of the archive (indicated by PK...).
# (Cited from StackExchange article)

(cat << 'EOF'
#!/bin/bash
exec java -jar "$0" "$@"
exit 0
EOF
) > qstudio_app

# Append the JAR file to the script
cat qstudio.jar >> qstudio_app

# Make the resulting file executable
chmod +x qstudio_app
richb-hanover commented 1 week ago

I submitted this report through the main website, but thought I would add it to this ticket.

I used the technique above to create qstudio_app on macOS. I opened it, and immediately got this crash.

However, after I dismissed the crash dialog, qStudio worked flawlessly, even finding the prqlc compiler.

Details:

OS=Mac OS X
Java=16.0.1
Des=unknown
Stack=java.lang.StringIndexOutOfBoundsException: begin 0, end -1, length 11
    at java.base/java.lang.String.checkBoundsBeginEnd(String.java:3751)
    at java.base/java.lang.String.substring(String.java:1907)
    at com.formdev.flatlaf.ui.FlatNativeLibrary.buildLibraryName(FlatNativeLibrary.java:266)
    at com.formdev.flatlaf.ui.FlatNativeLibrary.findLibraryBesideJar(FlatNativeLibrary.java:201)
    at com.formdev.flatlaf.ui.FlatNativeLibrary.createNativeLibrary(FlatNativeLibrary.java:173)
    at com.formdev.flatlaf.ui.FlatNativeLibrary.initialize(FlatNativeLibrary.java:109)
    at com.formdev.flatlaf.ui.FlatNativeLibrary.isLoaded(FlatNativeLibrary.java:47)
    at com.formdev.flatlaf.ui.FlatNativeMacLibrary.isLoaded(FlatNativeMacLibrary.java:56)
    at com.formdev.flatlaf.ui.FullWindowContentSupport$1.componentResized(FullWindowContentSupport.java:144)
    at java.desktop/java.awt.AWTEventMulticaster.componentResized(AWTEventMulticaster.java:167)
    at java.desktop/java.awt.Component.processComponentEvent(Component.java:6443)
    at java.desktop/java.awt.Component.processEvent(Component.java:6397)
    at java.desktop/java.awt.Container.processEvent(Container.java:2264)
    at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:4993)
    at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2322)
    at java.desktop/java.awt.Component.dispatchEvent(Component.java:4825)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:772)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
    at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745)
    at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:743)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)