merge the formfield patch from ooo-build
[ooovba.git] / desktop / source / pkgchk / unopkg / unopkg_app.cxx
blobb4103f96b42ac23ef485bf793179d201c2d7e6f6
1 /*************************************************************************
2 *
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: unopkg_app.cxx,v $
10 * $Revision: 1.14.58.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
33 #include "dp_misc.h"
34 #include "unopkg_main.h"
35 #include "unopkg_shared.h"
36 #include "dp_identifier.hxx"
37 #include "sal/main.h"
38 #include "tools/extendapplicationenvironment.hxx"
39 #include "rtl/ustrbuf.hxx"
40 #include "rtl/uri.hxx"
41 #include "osl/thread.h"
42 #include "osl/process.h"
43 #include "osl/conditn.hxx"
44 #include "cppuhelper/implbase1.hxx"
45 #include "cppuhelper/exc_hlp.hxx"
46 #include "comphelper/anytostring.hxx"
47 #include "com/sun/star/deployment/thePackageManagerFactory.hpp"
48 #include "com/sun/star/deployment/ui/PackageManagerDialog.hpp"
49 #include "com/sun/star/ui/dialogs/XExecutableDialog.hpp"
50 #include "com/sun/star/lang/DisposedException.hpp"
51 #include "boost/scoped_array.hpp"
52 #include "com/sun/star/ui/dialogs/XDialogClosedListener.hpp"
53 #include "com/sun/star/bridge/XBridgeFactory.hpp"
54 #include <stdio.h>
55 #include <vector>
58 using namespace ::com::sun::star;
59 using namespace ::com::sun::star::uno;
60 using namespace ::unopkg;
61 using ::rtl::OUString;
62 namespace css = ::com::sun::star;
63 namespace {
65 //------------------------------------------------------------------------------
66 const char s_usingText [] =
67 "\n"
68 "using: " APP_NAME " add <options> extension-path...\n"
69 " " APP_NAME " remove <options> extension-identifier...\n"
70 " " APP_NAME " list <options> extension-identifier...\n"
71 " " APP_NAME " reinstall <options>\n"
72 " " APP_NAME " gui\n"
73 " " APP_NAME " -V\n"
74 " " APP_NAME " -h\n"
75 "\n"
76 "sub-commands:\n"
77 " add add extension\n"
78 " remove remove extensions by identifier\n"
79 " reinstall expert feature: reinstall all deployed extensions\n"
80 " list list information about deployed extensions\n"
81 " gui raise Extension Manager Graphical User Interface (GUI)\n"
82 "\n"
83 "options:\n"
84 " -h, --help this help\n"
85 " -V, --version version information\n"
86 " -v, --verbose verbose output to stdout\n"
87 " -f, --force force overwriting existing extensions\n"
88 #ifdef UNX
89 " -l, --link attempt to link to instead of copying extensions\n"
90 #endif
91 " --log-file <file> custom log file; default: <cache-dir>/log.txt\n"
92 " --shared expert feature: operate on shared installation\n"
93 " deployment context;\n"
94 " run only when no concurrent Office\n"
95 " process(es) are running!\n"
96 " --deployment-context expert feature: explicit deployment context\n"
97 " <context>\n"
98 "\n"
99 "To learn more about the Extension Manager and extensions, see:\n"
100 "http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/Extensions/Extensions\n\n";
102 //------------------------------------------------------------------------------
103 const OptionInfo s_option_infos [] = {
104 { RTL_CONSTASCII_STRINGPARAM("help"), 'h', false },
105 { RTL_CONSTASCII_STRINGPARAM("version"), 'V', false },
106 { RTL_CONSTASCII_STRINGPARAM("verbose"), 'v', false },
107 { RTL_CONSTASCII_STRINGPARAM("force"), 'f', false },
108 #ifdef UNX
109 { RTL_CONSTASCII_STRINGPARAM("link"), 'l', false },
110 #endif
111 { RTL_CONSTASCII_STRINGPARAM("log-file"), '\0', true },
112 { RTL_CONSTASCII_STRINGPARAM("shared"), '\0', false },
113 { RTL_CONSTASCII_STRINGPARAM("deployment-context"), '\0', true },
114 { RTL_CONSTASCII_STRINGPARAM("bundled"), '\0', false},
116 { 0, 0, '\0', false }
119 class DialogClosedListenerImpl :
120 public ::cppu::WeakImplHelper1< ui::dialogs::XDialogClosedListener >
122 osl::Condition & m_rDialogClosedCondition;
124 public:
125 DialogClosedListenerImpl( osl::Condition & rDialogClosedCondition )
126 : m_rDialogClosedCondition( rDialogClosedCondition ) {}
128 // XEventListener (base of XDialogClosedListener)
129 virtual void SAL_CALL disposing( lang::EventObject const & Source )
130 throw (RuntimeException);
132 // XDialogClosedListener
133 virtual void SAL_CALL dialogClosed(
134 ui::dialogs::DialogClosedEvent const & aEvent )
135 throw (RuntimeException);
138 // XEventListener (base of XDialogClosedListener)
139 void DialogClosedListenerImpl::disposing( lang::EventObject const & )
140 throw (RuntimeException)
142 // nothing to do
145 // XDialogClosedListener
146 void DialogClosedListenerImpl::dialogClosed(
147 ui::dialogs::DialogClosedEvent const & )
148 throw (RuntimeException)
150 m_rDialogClosedCondition.set();
153 // If a package had been installed with a pre OOo 2.2, it could not normally be
154 // found via its identifier; similarly (and for ease of use), a package
155 // installed with OOo 2.2 or later could not normally be found via its file
156 // name.
157 Reference<deployment::XPackage> findPackage(
158 Reference<deployment::XPackageManager> const & manager,
159 Reference<ucb::XCommandEnvironment > const & environment,
160 OUString const & idOrFileName )
162 Sequence< Reference<deployment::XPackage> > ps(
163 manager->getDeployedPackages(
164 Reference<task::XAbortChannel>(), environment ) );
165 for ( sal_Int32 i = 0; i < ps.getLength(); ++i )
166 if ( dp_misc::getIdentifier( ps[i] ) == idOrFileName )
167 return ps[i];
168 for ( sal_Int32 i = 0; i < ps.getLength(); ++i )
169 if ( ps[i]->getName() == idOrFileName )
170 return ps[i];
171 return Reference<deployment::XPackage>();
174 } // anon namespace
177 //workaround for some reason the bridge threads which communicate with the uno.exe
178 //process are not releases on time
179 void disposeBridges(Reference<css::uno::XComponentContext> ctx)
181 if (!ctx.is())
182 return;
184 Reference<css::bridge::XBridgeFactory> bridgeFac(
185 ctx->getServiceManager()->createInstanceWithContext(
186 OUSTR("com.sun.star.bridge.BridgeFactory"), ctx),
187 UNO_QUERY);
189 if (bridgeFac.is())
191 const Sequence< Reference<css::bridge::XBridge> >seqBridges = bridgeFac->getExistingBridges();
192 for (sal_Int32 i = 0; i < seqBridges.getLength(); i++)
194 Reference<css::lang::XComponent> comp(seqBridges[i], UNO_QUERY);
195 if (comp.is())
197 try {
198 comp->dispose();
200 catch (css::lang::DisposedException& )
208 //##############################################################################
209 extern "C" int unopkg_main()
211 tools::extendApplicationEnvironment();
212 DisposeGuard disposeGuard;
213 bool bNoOtherErrorMsg = false;
214 OUString subCommand;
215 bool option_shared = false;
216 bool option_force = false;
217 bool option_link = false;
218 bool option_verbose = false;
219 bool option_bundled = false;
220 bool subcmd_add = false;
221 bool subcmd_gui = false;
222 OUString logFile;
223 OUString deploymentContext;
224 OUString cmdArg;
225 ::std::vector<OUString> cmdPackages;
227 OptionInfo const * info_shared = getOptionInfo(
228 s_option_infos, OUSTR("shared") );
229 OptionInfo const * info_force = getOptionInfo(
230 s_option_infos, OUSTR("force") );
231 OptionInfo const * info_link = getOptionInfo(
232 s_option_infos, OUSTR("link") );
233 OptionInfo const * info_verbose = getOptionInfo(
234 s_option_infos, OUSTR("verbose") );
235 OptionInfo const * info_log = getOptionInfo(
236 s_option_infos, OUSTR("log-file") );
237 OptionInfo const * info_context = getOptionInfo(
238 s_option_infos, OUSTR("deployment-context") );
239 OptionInfo const * info_help = getOptionInfo(
240 s_option_infos, OUSTR("help") );
241 OptionInfo const * info_version = getOptionInfo(
242 s_option_infos, OUSTR("version") );
243 OptionInfo const * info_bundled = getOptionInfo(
244 s_option_infos, OUSTR("bundled") );
246 Reference<XComponentContext> xComponentContext;
247 Reference<XComponentContext> xLocalComponentContext;
249 try {
250 sal_uInt32 nPos = 0;
251 sal_uInt32 nCount = osl_getCommandArgCount();
252 if (nCount == 0 || isOption( info_help, &nPos ))
254 dp_misc::writeConsole(s_usingText);
255 return 0;
257 else if (isOption( info_version, &nPos )) {
258 dp_misc::writeConsole("\n"APP_NAME" Version 3.0\n");
259 return 0;
261 //consume all bootstrap variables which may occur before the subcommannd
262 while(isBootstrapVariable(&nPos));
264 if(nPos >= nCount)
265 return 0;
266 //get the sub command
267 osl_getCommandArg( nPos, &subCommand.pData );
268 ++nPos;
269 subCommand = subCommand.trim();
270 subcmd_add = subCommand.equalsAsciiL(
271 RTL_CONSTASCII_STRINGPARAM("add") );
272 subcmd_gui = subCommand.equalsAsciiL(
273 RTL_CONSTASCII_STRINGPARAM("gui") );
275 // sun-command options and packages:
276 while (nPos < nCount)
278 if (readArgument( &cmdArg, info_log, &nPos )) {
279 logFile = makeAbsoluteFileUrl(
280 cmdArg.trim(), getProcessWorkingDir() );
282 else if (!readOption( &option_verbose, info_verbose, &nPos ) &&
283 !readOption( &option_shared, info_shared, &nPos ) &&
284 !readOption( &option_force, info_force, &nPos ) &&
285 !readOption( &option_bundled, info_bundled, &nPos ) &&
286 !readOption( &option_link, info_link, &nPos ) &&
287 !readArgument( &deploymentContext, info_context, &nPos ) &&
288 !isBootstrapVariable(&nPos))
290 osl_getCommandArg( nPos, &cmdArg.pData );
291 ++nPos;
292 cmdArg = cmdArg.trim();
293 if (cmdArg.getLength() > 0)
295 if (cmdArg[ 0 ] == '-')
297 // is option:
298 dp_misc::writeConsoleError(
299 OUSTR("\nERROR: unexpected option ") +
300 cmdArg +
301 OUSTR("!\n") +
302 OUSTR(" Use " APP_NAME " ") +
303 toString(info_help) +
304 OUSTR(" to print all options.\n"));
305 return 1;
307 else
309 // is package:
310 cmdPackages.push_back(
311 subcmd_add || subcmd_gui
312 ? makeAbsoluteFileUrl(
313 cmdArg, getProcessWorkingDir() )
314 : cmdArg );
320 //make sure the bundled option was provided together with shared
321 if (option_bundled && !option_shared)
323 dp_misc::writeConsoleError(
324 "\nERROR: option --bundled can only be used together with --shared!");
325 return 1;
329 xComponentContext = getUNO(
330 disposeGuard, option_verbose, option_shared, subcmd_gui,
331 xLocalComponentContext );
333 if (deploymentContext.getLength() == 0) {
334 deploymentContext = option_shared ? OUSTR("shared") : OUSTR("user");
336 else
338 if (deploymentContext.equalsAsciiL(
339 RTL_CONSTASCII_STRINGPARAM("shared") )) {
340 option_shared = true;
342 else if (option_shared) {
343 dp_misc::writeConsoleError(
344 OUSTR("WARNING: explicit context given! ") +
345 OUSTR("Ignoring option ") +
346 toString( info_shared ) +
347 OUSTR("!\n") );
351 Reference<deployment::XPackageManagerFactory> xPackageManagerFactory(
352 deployment::thePackageManagerFactory::get( xComponentContext ) );
353 Reference<deployment::XPackageManager> xPackageManager(
354 xPackageManagerFactory->getPackageManager( deploymentContext ) );
356 Reference< ::com::sun::star::ucb::XCommandEnvironment > xCmdEnv(
357 createCmdEnv( xComponentContext, logFile,
358 option_force, option_link, option_verbose, option_bundled) );
360 if (subcmd_add ||
361 subCommand.equalsAsciiL(
362 RTL_CONSTASCII_STRINGPARAM("remove") ))
364 for ( ::std::size_t pos = 0; pos < cmdPackages.size(); ++pos )
366 OUString const & cmdPackage = cmdPackages[ pos ];
367 if (subcmd_add)
369 Reference<deployment::XPackage> xPackage(
370 xPackageManager->addPackage(
371 cmdPackage, OUString() /* to be detected */,
372 Reference<task::XAbortChannel>(), xCmdEnv ) );
373 OSL_ASSERT( xPackage.is() );
375 else
379 xPackageManager->removePackage(
380 cmdPackage, cmdPackage,
381 Reference<task::XAbortChannel>(), xCmdEnv );
383 catch (lang::IllegalArgumentException &)
385 Reference<deployment::XPackage> p(
386 findPackage(
387 xPackageManager, xCmdEnv, cmdPackage ) );
388 //Todo. temporary preventing exception in bundled case.
389 //In case of a bundled extension, remove would be called as a result of
390 //uninstalling a rpm. Then we do not want to show an error when the
391 //extension does not exist, because the package will be uninstalled anyway
392 //and the error would only confuse people.
393 if ( !p.is() && !option_bundled)
394 throw;
395 else if (p.is())
396 xPackageManager->removePackage(
397 ::dp_misc::getIdentifier(p), p->getName(),
398 Reference<task::XAbortChannel>(), xCmdEnv );
403 else if (subCommand.equalsAsciiL(
404 RTL_CONSTASCII_STRINGPARAM("reinstall") ))
406 xPackageManager->reinstallDeployedPackages(
407 Reference<task::XAbortChannel>(), xCmdEnv );
409 else if (subCommand.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("list") ))
411 Sequence< Reference<deployment::XPackage> > packages;
412 if (cmdPackages.empty())
414 packages = xPackageManager->getDeployedPackages(
415 Reference<task::XAbortChannel>(), xCmdEnv );
416 dp_misc::writeConsole(
417 OUSTR("all deployed ") + deploymentContext + OUSTR(" packages:\n"));
419 else
421 packages.realloc( cmdPackages.size() );
422 for ( ::std::size_t pos = 0; pos < cmdPackages.size(); ++pos )
425 packages[ pos ] = xPackageManager->getDeployedPackage(
426 cmdPackages[ pos ], cmdPackages[ pos ], xCmdEnv );
428 catch (lang::IllegalArgumentException &)
430 packages[ pos ] = findPackage(
431 xPackageManager, xCmdEnv, cmdPackages[ pos ] );
432 if ( !packages[ pos ].is() )
433 throw;
436 printf_packages( packages, xCmdEnv );
438 else if (subCommand.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("gui") ))
440 Reference<ui::dialogs::XAsynchronousExecutableDialog> xDialog(
441 deployment::ui::PackageManagerDialog::createAndInstall(
442 xComponentContext,
443 cmdPackages.size() > 0 ? cmdPackages[0] : OUString() ));
445 osl::Condition dialogEnded;
446 dialogEnded.reset();
448 Reference< ui::dialogs::XDialogClosedListener > xListener(
449 new DialogClosedListenerImpl( dialogEnded ) );
451 xDialog->startExecuteModal(xListener);
452 dialogEnded.wait();
454 else
456 dp_misc::writeConsoleError(
457 OUSTR("\nERROR: unknown sub-command ") +
458 subCommand +
459 OUSTR("!\n") +
460 OUSTR(" Use " APP_NAME " ") +
461 toString(info_help) +
462 OUSTR(" to print all options.\n"));
463 return 1;
466 if (option_verbose)
467 dp_misc::writeConsole(OUSTR("\n"APP_NAME" done.\n"));
468 //Force to release all bridges which connect us to the child processes
469 disposeBridges(xLocalComponentContext);
470 return 0;
472 catch (ucb::CommandFailedException &e)
474 dp_misc::writeConsoleError(e.Message + OUSTR("\n"));
475 bNoOtherErrorMsg = true;
477 catch (ucb::CommandAbortedException &)
479 dp_misc::writeConsoleError("\n"APP_NAME" aborted!\n");
481 catch (deployment::DeploymentException & exc)
483 OUString cause;
484 if (option_verbose)
486 cause = ::comphelper::anyToString(exc.Cause);
488 else
490 css::uno::Exception e;
491 if (exc.Cause >>= e)
492 cause = e.Message;
495 dp_misc::writeConsoleError(
496 OUSTR("\nERROR: ") + exc.Message + OUSTR("\n"));
497 if (cause.getLength())
498 dp_misc::writeConsoleError(
499 OUSTR(" Cause: ") + cause + OUSTR("\n"));
501 catch (LockFileException & e)
503 if (!subcmd_gui)
504 dp_misc::writeConsoleError(e.Message);
505 bNoOtherErrorMsg = true;
507 catch (::com::sun::star::uno::Exception & e ) {
508 Any exc( ::cppu::getCaughtException() );
510 dp_misc::writeConsoleError(
511 OUSTR("\nERROR: ") +
512 OUString(option_verbose ? e.Message + OUSTR("\nException details: \n") +
513 ::comphelper::anyToString(exc) : e.Message) +
514 OUSTR("\n"));
516 if (!bNoOtherErrorMsg)
517 dp_misc::writeConsoleError("\n"APP_NAME" failed.\n");
518 disposeBridges(xLocalComponentContext);
519 return 1;