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 / modules / ProductControl.ycp < prev    next >
Text File  |  2006-11-29  |  28KB  |  1,142 lines

  1. /**
  2.  * File:    modules/ProductControl.ycp
  3.  * Package:    installation
  4.  * Summary:    Product Control routines
  5.  * Authors:    Anas Nashif <nashif@suse.de>
  6.  *
  7.  * $Id: ProductControl.ycp 33822 2006-10-30 08:53:52Z locilka $
  8.  */
  9. {
  10. textdomain "base";
  11. module "ProductControl";
  12.  
  13. import "XML";
  14. import "ProductFeatures";
  15. import "Mode";
  16. import "Arch";
  17. import "Stage";
  18. import "Directory";
  19. import "Label";
  20. import "Wizard";
  21. import "Report";
  22. import "Hooks";
  23. import "Popup";
  24.  
  25.  
  26. // The complete parsed control file
  27. global map productControl = $[];
  28.  
  29. // all workflows
  30. global list<map> workflows = [];
  31.  
  32. // all proposals
  33. global list<map> proposals = [];
  34.  
  35. // inst_finish steps
  36. global list<map<string,any> > inst_finish = [];
  37.  
  38. // modules to be offered to clone configuration at the end of installation
  39. global list<string> clone_modules = [];
  40.  
  41. // texts which are product specific
  42. map<string,map<string, string> > texts = $[];
  43.  
  44. // Location of a custom control file
  45. global string custom_control_file = "";
  46.  
  47. // Control file in service packs
  48. global string y2update_control_file = "/y2update/control.xml";
  49.  
  50. // The custom control file location, usually copied from
  51. // the root of the CD to the installation directory by linuxrc
  52. global string default_control_file = "/control.xml";
  53.  
  54. // The file above get saved into the installed system for later
  55. // processing
  56. global string saved_control_file = Directory::etcdir + "/control.xml";
  57.  
  58. // The packaged file which contains all default worklfows
  59. global string packaged_control_file = "/usr/share/YaST2/control/control.xml";
  60.  
  61. // The control file we are using for this session.
  62. global string current_control_file = "";
  63.  
  64.  
  65. // Current Wizard Step
  66. global string CurrentWizardStep = "";
  67.  
  68.  
  69. // Last recently used stage_mode for RetranslateWizardSteps
  70. global list<map> last_stage_mode = [];
  71.  
  72.  
  73. // List of module to disable in the current run
  74. global list<string> DisabledModules = [];
  75.  
  76. // List of proposals to disable in the current run
  77. global list<string> DisabledProposals = [];
  78.  
  79.  
  80. // Log files for hooks
  81. global list<string> logfiles = [];
  82.  
  83. global integer first_step = nil;
  84.  
  85. global integer restarting_step = nil;
  86.  
  87.  
  88.  
  89.  
  90. string _client_prefix = "inst_";
  91.  
  92. list stack = [];
  93.  
  94.  
  95. string first_id = "";
  96.  
  97. integer current_step = 0;
  98.  
  99. global integer CurrentStep () {
  100.     return current_step;
  101. }
  102.  
  103.  
  104. /**
  105.  * Set Client Prefix 
  106.  */
  107. global define void setClientPrefix(string prefix)  {
  108.     _client_prefix = prefix;
  109.     return;
  110. }
  111.  
  112. /**
  113.  * Check if a module is disabled
  114.  * @param map module map
  115.  * @return boolean
  116.  */
  117. global define boolean checkDisabled (map mod ) 
  118. {
  119.     if (contains(DisabledModules, mod["name"]:""))
  120.     {
  121.         return true;
  122.     }
  123.     return false;
  124. }
  125.  
  126. global boolean checkHeading(map mod) {
  127.     return haskey (mod, "heading");
  128. }
  129.  
  130. /**
  131.   * Read XML Control File
  132.   * @param string control file
  133.   * @return boolean
  134.   */
  135. global define boolean ReadControlFile( string controlfile) 
  136. {
  137.     productControl = XML::XMLToYCPFile(controlfile);
  138.  
  139.     if (productControl == nil)
  140.         return false;
  141.  
  142.     workflows = productControl["workflows"]:[];
  143.     proposals = productControl["proposals"]:[];
  144.     inst_finish = productControl["inst_finish_stages"]:[];
  145.     clone_modules = productControl["clone_modules"]:[];
  146.  
  147.     foreach (string section,
  148.     ["software", "globals", "network", "partitioning"],
  149.     {
  150.     if (haskey (productControl, section))
  151.     {
  152.         ProductFeatures::SetSection (section,
  153.         (map<string,any>)(productControl[section]:$[]));
  154.     }
  155.     });
  156.  
  157.     // FIXME would be nice if it could be done generic way
  158.     if (size( productControl["partitioning", "partitions"]:[] ) > 0)
  159.     {
  160.     map partitioning = productControl["partitioning"]:$[];
  161.     ProductFeatures::SetBooleanFeature ("partitioning",
  162.         "flexible_partitioning", true);
  163.     ProductFeatures::SetFeature ("partitioning", "FlexiblePartitioning",
  164.         partitioning);
  165.     }
  166.     string textdom = productControl["textdomain"]:"control";
  167.     texts = mapmap (string key, map<string,string> text,
  168.     productControl["texts"]:$[],
  169.     {
  170.     string label = text["label"]:"";
  171.     return $[ key : $[
  172.         "label" : label,
  173.         "textdomain" : textdom,
  174.     ] ];
  175.     });
  176.     return true;
  177. }
  178.  
  179.  
  180.  
  181. boolean Check(string allowed, string current)
  182. {
  183.     // create allowed list
  184.     list<string> allowedlist = filter(string s,
  185.             splitstring(deletechars(allowed, " "), ","), ``(s!=""));
  186.     y2debug("allowedlist: %1", allowedlist );
  187.     y2debug("current: %1", current );
  188.     if (size(allowedlist) == 0 )
  189.     {
  190.         return true;
  191.     }
  192.     else if (contains(allowedlist, current ))
  193.     {
  194.         return true;
  195.     }
  196.     else
  197.     {
  198.         return false;
  199.     }
  200. }
  201.  
  202.  
  203.  
  204. /**
  205.  * Check if valid architecture
  206.  * @param map module data
  207.  * @param map default data
  208.  * @return boolean true if arch match
  209.  */
  210. global define boolean checkArch(map mod , map def)
  211. {
  212.     y2milestone("mod: %1", mod);
  213.     string archs = mod["archs"]:"";
  214.     if (archs == "")
  215.     {
  216.         archs=def["archs"]:"all";
  217.     }
  218.  
  219.     if (archs == "all") {
  220.         return true;
  221.     }
  222.  
  223.     y2milestone("short arch desc: %1", Arch::arch_short () );
  224.     y2milestone("supported archs: %1", archs );
  225.     if (issubstring(archs,Arch::arch_short ()))
  226.     {
  227.         return true;
  228.     }
  229.  
  230.     return false;
  231. };
  232.  
  233.  
  234. string getClientName(string name ) {
  235.  
  236.     if (Mode::test()) 
  237.     {
  238.         return "inst_test_workflow";
  239.     }
  240.     // All client start with "inst_".
  241.     string client = "";
  242.     if ( custom_control_file != "")
  243.     {
  244.         return name;
  245.     }
  246.     else
  247.     {
  248.         if (issubstring(name, _client_prefix)) {
  249.             return name;        
  250.     } else {
  251.             client = _client_prefix + name;
  252.         return client;
  253.     }
  254.     
  255.     }
  256. }
  257.  
  258. /**
  259.  * Return term to be used to run module with CallFunction
  260.  * @param map module data
  261.  * @param map default data
  262.  * @return term module data with params
  263.  */
  264. global define term getClientTerm (map step, map def, any former_result)
  265. {    
  266.     string client =  getClientName(step["name"]:"dummy");
  267.     term result = toterm(client);
  268.     map<string,any> arguments = $[];
  269.     
  270.     foreach(string button, ["enable_back", "enable_next"], ``{
  271.     
  272.             string default_setting = def[button]:"yes";            
  273.         arguments[button] = step[button]:default_setting == "yes";           
  274.             });
  275.  
  276.     if (haskey(step,"proposal"))
  277.     {
  278.     arguments["proposal"] = step["proposal"]:"";
  279.     }
  280.     map<string, any> other_args = step["arguments"]:$[];
  281.     
  282.     if (size(other_args) > 0 )
  283.         arguments = (map<string, any>)union(arguments, other_args );
  284.  
  285.     if (is(former_result,symbol) && former_result == `back)
  286.         arguments["going_back"] = true;
  287.  
  288.     if (Mode::test())
  289.     {
  290.         arguments["step_name"] = step["name"]:"";
  291.         arguments["step_id"] = step["id"]:"";
  292.     }
  293.     result = add(result, arguments);
  294.     return result;
  295.  
  296. }
  297.  
  298.  
  299. /**
  300.  * Get workflow defaults
  301.  * @param string stage
  302.  * @param string mode
  303.  * @return map defaults
  304.  */
  305. global define map getModeDefaults(string stage, string mode)
  306. {
  307.     list<map> tmp = filter(map wf, workflows, ``(
  308.                 Check(wf["stage"]:"", stage) && Check(wf["mode"]:"", mode )
  309.     ));
  310.     map workflow = tmp[0]:$[];
  311.     return workflow["defaults"]:$[];
  312. }
  313.  
  314. /**
  315.  * Prepare Workflow Scripts
  316.  * @param m Workflow module map
  317.  * @return void
  318.  */
  319. void PrepareScripts(map m)
  320. {
  321.     string tmp_dir = (string)WFM::Read(.local.tmpdir, []);
  322.     if (haskey(m,"prescript"))
  323.     {
  324.         string interpreter = m["prescript", "interpreter"]:"shell";
  325.         string source = m["prescript", "source"]:"";
  326.         string type = (interpreter == "shell") ? "sh" : "pl";
  327.         string f = sformat("%1/%2_pre.%3", tmp_dir, m["name"]:"", type);
  328.         WFM::Write(.local.string,f , source);
  329.         logfiles = add(logfiles, sformat("%1.log", sformat("%1_pre.%2",
  330.                         m["name"]:"", type)));
  331.     }
  332.     if (haskey(m,"postscript"))
  333.     {
  334.         string interpreter = m["postscript", "interpreter"]:"shell";
  335.         string source = m["postscript", "source"]:"";
  336.         string type = (interpreter == "shell") ? "sh" : "pl";
  337.         string f = sformat("%1/%2_post.%3", tmp_dir, m["name"]:"", type);
  338.         WFM::Write(.local.string, f, source);
  339.         logfiles = add(logfiles, sformat("%1.log", sformat("%1_post.%2",
  340.                          m["name"]:"", type)));
  341.     }
  342.     return;
  343. }
  344.  
  345.  
  346.  
  347. /**
  348.  * Get list of required files for the workflow.
  349.  * @return list<string> Required files list.
  350.  */
  351. global list<string> RequiredFiles (string stage, string mode) 
  352. {
  353.     // Files needed during installation.
  354.     list<string> needed_client_files = [];
  355.  
  356.     list<map> tmp = filter(map wf, workflows, ``(
  357.                 Check(wf["stage"]:"", stage) && Check(wf["mode"]:"", mode )
  358.     ));
  359.     map workflow = tmp[0]:$[];
  360.  
  361.     list<map> modules = workflow["modules"]:[];
  362.     integer id = 1;
  363.     modules = filter(map m, modules, ``(m["enabled"]:true));
  364.  
  365.     foreach(map m, modules,
  366.     {
  367.     string client = "";
  368.     if (Stage::firstboot ())
  369.     {
  370.         client = m["name"]:"dummy";
  371.     }
  372.     else
  373.     {
  374.         if (issubstring(m["name"]:"dummy", "inst_"))
  375.         {
  376.         client = m["name"]:"dummy";
  377.         }
  378.         else
  379.         {
  380.         client = "inst_" + m["name"]:"dummy";
  381.         }
  382.     }
  383.     client = Directory::clientdir + "/" + client + ".ycp";
  384.     needed_client_files = add(needed_client_files, client);
  385.     });
  386.     
  387.     needed_client_files=toset(needed_client_files);
  388.     return needed_client_files;
  389. }
  390.  
  391.  
  392.  
  393. /**
  394.  * Get Workflow
  395.  * @param stage Stage
  396.  * @param mode Mdoe
  397.  * @return map Workflow map
  398.  */
  399. global define map getCompleteWorkflow(string stage, string mode)
  400. {
  401.     list<map> tmp = filter(map wf, workflows, ``(
  402.                 Check(wf["stage"]:"", stage) && Check(wf["mode"]:"", mode )
  403.     ));
  404.     map workflow = tmp[0]:$[];
  405.     return workflow;
  406. }
  407.  
  408.  
  409. /**
  410.  * Get modules of current Workflow
  411.  * @param string stage
  412.  * @param string mode
  413.  * @param boolean all enabled and disabled or enabled only
  414.  * @return list<map> modules
  415.  */
  416. global define list<map> getModules(string stage, string mode, symbol which)
  417. {
  418.     y2debug("workflows: %1", workflows );
  419.     list<map> tmp = filter(map wf, workflows, ``(
  420.                 Check(wf["stage"]:"", stage) && Check(wf["mode"]:"", mode )
  421.     ));
  422.     map workflow = tmp[0]:$[];
  423.  
  424.     y2debug("Workflow: %1", workflow );
  425.     list<map> modules = workflow["modules"]:[];
  426.     y2debug("modules: %1", modules );
  427.  
  428.     integer id = 1;
  429.     if (which == `enabled)
  430.     {
  431.     modules = filter (map m, modules, {
  432.         return m["enabled"]:true && ! checkDisabled (m);
  433.     });
  434.     }
  435.  
  436.     modules = maplist(map m, modules, ``{
  437.             m["id"] = sformat("%1_%2", stage, id);
  438.             PrepareScripts(m);
  439.             id = id + 1;
  440.             return (m);
  441.             });
  442.  
  443.     y2debug("Log files: %1", logfiles);
  444.     return modules;
  445. }
  446.  
  447. /**
  448.  * Get Workflow Label
  449.  * @param string stage
  450.  * @param string mode
  451.  * @return string
  452.  */
  453. global string getWorkflowLabel(string stage, string mode, string wz_td)
  454. {
  455.     list<map> tmp = filter(map wf, workflows, ``(
  456.                 Check(wf["stage"]:"", stage) && Check(wf["mode"]:"", mode )
  457.     ));
  458.     map workflow = tmp[0]:$[];
  459.     string label = workflow["label"]:"";
  460.     if (label == "")
  461.     return "";
  462.     if (haskey (workflow, "textdomain"))
  463.     return dgettext (workflow["textdomain"]:"", label);
  464.     else
  465.     return dgettext (wz_td, label);
  466. }
  467.  
  468.  
  469.  
  470. /**
  471.  * Add Wizard Steps
  472.  * @param list<map> stagemode A List of maps containing info about complete
  473.  *                  installation workflow.
  474.  * @return void
  475.  */
  476. global define void AddWizardSteps(list<map> stagemode)
  477. {
  478.     last_stage_mode = stagemode;
  479.  
  480.     // UI::WizardCommand() can safely be called even if the respective UI
  481.     // doesn't support the wizard widget, but for optimization it makes sense
  482.     // to do expensive operations only when it is available.
  483.  
  484.     // if ( ! UI::HasSpecialWidget(`Wizard ) )
  485.     // return;
  486.  
  487.     string wizard_textdomain = (string) productControl["textdomain"]:"control";
  488.     y2debug( "Using textdomain '%1' for wizard steps", wizard_textdomain );
  489.  
  490.     string first_id = "";
  491.     // UI::WizardCommand(`SetVerboseCommands( true ) );
  492.     foreach (map sm , stagemode, ``{
  493.         y2debug( "Adding wizard steps for %1", sm );
  494.         string slabel = getWorkflowLabel(sm["stage"]:"", sm["mode"]:"", wizard_textdomain);
  495.         if ( slabel != "" )
  496.         {
  497.             UI::WizardCommand (`AddStepHeading (slabel));
  498.         }
  499.  
  500.         string last_label = "";
  501.     string last_domain = "";
  502.         foreach(map m, getModules(sm["stage"]:"", sm["mode"]:"", `enabled),
  503.                 ``{
  504.             y2debug("Adding wizard step: %1", m );
  505.         if (haskey (m, "heading") && m["label"]:"" != "")
  506.         {
  507.         UI::WizardCommand (`AddStepHeading (
  508.             haskey (m, "textdomain")
  509.             ? dgettext (m["textdomain"]:"", m["label"]:"")
  510.             : dgettext (wizard_textdomain, m["label"]:"")));
  511.         }
  512.             else if (m["label"]:"" != "")
  513.         {
  514.                 if (first_id=="")
  515.                 {
  516.                     first_id = m["id"]:"";
  517.                 }
  518.                 UI::WizardCommand(`AddStep (
  519.             haskey (m, "textdomain")
  520.             ? dgettext (m["textdomain"]:"", m["label"]:"")
  521.             : dgettext (wizard_textdomain, m["label"]:""),
  522.             m["id"]:"" ));
  523.                 last_label = m["label"]:"";
  524.         last_domain = m["textdomain"]:"";
  525.             } else {
  526.                 if (first_id=="")
  527.                 {
  528.                     first_id = m["id"]:"";
  529.                 }
  530.         if (last_label != "")
  531.         {
  532.             if (last_domain != "")
  533.             UI::WizardCommand(`AddStep( dgettext(
  534.                 last_domain,
  535.                 last_label ),
  536.                             m["id"]:"" )
  537.             );
  538.             else
  539.             UI::WizardCommand(`AddStep( dgettext(
  540.                 wizard_textdomain,
  541.                 last_label ),
  542.                             m["id"]:"" )
  543.             );
  544.         }
  545.             }
  546.         });
  547.     });
  548.  
  549.     UI::WizardCommand(`SetCurrentStep( first_id ) );
  550.     return;
  551. }
  552.  
  553.  
  554.  
  555.  
  556. /**
  557.  * Update Steps
  558.  */
  559. global define void UpdateWizardSteps(list<map> stagemode)
  560. {
  561.     last_stage_mode = stagemode;
  562.  
  563.     UI::WizardCommand(`DeleteSteps());
  564.     AddWizardSteps( stagemode );
  565.     UI::WizardCommand(`UpdateSteps());
  566.     UI::WizardCommand(`SetCurrentStep( CurrentWizardStep ) );
  567.     return;
  568. }
  569.  
  570.  
  571. /**
  572.  * Retranslate Wizard Steps
  573.  */
  574. global define void RetranslateWizardSteps()
  575. {
  576.     if ( size( last_stage_mode ) > 0 )
  577.     {
  578.     y2debug( "Retranslating wizard steps" );
  579.     UpdateWizardSteps( last_stage_mode );
  580.     }
  581. }
  582.  
  583.  
  584. define list<map> getMatchingProposal(
  585.         string stage,
  586.         string mode,
  587.         string proptype)
  588. {
  589.     y2milestone("Stage: %1 Mode: %2, Type: %3", stage, mode, proptype);
  590.     
  591.     // First we search for proposals for current stage if there are
  592.     // any. 
  593.     list<map> props = filter(map p, proposals, ``(Check(p["stage"]:"", stage)));
  594.     y2debug("1. proposals: %1", props);
  595.  
  596.     // Then we check for mode: installation or update
  597.     props = filter(map p, props, ``(
  598.                     Check(p["mode"]:"", mode)));
  599.  
  600.     y2debug("2. proposals: %1", props);
  601.  
  602.     // Now we check for architecture
  603.     y2debug("Architecture: %1, Proposals: %2", Arch::architecture (), props );
  604.     
  605.     list<map> arch_proposals = filter(map p, props, ``(
  606.                 p["name"]:"" == proptype &&
  607.                 issubstring(p["archs"]:"dummy", Arch::arch_short () )));
  608.  
  609.     y2debug("3. arch proposals: %1", arch_proposals );
  610.     
  611.     props = filter(map p, props, ``(
  612.                     p["archs"]:"" == "" || p["archs"]:"" == "all"
  613.                     )
  614.            );
  615.  
  616.     y2debug("4. other proposals: %1", props );
  617.     // If architecture specific proposals are available, we continue with those
  618.     // and check for proposal type, else we continue with pre arch proposal
  619.     // list
  620.     if (size(arch_proposals) > 0 )
  621.     {
  622.         props = filter(map p, arch_proposals, ``(
  623.                      p["name"]:"" == proptype ));
  624.     y2debug ("5. arch proposals: %1", props);
  625.     }
  626.     else
  627.     {
  628.         props = filter(map p, props, ``(
  629.                      p["name"]:"" == proptype ));
  630.     y2debug ("5. other proposals: %1", props);
  631.     }
  632.  
  633.     if (size(props)> 1 )
  634.     {
  635.         y2error("Something Wrong happened, more than one proposal after filter:
  636.                 %1", props);
  637.     }
  638.  
  639.     // old style proposal
  640.     y2milestone ("Proposal modules: %1",props[0, "proposal_modules"]:nil );
  641.     return props;
  642. }
  643.  
  644.  
  645.  
  646. /**
  647.  * Get modules of current Workflow
  648.  * @param string stage
  649.  * @param string mode
  650.  * @return list<string> modules
  651.  */
  652. global define list < list > getProposals(string stage, string mode, string proptype) {
  653.  
  654.     list<map> props = getMatchingProposal(stage, mode, proptype);
  655.     
  656.     list< list > final_proposals = maplist(any p, props[0, "proposal_modules"]:[], ``{
  657.         
  658.         string proposal_name = "";
  659.         integer order_value = 50;
  660.         if ( is (p, string) )
  661.         {
  662.         proposal_name = (string)p;
  663.         }
  664.         else
  665.         {
  666.         map<string,string> pm = (map<string,string>)p;
  667.         proposal_name = pm["name"]:"";
  668.         string proposal_order = pm["presentation_order"]:"50";
  669.         
  670.         order_value = tointeger (proposal_order);
  671.         if (order_value == nil)
  672.         {
  673.             y2error ("Unable to use '%1' as proposal order, using %2 instead"
  674.             , proposal_order, 50);
  675.             order_value = 50;
  676.         }
  677.         }
  678.  
  679.         // All proposal file names end with _proposal
  680.             if (!issubstring(proposal_name, "_proposal"))
  681.                 return( [proposal_name + "_proposal", order_value ] );
  682.             else
  683.                 return( [proposal_name, order_value] );
  684.  
  685.     });
  686.  
  687.   
  688.     y2debug("final proposals: %1", final_proposals );
  689.     return final_proposals;
  690. }
  691.  
  692.  
  693. /**
  694.  * Get Proposal list that can not be changed by the user.
  695.  * @return list<string> list of locked proposals
  696.  */
  697. global list<string> getLockedProposals (string stage,string mode,string proptype) {
  698.  
  699.     list<map> props = getMatchingProposal(stage, mode, proptype);
  700.     list<string> locked_proposals = maplist(string p, props[0, "locked_modules"]:[], ``{
  701.     if (!issubstring(p, "_proposal"))
  702.     return(p + "_proposal");
  703.     else
  704.     return(p);
  705.  
  706.     });
  707.     return locked_proposals;
  708. }
  709.  
  710. /**
  711.  * Return text domain
  712.  */
  713. global string getProposalTextDomain() {
  714.     string current_proposal_textdomain = (string)
  715.     productControl["textdomain"]:"control";
  716.  
  717.     y2debug( "Using textdomain '%1' for proposals", current_proposal_textdomain);
  718.     return current_proposal_textdomain;
  719. }
  720.  
  721.  
  722. /**
  723.  * Return proposal Label
  724.  */
  725. global map getProposalProperties( string stage, string mode, string proptype
  726. )
  727. {
  728.     list<map> proposals = getMatchingProposal(stage, mode, proptype);
  729.     map proposal = proposals[0]:$[];
  730.     if (haskey (proposal, "proposal_tabs"))
  731.     {
  732.     string text_domain = productControl["textdomain"]:"control";
  733.     proposal["proposal_tabs"] = maplist (map tab,
  734.         proposal["proposal_tabs"]:[],
  735.     {
  736.         string domain = tab["textdomain"]:text_domain;
  737.         tab["label"] = dgettext (domain, tab["label"]:"");
  738.         return tab;
  739.     });
  740.     }
  741.     return proposal;
  742.  
  743. }
  744.  
  745. global string GetTranslatedText (string key) {
  746.     map<string,string> text = texts[key]:$[];
  747.     string label = text["label"]:"";
  748.     if (label == "")
  749.     {
  750.     y2error ("The requested label %1 does not exist", key);
  751.     return "";
  752.     }
  753.     string domain = text["textdomain"]:"";
  754.     if (domain == "")
  755.     {
  756.     y2error ("The text domain for label %1 not set", key);
  757.     return label;
  758.     }
  759.     return dgettext (domain, label);
  760. }
  761.  
  762.  
  763. /**
  764.  * Initialize Product Control
  765.  * @return boolean True on success
  766.  */
  767. global define boolean Init()
  768. {
  769.  
  770.     boolean ret = false;
  771.     current_control_file = "";
  772.     list<string> order =
  773.         [
  774.      y2update_control_file,  // /y2update/control.xml
  775.      default_control_file,  // /control.xml
  776.      saved_control_file, // /etc/YaST2/control.xml
  777.      packaged_control_file // /usr/share/YaST2/control/control.xml
  778.      ];
  779.  
  780.     if ( custom_control_file != "")
  781.     {
  782.         order=prepend(order, custom_control_file);
  783.     }
  784.  
  785.     y2milestone("Candidates: %1", order );
  786.     foreach(string cf, order,
  787.     {
  788.     if ((integer)SCR::Read( .target.size, cf )>0
  789.             && current_control_file == "")
  790.     {
  791.         current_control_file = cf;
  792.     }
  793.     });
  794.  
  795.     if (current_control_file == "")
  796.     {
  797.         y2error("Control file not found");
  798.         return false;
  799.     }
  800.  
  801.     y2milestone("Reading control file: %1", current_control_file );
  802.     ReadControlFile( current_control_file );
  803.     return (current_control_file != "");
  804. }
  805.  
  806. /**
  807.  * Re-translate static part of wizard dialog and other predefined messages
  808.  * after language change
  809.  */
  810. void retranslateWizardDialog()
  811.     {
  812.     y2milestone( "Retranslating messages 1" );
  813.  
  814.     // Make sure the labels for default function keys are retranslated, too.
  815.     // Using Label::DefaultFunctionKeyMap() from Label module.
  816.     UI::SetFunctionKeys( Label::DefaultFunctionKeyMap() );
  817.  
  818.     // Activate language changes on static part of wizard dialog
  819.  
  820.     ProductControl::RetranslateWizardSteps();
  821.     Wizard::RetranslateButtons();
  822.     Wizard::SetFocusToNextButton();
  823.         return;
  824.     }
  825.  
  826.  
  827.  
  828. void addToStack(string name) {
  829.     stack=add(stack, name);
  830.     return;
  831. }
  832.  
  833. global boolean wasRun(string name)
  834. {
  835.     return contains(stack, name);
  836. }
  837.  
  838. global symbol RunFrom (integer from, boolean allow_back)
  839. {
  840.     any  former_result = `next;
  841.     symbol final_result = nil;
  842.     current_step = from;            // current module
  843.  
  844.     Wizard::SetFocusToNextButton();
  845.  
  846.     y2debug("Starting Workflow with  \"%1\" \"%2\"",  Stage::stage (), Mode::mode ());
  847.     
  848.     list<map> modules = 
  849.     getModules( Stage::stage (), Mode::mode (), `enabled);
  850.  
  851.     map defaults = getModeDefaults(Stage::stage (), Mode::mode ());
  852.  
  853.     y2debug("modules: %1", modules);
  854.  
  855.     if (size(modules) == 0 )
  856.     {
  857.     y2error("No workflow found: %1", modules );
  858.     // error report
  859.     Report::Error(_("No workflow defined for this installation mode."));
  860.     return `abort;
  861.     }
  862.  
  863.     integer minimum_step = allow_back ? 0 : from;
  864.     while ((current_step >= 0) && (current_step < size(modules)))
  865.     {
  866.     map step = modules[current_step]:$[];
  867.     string  step_name = step["name"]:"";
  868.     boolean run_in_update_mode = step["update"]:true; // default is true
  869.     boolean retranslate = step["retranslate"]:false;
  870.         string step_id = step["id"]:"";
  871.  
  872.         if (current_step <= minimum_step)
  873.         {
  874.             step["enable_back"] = "no";
  875.         }
  876.  
  877.     boolean   do_continue           = false;
  878.  
  879.     if (!checkArch(step, defaults))
  880.     {
  881.         do_continue = true;
  882.     }
  883.  
  884.     if (checkDisabled(step))
  885.     {
  886.         do_continue = true;
  887.     }
  888.  
  889.     if (checkHeading(step))
  890.     {
  891.         do_continue = true;
  892.     }
  893.  
  894.     if (!run_in_update_mode && Mode::update ())
  895.     {
  896.         do_continue = true;
  897.     }
  898.  
  899.     if ( do_continue )
  900.     {
  901.         if (former_result == `next)
  902.         {
  903.         if (current_step <= minimum_step && ! allow_back)
  904.             minimum_step = minimum_step + 1;
  905.         current_step = current_step + 1;
  906.         }
  907.         else
  908.         current_step = current_step - 1;
  909.     }
  910.     if ( do_continue ) continue;
  911.  
  912.     term argterm = getClientTerm( step, defaults, former_result);
  913.     y2debug("Running module: %1 (%2)", argterm, current_step);
  914.  
  915.     symbol module_name = symbolof( argterm );
  916.  
  917.     y2milestone( "Calling %1", argterm );
  918.  
  919.         if (!wasRun(step_name)) {
  920.             Hooks::Checkpoint (sformat("%1", module_name), true);
  921.             Hooks::Run (step_name, true);
  922.         }
  923.  
  924.     list args = [];
  925.     integer i = 0;
  926.     while (i < size(argterm)) 
  927.     {
  928.         any def = nil;
  929.         args[i] = argterm[i]:def;
  930.         i = i + 1;
  931.     }
  932.  
  933.     UI::WizardCommand(`SetCurrentStep( step_id ) );
  934.     CurrentWizardStep = step_id;
  935.  
  936.         // Register what step we are going to run
  937.         if (!Stage::initial())
  938.         {
  939.             if (!SCR::Write (.target.string, "/var/lib/YaST2/step", step_id))
  940.                 y2error("Error writing step identifier");
  941.         }
  942.  
  943.     symbol result = (symbol) WFM::CallFunction (getClientName(step_name), args);
  944.     y2milestone ("Calling %1 returned %2", argterm, result);
  945.  
  946.         // Remove file if step was run and returned (without a crash);
  947.     if (current_step < size(modules) - 1 && !Stage::initial())
  948.         {
  949.             if (!(boolean)SCR::Execute(.target.remove, "/var/lib/YaST2/step"))
  950.                 y2error("Error removing step identifier");
  951.         }
  952.  
  953.     // Dont call hook scripts after installation is done. (#36831)
  954.     if (current_step < size(modules) - 1 && !wasRun(step_name))
  955.         Hooks::Run (step_name, false );
  956.     else
  957.         y2milestone("Not running hooks at the end of the installation");
  958.  
  959.     // This should be safe (#36831)
  960.     Hooks::Checkpoint ( step_name, false);          // exit hook
  961.  
  962.     addToStack(step_name);
  963.  
  964.     if ( retranslate )
  965.     {
  966.             y2milestone("retranslate");
  967.         retranslateWizardDialog();
  968.         retranslate = false;
  969.     }
  970.  
  971.     // If the module return nil, something basic went wrong.
  972.     // We show a stub dialog instead.
  973.     if (result == nil)
  974.     {
  975.         /**
  976.          * If workflow module is marked as optional, skip if it returns nil,
  977.          * For example, if it is not installed.
  978.          */
  979.         if (step["optional"]:false)
  980.         {
  981.         y2milestone("Skipping optional %1", symbolof(argterm) );
  982.         current_step = current_step + 1;
  983.         continue;
  984.         }
  985.  
  986.         any r = nil;
  987.         r = Popup::ModuleError(sformat("The module %1 does not work.", symbolof(argterm)));
  988.  
  989.         if (r == `next)
  990.         current_step = current_step + 1;
  991.         else if (r == `back)
  992.         current_step = current_step - 1;
  993.         else if (r != `again)
  994.         {
  995.         UI::CloseDialog();
  996.         return nil;
  997.         }
  998.         continue;
  999.     }
  1000.  
  1001.     if (result == `next)
  1002.     {
  1003.         current_step = current_step + 1;
  1004.     }
  1005.     else if (result == `back)
  1006.     {
  1007.         current_step = current_step - 1;
  1008.     }
  1009.     else if (result == `cancel)
  1010.     {
  1011.         break;
  1012.     }
  1013.     else if (result == `abort)
  1014.     {
  1015.         // FATE #300422
  1016.         // handling when user aborts the second stage installation
  1017.         if (Stage::cont ()) {
  1018.         final_result = result;
  1019.         }
  1020.         break;
  1021.     }
  1022.     else if (result == `finish)
  1023.     {
  1024.         break;
  1025.     }
  1026.     else if (result == `again)
  1027.     {
  1028.         continue; // Show same dialog again
  1029.     }
  1030.     else if (result == `restart_yast)
  1031.     {
  1032.         final_result = result;
  1033.         break;
  1034.     }
  1035.     else if (result == `restart_same_step)
  1036.     {
  1037.         final_result = result;
  1038.         break;
  1039.     }
  1040.     else if (result == `reboot)
  1041.     {
  1042.         final_result = result;
  1043.         break;
  1044.     }
  1045.     else if (result == `auto)
  1046.     {
  1047.         if (former_result != nil)
  1048.         {
  1049.         if (former_result == `next)
  1050.         {
  1051.             // if the first client just returns `auto , the back button
  1052.             // of the next client must be disabled
  1053.             if (current_step <= minimum_step && ! allow_back)
  1054.             minimum_step = minimum_step + 1;
  1055.             current_step = current_step + 1;
  1056.         }
  1057.         else if (former_result == `back)
  1058.             current_step = current_step - 1;
  1059.         }
  1060.         continue;
  1061.     }
  1062.     former_result = result;
  1063.     }
  1064.     if (former_result == `abort)
  1065.     {
  1066.     final_result = `abort;
  1067.     }
  1068.  
  1069.     y2milestone ("Former result: %1, Final result: %2", former_result, final_result);
  1070.  
  1071.     if (final_result != nil) {
  1072.     y2milestone ("Final result already set.");
  1073.     } else if (current_step <= -1) {
  1074.     final_result = `back;
  1075.     } else {
  1076.     final_result = `next;
  1077.     }
  1078.  
  1079.     y2milestone ("Current step: %1, Returning: %2", current_step, final_result);    
  1080.     return final_result;
  1081. }
  1082.  
  1083. /**
  1084.  * Run Workflow
  1085.  *
  1086.  */
  1087. global symbol Run () {
  1088.     symbol ret = RunFrom (0, false);
  1089.     y2milestone ("Run() returning %1", ret);
  1090.     return ret;
  1091. }
  1092.  
  1093. // Functions to access restart information
  1094.  
  1095. /**
  1096.  * List steps which were skipped since last restart of YaST
  1097.  * @return a list of maps describing the steps
  1098.  */
  1099. global list<map> SkippedSteps () {
  1100.     list<map> modules = getModules( Stage::stage (), Mode::mode (), `enabled);
  1101.     if (first_step == nil)
  1102.     return nil;
  1103.     if (first_step >= size (modules))
  1104.     return nil;
  1105.     integer index = 0;
  1106.     list<map> ret = [];
  1107.     while (index < first_step)
  1108.     {
  1109.     ret = add (ret, modules[index]:$[]);
  1110.     index = index + 1;
  1111.     }
  1112.     return ret;
  1113. }
  1114.  
  1115. /**
  1116.  * Return step which restarted YaST (or rebooted the system)
  1117.  * @return a map describing the step
  1118.  */
  1119. global map RestartingStep () {
  1120.     if (restarting_step == nil)
  1121.     return nil;
  1122.     list<map> modules = getModules( Stage::stage (), Mode::mode (), `enabled);
  1123.     return modules[restarting_step]:$[];
  1124. }
  1125.  
  1126.  
  1127. /**
  1128.  * ProductControl Constructor
  1129.  * @return void
  1130.  */
  1131. global define void ProductControl()
  1132. {
  1133.     if (!Init())
  1134.     {
  1135.     y2error("control file missing");
  1136.     }
  1137.     return;
  1138. }
  1139.  
  1140. // EOF
  1141. }
  1142.