trevorsandy / lpub3d

An LDraw™ editor for LEGO® style digital building instructions.
https://trevorsandy.github.io/lpub3d/
133 stars 19 forks source link

Bundle LDraw library folder in AppImage #19

Closed probonopd closed 6 years ago

probonopd commented 6 years ago

Launching the AppImage shows

ldraw

It would be nice if the LDraw library folder was bundled inside the AppImage and used automatically without user intervention.

trevorsandy commented 6 years ago

An LDraw Library (official and unofficial parts) is bundled within LPub3D.

However, normally, users will have their LDraw library already installed and accessible as it is quite likely they'll have custom parts, color configurations, models etc which must be available not just to LPub3D but to the myriad of other LDraw-based applications (model editors, part editors, viewers etc...) that use the library. Based on this scenario, I decided not to fully automate the LDraw library install, instead, give the user some install options.

As you can see from the message prompt, the user may choose to select his/her LDraw library folder or, in the event no library is installed, extract the bundled library archive.

Anyway, to improve the user experience, I imagine it may be better to tailor the library install prompt for AppImage distros as the Library will 'always' not be detected since there will never be a prompt to enter the library path during install as there is no installation.

So how can I definitely conclude that the application is being run as an AppImage payload ?

I checked the AppImageSpec but nothing immediately stuck out. Detecting the AppRun may be a path forward but, to me, 'AppRun' is not sufficiently unique to definitively determine that the application is being run from an AppImage.

Cheers,

probonopd commented 6 years ago

Ah, with your explanation it looks to me like "Extract Archive" is what I was looking for (and would appreciate if it would be done automatically in case there is no pre-existing LDraw library already installed at the target location).

If you have the environment variables $APPIMAGE (pointing to the AppImage file) and $APPDIR (pointing to the mount point) then you can assume you are running from an AppImage.

trevorsandy commented 6 years ago

So can I can do something like

#if defined Q_OS_LINUX

    bool Preferences::isAppImage = false;
    const QByteArray appImageEnv = qgetenv("APPIMAGE");
    const QByteArray appDirEnv = qgetenv("APPDIR ");
    if (! appImageEnv.isEmpty() && ! appDirEnv.isEmpty())
        isAppImage = true;

#endif
probonopd commented 6 years ago

An AppImage, when extracted, should still work (as an AppDir).

Hence, it's better to check only for APPDIR because APPIMAGE is not there when the AppImage is extracted. Also we need to make sure that AppRun sets APPIMAGE so that this also works when the AppImage is extracted.

trevorsandy commented 6 years ago

Ok - so what do you suggest to confirm an app is running from an AppImage extraction ?

probonopd commented 6 years ago

Check for the presence of $ORIGIN/../AppRun *or* $ORIGIN/../../AppRun (can be a file or a symlink) (with $ORIGIN being the directory of the application itself, usually .../bin)

trevorsandy commented 6 years ago

Excellent - many thanks.

IMHO, it would be good to add this to the spec documentation. It could be helpful.

Cheers,

trevorsandy commented 6 years ago

Here's what I'll use:

    // Check if running as AppImage payload
    QFileInfo appRunInfo("../AppRun");
    if (appRunInfo.exists() && (appRunInfo.isFile() || appRunInfo.isSymLink()))
      isAppImagePayload = true;
    if (! isAppImagePayload) {
        appRunInfo.setFile("../../AppRun");
        if (appRunInfo.exists() && (appRunInfo.isFile() || appRunInfo.isSymLink()))
          isAppImagePayload = true;
    }
trevorsandy commented 6 years ago

I've added the automatic LDraw library install for AppImage when no library was detected in the library search paths. However, users will still receive a dialogue - much like the one above - telling them the the library was installed.

probonopd commented 6 years ago

telling them the the library was installed

What I simply don't understand is why the library needs to be "installed" when in fact it comes bundled as part of the AppImage. But hey, it's better than before :+1:

trevorsandy commented 6 years ago

...why the library needs to be "installed" when in fact it comes bundled as part of the AppImage

Indeed, the logic here is a bit obtuse. Full details are in README.txt but I'll give a brief explanation.

Basically, LPub3D uses archived (.zip) instances (official and unofficial bundles) of the LDraw library for 3DViewer compatibility and improved performance - the 3D viewer is powered by LeoCAD. These files are automatically managed by LPub3D including their setup in the user's application data folder at application launch if they do not already exist there.

Additionally, 'fade' versions of the LDraw parts are generated and cached in the user's application data folder and the unofficial archive file, again, for improved performance. Placing these files in the LDraw library folder adds unnecessary clutter for the user who will likely be managing his/her content in the Library and may not wish to have LPub3D-specific files (fade file instances) deposited there. For example, additional content not used by LPub3D, and consequently not in the archive library instance, include LGEO include files (for lifelike image rendering) used by the raytracer renderer (POV-Ray).

Instead of 'archiving' the user's LDraw library, LPub3D pre-bundles these archives (and can also download/refresh them from the UI) and 'captures, and appends' any delta between them and the LDraw library folder at application startup. This way, the archive library files do not require any user manipulation.

Obviously, one would consider 'then why do we need the LDraw library folder?' Well, the LDraw library folder is needed by the integrated renderers (LDView, LDGlite) which do not use the archive instance. Moreover, user interaction (creating and managing custom part files) is better facilitated by having the LDraw library folder versus having to work with a .zip file.

When comprehensively considering the instruction editor use cases, this behaviour poses the best balance across, performance, flexibility, robustness, technical complexity and maintainability. Hopefully, this explanation brings better understanding about why both archive and folder instance of the LDraw library are used by LPub3D and why the folder instance is required even though archive bundles exists.

So to conclude, using the LDraw library archive instance provides compatibility for LPub3D 3DViewer , improves performance and also serve as a 'backup' by automatically (in the case of AppImage) installing or offering the user to extract the library in case there is no LDraw library folder installed.

Cheers,

probonopd commented 6 years ago

Thanks for the explanation @trevorsandy - you know the application better than me, so I trust you make the better decision here.