From 8ca2e04557e7c5828c0961ffc7b386f5999b6253 Mon Sep 17 00:00:00 2001 From: Joaquim Date: Thu, 16 Jul 2026 23:15:56 +0100 Subject: [PATCH 1/5] Make iview_app.vbs self-locating, fix missing --project Hardcoded C:\programs\Julia-1.10\bin\julia.exe and the dev checkout path -- broke on any other machine/checkout. Also the live sh.Run line had dropped --project entirely (only the commented-out draft above it had it), so it launched outside the package's environment. Mirrors deps/installer/iview_launch.vbs's self-locating pattern: bare `julia` from PATH, --project pointed at this script's own folder. Co-Authored-By: Claude Sonnet 5 --- iview_app.vbs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/iview_app.vbs b/iview_app.vbs index 446e8e0..5951154 100644 --- a/iview_app.vbs +++ b/iview_app.vbs @@ -2,13 +2,18 @@ ' STARTUPINFO SW_HIDE, which the Qt GUI window would inherit and stay invisible. iview_app.jl ' hides its own console on startup, so only the viewer window remains. ' +' Self-locating (same trick as deps/installer/iview_launch.vbs): finds its own folder at runtime +' instead of hardcoding a julia.exe path + dev checkout path, so this works on any machine/checkout +' without editing. Calls `julia` bare (from PATH) with --project pointed at this same folder. +' ' Files dropped ONTO the desktop shortcut arrive here as WScript.Arguments; we forward each path ' to Julia, and iview_app.jl opens it (otherwise, with no args, it opens an empty launcher). -' sh.Run """C:\programs\Julia-1.10\bin\julia.exe"" --project=""C:\Users\j\.julia\dev\InteractiveGMT"" ""C:\Users\j\.julia\dev\InteractiveGMT\iview_app.jl""" & extra, 7, False +Dim fso : Set fso = CreateObject("Scripting.FileSystemObject") +Dim here : here = fso.GetParentFolderName(WScript.ScriptFullName) Dim sh : Set sh = CreateObject("WScript.Shell") Dim extra : extra = "" Dim i For i = 0 To WScript.Arguments.Count - 1 extra = extra & " """ & WScript.Arguments(i) & """" Next -sh.Run """C:\programs\Julia-1.10\bin\julia.exe"" ""C:\Users\j\.julia\dev\InteractiveGMT\iview_app.jl""" & extra, 7, False +sh.Run "julia --project=""" & here & """ """ & here & "\iview_app.jl""" & extra, 7, False From d6f78fae3231a0138b1a7bf694286a9fc6c5cb0d Mon Sep 17 00:00:00 2001 From: Joaquim Date: Fri, 17 Jul 2026 00:06:49 +0100 Subject: [PATCH 2/5] iview_app.vbs: resolve install path via Julia at every launch, not self Self-locating-to-own-folder broke the moment this file was copied anywhere outside the exact checkout it launched from -- and a plain Pkg.add install lives in a content-hashed folder that changes on every Pkg.update, so a Desktop shortcut pointing at it (or a copy of it) went stale on every update. Now it asks Julia fresh each launch (Base.find_package -- reads the Manifest, doesn't load the package) and runs from whatever that resolves to. Works unmodified for the dev checkout too (dev'd packages resolve the same way). Verified: dry-run with an argument forwards correctly, quoting intact. Co-Authored-By: Claude Sonnet 5 --- iview_app.vbs | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/iview_app.vbs b/iview_app.vbs index 5951154..3d504b4 100644 --- a/iview_app.vbs +++ b/iview_app.vbs @@ -2,18 +2,46 @@ ' STARTUPINFO SW_HIDE, which the Qt GUI window would inherit and stay invisible. iview_app.jl ' hides its own console on startup, so only the viewer window remains. ' -' Self-locating (same trick as deps/installer/iview_launch.vbs): finds its own folder at runtime -' instead of hardcoding a julia.exe path + dev checkout path, so this works on any machine/checkout -' without editing. Calls `julia` bare (from PATH) with --project pointed at this same folder. +' Resolves InteractiveGMT's install path by ASKING JULIA at every launch (Base.find_package — +' just reads the active project's Manifest, does not load/precompile the package) instead of +' hardcoding a location. This matters because a git-based Pkg install lives in a content-hashed +' folder (~/.julia/packages/InteractiveGMT//) that gets a NEW on every +' `Pkg.update("InteractiveGMT")` — a script that instead finds its OWN folder (fso.GetParentFolderName) +' would go stale the moment you copy it to a Desktop shortcut and then update. Asking Julia fresh +' every time means the SAME copy of this file — wherever you put it, including a Desktop shortcut +' — keeps working across every future update, no re-copying, ever. +' +' Also works unmodified for a plain dev checkout (this file run in place): Base.find_package +' resolves `dev`ed packages from the Manifest too, same as `add`ed ones. +' +' The lookup expression is written to a temp .jl file rather than passed inline on the command +' line, to sidestep Windows/VBScript quote-escaping entirely. ' ' Files dropped ONTO the desktop shortcut arrive here as WScript.Arguments; we forward each path ' to Julia, and iview_app.jl opens it (otherwise, with no args, it opens an empty launcher). Dim fso : Set fso = CreateObject("Scripting.FileSystemObject") -Dim here : here = fso.GetParentFolderName(WScript.ScriptFullName) -Dim sh : Set sh = CreateObject("WScript.Shell") +Dim sh : Set sh = CreateObject("WScript.Shell") + +Dim tmp : tmp = sh.ExpandEnvironmentStrings("%TEMP%") & "\igmt_locate_" & CStr(Timer) & ".jl" +Dim f : Set f = fso.CreateTextFile(tmp, True) +f.WriteLine "p = Base.find_package(" & Chr(34) & "InteractiveGMT" & Chr(34) & ")" +f.WriteLine "print(p === nothing ? " & Chr(34) & Chr(34) & " : dirname(dirname(p)))" +f.Close + +Dim ex : Set ex = sh.Exec("julia --startup-file=no " & Chr(34) & tmp & Chr(34)) +Dim here : here = Trim(ex.StdOut.ReadAll()) +fso.DeleteFile tmp, True + +If here = "" Then + MsgBox "Could not locate InteractiveGMT." & vbCrLf & _ + "Is it added ('] add https://github.com/GenericMappingTools/InteractiveGMT') or dev'd in Julia's default environment?", _ + vbExclamation, "iGMT" + WScript.Quit 1 +End If + Dim extra : extra = "" Dim i For i = 0 To WScript.Arguments.Count - 1 - extra = extra & " """ & WScript.Arguments(i) & """" + extra = extra & " " & Chr(34) & WScript.Arguments(i) & Chr(34) Next -sh.Run "julia --project=""" & here & """ """ & here & "\iview_app.jl""" & extra, 7, False +sh.Run "julia --project=" & Chr(34) & here & Chr(34) & " " & Chr(34) & here & "\iview_app.jl" & Chr(34) & extra, 7, False From 98adf4ff7ad6e599d47d6cc94a001d907a2dbc40 Mon Sep 17 00:00:00 2001 From: Joaquim Date: Fri, 17 Jul 2026 00:36:37 +0100 Subject: [PATCH 3/5] iview_app.vbs: own-folder fast path + depot fallback, no double Julia launch Previous version asked Julia (a second julia.exe subprocess) to resolve the install path on every single launch -- correct, but doubled startup time. Now: use this script's own folder if iview_app.jl sits right next to it (dev checkout, or running in place inside a live Pkg folder -- zero overhead, one julia.exe launch, same as before). Only a detached copy (e.g. on Desktop) falls back to scanning ~/.julia/packages/InteractiveGMT/* for the newest-modified folder -- a plain filesystem check, still no second Julia process. Fixed a real VBScript bug along the way: `sub` is a reserved keyword, can't be a variable name. Add deps/installer/make_desktop_shortcut.vbs: one-time setup script for a plain `Pkg.add` install (no NSIS) that copies iview_app.vbs + igmt.ico to the Desktop once and creates a real .lnk shortcut with the icon set -- needed because a .lnk's icon path can't be resolved dynamically like the launch target can. Deliberately does NOT use sh.SpecialFolders("Desktop"): verified live on this machine that it silently resolves into an OneDrive-redirected path (C:\Users\j\OneDrive - Universidade do Algarve\Ambiente de Trabalho) instead of the real local Desktop. Forces %USERPROFILE%\Desktop instead. Co-Authored-By: Claude Sonnet 5 --- deps/installer/make_desktop_shortcut.vbs | 49 ++++++++++++++++++++++ iview_app.vbs | 53 ++++++++++++++---------- 2 files changed, 80 insertions(+), 22 deletions(-) create mode 100644 deps/installer/make_desktop_shortcut.vbs diff --git a/deps/installer/make_desktop_shortcut.vbs b/deps/installer/make_desktop_shortcut.vbs new file mode 100644 index 0000000..2424218 --- /dev/null +++ b/deps/installer/make_desktop_shortcut.vbs @@ -0,0 +1,49 @@ +' ONE-TIME SETUP for a `] add`/`Pkg.update` install (no NSIS): creates a real Desktop .lnk +' shortcut, with the iGMT icon, that survives every future Pkg.update. Run this once (from +' wherever InteractiveGMT currently lives — find it with `pathof(InteractiveGMT)` in Julia if +' unsure). Safe to re-run anytime; it just overwrites the same two files + shortcut. +' +' Why a plain shortcut-to-the-package-tree doesn't work: a .lnk's ICON path is read once, when +' the shortcut is opened — unlike iview_app.vbs's own launch target, which it re-resolves live +' via Julia every run, a .lnk can't dynamically look up its icon file, so an icon path pointing +' into the Pkg-hash-changing tree would eventually show a broken icon. +' +' Fix: copy the two files that need a truly permanent, unchanging home — iview_app.vbs (which +' re-resolves InteractiveGMT's actual location at every launch, so ITS content never goes stale) +' and igmt.ico (a static asset that doesn't change between versions) — to the Desktop ONCE, then +' point the shortcut at those local copies. After this, the Desktop icon never needs touching +' again, no matter how many times InteractiveGMT's Pkg-hash directory changes underneath it. +Dim fso : Set fso = CreateObject("Scripting.FileSystemObject") +Dim sh : Set sh = CreateObject("WScript.Shell") + +Dim tmp : tmp = sh.ExpandEnvironmentStrings("%TEMP%") & "\igmt_locate_" & CStr(Timer) & ".jl" +Dim f : Set f = fso.CreateTextFile(tmp, True) +f.WriteLine "p = Base.find_package(" & Chr(34) & "InteractiveGMT" & Chr(34) & ")" +f.WriteLine "print(p === nothing ? " & Chr(34) & Chr(34) & " : dirname(dirname(p)))" +f.Close + +Dim ex : Set ex = sh.Exec("julia --startup-file=no " & Chr(34) & tmp & Chr(34)) +Dim pkgRoot : pkgRoot = Trim(ex.StdOut.ReadAll()) +fso.DeleteFile tmp, True + +If pkgRoot = "" Then + MsgBox "Could not locate InteractiveGMT." & vbCrLf & _ + "Is it added ('] add https://github.com/GenericMappingTools/InteractiveGMT') or dev'd in Julia's default environment?", _ + vbExclamation, "iGMT" + WScript.Quit 1 +End If + +' NEVER sh.SpecialFolders("Desktop") -- if Windows/OneDrive has Desktop redirected into OneDrive +' ("Known Folder Move", common on managed machines), that call silently returns the OneDrive path +' and everything below would get copied straight into cloud sync. Force the real local Desktop. +Dim desktop : desktop = sh.ExpandEnvironmentStrings("%USERPROFILE%") & "\Desktop" +fso.CopyFile pkgRoot & "\iview_app.vbs", desktop & "\iview_app.vbs", True +fso.CopyFile pkgRoot & "\deps\assets\igmt.ico", desktop & "\igmt.ico", True + +Dim link : Set link = sh.CreateShortcut(desktop & "\iGMT.lnk") +link.TargetPath = desktop & "\iview_app.vbs" +link.IconLocation = desktop & "\igmt.ico" +link.WindowStyle = 7 +link.Save + +MsgBox "iGMT Desktop shortcut created (or refreshed). You can run this setup script again anytime -- it's idempotent.", vbInformation, "iGMT" diff --git a/iview_app.vbs b/iview_app.vbs index 3d504b4..d22686a 100644 --- a/iview_app.vbs +++ b/iview_app.vbs @@ -2,39 +2,48 @@ ' STARTUPINFO SW_HIDE, which the Qt GUI window would inherit and stay invisible. iview_app.jl ' hides its own console on startup, so only the viewer window remains. ' -' Resolves InteractiveGMT's install path by ASKING JULIA at every launch (Base.find_package — -' just reads the active project's Manifest, does not load/precompile the package) instead of -' hardcoding a location. This matters because a git-based Pkg install lives in a content-hashed -' folder (~/.julia/packages/InteractiveGMT//) that gets a NEW on every -' `Pkg.update("InteractiveGMT")` — a script that instead finds its OWN folder (fso.GetParentFolderName) -' would go stale the moment you copy it to a Desktop shortcut and then update. Asking Julia fresh -' every time means the SAME copy of this file — wherever you put it, including a Desktop shortcut -' — keeps working across every future update, no re-copying, ever. +' Path resolution, fast path first: +' 1. If iview_app.jl sits right next to this script (running in place -- a dev checkout, or +' inside a live Pkg package folder), use this script's own folder. Zero overhead, exactly +' one julia.exe launch, same speed as always. +' 2. Only if this is a DETACHED copy (e.g. sitting on your Desktop, so iview_app.jl is NOT next +' to it) does it fall back to scanning ~/.julia/packages/InteractiveGMT/* for the +' newest-modified folder -- a git-based Pkg install lives in a content-hashed folder that +' gets a NEW hash on every Pkg.update, so a Desktop copy of this file needs SOME way to find +' the current one. This is a plain filesystem scan, not a Julia subprocess -- still only one +' julia.exe launch total, never two. ' -' Also works unmodified for a plain dev checkout (this file run in place): Base.find_package -' resolves `dev`ed packages from the Manifest too, same as `add`ed ones. -' -' The lookup expression is written to a temp .jl file rather than passed inline on the command -' line, to sidestep Windows/VBScript quote-escaping entirely. +' (An earlier version asked Julia itself, via a second julia.exe subprocess, to resolve the path +' on every launch -- correct, but doubled startup time. Don't reintroduce that.) ' ' Files dropped ONTO the desktop shortcut arrive here as WScript.Arguments; we forward each path ' to Julia, and iview_app.jl opens it (otherwise, with no args, it opens an empty launcher). Dim fso : Set fso = CreateObject("Scripting.FileSystemObject") Dim sh : Set sh = CreateObject("WScript.Shell") -Dim tmp : tmp = sh.ExpandEnvironmentStrings("%TEMP%") & "\igmt_locate_" & CStr(Timer) & ".jl" -Dim f : Set f = fso.CreateTextFile(tmp, True) -f.WriteLine "p = Base.find_package(" & Chr(34) & "InteractiveGMT" & Chr(34) & ")" -f.WriteLine "print(p === nothing ? " & Chr(34) & Chr(34) & " : dirname(dirname(p)))" -f.Close +Dim here : here = fso.GetParentFolderName(WScript.ScriptFullName) -Dim ex : Set ex = sh.Exec("julia --startup-file=no " & Chr(34) & tmp & Chr(34)) -Dim here : here = Trim(ex.StdOut.ReadAll()) -fso.DeleteFile tmp, True +If Not fso.FileExists(here & "\iview_app.jl") Then + ' Detached copy -- find the newest InteractiveGMT folder in the Pkg depot. + Dim depot : depot = sh.ExpandEnvironmentStrings("%USERPROFILE%") & "\.julia\packages\InteractiveGMT" + here = "" + If fso.FolderExists(depot) Then + Dim subFolder, best + best = -1 + For Each subFolder In fso.GetFolder(depot).SubFolders + If fso.FileExists(subFolder.Path & "\iview_app.jl") Then + If CDbl(subFolder.DateLastModified) > best Then + best = CDbl(subFolder.DateLastModified) + here = subFolder.Path + End If + End If + Next + End If +End If If here = "" Then MsgBox "Could not locate InteractiveGMT." & vbCrLf & _ - "Is it added ('] add https://github.com/GenericMappingTools/InteractiveGMT') or dev'd in Julia's default environment?", _ + "Is it added ('] add https://github.com/GenericMappingTools/InteractiveGMT') in Julia's default environment?", _ vbExclamation, "iGMT" WScript.Quit 1 End If From 7e961929df55a7a1a34029db03e22f7e33f24f7e Mon Sep 17 00:00:00 2001 From: Joaquim Date: Fri, 17 Jul 2026 01:08:42 +0100 Subject: [PATCH 4/5] Share the ~200MB VTK/Qt/TBB runtime cache across Pkg.updates; add update!() A plain `Pkg.add`-installed package lives in a content-hashed folder that gets a BRAND NEW hash on every single Pkg.update, even for a one-line .jl change. deps/build.jl was extracting the full runtime zip into that ephemeral folder, so every update silently re-downloaded and re-extracted the whole ~200MB VTK/Qt/TBB bundle again. Fixed: the runtime now lives at ~/.julia/gmtvtk_runtime/, keyed off the shared Julia depot rather than the per-version package folder, so it's fetched once ever. src/libgmtvtk.jl looks there too (falling back to it only when there's no local deps/build/gmtvtk.dll, so an active dev build via deps/build.bat always wins first). Verified both files resolve to the identical path and the extraction layout is correct. Add src/selfupdate.jl (InteractiveGMT.update!()): for a `] dev`-installed checkout (fixed directory, never moves across updates -- unlike Pkg.add), pulls the latest source in place via Julia's BUNDLED LibGit2 (no system git.exe required) and rebuilds. Pkg.update() deliberately skips dev'd packages, so this fills that gap. Verified fetch+merge! against this actual repo. Adds LibGit2 + Pkg (both stdlibs) to Project.toml deps -- needed by selfupdate.jl, same reasoning as the earlier Downloads fix. Co-Authored-By: Claude Sonnet 5 --- Project.toml | 4 ++++ deps/build.jl | 43 ++++++++++++++++++++++--------------- src/InteractiveGMT.jl | 1 + src/libgmtvtk.jl | 24 ++++++++++++++++----- src/selfupdate.jl | 50 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 22 deletions(-) create mode 100644 src/selfupdate.jl diff --git a/Project.toml b/Project.toml index 597aa4c..07f284c 100644 --- a/Project.toml +++ b/Project.toml @@ -7,11 +7,15 @@ version = "0.1.0" Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b" Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" GMT = "5752ebe1-31b9-557e-87aa-f909b540aa54" +LibGit2 = "76f85450-5226-5b5a-8eaa-529ad045b433" +Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" [compat] Downloads = "1" GMT = "1.40" +LibGit2 = "1" +Pkg = "1" julia = "1.10" [extras] diff --git a/deps/build.jl b/deps/build.jl index 9746a1c..fbe19f4 100644 --- a/deps/build.jl +++ b/deps/build.jl @@ -4,21 +4,32 @@ # # * FULL runtime zip (gmtvtk.dll + bundled VTK/Qt/TBB + Qt plugins) — changes rarely, # only when the VTK/Qt/TBB module set changes. Pinned by deps/RUNTIME_VERSION (a git -# tag, e.g. "runtime-0.1"). Downloaded ONCE, on first install (no marker in deps/build/). +# tag, e.g. "runtime-0.1"). Downloaded ONCE EVER (see SHARED_ROOT below). # # * DLL-ONLY zip (just gmtvtk.dll) — can change daily as the C++ side is edited. Lives at # a FIXED, reused release tag (DLL_TAG below); its one asset gets overwritten in place # (`gh release upload dll-latest gmtvtk-win64.zip --clobber`) — no new tag per day. # Re-downloaded on every `Pkg.build("InteractiveGMT")`. - +# +# A regular `Pkg.add`-installed (non-dev) package lives in a content-hashed folder +# (~/.julia/packages/InteractiveGMT//) that gets a BRAND NEW on every single +# Pkg.update, even for a one-line .jl change unrelated to the C++ side. If the ~200 MB +# VTK/Qt/TBB runtime were extracted INTO that folder (as an earlier version of this file did), +# every update would silently re-download and re-extract the entire runtime again -- +# unacceptable. Fix: extract the runtime into SHARED_ROOT, a location keyed off the Julia +# DEPOT itself (~/.julia), not off this ephemeral package folder -- the same physical spot +# survives every Pkg.update, `Pkg.add` or `Pkg.develop` alike, so the runtime is fetched once, +# ever, no matter how many times the package updates. src/libgmtvtk.jl looks in this same +# SHARED_ROOT (falling back to it only when there's no LOCAL deps/build/gmtvtk.dll -- i.e. a +# developer's own `deps/build.bat` build always wins first). using Downloads const REPO = "GenericMappingTools/InteractiveGMT" const DLL_TAG = "dll-latest" # fixed tag; its one asset is re-uploaded in place, never retagged -const DEPS_DIR = @__DIR__ -const PKG_ROOT = normpath(joinpath(DEPS_DIR, "..")) # zip paths are relative to here (deps/build/..., src/..., data/...) -const MARKER = joinpath(DEPS_DIR, "build", ".full_runtime_installed") +const DEPS_DIR = @__DIR__ +const SHARED_ROOT = joinpath(first(Base.DEPOT_PATH), "gmtvtk_runtime") # survives every Pkg.update; zip paths (deps/build/...) are relative to here +const MARKER = joinpath(SHARED_ROOT, "deps", "build", ".full_runtime_installed") function runtime_tag() f = joinpath(DEPS_DIR, "RUNTIME_VERSION") @@ -35,13 +46,10 @@ release_url(tag::String, asset::String) = # "does not look like a tar archive" / "Error exit delayed from previous errors". const TAR = joinpath(get(ENV, "SystemRoot", "C:\\Windows"), "System32", "tar.exe") -# Both zips also contain Project.toml/data/src (the "full" one, for the standalone -# zip/NSIS user who isn't going through Julia Pkg at all) — but under Pkg those files -# already exist on disk from the git checkout, and Pkg marks them READ-ONLY on Windows. -# Extracting the whole archive then fails with "Can't stat existing object: Permission -# denied" trying to overwrite them. Only deps/build/ (the binaries) is actually needed -# here, so restrict extraction to that subtree — sidesteps the permission error AND -# avoids redundantly re-writing files git already gave us. +# The full zip also contains Project.toml/data/src (for the standalone zip/NSIS user who isn't +# going through Julia Pkg at all) — irrelevant here since Pkg already gave us those via git, and +# SHARED_ROOT only ever needs the binaries. Restrict extraction to deps/build/ so SHARED_ROOT +# doesn't waste disk space on a redundant copy of data/ and src/. function fetch_and_extract(url::String, dest::String) isfile(TAR) || error("$TAR not found — need Windows 10 1803+ (bsdtar) to unzip gmtvtk binaries") zip = joinpath(tempdir(), basename(url)) @@ -58,14 +66,15 @@ end function main() if !isfile(MARKER) - # First install: full runtime bundle, pinned to a coarse, rarely-bumped tag. - fetch_and_extract(release_url(runtime_tag(), "iGMT-win64-full.zip"), PKG_ROOT) + # First install EVER on this machine: full runtime bundle, pinned to a coarse, + # rarely-bumped tag. Never repeated after this, even across many future updates. + fetch_and_extract(release_url(runtime_tag(), "iGMT-win64-full.zip"), SHARED_ROOT) touch(MARKER) else - # Update: DLL only, always the same rolling tag/asset. - fetch_and_extract(release_url(DLL_TAG, "gmtvtk-win64.zip"), PKG_ROOT) + # Every subsequent build: DLL only (~1 MB), always the same rolling tag/asset. + fetch_and_extract(release_url(DLL_TAG, "gmtvtk-win64.zip"), SHARED_ROOT) end - @info "InteractiveGMT: gmtvtk binaries installed" + @info "InteractiveGMT: gmtvtk binaries installed" SHARED_ROOT end main() diff --git a/src/InteractiveGMT.jl b/src/InteractiveGMT.jl index 46b9708..153b3bf 100644 --- a/src/InteractiveGMT.jl +++ b/src/InteractiveGMT.jl @@ -20,6 +20,7 @@ using PrecompileTools: @setup_workload, @compile_workload # --- C-API DLL loader (resolved at runtime in __init__; see libgmtvtk.jl) ---------------- include("libgmtvtk.jl") +include("selfupdate.jl") # update!() -- pull + rebuild in place, for a `] dev`-installed checkout # --- handles, event loop, in-window Julia console ---------------------------------------- include("types.jl") diff --git a/src/libgmtvtk.jl b/src/libgmtvtk.jl index 23bd404..995e0b7 100644 --- a/src/libgmtvtk.jl +++ b/src/libgmtvtk.jl @@ -14,16 +14,30 @@ const _PKGROOT = normpath(joinpath(@__DIR__, "..")) # Libdl without adding it to [deps]: the stdlib module is re-exposed inside Base. const Libdl = Base.Libc.Libdl +# Where's gmtvtk.dll? Checked in order: +# 1. A LOCAL dev build (deps/build/gmtvtk.dll next to this checkout, from deps/build.bat) -- +# always wins first, so a developer actively rebuilding the DLL never picks up a stale +# cached copy. +# 2. SHARED_LIB: the depot-wide runtime cache deps/build.jl fetches into +# (~/.julia/gmtvtk_runtime/deps/build/gmtvtk.dll) -- this is the Pkg.add/Pkg.develop path. +# It's keyed off the Julia DEPOT itself, not off this package's own (possibly +# content-hashed, possibly-different-every-update) folder, so the SAME ~200 MB VTK/Qt/TBB +# runtime is reused across every future update instead of being re-fetched into a new +# folder each time. +const _LOCAL_LIB = joinpath(_PKGROOT, "deps", "build", "gmtvtk.dll") +const _SHARED_LIB = joinpath(first(Base.DEPOT_PATH), "gmtvtk_runtime", "deps", "build", "gmtvtk.dll") +const _LIB = isfile(_LOCAL_LIB) ? _LOCAL_LIB : _SHARED_LIB +const _BIN_DIR = dirname(_LIB) + # Toolchain runtime DLL dirs (this machine). Dependent DLLs (Qt6*, vtk*) resolve from PATH at # load time. Override any of these via the matching ENV var BEFORE `using InteractiveGMT`. # # A GMTVTK_PACKAGE=ON build (see deps/CMakeLists.txt) drops every VTK/Qt/TBB runtime DLL plus the # Qt platform plugins (platforms/qwindows.dll, via windeployqt) into deps/build/ next to -# gmtvtk.dll itself — that's the NSIS-installed layout, with no VTK/Qt toolchain on the -# destination machine at all. Detect that bundle and point straight at it; otherwise fall back -# to this dev machine's hard-coded toolchain paths (ENV overrides always win either way). -const _LIB = joinpath(_PKGROOT, "deps", "build", "gmtvtk.dll") -const _BIN_DIR = dirname(_LIB) +# gmtvtk.dll itself — that's the NSIS-installed / shared-runtime-cache layout, with no VTK/Qt +# toolchain on the destination machine at all. Detect that bundle and point straight at it; +# otherwise fall back to this dev machine's hard-coded toolchain paths (ENV overrides always +# win either way). const _BUNDLED = isdir(joinpath(_BIN_DIR, "platforms")) const _VTK_BIN = get(ENV, "INTERACTIVEGMT_VTK_BIN", _BUNDLED ? _BIN_DIR : raw"C:\programs\compa_libs\VTK-9.6.2\compileds\bin") const _QT_BIN = get(ENV, "INTERACTIVEGMT_QT_BIN", _BUNDLED ? _BIN_DIR : raw"C:\programs\Qt6\6.11.1\msvc2022_64\bin") diff --git a/src/selfupdate.jl b/src/selfupdate.jl new file mode 100644 index 0000000..a1be9ad --- /dev/null +++ b/src/selfupdate.jl @@ -0,0 +1,50 @@ +# selfupdate.jl — update!() pulls the latest InteractiveGMT source in place and rebuilds the +# binaries, for a `] dev`-installed checkout ONLY. +# +# Why this exists: `] dev https://github.com/GenericMappingTools/InteractiveGMT` clones ONCE to +# a fixed, permanent directory (~/.julia/dev/InteractiveGMT by default) that never moves again -- +# unlike a plain `Pkg.add`, which re-checks-out into a brand NEW content-hashed folder on every +# single `Pkg.update`. A fixed directory means a Desktop shortcut never goes stale. The one thing +# `dev` doesn't give you for free is an update mechanism: Pkg.update() deliberately skips dev'd +# packages (you're expected to manage their git state yourself). update!() is that missing piece +# — using Julia's BUNDLED LibGit2, not a system `git.exe`, so end users never need git installed. + +using LibGit2 +import Pkg + +""" + InteractiveGMT.update!() + +Pull the latest InteractiveGMT source in place (fast-forward only) and rebuild the binaries. +Only works for a `] dev`-installed checkout — a plain `Pkg.add` install should use +`Pkg.update("InteractiveGMT")` instead. +""" +function update!() + isdir(joinpath(_PKGROOT, ".git")) || error( + "InteractiveGMT at $_PKGROOT isn't a git checkout -- update! only works for a " * + "`] dev`-installed copy. For a plain `Pkg.add` install, use " * + "Pkg.update(\"InteractiveGMT\") instead.") + + repo = LibGit2.GitRepo(_PKGROOT) + try + @info "InteractiveGMT: fetching latest changes..." path=_PKGROOT + LibGit2.fetch(repo) + before = LibGit2.head_oid(repo) + ok = LibGit2.merge!(repo; fastforward=true) + ok || error("InteractiveGMT: local changes or diverged history -- couldn't fast-forward. " * + "This checkout is a normal git repo at $_PKGROOT; resolve manually (e.g. `git status`).") + after = LibGit2.head_oid(repo) + if before == after + @info "InteractiveGMT: already up to date." + return nothing + end + @info "InteractiveGMT: updated." from = string(before)[1:8] to = string(after)[1:8] + finally + close(repo) + end + + @info "InteractiveGMT: rebuilding binaries..." + Pkg.build("InteractiveGMT") + @info "InteractiveGMT: update complete. Restart Julia to use the new version." + return nothing +end From de8bdbd66d46ddd5e52726dfbe993262f5c0de71 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 00:11:34 +0000 Subject: [PATCH 5/5] Update PrecompileTools requirement to 1.3.4 Updates the requirements on [PrecompileTools](https://github.com/JuliaLang/PrecompileTools.jl) to permit the latest version. - [Release notes](https://github.com/JuliaLang/PrecompileTools.jl/releases) - [Commits](https://github.com/JuliaLang/PrecompileTools.jl/compare/v1.0.0...v1.3.4) --- updated-dependencies: - dependency-name: PrecompileTools dependency-version: 1.3.4 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- Project.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Project.toml b/Project.toml index 07f284c..b3e37af 100644 --- a/Project.toml +++ b/Project.toml @@ -16,6 +16,7 @@ Downloads = "1" GMT = "1.40" LibGit2 = "1" Pkg = "1" +PrecompileTools = "1.3.4" julia = "1.10" [extras]