26#include <rtl/bootstrap.hxx>
27#include <rtl/textenc.h>
28#include <rtl/ustring.hxx>
29#include <osl/process.h>
30#include <osl/conditn.hxx>
37#include <com/sun/star/deployment/DeploymentException.hpp>
38#include <com/sun/star/deployment/ExtensionManager.hpp>
40#include <com/sun/star/deployment/ui/PackageManagerDialog.hpp>
41#include <com/sun/star/lang/IllegalArgumentException.hpp>
42#include <com/sun/star/logging/ConsoleHandler.hpp>
43#include <com/sun/star/logging/FileHandler.hpp>
44#include <com/sun/star/logging/LogLevel.hpp>
45#include <com/sun/star/logging/SimpleTextFormatter.hpp>
46#include <com/sun/star/logging/XLogger.hpp>
47#include <com/sun/star/ucb/CommandAbortedException.hpp>
48#include <com/sun/star/ucb/CommandFailedException.hpp>
49#include <com/sun/star/ui/dialogs/XDialogClosedListener.hpp>
68 explicit ExtensionName( OUString str ) :
m_str(
std::move( str )) {}
69 bool operator () ( Reference<deployment::XPackage>
const & e )
const
72 ||
m_str == e->getName();
77const char16_t s_usingText [] =
79"using: " APP_NAME " add <options> extension-path...\n"
80" " APP_NAME " validate <options> extension-identifier...\n"
81" " APP_NAME " remove <options> extension-identifier...\n"
82" " APP_NAME " list <options> extension-identifier...\n"
90" validate checks the prerequisites of an installed extension and\n"
91" registers it if possible\n"
92" remove remove extensions by identifier\n"
93" reinstall expert feature: reinstall all deployed extensions\n"
94" list list information about deployed extensions\n"
95" gui raise Extensions dialog\n"
98" -h, --help this help\n"
99" -V, --version version information\n"
100" -v, --verbose verbose output\n"
101" -f, --force force overwriting existing extensions\n"
102" -s, --suppress-license prevents showing the license\n"
103" --log-file <file> custom log file; default: <cache-dir>/log.txt\n"
104" --shared expert feature: operate on shared installation\n"
105" deployment context;\n"
106" run only when no concurrent Office\n"
107" process(es) are running!\n"
108" --bundled expert feature: operate on bundled extensions. Only\n"
109" works with list, validate, reinstall;\n"
110" --deployment-context expert feature: explicit deployment context\n"
113"To learn more about extensions, see:\n"
114"https://wiki.documentfoundation.org/Documentation/DevGuide/Extensions\n\n";
117const OptionInfo s_option_infos [] = {
118 { RTL_CONSTASCII_STRINGPARAM(
"help"),
'h',
false },
119 { RTL_CONSTASCII_STRINGPARAM(
"version"),
'V',
false },
120 { RTL_CONSTASCII_STRINGPARAM(
"verbose"),
'v',
false },
121 { RTL_CONSTASCII_STRINGPARAM(
"force"),
'f',
false },
122 { RTL_CONSTASCII_STRINGPARAM(
"log-file"),
'\0',
true },
123 { RTL_CONSTASCII_STRINGPARAM(
"shared"),
'\0',
false },
124 { RTL_CONSTASCII_STRINGPARAM(
"deployment-context"),
'\0',
true },
125 { RTL_CONSTASCII_STRINGPARAM(
"bundled"),
'\0',
false},
126 { RTL_CONSTASCII_STRINGPARAM(
"suppress-license"),
's',
false},
128 {
nullptr, 0,
'\0',
false }
133 OUString
const & argument)
135 if (logger ==
nullptr) {
139 <<
OUStringToOString(message.replaceFirst(
"$1$", argument), RTL_TEXTENCODING_UTF8)
142 logger->
log(level, message, argument);
146class DialogClosedListenerImpl :
147 public ::cppu::WeakImplHelper< ui::dialogs::XDialogClosedListener >
149 osl::Condition & m_rDialogClosedCondition;
152 explicit DialogClosedListenerImpl( osl::Condition & rDialogClosedCondition )
153 : m_rDialogClosedCondition( rDialogClosedCondition ) {}
156 virtual void SAL_CALL disposing( lang::EventObject
const & Source )
override;
159 virtual void SAL_CALL dialogClosed(
160 ui::dialogs::DialogClosedEvent
const & aEvent )
override;
164void DialogClosedListenerImpl::disposing( lang::EventObject
const & )
170void DialogClosedListenerImpl::dialogClosed(
171 ui::dialogs::DialogClosedEvent
const & )
173 m_rDialogClosedCondition.set();
180Reference<deployment::XPackage> findPackage(
181 OUString
const & repository,
182 Reference<deployment::XExtensionManager>
const & manager,
183 Reference<ucb::XCommandEnvironment >
const & environment,
184 std::u16string_view idOrFileName )
186 const Sequence< Reference<deployment::XPackage> > ps(
187 manager->getDeployedExtensions(repository,
188 Reference<task::XAbortChannel>(), environment ) );
189 for (
auto const &
package : ps )
192 for (
auto const &
package : ps )
193 if (
package->getName() == idOrFileName )
195 return Reference<deployment::XPackage>();
203 bool bShowFailedMsg =
true;
205 bool option_shared =
false;
206 bool option_force =
false;
207 bool option_verbose =
false;
208 bool option_bundled =
false;
209 bool option_suppressLicense =
false;
210 bool option_help =
false;
211 bool subcmd_gui =
false;
215 std::vector<OUString> cmdPackages;
216 Reference<XLogHandler> xFileHandler;
217 Reference<XLogHandler> xConsoleHandler;
218 std::unique_ptr<comphelper::EventLogger> logger;
219 std::unique_ptr<utl::TempFileNamed> pUserProfileTempDir;
222 s_option_infos,
"shared" );
224 s_option_infos,
"force" );
226 s_option_infos,
"verbose" );
228 s_option_infos,
"log-file" );
230 s_option_infos,
"deployment-context" );
232 s_option_infos,
"help" );
234 s_option_infos,
"version" );
236 s_option_infos,
"bundled" );
238 s_option_infos,
"suppress-license" );
241 Reference<XComponentContext> xComponentContext;
242 Reference<XComponentContext> xLocalComponentContext;
246 sal_uInt32
nCount = osl_getCommandArgCount();
263 osl_getCommandArg(
nPos, &subCommand.pData );
265 subCommand = subCommand.trim();
266 bool subcmd_add = subCommand ==
"add";
267 subcmd_gui = subCommand ==
"gui";
280 !
readOption( &option_suppressLicense, info_suppressLicense, &
nPos ) &&
285 osl_getCommandArg(
nPos, &cmdArg.pData );
287 cmdArg = cmdArg.trim();
288 if (!cmdArg.isEmpty())
290 if (cmdArg[ 0 ] ==
'-')
294 "\nERROR: unexpected option " +
298 " to print all options.\n"));
304 cmdPackages.push_back(
305 subcmd_add || subcmd_gui
318 pUserProfileTempDir->EnableKillingFile();
321 xComponentContext =
getUNO(option_verbose, subcmd_gui,
322 pUserProfileTempDir ? pUserProfileTempDir->GetURL() :
"",
323 xLocalComponentContext);
328 const Reference<XLogger> xLogger(logger->getLogger());
329 xLogger->setLevel(LogLevel::WARNING);
331 Sequence < beans::NamedValue >
aSeq { {
"Formatter",
Any(xLogFormatter) } };
333 xConsoleHandler.set(ConsoleHandler::createWithSettings(xLocalComponentContext,
aSeq));
334 xLogger->addLogHandler(xConsoleHandler);
335 xConsoleHandler->setLevel(LogLevel::WARNING);
336 xLogger->setLevel(LogLevel::WARNING);
339 if (!logFile.isEmpty())
341 Sequence < beans::NamedValue > aSeq2 { {
"Formatter",
Any(xLogFormatter) }, {
"FileURL",
Any(logFile)} };
342 xFileHandler.set(css::logging::FileHandler::createWithSettings(xLocalComponentContext, aSeq2));
343 xFileHandler->setLevel(LogLevel::WARNING);
344 xLogger->addLogHandler(xFileHandler);
349 xLogger->setLevel(LogLevel::INFO);
350 xConsoleHandler->setLevel(LogLevel::INFO);
351 if (xFileHandler.is())
352 xFileHandler->setLevel(LogLevel::INFO);
355 if (repository.isEmpty())
358 repository =
"shared";
359 else if (option_bundled)
360 repository =
"bundled";
366 if ( repository ==
"shared" ) {
367 option_shared =
true;
369 else if (option_shared)
371 logger->log(LogLevel::WARNING,
"Explicit context given! Ignoring option '$1$'",
toString(info_shared));
375 if ( geteuid() == 0 )
377 if ( !(option_shared || option_bundled || option_help) )
379 logger->log(LogLevel::SEVERE,
"Cannot run $1$ as root without $2$ or $3$ option.",
386 if (subCommand ==
"reinstall")
390 OUString extensionUnorc;
391 if (repository ==
"user")
392 extensionUnorc =
"$UNO_USER_PACKAGES_CACHE/registry/com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc";
393 else if (repository ==
"shared")
394 extensionUnorc =
"$SHARED_EXTENSIONS_USER/registry/com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc";
395 else if (repository ==
"bundled")
396 extensionUnorc =
"$BUNDLED_EXTENSIONS_USER/registry/com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc";
400 ::rtl::Bootstrap::expandMacros(extensionUnorc);
401 oslFileError e = osl_removeFile(extensionUnorc.pData);
402 if (e != osl_File_E_None && e != osl_File_E_NOENT)
403 throw Exception(
"Could not delete " + extensionUnorc,
nullptr);
406 Reference<deployment::XExtensionManager> xExtensionManager(
407 deployment::ExtensionManager::get( xComponentContext ) );
409 Reference<css::ucb::XCommandEnvironment> xCmdEnv(
410 createCmdEnv(xComponentContext, option_force, option_verbose, option_suppressLicense));
416 if (!subcmd_gui && subCommand !=
"reinstall"
420 if ( subcmd_add || subCommand ==
"remove" )
422 for (
const OUString & cmdPackage : cmdPackages)
426 beans::NamedValue nvSuppress(
427 "SUPPRESS_LICENSE", option_suppressLicense ?
428 Any(OUString(
"1")):
Any(OUString(
"0")));
429 xExtensionManager->addExtension(
430 cmdPackage, Sequence<beans::NamedValue>(&nvSuppress, 1),
431 repository, Reference<task::XAbortChannel>(), xCmdEnv);
437 xExtensionManager->removeExtension(
438 cmdPackage, cmdPackage, repository,
439 Reference<task::XAbortChannel>(), xCmdEnv );
441 catch (
const lang::IllegalArgumentException &)
443 Reference<deployment::XPackage>
p(
444 findPackage(repository,
445 xExtensionManager, xCmdEnv, cmdPackage ) );
449 xExtensionManager->removeExtension(
452 Reference<task::XAbortChannel>(), xCmdEnv );
457 else if ( subCommand ==
"reinstall" )
459 xExtensionManager->reinstallDeployedExtensions(
460 false, repository, Reference<task::XAbortChannel>(), xCmdEnv);
462 else if ( subCommand ==
"list" )
464 std::vector<Reference<deployment::XPackage> > vecExtUnaccepted;
465 ::comphelper::sequenceToContainer(vecExtUnaccepted,
466 xExtensionManager->getExtensionsWithUnacceptedLicenses(
467 repository, xCmdEnv));
471 std::vector<bool> vecUnaccepted;
472 std::vector<Reference<deployment::XPackage> > allExtensions;
473 if (cmdPackages.empty())
475 Sequence< Reference<deployment::XPackage> >
476 packages = xExtensionManager->getDeployedExtensions(
477 repository, Reference<task::XAbortChannel>(), xCmdEnv );
479 std::vector<Reference<deployment::XPackage> > vec_packages;
480 ::comphelper::sequenceToContainer(vec_packages, packages);
484 allExtensions.resize(vecExtUnaccepted.size() + vec_packages.size());
486 std::vector<Reference<deployment::XPackage> >::iterator i_all_ext =
487 std::copy(vecExtUnaccepted.begin(), vecExtUnaccepted.end(),
488 allExtensions.begin());
490 std::copy(vec_packages.begin(), vec_packages.end(), i_all_ext);
494 vecUnaccepted.resize(vecExtUnaccepted.size() + vec_packages.size());
495 std::fill_n(vecUnaccepted.begin(), vecExtUnaccepted.size(),
true);
496 std::fill_n(vecUnaccepted.begin() + vecExtUnaccepted.size(),
497 vec_packages.size(),
false);
500 Concat2View(
"All deployed " + repository +
" extensions:\n\n"));
506 for (
const OUString & cmdPackage : cmdPackages)
508 Reference<deployment::XPackage> extension;
511 extension = xExtensionManager->getDeployedExtension(
512 repository, cmdPackage, cmdPackage, xCmdEnv );
514 catch (
const lang::IllegalArgumentException &)
516 extension = findPackage(repository,
517 xExtensionManager, xCmdEnv, cmdPackage );
521 bool bUnacceptedLic =
false;
524 std::vector<Reference<deployment::XPackage> >::const_iterator
526 vecExtUnaccepted.begin(),
527 vecExtUnaccepted.end(), ExtensionName(cmdPackage));
528 if (
i != vecExtUnaccepted.end())
531 bUnacceptedLic =
true;
536 throw lang::IllegalArgumentException(
537 "There is no such extension deployed: " +
538 cmdPackage,
nullptr,-1);
539 allExtensions.push_back(extension);
540 vecUnaccepted.push_back(bUnacceptedLic);
547 else if ( subCommand ==
"validate" )
549 std::vector<Reference<deployment::XPackage> > vecExtUnaccepted;
550 ::comphelper::sequenceToContainer(
551 vecExtUnaccepted, xExtensionManager->getExtensionsWithUnacceptedLicenses(
552 repository, xCmdEnv));
554 for (
const OUString & cmdPackage : cmdPackages)
556 Reference<deployment::XPackage> extension;
559 extension = xExtensionManager->getDeployedExtension(
560 repository, cmdPackage, cmdPackage, xCmdEnv );
562 catch (
const lang::IllegalArgumentException &)
564 extension = findPackage(
565 repository, xExtensionManager, xCmdEnv, cmdPackage );
570 std::vector<Reference<deployment::XPackage> >::const_iterator
572 vecExtUnaccepted.begin(),
573 vecExtUnaccepted.end(), ExtensionName(cmdPackage));
574 if (
i != vecExtUnaccepted.end())
581 xExtensionManager->checkPrerequisitesAndEnable(
582 extension, Reference<task::XAbortChannel>(), xCmdEnv);
585 else if ( subCommand ==
"gui" )
587 Reference<ui::dialogs::XAsynchronousExecutableDialog> xDialog(
588 deployment::ui::PackageManagerDialog::createAndInstall(
590 !cmdPackages.empty() ? cmdPackages[0] : OUString() ));
592 osl::Condition dialogEnded;
595 Reference< ui::dialogs::XDialogClosedListener > xListener(
596 new DialogClosedListenerImpl( dialogEnded ) );
598 xDialog->startExecuteModal(xListener);
604 logger->log(LogLevel::SEVERE,
605 "Unknown sub-command: '$1$'. Use $2$ $3$ to print all options.",
610 logger->log(LogLevel::INFO,
"$1$ done.",
APP_NAME);
613 css::uno::Reference<css::lang::XComponent>(
614 xLocalComponentContext, css::uno::UNO_QUERY_THROW)->dispose();
617 catch (
const ucb::CommandFailedException &e)
619 logFatal(logger.get(), LogLevel::SEVERE,
"Exception occurred: $1$", e.Message);
621 catch (
const ucb::CommandAbortedException &)
623 logFatal(logger.get(), LogLevel::SEVERE,
"$1$ aborted.",
APP_NAME);
624 bShowFailedMsg =
false;
626 catch (
const deployment::DeploymentException & exc)
628 logFatal(logger.get(), LogLevel::SEVERE,
"Exception occurred: $1$", exc.Message);
632 catch (
const LockFileException & e)
636 bShowFailedMsg =
false;
638 catch (
const css::uno::Exception & e ) {
639 Any exc( ::cppu::getCaughtException() );
641 logFatal(logger.get(), LogLevel::SEVERE,
"Exception occurred: $1$", e.Message);
645 logFatal(logger.get(), LogLevel::SEVERE,
"$1$ failed.",
APP_NAME);
647 if (xLocalComponentContext.is()) {
648 css::uno::Reference<css::lang::XComponent>(
649 xLocalComponentContext, css::uno::UNO_QUERY_THROW)->dispose();
void log(const sal_Int32 _nLogLevel, const OUString &rMessage) const
rtl::Reference< ParseManager > manager
Sequence< sal_Int8 > aSeq
OUString anyToString(uno::Any const &value)
void syncRepositories(bool force, Reference< ucb::XCommandEnvironment > const &xCmdEnv)
void writeConsoleError(std::u16string_view sText)
writes the argument to the console using the error stream.
void writeConsole(std::u16string_view sText)
writes the argument string to the console.
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC OUString getIdentifier(css::uno::Reference< css::deployment::XPackage > const &package)
Gets the identifier of a package.
void disposeBridges(Reference< css::uno::XComponentContext > const &ctx)
css::uno::Reference< css::deployment::XPackageRegistry > create(css::uno::Reference< css::deployment::XPackageRegistry > const &xRootRegistry, OUString const &context, OUString const &cachePath, css::uno::Reference< css::uno::XComponentContext > const &xComponentContext)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
Reference< XCommandEnvironment > createCmdEnv(Reference< XComponentContext > const &xContext, bool option_force_overwrite, bool option_verbose, bool option_suppress_license)
Reference< XComponentContext > getUNO(bool verbose, bool bGui, const OUString &sTempDir, Reference< XComponentContext > &out_localContext)
OUString toString(OptionInfo const *info)
bool isOption(OptionInfo const *option_info, sal_uInt32 *pIndex)
bool readOption(bool *flag, OptionInfo const *option_info, sal_uInt32 *pIndex)
OUString const & getProcessWorkingDir()
bool readArgument(OUString *pValue, OptionInfo const *option_info, sal_uInt32 *pIndex)
void printf_packages(std::vector< Reference< deployment::XPackage > > const &allExtensions, std::vector< bool > const &vecUnaccepted, Reference< XCommandEnvironment > const &xCmdEnv, sal_Int32 level)
bool isBootstrapVariable(sal_uInt32 *pIndex)
checks if an argument is a bootstrap variable.
OptionInfo const * getOptionInfo(OptionInfo const *list, OUString const &opt)
OUString makeAbsoluteFileUrl(OUString const &sys_path, OUString const &base_url)