diff --git a/README.md b/README.md index d43568a..15ae172 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,13 @@ Notice: `WhatsNew` is not supported. ### File based deployment -The app uri can be a file:// based url instead of an web uri if your application is hosted on a common network location for your users. +The app uri can be a `file://` based url instead of a web uri if your application is hosted on a common network location for your users. + +#### UNC Paths +FXLauncher can deal with [UNC paths], if you ask it nicely. Instead of `\\server\share\myapp` use `file:////server/share/myapp`. +Yes, that's four forward slashes; two for the `file://` protocol and two for the UNC path. + +[UNC paths]: https://www.lifewire.com/unc-universal-naming-convention-818230 ### Native installers @@ -116,16 +122,26 @@ Check out these prebuilt installers for a more complex demo application ## Specify cache directory -By default, the artifacts are downloaded to the current working directory. This is usually fine for native installers, but if you distribute -your application via just the launcher jar, you might want to specify where the downloaded artifacts land. See the -[cache dir documentation](https://github.com/edvin/fxlauncher/wiki/Optional-Cache-Directory) for more information. +By default, the artifacts are downloaded to the current working directory. This is usually fine for per-user native +installers, but if you distribute your application via a system-wide native installer, or just the launcher +jar, you might want to specify where the downloaded artifacts land. See the +[cache dir documentation] for more information. + +[cache dir documentation]: https://github.com/edvin/fxlauncher/wiki/Optional-Cache-Directory ## Installation location -It's worth noting that the two package alternatives for Windows, (EXE and MSI) have different install location defaults. -While EXE will default to %APPDATALOCAL%, the MSI installer will default to %ProgramFiles%. If you use the MSI installer you -might therefore need to specify the cache dir parameter as `cacheDir 'USERLIB/MyApp'` to make sure that the launcher has -write access to download the artifacts for your application. +It's worth noting that the two package alternatives for Windows, (EXE and MSI) have different default install locations. +While EXE will default to [`%AppDataLocal%`], the MSI installer will default to `%ProgramFiles%`. To write to +`%ProgramFiles%` one definitely does need admin privileges—that poses a problem for FXLauncher which, by default, +downloads updates to where it was installed. + +If you use the MSI installer you will therefore need to tell FXLauncher to cache artifacts somewhere it is allowed +to put them. For an OS-independent answer to this problem, look no further than the +[two magical strings][cache dir documentation], `USERLIB` and `ALLUSERS`. + + +[`%AppDataLocal%`]: https://www.howtogeek.com/318177/what-is-the-appdata-folder-in-windows/ Read more about Java Packager in the official documentation: diff --git a/src/main/java/fxlauncher/AbstractLauncher.java b/src/main/java/fxlauncher/AbstractLauncher.java index 172932a..6d097fe 100644 --- a/src/main/java/fxlauncher/AbstractLauncher.java +++ b/src/main/java/fxlauncher/AbstractLauncher.java @@ -125,7 +125,12 @@ protected boolean syncFiles() throws Exception { Path target = cacheDir.resolve(lib.file).toAbsolutePath(); Files.createDirectories(target.getParent()); - URI uri = manifest.uri.resolve(lib.file); + URI uri; + + // We avoid using uri.resolve() here so as to not break UNC paths. See issue #143 + String separator = manifest.uri.getPath().endsWith("/") ? "" : "/"; + uri = URI.create(manifest.uri.toString() + separator + lib.file); + try (InputStream input = openDownloadStream(uri); OutputStream output = Files.newOutputStream(target)) { @@ -184,6 +189,10 @@ protected void syncManifest() throws Exception { log.info(String.format("Loading manifest from 'app' parameter supplied: %s", appStr)); } + if (appStr != null && !appStr.endsWith("/")) { + appStr += "/"; + } + if (namedParams.containsKey("uri")) { // get --uri-param String uriStr = namedParams.get("uri"); @@ -192,9 +201,15 @@ protected void syncManifest() throws Exception { } log.info(String.format("Syncing files from 'uri' parameter supplied: %s", uriStr)); + if (!uriStr.endsWith("/")) { + uriStr += "/"; + } URI uri = URI.create(uriStr); + // load manifest from --app param if supplied, else default file at supplied uri - URI app = appStr != null ? URI.create(appStr) : uri.resolve("app.xml"); + URI app = (appStr != null) + ? URI.create(appStr) + : URI.create(uriStr + "app.xml"); // We avoid using uri.resolve() here so as to not break UNC paths. See issue #143 manifest = FXManifest.load(app); // set supplied uri in manifest manifest.uri = uri; diff --git a/src/main/java/fxlauncher/FXManifest.java b/src/main/java/fxlauncher/FXManifest.java index c020a92..62df620 100644 --- a/src/main/java/fxlauncher/FXManifest.java +++ b/src/main/java/fxlauncher/FXManifest.java @@ -65,10 +65,11 @@ public String getFilename() { } public URI getFXAppURI() { - if (uri.getPath().endsWith("/")) - return uri.resolve("app.xml"); - return URI.create(uri.toString() + "/app.xml"); + String separator = uri.getPath().endsWith("/") ? "" : "/"; + + // We avoid using uri.resolve() here so as to not break UNC paths. See issue #143 + return URI.create(uri.toString() + separator + "app.xml"); } public Path getPath(Path cacheDir) {