26 #include <rtl/bootstrap.hxx>
27 #include <osl/process.h>
28 #include <osl/conditn.hxx>
35 #include <com/sun/star/deployment/DeploymentException.hpp>
36 #include <com/sun/star/deployment/ExtensionManager.hpp>
38 #include <com/sun/star/deployment/ui/PackageManagerDialog.hpp>
39 #include <com/sun/star/lang/IllegalArgumentException.hpp>
40 #include <com/sun/star/logging/ConsoleHandler.hpp>
41 #include <com/sun/star/logging/FileHandler.hpp>
42 #include <com/sun/star/logging/LogLevel.hpp>
43 #include <com/sun/star/logging/SimpleTextFormatter.hpp>
44 #include <com/sun/star/logging/XLogger.hpp>
45 #include <com/sun/star/ucb/CommandAbortedException.hpp>
46 #include <com/sun/star/ucb/CommandFailedException.hpp>
47 #include <com/sun/star/ui/dialogs/XDialogClosedListener.hpp>
64 explicit ExtensionName( OUString
const & str ) : m_str( str ) {}
65 bool operator () ( Reference<deployment::XPackage>
const & e )
const
68 || m_str == e->getName();
73 const char16_t s_usingText [] =
75 "using: " APP_NAME " add <options> extension-path...\n"
76 " " APP_NAME " validate <options> extension-identifier...\n"
77 " " APP_NAME " remove <options> extension-identifier...\n"
78 " " APP_NAME " list <options> extension-identifier...\n"
79 " " APP_NAME " reinstall <options>\n"
85 " add add extension\n"
86 " validate checks the prerequisites of an installed extension and\n"
87 " registers it if possible\n"
88 " remove remove extensions by identifier\n"
89 " reinstall expert feature: reinstall all deployed extensions\n"
90 " list list information about deployed extensions\n"
91 " gui raise Extension Manager Graphical User Interface (GUI)\n"
94 " -h, --help this help\n"
95 " -V, --version version information\n"
96 " -v, --verbose verbose output\n"
97 " -f, --force force overwriting existing extensions\n"
98 " -s, --suppress-license prevents showing the license\n"
99 " --log-file <file> custom log file; default: <cache-dir>/log.txt\n"
100 " --shared expert feature: operate on shared installation\n"
101 " deployment context;\n"
102 " run only when no concurrent Office\n"
103 " process(es) are running!\n"
104 " --bundled expert feature: operate on bundled extensions. Only\n"
105 " works with list, validate, reinstall;\n"
106 " --deployment-context expert feature: explicit deployment context\n"
109 "To learn more about the Extension Manager and extensions, see:\n"
110 "http://wiki.openoffice.org/wiki/Documentation/DevGuide/Extensions/Extensions\n\n";
113 const OptionInfo s_option_infos [] = {
114 { RTL_CONSTASCII_STRINGPARAM(
"help"),
'h',
false },
115 { RTL_CONSTASCII_STRINGPARAM(
"version"),
'V',
false },
116 { RTL_CONSTASCII_STRINGPARAM(
"verbose"),
'v',
false },
117 { RTL_CONSTASCII_STRINGPARAM(
"force"),
'f',
false },
118 { RTL_CONSTASCII_STRINGPARAM(
"log-file"),
'\0',
true },
119 { RTL_CONSTASCII_STRINGPARAM(
"shared"),
'\0',
false },
120 { RTL_CONSTASCII_STRINGPARAM(
"deployment-context"),
'\0',
true },
121 { RTL_CONSTASCII_STRINGPARAM(
"bundled"),
'\0',
false},
122 { RTL_CONSTASCII_STRINGPARAM(
"suppress-license"),
's',
false},
124 {
nullptr, 0,
'\0',
false }
127 class DialogClosedListenerImpl :
128 public ::cppu::WeakImplHelper< ui::dialogs::XDialogClosedListener >
130 osl::Condition & m_rDialogClosedCondition;
133 explicit DialogClosedListenerImpl( osl::Condition & rDialogClosedCondition )
134 : m_rDialogClosedCondition( rDialogClosedCondition ) {}
137 virtual void SAL_CALL disposing( lang::EventObject
const & Source )
override;
140 virtual void SAL_CALL dialogClosed(
141 ui::dialogs::DialogClosedEvent
const & aEvent )
override;
145 void DialogClosedListenerImpl::disposing( lang::EventObject
const & )
151 void DialogClosedListenerImpl::dialogClosed(
152 ui::dialogs::DialogClosedEvent
const & )
154 m_rDialogClosedCondition.set();
161 Reference<deployment::XPackage> findPackage(
162 OUString
const & repository,
163 Reference<deployment::XExtensionManager>
const & manager,
164 Reference<ucb::XCommandEnvironment >
const & environment,
165 std::u16string_view idOrFileName )
167 const Sequence< Reference<deployment::XPackage> > ps(
168 manager->getDeployedExtensions(repository,
169 Reference<task::XAbortChannel>(), environment ) );
170 for (
auto const &
package : ps )
173 for (
auto const &
package : ps )
174 if (
package->getName() == idOrFileName )
176 return Reference<deployment::XPackage>();
184 bool bShowFailedMsg =
true;
186 bool option_shared =
false;
187 bool option_force =
false;
188 bool option_verbose =
false;
189 bool option_bundled =
false;
190 bool option_suppressLicense =
false;
191 bool option_help =
false;
192 bool subcmd_gui =
false;
196 std::vector<OUString> cmdPackages;
197 Reference<XLogHandler> xFileHandler;
198 Reference<XLogHandler> xConsoleHandler;
199 std::unique_ptr<comphelper::EventLogger> logger;
200 std::unique_ptr<utl::TempFile> pUserProfileTempDir;
203 s_option_infos,
"shared" );
205 s_option_infos,
"force" );
207 s_option_infos,
"verbose" );
209 s_option_infos,
"log-file" );
211 s_option_infos,
"deployment-context" );
213 s_option_infos,
"help" );
215 s_option_infos,
"version" );
217 s_option_infos,
"bundled" );
219 s_option_infos,
"suppress-license" );
227 sal_uInt32
nCount = osl_getCommandArgCount();
228 if (nCount == 0 ||
isOption( info_help, &nPos ))
233 else if (
isOption( info_version, &nPos )) {
244 osl_getCommandArg( nPos, &subCommand.pData );
246 subCommand = subCommand.trim();
247 bool subcmd_add = subCommand ==
"add";
248 subcmd_gui = subCommand ==
"gui";
251 while (nPos < nCount)
257 else if (!
readOption( &option_verbose, info_verbose, &nPos ) &&
258 !
readOption( &option_shared, info_shared, &nPos ) &&
259 !
readOption( &option_force, info_force, &nPos ) &&
260 !
readOption( &option_bundled, info_bundled, &nPos ) &&
261 !
readOption( &option_suppressLicense, info_suppressLicense, &nPos ) &&
262 !
readOption( &option_help, info_help, &nPos ) &&
266 osl_getCommandArg( nPos, &cmdArg.pData );
268 cmdArg = cmdArg.trim();
269 if (!cmdArg.isEmpty())
271 if (cmdArg[ 0 ] ==
'-')
275 "\nERROR: unexpected option " +
277 "!\n Use " APP_NAME
" " +
279 " to print all options.\n"));
285 cmdPackages.push_back(
286 subcmd_add || subcmd_gui
299 pUserProfileTempDir->EnableKillingFile();
302 xComponentContext =
getUNO(option_verbose, subcmd_gui,
303 pUserProfileTempDir ? pUserProfileTempDir->GetURL() :
"",
304 xLocalComponentContext);
309 const Reference<XLogger> xLogger(logger->getLogger());
310 xLogger->setLevel(LogLevel::WARNING);
314 xConsoleHandler.set(ConsoleHandler::createWithSettings(xLocalComponentContext,
aSeq));
315 xLogger->addLogHandler(xConsoleHandler);
316 xConsoleHandler->setLevel(LogLevel::WARNING);
317 xLogger->setLevel(LogLevel::WARNING);
320 if (!logFile.isEmpty())
323 xFileHandler.set(css::logging::FileHandler::createWithSettings(xLocalComponentContext, aSeq2));
324 xFileHandler->setLevel(LogLevel::WARNING);
325 xLogger->addLogHandler(xFileHandler);
330 xLogger->setLevel(LogLevel::INFO);
331 xConsoleHandler->setLevel(LogLevel::INFO);
332 if (xFileHandler.is())
333 xFileHandler->setLevel(LogLevel::INFO);
336 if (repository.isEmpty())
339 repository =
"shared";
340 else if (option_bundled)
341 repository =
"bundled";
347 if ( repository ==
"shared" ) {
348 option_shared =
true;
350 else if (option_shared)
352 logger->log(LogLevel::WARNING,
"Explicit context given! Ignoring option '$1$'",
toString(info_shared));
356 if ( geteuid() == 0 )
358 if ( !(option_shared || option_bundled || option_help) )
360 logger->log(LogLevel::SEVERE,
"Cannot run $1$ as root without $2$ or $3$ option.",
367 if (subCommand ==
"reinstall")
371 OUString extensionUnorc;
372 if (repository ==
"user")
373 extensionUnorc =
"$UNO_USER_PACKAGES_CACHE/registry/com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc";
374 else if (repository ==
"shared")
375 extensionUnorc =
"$SHARED_EXTENSIONS_USER/registry/com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc";
376 else if (repository ==
"bundled")
377 extensionUnorc =
"$BUNDLED_EXTENSIONS_USER/registry/com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc";
381 ::rtl::Bootstrap::expandMacros(extensionUnorc);
382 oslFileError e = osl_removeFile(extensionUnorc.pData);
383 if (e != osl_File_E_None && e != osl_File_E_NOENT)
384 throw Exception(
"Could not delete " + extensionUnorc,
nullptr);
387 Reference<deployment::XExtensionManager> xExtensionManager(
388 deployment::ExtensionManager::get( xComponentContext ) );
391 createCmdEnv(xComponentContext, option_force, option_verbose, option_suppressLicense));
397 if (!subcmd_gui && subCommand !=
"reinstall"
401 if ( subcmd_add || subCommand ==
"remove" )
403 for (
const OUString & cmdPackage : cmdPackages)
407 beans::NamedValue nvSuppress(
408 "SUPPRESS_LICENSE", option_suppressLicense ?
410 xExtensionManager->addExtension(
412 repository, Reference<task::XAbortChannel>(), xCmdEnv);
418 xExtensionManager->removeExtension(
419 cmdPackage, cmdPackage, repository,
420 Reference<task::XAbortChannel>(), xCmdEnv );
422 catch (
const lang::IllegalArgumentException &)
424 Reference<deployment::XPackage>
p(
425 findPackage(repository,
426 xExtensionManager, xCmdEnv, cmdPackage ) );
430 xExtensionManager->removeExtension(
433 Reference<task::XAbortChannel>(), xCmdEnv );
438 else if ( subCommand ==
"reinstall" )
440 xExtensionManager->reinstallDeployedExtensions(
441 false, repository, Reference<task::XAbortChannel>(), xCmdEnv);
443 else if ( subCommand ==
"list" )
445 std::vector<Reference<deployment::XPackage> > vecExtUnaccepted;
446 ::comphelper::sequenceToContainer(vecExtUnaccepted,
447 xExtensionManager->getExtensionsWithUnacceptedLicenses(
448 repository, xCmdEnv));
452 std::vector<bool> vecUnaccepted;
453 std::vector<Reference<deployment::XPackage> > allExtensions;
454 if (cmdPackages.empty())
456 Sequence< Reference<deployment::XPackage> >
457 packages = xExtensionManager->getDeployedExtensions(
458 repository, Reference<task::XAbortChannel>(), xCmdEnv );
460 std::vector<Reference<deployment::XPackage> > vec_packages;
461 ::comphelper::sequenceToContainer(vec_packages, packages);
465 allExtensions.resize(vecExtUnaccepted.size() + vec_packages.size());
467 std::vector<Reference<deployment::XPackage> >::iterator i_all_ext =
468 std::copy(vecExtUnaccepted.begin(), vecExtUnaccepted.end(),
469 allExtensions.begin());
471 std::copy(vec_packages.begin(), vec_packages.end(), i_all_ext);
475 vecUnaccepted.resize(vecExtUnaccepted.size() + vec_packages.size());
476 std::fill_n(vecUnaccepted.begin(), vecExtUnaccepted.size(),
true);
477 std::fill_n(vecUnaccepted.begin() + vecExtUnaccepted.size(),
478 vec_packages.size(),
false);
481 OUString(
"All deployed " + repository +
" extensions:\n\n"));
487 for (
const OUString & cmdPackage : cmdPackages)
489 Reference<deployment::XPackage> extension;
492 extension = xExtensionManager->getDeployedExtension(
493 repository, cmdPackage, cmdPackage, xCmdEnv );
495 catch (
const lang::IllegalArgumentException &)
497 extension = findPackage(repository,
498 xExtensionManager, xCmdEnv, cmdPackage );
502 bool bUnacceptedLic =
false;
505 std::vector<Reference<deployment::XPackage> >::const_iterator
507 vecExtUnaccepted.begin(),
508 vecExtUnaccepted.end(), ExtensionName(cmdPackage));
509 if (i != vecExtUnaccepted.end())
512 bUnacceptedLic =
true;
517 throw lang::IllegalArgumentException(
518 "There is no such extension deployed: " +
519 cmdPackage,
nullptr,-1);
520 allExtensions.push_back(extension);
521 vecUnaccepted.push_back(bUnacceptedLic);
528 else if ( subCommand ==
"validate" )
530 std::vector<Reference<deployment::XPackage> > vecExtUnaccepted;
531 ::comphelper::sequenceToContainer(
532 vecExtUnaccepted, xExtensionManager->getExtensionsWithUnacceptedLicenses(
533 repository, xCmdEnv));
535 for (
const OUString & cmdPackage : cmdPackages)
537 Reference<deployment::XPackage> extension;
540 extension = xExtensionManager->getDeployedExtension(
541 repository, cmdPackage, cmdPackage, xCmdEnv );
543 catch (
const lang::IllegalArgumentException &)
545 extension = findPackage(
546 repository, xExtensionManager, xCmdEnv, cmdPackage );
551 std::vector<Reference<deployment::XPackage> >::const_iterator
553 vecExtUnaccepted.begin(),
554 vecExtUnaccepted.end(), ExtensionName(cmdPackage));
555 if (i != vecExtUnaccepted.end())
562 xExtensionManager->checkPrerequisitesAndEnable(
563 extension, Reference<task::XAbortChannel>(), xCmdEnv);
566 else if ( subCommand ==
"gui" )
568 Reference<ui::dialogs::XAsynchronousExecutableDialog> xDialog(
569 deployment::ui::PackageManagerDialog::createAndInstall(
571 !cmdPackages.empty() ? cmdPackages[0] : OUString() ));
573 osl::Condition dialogEnded;
576 Reference< ui::dialogs::XDialogClosedListener > xListener(
577 new DialogClosedListenerImpl( dialogEnded ) );
579 xDialog->startExecuteModal(xListener);
585 logger->log(LogLevel::SEVERE,
586 "Unknown sub-command: '$1$'. Use $2$ $3$ to print all options.",
587 subCommand, APP_NAME,
toString(info_help));
591 logger->log(LogLevel::INFO,
"$1$ done.", APP_NAME);
594 css::uno::Reference<css::lang::XComponent>(
595 xLocalComponentContext, css::uno::UNO_QUERY_THROW)->
dispose();
598 catch (
const ucb::CommandFailedException &e)
600 logger->log(LogLevel::SEVERE,
"Exception occurred: $1$", e.Message);
602 catch (
const ucb::CommandAbortedException &)
604 logger->log(LogLevel::SEVERE,
"$1$ aborted.", APP_NAME);
605 bShowFailedMsg =
false;
607 catch (
const deployment::DeploymentException & exc)
609 logger->log(LogLevel::SEVERE,
"Exception occurred: $1$", exc.Message);
612 catch (
const LockFileException & e)
616 bShowFailedMsg =
false;
618 catch (
const css::uno::Exception & e ) {
621 logger->log(LogLevel::SEVERE,
"Exception occurred: $1$", e.Message);
625 logger->log(LogLevel::SEVERE,
"$1$ failed.", APP_NAME);
627 if (xLocalComponentContext.is()) {
628 css::uno::Reference<css::lang::XComponent>(
629 xLocalComponentContext, css::uno::UNO_QUERY_THROW)->
dispose();
OUString const & getProcessWorkingDir()
exports com.sun.star. packages
Reference< XCommandEnvironment > createCmdEnv(Reference< XComponentContext > const &xContext, bool option_force_overwrite, bool option_verbose, bool option_suppress_license)
OptionInfo const * getOptionInfo(OptionInfo const *list, OUString const &opt)
void printf_packages(std::vector< Reference< deployment::XPackage > > const &allExtensions, std::vector< bool > const &vecUnaccepted, Reference< XCommandEnvironment > const &xCmdEnv, sal_Int32 level)
bool readOption(bool *flag, OptionInfo const *option_info, sal_uInt32 *pIndex)
OUString makeAbsoluteFileUrl(OUString const &sys_path, OUString const &base_url)
void syncRepositories(bool force, Reference< ucb::XCommandEnvironment > const &xCmdEnv)
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)
Any SAL_CALL getCaughtException()
bool isOption(OptionInfo const *option_info, sal_uInt32 *pIndex)
Reference< XComponentContext > getUNO(bool verbose, bool bGui, const OUString &sTempDir, Reference< XComponentContext > &out_localContext)
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.
bool readArgument(OUString *pValue, OptionInfo const *option_info, sal_uInt32 *pIndex)
bool isBootstrapVariable(sal_uInt32 *pIndex)
checks if an argument is a bootstrap variable.
void disposeBridges(Reference< css::uno::XComponentContext > const &ctx)
Sequence< sal_Int8 > aSeq
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC OUString getIdentifier(css::uno::Reference< css::deployment::XPackage > const &package)
Gets the identifier of a package.
OUString toString(OptionInfo const *info)
OUString anyToString(uno::Any const &value)
css::uno::Any SAL_CALL makeAny(const SharedUNOComponent< INTERFACE, COMPONENT > &value)