[Libreoffice-commits] core.git: Branch 'libreoffice-6-2' - desktop/source distro-configs/LibreOfficeFlatpak.conf include/sfx2 sfx2/source solenv/flatpak-manifest.in
Libreoffice Gerrit user
logerrit at kemper.freedesktop.org
Thu Dec 20 21:32:28 UTC 2018
desktop/source/app/app.cxx | 2
distro-configs/LibreOfficeFlatpak.conf | 1
include/sfx2/sfxhelp.hxx | 2
sfx2/source/appl/sfxhelp.cxx | 258 ++++++++++++++++++++++++++++++++-
solenv/flatpak-manifest.in | 8 +
5 files changed, 268 insertions(+), 3 deletions(-)
New commits:
commit e03924c5d8a817e0ea5b56b96185aca152836dc9
Author: Stephan Bergmann <sbergman at redhat.com>
AuthorDate: Wed Dec 12 17:13:03 2018 +0100
Commit: Caolán McNamara <caolanm at redhat.com>
CommitDate: Thu Dec 20 22:32:02 2018 +0100
Enable --help=html for flatpak
To not increase the size of the main org.libreoffice.LibreOffice app further,
the plan was to realize this as an org.libreoffice.LibreOffice.Help extension.
Ideally, this would be a localized extension, so that, by default, only a
relevant subset of the extension would be downloaded and installed. (But see
below.)
There are multiple technical problems, as discussed at <https://github.com/
flathub/org.libreoffice.LibreOffice/issues/35#issuecomment-447295308> "Add
integrated LibreOffice Help offline":
* LO can't pass a file URL with query part to xdg-open, so uses a temporary
wrapper .html file that redirects to the target URL. But for the flatpak case
this wrapper can't be in /tmp (which isn't visible from outside the flatpak
sandbox), but is instead stored in a new temp dir under $XDG_CACHE_HOME (which
is always set for flatpaks and /is/ visible form the outside) that is
removed on LO exit.
* The file URL stored in the temp file must be rewritten from the internal path
(/app/libreoffice/help/...) to the path as seen outside the flatpak sandbox.
While the path for the org.libreoffice.LibreOffice /app is stored in
/.flatpak-info, the external path for the org.libreoffice.LibreOffice.Help
extension is different and not stored there. So use a hack trying to
construct that path from what information is available in /.flatpak-info.
* But the help content consists of locale-specific and shared files, and those
reference each other with relative links. But a localized flatpak extension
cannot contain shared files, it can only contain per-language sub-dirs. And
if the shared help files were kept out of the extension, as part of the app
itself, the relative paths among these files inside the flatpak sandbox would
differ from those outside of it, so would be broken when viewing the content
in the external browser. A solution would either (a) need to somehow rewrite
the content of all the help files being served from LO to the external
browser, or (b) replicate the shared help files in all the extension's per-
language sub-dirs (and if some localization uses en-US content as a fallback
for only part of its translated content, e.g., in the case of media files,
would need to also replicate that en-US content), or (c) use a non-localized
extension that always contains the content for all localizations.
For now, I chose the third approach. This makes the
org.libreoffice.LibreOffice.Help extension relatively large (the current
/app/libreoffice/help tree has a size of ca. 100MB), so that I decided to not
have it downloaded and installed automatically ("no-autodownload": true in
solenv/flatpak-manifest.in). (I checked with Flatpak 1.0.6 that if the
extension should be changed to a localized one with the same name in the future,
updating from an older version would work. If the old extension was not
installed, just the relevant localizations of the new version will be downloaded
and installed. If the old extension was installed, the full set of
localizations of the new version will be downloaded and installed.)
(As also mentioned at <https://github.com/flathub/org.libreoffice.LibreOffice/
issues/35#issuecomment-447295308>: "A second, minor, nuisance is that, for
security reasons, an `xdg-open file:///...html` call from a flatpak leads to an
intermediate popup dialog letting the user chose which application to use to
open the URI, while e.g. an `xdg-open http:///...html` is allowed to go directly
to the user's preferred browser. So accessing help content from LO flatpak
would present that popup dialog first, forcing the user to select a browser to
proceed.")
Reviewed-on: https://gerrit.libreoffice.org/65451
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman at redhat.com>
(cherry picked from commit 72b936d70b7eaa6d9f5f911b27e3c955382de967)
Change-Id: I35f5a23947dd551dc1b9bff1dd2abd6710073b5f
Reviewed-on: https://gerrit.libreoffice.org/65482
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm at redhat.com>
Tested-by: Caolán McNamara <caolanm at redhat.com>
diff --git a/desktop/source/app/app.cxx b/desktop/source/app/app.cxx
index b74defb1f640..03448b5f1a41 100644
--- a/desktop/source/app/app.cxx
+++ b/desktop/source/app/app.cxx
@@ -108,6 +108,7 @@
#include <vcl/help.hxx>
#include <vcl/weld.hxx>
#include <vcl/settings.hxx>
+#include <sfx2/sfxhelp.hxx>
#include <sfx2/sfxsids.hrc>
#include <sfx2/app.hxx>
#include <sfx2/safemode.hxx>
@@ -1711,6 +1712,7 @@ int Desktop::doShutdown()
// remove temp directory
RemoveTemporaryDirectory();
+ SfxHelp::removeFlatpakHelpTemporaryDirectory();
// flush evtl. configuration changes so that all config files in user
// dir are written
diff --git a/distro-configs/LibreOfficeFlatpak.conf b/distro-configs/LibreOfficeFlatpak.conf
index be8689996c85..c0c79b7ce959 100644
--- a/distro-configs/LibreOfficeFlatpak.conf
+++ b/distro-configs/LibreOfficeFlatpak.conf
@@ -3,6 +3,7 @@
--enable-release-build
--with-ant-home=/run/build/libreoffice/ant
--with-extra-buildid=Flatpak
+--with-help=html
--with-jdk-home=/usr/lib/sdk/openjdk10/jvm/openjdk-10
--with-lang=ALL
--with-system-libs
diff --git a/include/sfx2/sfxhelp.hxx b/include/sfx2/sfxhelp.hxx
index 99ca1a062f04..d7afeb2b9af0 100644
--- a/include/sfx2/sfxhelp.hxx
+++ b/include/sfx2/sfxhelp.hxx
@@ -53,6 +53,8 @@ public:
static OUString GetCurrentModuleIdentifier();
// Check for built-in help
static bool IsHelpInstalled();
+
+ static void removeFlatpakHelpTemporaryDirectory();
};
#endif // INCLUDED_SFX2_SFXHELP_HXX
diff --git a/sfx2/source/appl/sfxhelp.cxx b/sfx2/source/appl/sfxhelp.cxx
index 4f753c6b442d..9e457b7968a8 100644
--- a/sfx2/source/appl/sfxhelp.cxx
+++ b/sfx2/source/appl/sfxhelp.cxx
@@ -22,6 +22,8 @@
#include <set>
#include <algorithm>
+#include <cassert>
+
#include <sal/log.hxx>
#include <com/sun/star/uno/Reference.h>
#include <com/sun/star/frame/Desktop.hpp>
@@ -47,12 +49,14 @@
#include <tools/urlobj.hxx>
#include <ucbhelper/content.hxx>
#include <unotools/pathoptions.hxx>
+#include <rtl/byteseq.hxx>
#include <rtl/ustring.hxx>
#include <officecfg/Office/Common.hxx>
#include <osl/process.h>
#include <osl/file.hxx>
#include <unotools/bootstrap.hxx>
#include <unotools/tempfile.hxx>
+#include <unotools/ucbhelper.hxx>
#include <rtl/uri.hxx>
#include <vcl/commandinfoprovider.hxx>
#include <vcl/layout.hxx>
@@ -727,6 +731,232 @@ static bool impl_showOnlineHelp( const OUString& rURL )
return false;
}
+namespace {
+
+bool isFlatpak() {
+ static auto const flatpak = [] { return std::getenv("LIBO_FLATPAK") != nullptr; }();
+ return flatpak;
+}
+
+bool rewriteFlatpakHelpRootUrl(OUString * helpRootUrl) {
+ assert(helpRootUrl != nullptr);
+ //TODO: This function for now assumes that the passed-in *helpRootUrl references
+ // /app/libreoffice/help (which belongs to the org.libreoffice.LibreOffice.Help
+ // extension); it replaces it with the correpsonding file URL as seen outside the flatpak
+ // sandbox:
+ struct Failure: public std::exception {};
+ try {
+ static auto const url = [] {
+ // From /.flatpak-info [Instance] section, read
+ // app-path=<path>
+ // app-extensions=...;org.libreoffice.LibreOffice.Help=<sha>;...
+ // lines:
+ osl::File ini("file:///.flatpak-info");
+ auto err = ini.open(osl_File_OpenFlag_Read);
+ if (err != osl::FileBase::E_None) {
+ SAL_WARN("sfx.appl", "LIBO_FLATPAK mode failure opening /.flatpak-info: " << err);
+ throw Failure();
+ }
+ OUString path;
+ OUString extensions;
+ bool havePath = false;
+ bool haveExtensions = false;
+ for (bool instance = false; !(havePath && haveExtensions);) {
+ rtl::ByteSequence bytes;
+ err = ini.readLine(bytes);
+ if (err != osl::FileBase::E_None) {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode reading /.flatpak-info fails with " << err
+ << " before [Instance] app-path");
+ throw Failure();
+ }
+ o3tl::string_view const line(
+ reinterpret_cast<char const *>(bytes.getConstArray()), bytes.getLength());
+ if (instance) {
+ static constexpr auto keyPath = OUStringLiteral("app-path=");
+ static constexpr auto keyExtensions = OUStringLiteral("app-extensions=");
+ if (!havePath && line.length() >= unsigned(keyPath.size)
+ && line.substr(0, keyPath.size) == keyPath.data)
+ {
+ auto const value = line.substr(keyPath.size);
+ if (!rtl_convertStringToUString(
+ &path.pData, value.data(), value.length(),
+ osl_getThreadTextEncoding(),
+ (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
+ | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
+ | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
+ {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode failure converting app-path \"" << value
+ << "\" encoding");
+ throw Failure();
+ }
+ havePath = true;
+ } else if (!haveExtensions && line.length() >= unsigned(keyExtensions.size)
+ && line.substr(0, keyExtensions.size) == keyExtensions.data)
+ {
+ auto const value = line.substr(keyExtensions.size);
+ if (!rtl_convertStringToUString(
+ &extensions.pData, value.data(), value.length(),
+ osl_getThreadTextEncoding(),
+ (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
+ | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
+ | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
+ {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode failure converting app-extensions \"" << value
+ << "\" encoding");
+ throw Failure();
+ }
+ haveExtensions = true;
+ } else if (line.length() > 0 && line[0] == '[') {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode /.flatpak-info lacks [Instance] app-path and"
+ " app-extensions");
+ throw Failure();
+ }
+ } else if (line == "[Instance]") {
+ instance = true;
+ }
+ }
+ ini.close();
+ // Extract <sha> from ...;org.libreoffice.LibreOffice.Help=<sha>;...:
+ OUString sha;
+ for (sal_Int32 i = 0;;) {
+ OUString elem;
+ elem = extensions.getToken(0, ';', i);
+ if (elem.startsWith("org.libreoffice.LibreOffice.Help=", &sha)) {
+ break;
+ }
+ if (i == -1) {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode /.flatpak-info [Instance] app-extensions \""
+ << extensions << "\" org.libreoffice.LibreOffice.Help");
+ throw Failure();
+ }
+ }
+ // Assuming that <path> is of the form
+ // /.../app/org.libreoffice.LibreOffice/<arch>/<branch>/<sha'>/files
+ // rewrite it as
+ // /.../runtime/org.libreoffice.LibreOffice.Help/<arch>/<branch>/<sha>/files
+ // because the extension's files are stored at a different place than the app's files,
+ // so use this hack until flatpak itself provides a better solution:
+ static constexpr auto segments = OUStringLiteral("/app/org.libreoffice.LibreOffice/");
+ auto const i1 = path.lastIndexOf(segments);
+ // use lastIndexOf instead of indexOf, in case the user-controlled prefix /.../
+ // happens to contain such segments
+ if (i1 == -1) {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode /.flatpak-info [Instance] app-path \"" << path
+ << "\" doesn't contain /app/org.libreoffice.LibreOffice/");
+ throw Failure();
+ }
+ auto const i2 = i1 + segments.size;
+ auto i3 = path.indexOf('/', i2);
+ if (i3 == -1) {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode /.flatpak-info [Instance] app-path \"" << path
+ << "\" doesn't contain branch segment");
+ throw Failure();
+ }
+ i3 = path.indexOf('/', i3 + 1);
+ if (i3 == -1) {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode /.flatpak-info [Instance] app-path \"" << path
+ << "\" doesn't contain sha segment");
+ throw Failure();
+ }
+ ++i3;
+ auto const i4 = path.indexOf('/', i3);
+ if (i4 == -1) {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode /.flatpak-info [Instance] app-path \"" << path
+ << "\" doesn't contain files segment");
+ throw Failure();
+ }
+ path = path.copy(0, i1) + "/runtime/org.libreoffice.LibreOffice.Help/"
+ + path.copy(i2, i3 - i2) + sha + path.copy(i4);
+ // Turn <path> into a file URL:
+ OUString url_;
+ err = osl::FileBase::getFileURLFromSystemPath(path, url_);
+ if (err != osl::FileBase::E_None) {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode failure converting app-path \"" << path << "\" to URL: "
+ << err);
+ throw Failure();
+ }
+ return url_;
+ }();
+ *helpRootUrl = url;
+ return true;
+ } catch (Failure &) {
+ return false;
+ }
+}
+
+// Must only be accessed with SolarMutex locked:
+static struct {
+ bool created = false;
+ OUString url;
+} flatpakHelpTemporaryDirectoryStatus;
+
+bool createFlatpakHelpTemporaryDirectory(OUString ** url) {
+ assert(url != nullptr);
+ DBG_TESTSOLARMUTEX();
+ if (!flatpakHelpTemporaryDirectoryStatus.created) {
+ auto const env = std::getenv("XDG_CACHE_HOME");
+ if (env == nullptr) {
+ SAL_WARN("sfx.appl", "LIBO_FLATPAK mode but unset XDG_CACHE_HOME");
+ return false;
+ }
+ OUString path;
+ if (!rtl_convertStringToUString(
+ &path.pData, env, std::strlen(env), osl_getThreadTextEncoding(),
+ (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
+ | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
+ {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode failure converting XDG_CACHE_HOME \"" << env << "\" encoding");
+ return false;
+ }
+ OUString parent;
+ auto const err = osl::FileBase::getFileURLFromSystemPath(path, parent);
+ if (err != osl::FileBase::E_None) {
+ SAL_WARN(
+ "sfx.appl",
+ "LIBO_FLATPAK mode failure converting XDG_CACHE_HOME \"" << path << "\" to URL: "
+ << err);
+ return false;
+ }
+ if (!parent.endsWith("/")) {
+ parent += "/";
+ }
+ auto const tmp = utl::TempFile(&parent, true);
+ if (!tmp.IsValid()) {
+ SAL_WARN(
+ "sfx.appl", "LIBO_FLATPAK mode failure creating temp dir at <" << parent << ">");
+ return false;
+ }
+ flatpakHelpTemporaryDirectoryStatus.url = tmp.GetURL();
+ flatpakHelpTemporaryDirectoryStatus.created = true;
+ }
+ *url = &flatpakHelpTemporaryDirectoryStatus.url;
+ return true;
+}
+
+}
+
#define SHTML1 "<!DOCTYPE HTML><html lang=\"en-US\"><head><meta charset=\"UTF-8\">"
#define SHTML2 "<meta http-equiv=\"refresh\" content=\"1\" url=\""
#define SHTML3 "\"><script type=\"text/javascript\"> window.location.href = \""
@@ -734,16 +964,26 @@ static bool impl_showOnlineHelp( const OUString& rURL )
static bool impl_showOfflineHelp( const OUString& rURL )
{
- const OUString& aBaseInstallPath = getHelpRootURL();
+ OUString aBaseInstallPath = getHelpRootURL();
+ // For the flatpak case, find the pathname outside the flatpak sandbox that corresponds to
+ // aBaseInstallPath, because that is what needs to be stored in aTempFile below:
+ if (isFlatpak() && !rewriteFlatpakHelpRootUrl(&aBaseInstallPath)) {
+ return false;
+ }
OUString aHelpLink( aBaseInstallPath + "/index.html?" );
OUString aTarget = "Target=" + rURL.copy(RTL_CONSTASCII_LENGTH("vnd.sun.star.help://"));
aTarget = aTarget.replaceAll("%2F","/").replaceAll("?","&");
aHelpLink += aTarget;
- // get a html tempfile
+ // Get a html tempfile (for the flatpak case, create it in XDG_CACHE_HOME instead of /tmp for
+ // technical reasons, so that it can be accessed by the browser running outside the sandbox):
OUString const aExtension(".html");
- ::utl::TempFile aTempFile("NewHelp", true, &aExtension, nullptr, false );
+ OUString * parent = nullptr;
+ if (isFlatpak() && !createFlatpakHelpTemporaryDirectory(&parent)) {
+ return false;
+ }
+ ::utl::TempFile aTempFile("NewHelp", true, &aExtension, parent, false );
SvStream* pStream = aTempFile.GetStream(StreamMode::WRITE);
pStream->SetStreamCharSet(RTL_TEXTENCODING_UTF8);
@@ -1132,4 +1372,16 @@ bool SfxHelp::IsHelpInstalled()
return impl_hasHelpInstalled();
}
+void SfxHelp::removeFlatpakHelpTemporaryDirectory() {
+ DBG_TESTSOLARMUTEX();
+ if (flatpakHelpTemporaryDirectoryStatus.created) {
+ if (!utl::UCBContentHelper::Kill(flatpakHelpTemporaryDirectoryStatus.url)) {
+ SAL_INFO(
+ "sfx.appl",
+ "LIBO_FLATPAK mode failure removing directory <"
+ << flatpakHelpTemporaryDirectoryStatus.url << ">");
+ }
+ }
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/solenv/flatpak-manifest.in b/solenv/flatpak-manifest.in
index 6f654c998263..4647aa2d7c59 100644
--- a/solenv/flatpak-manifest.in
+++ b/solenv/flatpak-manifest.in
@@ -559,6 +559,14 @@
]
}
],
+ "add-extensions": {
+ "org.libreoffice.LibreOffice.Help": {
+ "directory": "libreoffice/help",
+ "bundle": true,
+ "autodelete": true,
+ "no-autodownload": true
+ }
+ },
"finish-args": [
"--share=network",
"--share=ipc",
More information about the Libreoffice-commits
mailing list