home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / boot / i386 / root / usr / share / YaST2 / clients / update_proposal.ycp < prev    next >
Text File  |  2006-11-29  |  14KB  |  480 lines

  1. /**
  2.  * Module:    update_proposal.ycp
  3.  *
  4.  * Author:    Arvin Schnell <arvin@suse.de>
  5.  *
  6.  * Purpose:    Let user choose update settings.
  7.  *
  8.  * $Id: update_proposal.ycp 34238 2006-11-10 09:18:34Z locilka $
  9.  */
  10. {
  11.     textdomain "update";
  12.  
  13.     import "HTML";
  14.     import "Update";
  15.     import "Packages";
  16.     import "PackageCallbacks";
  17.     import "SpaceCalculation";
  18.  
  19.     import "Installation";
  20.     import "Kernel";
  21.     import "Popup";
  22.     import "ProductFeatures";
  23.     import "Product";
  24.     import "FileUtils";
  25.     import "Label";
  26.  
  27.  
  28.     string func = (string) WFM::Args(0);
  29.     map param = (map) WFM::Args(1);
  30.     map <string, any> ret = $[];
  31.     
  32.     boolean rpm_db_existency_checked_already = false;
  33.  
  34.     // bugzilla #148105
  35.     // Check the current RPM Database if exists
  36.     //
  37.     // RPM DB found -> return true
  38.     // RPM DB not found & skipped -> return true
  39.     // RPM DB not found & aborted -> return false
  40.     //
  41.     boolean CheckRPMDBforExistency () {
  42.     y2milestone ("Checking the current RPM Database in '%1'...", Installation::destdir);
  43.  
  44.     // at least one must be there, the second one is for RPM v3
  45.     list <string> rpm_db_files = [ "/var/lib/rpm/Packages", "/var/lib/rpm/packages.rpm" ];
  46.     boolean ret = false;
  47.     boolean file_found_or_error_skipped = false;
  48.     
  49.     while (! file_found_or_error_skipped) {
  50.         foreach (string check_file, rpm_db_files, {
  51.         if (Installation::destdir != "/")
  52.             check_file = sformat("%1%2", Installation::destdir, check_file);
  53.         if (FileUtils::Exists (check_file)) {
  54.             y2milestone ("RPM Database '%1' found", check_file);
  55.             ret = true;
  56.             file_found_or_error_skipped = true;
  57.             break;
  58.         }
  59.         });
  60.         
  61.         // file not found
  62.         if (! ret) {
  63.         y2error ("None of files %1 exist in '%2'",
  64.             rpm_db_files, Installation::destdir
  65.         );
  66.         
  67.         string missing_files = "";
  68.         foreach (string check_file, rpm_db_files, {
  69.             if (Installation::destdir != "/")
  70.             check_file = sformat("%1%2", Installation::destdir, check_file);
  71.             missing_files = missing_files + "\n" + check_file;
  72.         });
  73.  
  74.         UI::OpenDialog (
  75.             `opt(`decorated),
  76.             `VBox (
  77.             // popup error
  78.             `Label (
  79.                 // part of error popup message
  80.                 _("Cannot read the current RPM Database.") + "\n\n" +
  81.                 // part of error popup message, %1 stands for newline-separated list of files
  82.                 sformat (_("None of these files exist:%1"), missing_files) + "\n\n"
  83.             ),
  84.             `HBox (
  85.                 `PushButton (`id(`abort),  Label::AbortButton()),
  86.                 `PushButton (`id(`retry),  Label::RetryButton())
  87.                 // disabled button - bugzilla #148105, comments #22 - #28
  88.                 // `PushButton (`id(`ignore), Label::IgnoreButton())
  89.             )
  90.             )
  91.         );
  92.         
  93.         any ui_r = UI::UserInput();
  94.         
  95.         if (ui_r == `cancel || ui_r == `abort) {
  96.             ret = false;
  97.             file_found_or_error_skipped = true;
  98.             y2milestone ("Check failed, returning error.");
  99.         } else if (ui_r == `retry) {
  100.             file_found_or_error_skipped = false;
  101.             y2milestone ("Trying again...");
  102.         //} else if (ui_r == `ignore) {
  103.         //    ret = true;
  104.         //    file_found_or_error_skipped = true;
  105.         //    y2warning ("Skipping missing RPM Database, problems might occur...");
  106.         } else {
  107.             file_found_or_error_skipped = false;
  108.             y2error ("Unexpected return: %1", ui_r);
  109.         }
  110.  
  111.         UI::CloseDialog();
  112.         }
  113.     }
  114.     
  115.     y2milestone ("CheckRPMDBforExistency - returning: %1", ret);
  116.     return ret;
  117.     }
  118.  
  119.     define void SelectKernelPackages () {
  120.     list <list> provides = Pkg::PkgQueryProvides ("kernel");
  121.     y2milestone ("provides: %1", provides);
  122.  
  123.     list <list> kernels = filter (list l, provides, {
  124.         return l[1]:`NONE == `BOTH || l[1]:`NONE == l[2]:`NONE;
  125.     });
  126.  
  127.     if (size (kernels) != 1)
  128.         y2error ("not exactly one package provides tag kernel");
  129.  
  130.     string selected_kernel = kernels[0,0]:"none";
  131.     list<string> recom_kernel = Kernel::ComputePackages ();
  132.     y2milestone ("Selected kernel: %1, recommended kernel: %2",
  133.         selected_kernel, recom_kernel);
  134.     list<string> kernel_packs = Kernel::ComputePackages ();
  135.     boolean kernel_refresh_needed = false;
  136.     foreach (string p, kernel_packs, {
  137.         if (! Pkg::IsProvided (p))
  138.         {
  139.         kernel_refresh_needed = true;
  140.         y2milestone ("Package %1 is not installed - forcing kernel update", p);
  141.         }
  142.     });
  143.     if (kernel_refresh_needed)
  144.     {
  145.         foreach (string p, kernel_packs, {
  146.         Pkg::PkgInstall (p);
  147.         });
  148.     }
  149.     }
  150.  
  151.     define void init_stuff ()
  152.     {
  153.     // initialize package manager
  154.     if (true)
  155.     {
  156.         UI::OpenDialog (`opt(`decorated),
  157.                 // intermediate popup while initializing internal packagemanagement
  158.                 `Label(_("Reading package information. One moment please...")));
  159.  
  160.         Packages::Init (true);
  161.  
  162.         UI::CloseDialog();
  163.     }
  164.  
  165.     // initialize target
  166.     if (true)
  167.     {
  168.         PackageCallbacks::SetConvertDBCallbacks ();
  169.  
  170.         Pkg::TargetInit (Installation::destdir, false);
  171.  
  172.         Update::GetProductName ();
  173.     }
  174.  
  175.     // connect target with package manager
  176.     if (!Update::did_init1)
  177.     {
  178.         Update::did_init1 = true;
  179.  
  180.         if (size (Pkg::ResolvableProperties ("", `pattern, "")) > 0)
  181.         {
  182.         y2milestone ("No base selection found, but patterns found...");
  183.         Packages::using_patterns = true;
  184.         }
  185.  
  186.         list<string> restore = [];
  187.         list<map<string,any> > selected = Pkg::ResolvableProperties ("", `product, "");
  188.         foreach (map<string,any> s, selected, {
  189.             restore = add (restore, s["name"]:"");
  190.         });
  191.         Pkg::PkgApplReset ();
  192.         foreach (string res, restore, {
  193.             Pkg::ResolvableInstall (res, `product);
  194.         });
  195.         if (! Update::onlyUpdateInstalled)
  196.         {
  197.             if (Packages::using_patterns)
  198.             {
  199.             Update::SetDesktopPattern ();
  200.             }
  201.             else
  202.             {
  203.             Update::ProposeSelection ();
  204.             }
  205.         }
  206.  
  207.         if (Update::onlyUpdateInstalled)            // just consider already installed packages
  208.         {
  209.         Pkg::SetSelection ("");                // -> don't select any additional selections
  210.         }
  211.         else if (Packages::using_patterns)
  212.         {
  213.         if (! ProductFeatures::GetBooleanFeature ("software",
  214.             "only_update_installed"))
  215.         {
  216.             foreach (string pat, Product::patterns, {
  217.             y2milestone("Pre-select pattern %1", pat);
  218.             Pkg::ResolvableInstall( pat, `pattern );
  219.             });
  220.         }
  221.  
  222.         }
  223.         else                        // update selections too
  224.         {
  225.         Pkg::SetSelection (Update::selected_selection);    // -> set the base selection (minimal, default, ....)
  226.  
  227.         if (!Update::manual_interaction)
  228.         {
  229.             // now compare installed (old) selections against available (new) selections
  230.             //  and set all selections which are installed (old) and available (new)
  231.             //  as 'to be installed' -> UI will show "to be updated" for these selections
  232.  
  233.             list<string> available_addons = Pkg::GetSelections (`available, "");
  234.             list<string> installed_addons = Pkg::GetSelections (`installed, "");
  235.  
  236.             foreach (string installed, installed_addons,
  237.             {
  238.             if (contains (available_addons, installed))    // we have a newer selection for an installed one
  239.             {
  240.                 Pkg::SetSelection (installed);        // update this selection too (selection solving included)
  241.             }
  242.             });
  243.         }
  244.         }
  245.  
  246.         Packages::SelectProduct();
  247.         Pkg::ActivateSelections ();                    // now go through all selected selections and select their packages
  248.         map<symbol, integer> update_sum
  249.         = Pkg::PkgUpdateAll (Update::deleteOldPackages);
  250.         y2milestone ("Update summary: %1", update_sum);
  251.         Update::unknown_packages = update_sum[`ProblemListSze]:0;
  252.  
  253.         SelectKernelPackages ();
  254.         list<string> sys_patterns = Packages::ComputeSystemPatternList ();
  255.         foreach (string pat, sys_patterns, {
  256.         Pkg::ResolvableInstall (pat, `pattern);
  257.         });
  258.  
  259.         if (Pkg::PkgSolve (!Update::onlyUpdateInstalled))
  260.         Update::solve_errors = 0;
  261.         else
  262.          Update::solve_errors = Pkg::PkgSolveErrors ();
  263.     }
  264.     // check product compatibility
  265.     if (! (Update::ProductsCompatible () || Update::products_incompatible))
  266.     {
  267.         if (Popup::ContinueCancel (
  268. // continue-cancel popup
  269. _("The installed product is not compatible with the product
  270. on the installation media. If you try to update using the
  271. current installation media, the system may not start or
  272. some applications may not run properly.")))
  273.         {
  274.         Update::IgnoreProductCompatibility ();
  275.         }
  276.         else
  277.         {
  278.         Update::products_incompatible = true;
  279.         }
  280.     }
  281.     // Pkg::GetPackages()
  282.     //   `installed all installed packages
  283.     //   `selected returns all selected but not yet installed packages
  284.     //   `available returns all available packages (from the installation source)
  285.     //   `removed all packages selected for removal
  286.  
  287.     // recreate the update summary
  288.     list<string> installed = Pkg::GetPackages (`installed, true);
  289.     list<string> selected  = Pkg::GetPackages (`selected, true);
  290.     list<string> removed   = Pkg::GetPackages (`removed, true);
  291.     integer cnt_installed  = size (installed);
  292.     integer cnt_selected   = size (selected);
  293.     integer cnt_removed    = size (removed);
  294.     y2milestone ("Selected: %1, Installed: %2, Removed: %3", cnt_selected, cnt_installed, cnt_removed);
  295.     y2milestone("Removed: %1", removed);
  296.  
  297.     map<string,boolean> installed_m = listmap (string p, installed, {
  298.         return $[ p : true ];
  299.     });
  300.     map<string,boolean> selected_m = listmap (string p, selected, {
  301.         return $[ p : true ];
  302.     });
  303.  
  304.     // packages that are both 'installed' && 'selected'
  305.     Update::packages_to_update = size (filter (string p, selected, {
  306.         return haskey (installed_m, p);
  307.     }));
  308.     // packages that are 'selected' but not 'installed'
  309.     Update::packages_to_install = cnt_selected - Update::packages_to_update;
  310.  
  311.     // packages that are 'removed' but not 'selected again'
  312.     Update::packages_to_remove = size (filter (string p, removed, {
  313.         return ! haskey (selected_m, p);
  314.     }));
  315.  
  316.     y2milestone("Update statistics: Updated: %1, Installed: %2, Removed: %3",
  317.         Update::packages_to_update, Update::packages_to_install, Update::packages_to_remove);
  318.     }
  319.  
  320.  
  321.     if ( func == "MakeProposal" )
  322.     {
  323.     boolean force_reset      = param["force_reset"     ]:false;
  324.     boolean language_changed = param["language_changed"]:false;
  325.  
  326.     // call some function that makes a proposal here:
  327.     //
  328.     // DummyMod::MakeProposal( force_reset );
  329.  
  330.     if (force_reset)
  331.     {
  332.         Update::Reset ();
  333.         Packages::Reset ([`product]);
  334.         Update::did_init1 = false;
  335.         rpm_db_existency_checked_already = false;
  336.     }
  337.  
  338.     // bugzilla #148105
  339.     if (! rpm_db_existency_checked_already) {
  340.         rpm_db_existency_checked_already = true;
  341.  
  342.         // if it doesn't exist, user can still confirm to continue
  343.         // packager will then suggest some set of packages
  344.         if (! CheckRPMDBforExistency()) {
  345.         return $[
  346.             // error message in proposal
  347.             "warning" : _("Cannot read the current RPM Database."),
  348.             "warning_level" : `fatal,
  349.             "raw_proposal" : [],
  350.         ];
  351.         }
  352.     }
  353.  
  354.     // Fill return map
  355.  
  356.     init_stuff ();
  357.  
  358.     if (Update::products_incompatible)
  359.     {
  360.         return $[
  361.         // error message in proposal
  362.         "warning" : _("The installed product is not compatible with the product on the installatin media."),
  363.         "warning_level" : `fatal,
  364.         "raw_proposal" : [],
  365.         ];
  366.     }
  367.  
  368.     if (true)
  369.     {
  370.         list available_base_selections = Update::GetBaseSelections ();
  371.         if ((! Packages::using_patterns) && size (available_base_selections) == 0)
  372.         {
  373.         y2error ("No base selections available");
  374.         // Can't find any software data, probably a installation media error
  375.         // error message
  376.         return $[ "warning" : _("Cannot read package data from installation media. Media error?"),
  377.               "warning_level" : `blocker,
  378.               "raw_proposal" : [] ];
  379.         }
  380.     }
  381.  
  382.     if (Update::disallow_upgrade)
  383.     {
  384.         if (false)        // FIXME
  385.         {
  386.         // proposal error
  387.         return $[ "warning" : _("Updating to another version is not supported from the running system."),
  388.               "warning_level" : `fatal,
  389.               "raw_proposal" : [] ];
  390.         }
  391.     }
  392.  
  393.     list<string> tmp = [];
  394.  
  395.     tmp = Update::SelectedProducts ();
  396.     // summary text (%1 is package selection)
  397. //    tmp = add (tmp, sformat (_("Update to %1"), Update::updateVersion["nameandversion"]:"?"));
  398.  
  399.     if (Update::onlyUpdateInstalled)
  400.     {
  401.         // Proposal for backup during update
  402.         tmp = add (tmp, _("Only Update Installed Packages"));
  403.     }
  404.     else
  405.     {
  406.         if (Packages::using_patterns)
  407.         {
  408.         list<map<string,any> > patterns = Pkg::ResolvableProperties ("", `pattern, "");
  409.         patterns = filter (map<string,any> p, patterns, {
  410.             return p["status"]:nil == `selected && p["user_visible"]:true && p["summary"]:p["name"]:"" != "";
  411.         });
  412.         // proposal string
  413.         tmp = add (tmp, _("Update Based on Patterns"));
  414.         foreach (map<string,any> p, patterns, {
  415.             tmp = add (tmp, "+  " + p["summary"]:p["name"]:"");
  416.         });
  417.         }
  418.         else
  419.         {
  420.         map selection_data = Pkg::SelectionData (Update::selected_selection);
  421.         string selection_summary = selection_data["summary"]:"error";
  422.  
  423.         // Proposal for selection during update
  424.         tmp = add (tmp, sformat (_("Update Based on Selection \"%1\""),
  425.                      selection_summary));
  426.         }
  427.     }
  428.  
  429.     // recalculate the disk space usage data
  430.     SpaceCalculation::GetPartitionInfo();
  431.  
  432.     if (Update::deleteOldPackages)
  433.     {
  434.         // Proposal for backup during update
  435.         tmp = add (tmp, _("Delete Old Packages"));
  436.     }
  437.  
  438.     ret = $[ "preformatted_proposal" :
  439.          HTML::List (tmp)
  440.     ];
  441.     }
  442.     else if ( func == "AskUser" )
  443.     {
  444.     boolean has_next = param["has_next"]:false;
  445.  
  446.     // call some function that displays a user dialog
  447.     // or a sequence of dialogs here:
  448.     //
  449.     // sequence = DummyMod::AskUser( has_next );
  450.  
  451.     symbol result = (symbol) WFM::CallFunction ("inst_update", [true, has_next]);
  452.  
  453.     if (result == `next)
  454.     {
  455.         Update::did_init1 = false;
  456.     }
  457.  
  458.     // Fill return map
  459.  
  460.     ret = $[ "workflow_sequence" : result ];
  461.     }
  462.     else if ( func == "Description" )
  463.     {
  464.     // Fill return map.
  465.     //
  466.     // Static values do just nicely here, no need to call a function.
  467.  
  468.     ret =
  469.         $[
  470.           // this is a heading
  471.           "rich_text_title"    :    _("Update Options"),
  472.           // this is a menu entry
  473.           "menu_title"    :    _("&Update Options"),
  474.           "id"        :    "update_stuff"
  475.         ];
  476.     }
  477.  
  478.     return ret;
  479. }
  480.