1 //####COPYRIGHTBEGIN####
3 // ----------------------------------------------------------------------------
4 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
6 // This program is part of the eCos host tools.
8 // This program is free software; you can redistribute it and/or modify it
9 // under the terms of the GNU General Public License as published by the Free
10 // Software Foundation; either version 2 of the License, or (at your option)
13 // This program is distributed in the hope that it will be useful, but WITHOUT
14 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 // You should have received a copy of the GNU General Public License along with
19 // this program; if not, write to the Free Software Foundation, Inc.,
20 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 // ----------------------------------------------------------------------------
24 //####COPYRIGHTEND####
25 //==========================================================================
29 // The implementation of each ecosconfig command
31 //==========================================================================
32 //==========================================================================
33 //#####DESCRIPTIONBEGIN####
38 //####DESCRIPTIONEND####
39 //==========================================================================
42 #include <direct.h> /* for getcwd() */
44 #include <unistd.h> /* for getcwd() */
48 #include <sys/param.h> /* for MAXPATHLEN */
49 #include <sys/cygwin.h> /* for cygwin_conv_to_win32_path() */
52 #include "cdl_exec.hxx"
54 // ----------------------------------------------------------------------------
55 bool cdl_exec::quiet = false;
56 bool cdl_exec::verbose = false;
57 bool cdl_exec::ignore_errors = false;
58 bool cdl_exec::no_updates = false;
59 bool cdl_exec::debug_level_set = false;
60 int cdl_exec::debug_level = 0;
62 cdl_exec::cdl_exec (const std::string repository_arg, const std::string savefile_arg,
63 const std::string install_arg, bool no_resolve_arg)
64 : repository(repository_arg),
65 savefile(savefile_arg),
66 install_prefix(install_arg),
67 no_resolve(no_resolve_arg),
73 // The inference callback does not actually do anything at present.
74 // In future it may be useful for diagnostic purposes.
75 CdlTransactionBody::set_inference_callback_fn (&inference_callback);
77 // Automatic inference is always disabled. The inference engine
78 // only gets invoked explicitly, after a suitable transaction callback
79 // has been invoked. The problem here is that the transaction callback
80 // has to report changes made by the inference engine but there is
81 // no way of distinguishing between inferred values that come out of
82 // savefiles and inferred values determined by the inference engine.
83 CdlTransactionBody::disable_automatic_inference ();
87 cdl_exec::set_quiet_mode(bool new_val)
93 cdl_exec::set_verbose_mode(bool new_val)
96 CdlPackagesDatabaseBody::set_verbose(new_val);
100 cdl_exec::set_ignore_errors_mode(bool new_val)
102 ignore_errors = new_val;
106 cdl_exec::set_no_updates_mode(bool new_val)
108 no_updates = new_val;
112 cdl_exec::set_debug_level(int new_level)
114 debug_level_set = true;
115 debug_level = new_level;
118 // ----------------------------------------------------------------------------
120 cdl_exec::init(bool load_config)
122 pkgdata = CdlPackagesDatabaseBody::make(repository, &diagnostic_handler, &diagnostic_handler);
123 interp = CdlInterpreterBody::make();
125 config = CdlConfigurationBody::load (savefile, pkgdata, interp, &diagnostic_handler, &diagnostic_handler);
129 // ----------------------------------------------------------------------------
131 cdl_exec::delete_cdl_data ()
147 // ----------------------------------------------------------------------------
148 bool cdl_exec::cmd_new (const std::string cdl_hardware,
149 const std::string cdl_template /* = "default" */,
150 const std::string cdl_version /* = "" */)
156 config = CdlConfigurationBody::make ("eCos", pkgdata, interp);
158 // The hardware and template should be loaded in a single transaction.
159 // Validating the target name etc. can be left to libcdl.
160 CdlLocalTransaction transact(config);
161 config->set_hardware(transact.get(), resolve_hardware_alias(cdl_hardware), &diagnostic_handler, &diagnostic_handler);
162 config->set_template(transact.get(), cdl_template, cdl_version, &diagnostic_handler, &diagnostic_handler);
166 if (debug_level_set) {
167 this->update_debug_level();
170 // Unless inference has been suppressed, make sure that the
171 // inference engine gets invoked and that its results get
174 CdlTransactionBody::set_callback_fn(&transaction_callback);
175 config->resolve_all_conflicts();
178 // Now report any conflicts which the inference engine could not report.
181 // A savefile should be generated/updated even if there are conflicts.
182 // Otherwise the user does not have a chance to edit the savefile
185 config->save (savefile);
187 if (ignore_errors || (0 == config->get_all_conflicts().size())) {
190 } catch (CdlStringException exception) {
191 exception_handler (exception);
193 exception_handler ();
200 // ----------------------------------------------------------------------------
202 cdl_exec::cmd_target (const std::string cdl_target)
207 config->set_hardware (resolve_hardware_alias (cdl_target), &diagnostic_handler, &diagnostic_handler);
208 if (debug_level_set) {
209 this->update_debug_level();
212 CdlTransactionBody::set_callback_fn(&transaction_callback);
213 config->resolve_all_conflicts();
217 config->save (savefile);
219 if (ignore_errors || (0 == config->get_all_conflicts().size())) {
222 } catch (CdlStringException exception) {
223 exception_handler (exception);
225 exception_handler ();
232 // ----------------------------------------------------------------------------
234 cdl_exec::cmd_template (const std::string cdl_template, const std::string cdl_version /* = "" */)
239 config->set_template (cdl_template, cdl_version, &diagnostic_handler, &diagnostic_handler);
240 if (debug_level_set) {
241 this->update_debug_level();
244 CdlTransactionBody::set_callback_fn(&transaction_callback);
245 config->resolve_all_conflicts();
249 config->save (savefile);
251 if (ignore_errors || (0 == config->get_all_conflicts().size())) {
254 } catch (CdlStringException exception) {
255 exception_handler (exception);
257 exception_handler ();
264 // ----------------------------------------------------------------------------
266 cdl_exec::cmd_export (const std::string cdl_savefile)
271 if (debug_level_set) {
272 this->update_debug_level();
275 CdlTransactionBody::set_callback_fn(&transaction_callback);
276 config->resolve_all_conflicts();
279 // Exporting to another file should only happen if the
280 // configuration is conflict-free. This is different from
281 // updating the savefile.
282 if (ignore_errors || (0 == config->get_all_conflicts().size())) {
284 config->save (cdl_savefile, /* minimal = */ true);
288 } catch (CdlStringException exception) {
289 exception_handler (exception);
291 exception_handler ();
298 // ----------------------------------------------------------------------------
300 cdl_exec::cmd_import (const std::string cdl_savefile)
305 config->add(cdl_savefile, &diagnostic_handler, &diagnostic_handler);
306 if (debug_level_set) {
307 this->update_debug_level();
310 CdlTransactionBody::set_callback_fn(&transaction_callback);
311 config->resolve_all_conflicts();
315 config->save (savefile);
317 if (ignore_errors || (0 == config->get_all_conflicts().size())) {
320 } catch (CdlStringException exception) {
321 exception_handler (exception);
323 exception_handler ();
330 // ----------------------------------------------------------------------------
332 cdl_exec::cmd_add (const std::vector<std::string> cdl_packages)
337 for (unsigned int n = 0; n < cdl_packages.size (); n++) {
338 config->load_package (resolve_package_alias (cdl_packages [n]), "", &diagnostic_handler, &diagnostic_handler);
340 if (debug_level_set) {
341 this->update_debug_level();
344 CdlTransactionBody::set_callback_fn(&transaction_callback);
345 config->resolve_all_conflicts();
349 config->save (savefile);
351 if (ignore_errors || (0 == config->get_all_conflicts().size())) {
354 } catch (CdlStringException exception) {
355 exception_handler (exception);
357 exception_handler ();
364 // ----------------------------------------------------------------------------
366 cdl_exec::cmd_remove (const std::vector<std::string> cdl_packages)
372 for (n = 0; n < cdl_packages.size (); n++) {
373 if (! config->lookup (resolve_package_alias (cdl_packages [n]))) {
374 throw CdlStringException ("Unknown package " + cdl_packages [n]);
377 for (n = 0; n < cdl_packages.size (); n++) {
378 config->unload_package (resolve_package_alias (cdl_packages [n]));
380 if (debug_level_set) {
381 this->update_debug_level();
384 CdlTransactionBody::set_callback_fn(&transaction_callback);
385 config->resolve_all_conflicts();
389 config->save (savefile);
391 if (ignore_errors || (0 == config->get_all_conflicts().size())) {
394 } catch (CdlStringException exception) {
395 exception_handler (exception);
397 exception_handler ();
404 // ----------------------------------------------------------------------------
406 cdl_exec::cmd_version (const std::string cdl_version, const std::vector<std::string> cdl_packages)
411 for (unsigned int n = 0; n < cdl_packages.size (); n++) {
412 config->change_package_version(resolve_package_alias (cdl_packages [n]), cdl_version,
413 &diagnostic_handler, &diagnostic_handler, true);
415 if (debug_level_set) {
416 this->update_debug_level();
419 CdlTransactionBody::set_callback_fn(&transaction_callback);
420 config->resolve_all_conflicts();
424 config->save (savefile);
426 if (ignore_errors || (0 == config->get_all_conflicts().size())) {
429 } catch (CdlStringException exception) {
430 exception_handler (exception);
432 exception_handler ();
439 // ----------------------------------------------------------------------------
441 cdl_exec::cmd_tree ()
446 if (debug_level_set) {
447 this->update_debug_level();
450 CdlTransactionBody::set_callback_fn(&transaction_callback);
451 config->resolve_all_conflicts();
455 config->save (savefile);
457 // A build tree should only be generated if there are no conflicts,
458 // and suppressed if -n is given.
462 else if (ignore_errors || (0 == config->get_all_conflicts().size())) {
464 char cwd [_MAX_PATH + 1];
466 char cwd [PATH_MAX + 1];
468 getcwd (cwd, sizeof cwd);
470 char cwd_win32 [MAXPATHLEN + 1];
471 cygwin_conv_to_win32_path (cwd, cwd_win32);
472 generate_build_tree (config, cwd_win32, install_prefix);
474 generate_build_tree (config, cwd, install_prefix);
476 config->generate_config_headers (install_prefix.empty () ? "install/include/pkgconf" : install_prefix + "/include/pkgconf");
480 strcpy(buf, "mount.exe -f x: /ecos-x");
481 //printf("Cwd_win32: %s\n", cwd_win32);
483 if ( cwd_win32[1] == ':' )
485 buf[13] = cwd_win32[0];
486 buf[22] = cwd_win32[0];
490 //printf("Repository: %s\n", repository.c_str());
492 if ( repository[1] == ':' )
494 buf[13] = repository[0];
495 buf[22] = repository[0];
498 if ( !install_prefix.empty() )
500 //printf("Install prefix: %s\n", install_prefix.c_str());
501 if ( install_prefix[1] == ':' )
503 buf[13] = install_prefix[0];
504 buf[22] = install_prefix[0];
510 printf("\nUnable to generate build tree, this configuration still contains conflicts.\n");
511 printf("Either resolve the conflicts or use --ignore-errors\n");
513 } catch (CdlStringException exception) {
514 exception_handler (exception);
516 exception_handler ();
523 // ----------------------------------------------------------------------------
525 cdl_exec::cmd_list ()
531 // list the installed packages
532 std::vector<std::string> packages = pkgdata->get_packages ();
533 std::sort (packages.begin (), packages.end ());
534 for (unsigned int package = 0; package < packages.size (); package++) {
535 const std::vector<std::string> & aliases = pkgdata->get_package_aliases (packages [package]);
536 printf ("Package %s (%s):\n aliases:", packages [package].c_str (), aliases [0].c_str ());
537 for (unsigned int alias = 1; alias < aliases.size (); alias++) {
538 printf (" %s", aliases [alias].c_str ());
540 const std::vector<std::string> & versions = pkgdata->get_package_versions (packages [package]);
541 printf ("\n versions:");
542 for (unsigned int version = 0; version < versions.size (); version++) {
543 printf (" %s", versions [version].c_str ());
548 // list the available targets
549 std::vector<std::string> targets = pkgdata->get_targets ();
550 std::sort (targets.begin (), targets.end ());
551 for (unsigned int target = 0; target < targets.size (); target++) {
552 const std::vector<std::string> & aliases = pkgdata->get_target_aliases (targets [target]);
553 printf ("Target %s (%s):\n aliases:", targets [target].c_str (), aliases [0].c_str ());
554 for (unsigned int alias = 1; alias < aliases.size (); alias++) {
555 printf (" %s", aliases [alias].c_str ());
560 // list the available templates
561 std::vector<std::string> templates = pkgdata->get_templates ();
562 std::sort (templates.begin (), templates.end ());
563 for (unsigned int templ = 0; templ < templates.size (); templ++) {
564 const std::vector<std::string> & versions = pkgdata->get_template_versions (templates [templ]);
565 printf ("Template %s:\n versions:", templates [templ].c_str ());
566 for (unsigned int version = 0; version < versions.size (); version++) {
567 printf (" %s", versions [version].c_str ());
573 } catch (CdlStringException exception) {
574 exception_handler (exception);
576 exception_handler ();
583 // ----------------------------------------------------------------------------
585 cdl_exec::cmd_check ()
592 // check() should never invoke the inference engine. The user
593 // wants to determine the current status, which should not
595 // However, updating the savefile is worthwhile because it
596 // will now contain more accurate information about the state.
597 // Enabling/disabling debugs is allowed for now because that
598 // is unlikely to introduce conflicts.
599 if (debug_level_set) {
600 this->update_debug_level();
603 config->save (savefile);
606 // report current target and template
607 printf ("Target: %s\n", config->get_hardware ().c_str ());
608 printf ("Template: %s\n", config->get_template ().c_str ());
609 std::vector<std::string> template_packages = pkgdata->get_template_packages (config->get_template ());
610 const std::vector<std::string> & hardware_packages = pkgdata->get_target_packages (config->get_hardware ());
611 for (n = 0; n < hardware_packages.size (); n++) {
612 template_packages.push_back (hardware_packages [n]);
615 // report loaded packages not in the templates
616 const std::vector<CdlLoadable> & loadables = config->get_loadables ();
617 std::vector<std::string> added_packages;
618 std::vector<CdlLoadable>::const_iterator loadable_i;
619 for (loadable_i = loadables.begin (); loadable_i != loadables.end (); loadable_i++) {
620 const CdlNode & node = dynamic_cast<CdlNode> (* loadable_i);
621 if (template_packages.end () == std::find (template_packages.begin (), template_packages.end (), node->get_name ())) {
622 added_packages.push_back (node->get_name ());
625 if (added_packages.size ()) {
628 for (n = 0; n < added_packages.size (); n++) {
629 printf (" %s\n", added_packages [n].c_str ());
632 // report template packages not in the configuration
633 std::vector<std::string> removed_packages;
634 for (n = 0; n < template_packages.size (); n++) {
635 if (! config->lookup (template_packages [n])) {
636 removed_packages.push_back (template_packages [n]);
639 if (removed_packages.size ()) {
640 printf ("Removed:\n");
642 for (n = 0; n < removed_packages.size (); n++) {
643 printf (" %s\n", removed_packages [n].c_str ());
646 // report packages of non-default version
647 std::vector<CdlValuable> version_packages;
648 for (loadable_i = loadables.begin (); loadable_i != loadables.end (); loadable_i++) {
649 const CdlValuable & valuable = dynamic_cast<CdlValuable> (* loadable_i);
650 if (pkgdata->get_package_versions (valuable->get_name ()) [0] != valuable->get_value ()) {
651 version_packages.push_back (valuable);
654 if (version_packages.size ()) {
655 printf ("Version(s):\n");
657 for (n = 0; n < version_packages.size (); n++) {
658 printf (" %s %s\n", version_packages [n]->get_name ().c_str (), version_packages [n]->get_value ().c_str ());
662 const std::list<CdlConflict> & conflicts = config->get_all_conflicts ();
663 if (conflicts.size ()) {
664 printf ("%u conflict(s):\n", conflicts.size ());
666 printf ("No conflicts\n");
671 } catch (CdlStringException exception) {
672 exception_handler (exception);
674 exception_handler ();
681 // ----------------------------------------------------------------------------
683 cdl_exec::cmd_resolve ()
689 if (debug_level_set) {
690 this->update_debug_level();
692 CdlTransactionBody::set_callback_fn(&transaction_callback);
693 config->resolve_all_conflicts ();
696 config->save (savefile);
698 if (ignore_errors || (0 == config->get_all_conflicts().size())) {
701 } catch (CdlStringException exception) {
702 exception_handler (exception);
704 exception_handler ();
711 // ----------------------------------------------------------------------------
712 // The inference callback. This could give some useful diagnostics, or it
713 // could do useful things when running in some interactive mode. In batch
714 // mode it should not do anything.
716 CdlInferenceCallbackResult
717 cdl_exec::inference_callback (CdlTransaction transaction)
719 return CdlInferenceCallbackResult_Continue;
722 // ----------------------------------------------------------------------------
723 // Output a message with indentation after newlines.
725 dump_string(unsigned int indent, const std::string& str)
727 bool newline_pending = false;
729 for (i = 0; i < str.size(); i++) {
730 if (newline_pending) {
732 if ('\n' != str[i]) {
733 for (j = 0; j < indent; j++) {
737 newline_pending = false;
739 if ('\n' == str[i]) {
740 newline_pending = true;
745 if (newline_pending) {
746 putchar('\n'); // But not the indentation.
750 // ----------------------------------------------------------------------------
751 // The transaction callback. This should report any changes that have been
752 // made to the configuration. The amount of output depends on the verbosity
753 // level selected by the user.
755 // 1) quiet - no output at all
756 // 2) default - list updates done by the inference engine.
757 // 3) verbose - this does not currently add anything.
759 // There is no reporting of new or resolved conflicts. Resolved
760 // conflicts are probably of no interest in batch mode. New conflicts
761 // will be handled by report_conflicts(). There is also no information
762 // given about active state changes, although arguably there should be
763 // especially in the case of containers.
766 cdl_exec::transaction_callback(const CdlTransactionCallback& callback_data)
773 for (i = 0; i < callback_data.value_changes.size(); i++) {
774 CdlValuable valuable = callback_data.value_changes[i];
775 if (CdlValueSource_Inferred == valuable->get_source()) {
776 CdlEvalContext context(0, valuable, 0);
777 CdlSimpleValue simple_val;
778 CdlSimpleValue::eval_valuable(context, valuable, simple_val);
779 std::string msg = std::string("U ") + valuable->get_name() + ", new inferred value ";
780 std::string value = simple_val.get_value();
792 // ----------------------------------------------------------------------------
793 // Report the remaining conflicts in the configuration. These indicate
794 // problems that the user should fix before going further with the
795 // configuration, e.g. before generating a build tree.
797 // Quiet verbosity level has no effect on this, but at the verbose level
798 // it is a good idea to look for a possible solution to the conflict.
802 cdl_exec::report_conflicts()
804 const std::list<CdlConflict>& all_conflicts = config->get_all_conflicts();
805 std::list<CdlConflict>::const_iterator conf_i;
806 for (conf_i = all_conflicts.begin(); conf_i != all_conflicts.end(); conf_i++) {
807 CdlNode node = (*conf_i)->get_node();
809 std::string msg = std::string("C ") + node->get_name() + ", " + (*conf_i)->get_explanation() + "\n";
812 if (verbose && (*conf_i)->resolution_implemented()) {
813 // See if there is a possible solution to this conflict.
814 // This involves creating a transaction, invoking the
815 // inference engine, and cancelling the transaction
816 // (thus making sure that nothing actually changes).
818 // NOTE: at some stage libcdl may keep track of solutions
819 // globally. However, although it will know when a solution
820 // becomes invalid it will not necessarily try to resolve
821 // all global conflicts after every change, so attempting
822 // to do this in a transaction may still be necessary.
823 CdlTransaction transact = CdlTransactionBody::make(config);
824 transact->resolve(*conf_i);
825 if ((*conf_i)->has_known_solution()) {
826 std::string soln_msg = " Possible solution:\n";
827 const std::vector<std::pair<CdlValuable, CdlValue> > & soln = (*conf_i)->get_solution();
829 for (i = 0; i < soln.size(); i++) {
830 CdlValuable valuable = soln[i].first;
831 soln_msg += valuable->get_name();
833 switch(valuable->get_flavor()) {
834 case CdlValueFlavor_Bool :
835 if (!soln[i].second.is_enabled()) {
836 soln_msg += "0 (disabled)";
838 soln_msg += "1 (enabled)";
841 case CdlValueFlavor_Data:
842 soln_msg += soln[i].second.get_value();
844 case CdlValueFlavor_BoolData:
845 if (!soln[i].second.is_enabled()) {
846 soln_msg += "0 " + soln[i].second.get_value();
848 soln_msg += "1 " + soln[i].second.get_value();
851 // An option with flavor none cannot be involved
854 soln_msg += "<internal error>";
861 // FIXME: currently this member only works for nested sub-transactions.
862 if (transact->user_confirmation_required()) {
863 msg += "This change affects previous user settings.\n";
866 dump_string(4, soln_msg);
874 // ----------------------------------------------------------------------------
876 cdl_exec::diagnostic_handler (std::string message)
878 printf ("%s\n", message.c_str ());
881 void cdl_exec::exception_handler (CdlStringException exception) {
882 printf ("%s\n", exception.get_message ().c_str ());
886 cdl_exec::exception_handler ()
888 printf ("Unknown error\n");
892 // ----------------------------------------------------------------------------
894 cdl_exec::resolve_package_alias (const std::string alias)
896 std::string package = alias;
898 if (! pkgdata->is_known_package (alias)) { // if the alias is not a package name
899 const std::vector<std::string> & packages = pkgdata->get_packages (); // get packages
900 for (unsigned int n = 0; n < packages.size (); n++) { // for each package
901 const std::vector<std::string> & aliases = pkgdata->get_package_aliases (packages [n]); // get package aliases
902 if (aliases.end () != std::find (aliases.begin (), aliases.end (), alias)) { // if alias is found
903 package = packages [n]; // note the package
912 cdl_exec::resolve_hardware_alias (const std::string alias)
914 std::string target = alias;
916 if (! pkgdata->is_known_target (alias)) { // if the alias is not a target name
917 const std::vector<std::string> & targets = pkgdata->get_targets (); // get targets
918 for (unsigned int n = 0; n < targets.size (); n++) { // for each target
919 const std::vector<std::string> & aliases = pkgdata->get_target_aliases (targets [n]); // get target aliases
920 if (aliases.end () != std::find (aliases.begin (), aliases.end (), alias)) { // if alias is found
921 target = targets [n]; // note the target
929 // ----------------------------------------------------------------------------
930 // Enable or disable debugging in a configuration.
932 cdl_exec::update_debug_level()
934 CdlNode node = config->lookup("CYGPKG_INFRA_DEBUG");
935 CdlValuable valuable = 0;
937 valuable = dynamic_cast<CdlValuable>(node);
940 throw CdlStringException("Cannot enable or disable debugging, the infrastructure package is absent");
943 if (debug_level > 0) {
944 valuable->enable(CdlValueSource_User);
946 valuable->disable(CdlValueSource_User);