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 / Sequencer.ycp < prev    next >
Text File  |  2006-11-29  |  10KB  |  338 lines

  1. /**
  2.  * File:    modules/Sequencer.ycp
  3.  * Module:    yast2
  4.  * Summary:    Wizard Sequencer
  5.  * Authors:    Michal Svec <msvec@suse.cz>
  6.  * Flags:    Stable
  7.  *
  8.  * $Id: Sequencer.ycp 31242 2006-06-01 12:59:16Z locilka $
  9.  *
  10.  * This is an implementation of the wizard sequencer, the tool for
  11.  * processing workflows of dialogs.
  12.  * <br>
  13.  * All errors are reported to y2log, so if anything is unfunctional
  14.  * look to the y2log.
  15.  */
  16.  
  17. {
  18.  
  19. module "Sequencer";
  20. textdomain "base";
  21.  
  22. boolean docheck = true;
  23.  
  24. /**
  25.  * Test (run) all dialogs in the aliases map
  26.  * @param aliases the map of aliases
  27.  * @return returned values of tested dialogs
  28.  * @see WS documentation for the format of aliases map
  29.  */
  30. define list WS_testall(map aliases) {
  31.     return maplist(any id, any func, aliases, { return eval(func); });
  32. }
  33.  
  34. /**
  35.  * Check correct types in maps and alias presence for sequence.
  36.  * @param aliases the map of aliases
  37.  * @param sequence the sequence of dialogs
  38.  * @return check passed?
  39.  */
  40. define boolean WS_check(map aliases, map sequence) {
  41.     list<boolean> ret = [];
  42.  
  43.     /* check if aliases is not a nil */
  44.     if (aliases == nil) {
  45.     y2error(2, "sequencer check: aliases is nil");
  46.     return false;
  47.     }
  48.  
  49.     /* check if sequence is not a nil */
  50.     if (sequence == nil) {
  51.     y2error(2, "sequencer check: sequence is nil");
  52.     return false;
  53.     }
  54.  
  55.     /* check if ws_start is in aliases */
  56.     if (aliases["ws_start"]:nil != nil) {
  57.         y2error(2, "sequencer check: ws_start cannot be an alias name");
  58.         ret = add(ret, false);
  59.     }
  60.     else ret = add(ret, true);
  61.  
  62.     /* check aliases map types */
  63.     list<boolean> ret0 = maplist(any key, any val, aliases, {
  64.         if (!is(key, string)) {
  65.             y2error(2, "sequencer check: not a string: %1", key);
  66.             return false;
  67.         }
  68.         else if (is(val, list)) {
  69.             if(size((list) val) < 2) {
  70.                 y2error(2, "sequencer check: list too small: %1 (%2)", val, key);
  71.                 return false;
  72.             }
  73. /* FIXME: use function pointers
  74.             else if (!is(select((list) val, 0, nil), term)) {
  75.                 y2error(2, "sequencer check: not a term: %1", select((list) val, 0, nil));
  76.                 return false;
  77.             }
  78. */
  79.             else if (!is(select((list) val, 1, nil), boolean)) {
  80.                 y2error(2, "sequencer check: not a boolean: %1", select((list) val, 1, nil));
  81.                 return false;
  82.             }
  83.             else return true;
  84.         }
  85. /* FIXME: use function pointers
  86.         else if (!is(val, term)) {
  87.             y2error(2, "sequencer check: not a term: %1", val);
  88.             return false;
  89.         }
  90. */
  91.     else return true;
  92.     });
  93.     ret = flatten([ret, ret0]);
  94.  
  95.     /* check if ws_start is in sequence */
  96.     if (sequence["ws_start"]:nil == nil) {
  97.         y2error(2, "sequencer check: ws_start needs to be defined");
  98.         ret = add(ret, false);
  99.     }
  100.     else ret = add(ret, true);
  101.  
  102.     /* check all aliases in sequence */
  103.     ret0 = maplist(any key, any val, sequence, {
  104.         if (key=="ws_start") {
  105.             if (!is(val, symbol) && aliases[val]:nil == nil) {
  106.                 y2error(2, "sequencer check: alias not found: %1", val);
  107.                 return false;
  108.             }
  109.             else return true;
  110.         }
  111.         else if (aliases[key]:nil == nil) {
  112.             y2error(2, "sequencer check: alias not found: %1", key);
  113.             return false;
  114.         }
  115.         else if (!is(val, map)) {
  116.             y2error(2, "sequencer check: not a map: %1 %2", key, val);
  117.             return false;
  118.         }
  119.         else {
  120.             list<boolean> ret1 = maplist(any k, any v, (map) val, {
  121.                 if (!is(k, symbol)) {
  122.                     y2error(2, "sequencer check: not a symbol: %1", k);
  123.                     return false;
  124.                 }
  125.                 else if (!is(v, symbol) && aliases[v]:nil == nil) {
  126.                     y2error(2, "sequencer check: alias not found: %1", v);
  127.                     return false;
  128.                 }
  129.                 else return true;
  130.             });
  131.             if (find(boolean n, ret1, { return n == false; }) != nil) return false;
  132.             return true;
  133.         }
  134.     });
  135.     ret = flatten([ret, ret0]);
  136.  
  137.     /* check that all aliases are used */
  138.     ret0 = maplist(any key, any val, aliases, {
  139.         if (!haskey(sequence, key)) {
  140.             y2warning(2, "sequencer check: alias not used: %1", key);
  141.             // return false;
  142.         }
  143.     return true;
  144.     });
  145.     ret = flatten([ret, ret0]);
  146.  
  147.     if (find(boolean n, ret, { return n == false; }) != nil) return false;
  148.     return true;
  149. }
  150.  
  151. /**
  152.  * Report error and return nil
  153.  * @param error the error message text
  154.  * @return always nil
  155.  * @see bug #6474
  156.  */
  157. define any WS_error(string error) {
  158.     y2error(1, "sequencer: %1", error);
  159.     return nil;
  160. }
  161.  
  162. /**
  163.  * Find an aliases in the aliases map
  164.  * @param aliases map of aliases
  165.  * @param alias given alias
  166.  * @return term belonging to the given alias or nil, if error
  167.  */
  168. define any WS_alias(map aliases, string alias) {
  169.     any found = aliases[alias]:nil;
  170.     if (found == nil)
  171.         return WS_error(sformat("Alias not found: %1", alias));
  172.     if (is(found, list)) {
  173.         if (size((list) found) <= 0)
  174.         return WS_error(sformat("Invalid alias: %1", found));
  175.     found = select((list) found, 0, nil);
  176.     }
  177.     if (found == nil)
  178.     return WS_error(sformat("Invalid alias: %1", found));
  179. /* FIXME: use function pointers
  180.     if (is(found, term)) */
  181.         return found;
  182.     return WS_error(sformat("Invalid alias: %1", found));
  183. }
  184.  
  185. /**
  186.  * Decide if an alias is special
  187.  * @param aliases map of aliases
  188.  * @param alias given alias
  189.  * @return true if the given alias is special or nil, if not found
  190.  */
  191. define boolean WS_special(map aliases, string alias) {
  192.     any found = aliases[alias]:nil;
  193.     if (found == nil)
  194.         return (boolean) WS_error(sformat("Alias not found: %1", alias));
  195.     boolean ret = false;
  196.     if (is(found, list))
  197.         if (size((list) found) > 1)
  198.             ret = (boolean) select((list) found, 1, nil);
  199.     return ret;
  200. }
  201.  
  202. /**
  203.  * Find a next item in the sequence
  204.  * @param sequence sequence of dialogs
  205.  * @param current current dialog
  206.  * @param ret returned value (determines the next dialog)
  207.  * @return next dialog (symbol), WS action (string) or nil, if error (current or next not found)
  208.  */
  209. define any WS_next(map sequence, string current, symbol ret) {
  210.     map found = (map)(sequence[current]:nil);
  211.     if (found == nil) return WS_error(sformat("Current not found: %1", current));
  212.     /* string|symbol next */
  213.     any next = found[ret]:nil;
  214.     if (next == nil) return WS_error(sformat("Symbol not found: %1", ret));
  215.     return next;
  216. }
  217.  
  218. /**
  219.  * Run a function from the aliases map
  220.  * @param aliases map of aliases
  221.  * @param id function to run
  222.  * @return returned value from function or nil, if function is nil or returned something else than symbol
  223.  */
  224. define symbol WS_run(map aliases, string id) {
  225.     y2debug("Running: %1", id);
  226.     any function = nil;
  227.  
  228.     function = WS_alias(aliases, id);
  229.     if (function == nil)
  230.         return (symbol) WS_error(sformat("Bad id: %1", id));
  231.  
  232.     any ret = eval(function);
  233.  
  234.     if (!is(ret, symbol))
  235.     return (symbol) WS_error(sformat("Returned value not symbol: %1", ret));
  236.  
  237.     return (symbol) ret;
  238. }
  239.  
  240. /**
  241.  * Push one item to the stack
  242.  * @param stack stack of previously run dialogs
  243.  * @param item item to be pushed
  244.  * @return the new stack or nil, if the stack is nil
  245.  */
  246. define list WS_push(list stack, any item) {
  247.     if (stack == nil)
  248.         return nil;
  249.  
  250.     if (!contains(stack, item))
  251.         return add(stack, item);
  252.  
  253.     boolean found = false;
  254.     list newstack = filter(any v, stack, {
  255.         if (found) return false;
  256.         if (v == item) found=true;
  257.         return true;
  258.     });
  259.  
  260.     return newstack;
  261. }
  262.  
  263. /**
  264.  * Pop one item from the stack (remove an item and return the stack top item)
  265.  * @param stack stack of previously run dialogsk
  266.  * @return [ new stack, poped value ] or nil if the stack is empty or nil
  267.  */
  268. define list WS_pop(list stack) {
  269.     if (stack == nil) return nil;
  270.     integer num = size(stack);
  271.     if (num < 2) return nil;
  272.     list newstack = remove(stack, num-1);
  273.     any poped = select(stack, num-2, nil);
  274.     return [ newstack, poped ];
  275. }
  276.  
  277. /**
  278.  * The Wizard Sequencer
  279.  * @param aliases the map of aliases
  280.  * @param sequence the sequence of dialogs
  281.  * @return final symbol or nil, if error (see the y2log)
  282.  */
  283. global define symbol Run(map aliases, map sequence) {
  284.  
  285.     /* Check aliases and sequence correctness */
  286.     if (docheck && WS_check(aliases, sequence) != true)
  287.     return (symbol) WS_error("CHECK FAILED");
  288.  
  289.     list stack = [];
  290.     /* string|symbol current */
  291.     any current = sequence["ws_start"]:nil;
  292.     if (current == nil)
  293.     return (symbol) WS_error("Starting dialog not found");
  294.  
  295.     while (true) {
  296.     if (is(current, symbol)) {
  297.         y2debug("Finished");
  298.         return (symbol) current;
  299.     }
  300.  
  301.     stack = WS_push(stack, current);
  302.     y2debug("stack=%1", stack);
  303.     any ret = WS_run(aliases, (string) current);
  304.  
  305.     if (ret == nil || !is(ret, symbol))
  306.         return (symbol) WS_error(sformat("Invalid ret: %1", ret));
  307.  
  308.     else if (ret == `back) {
  309.         y2debug("Back");
  310.         list poped = [];
  311.         boolean special = true;
  312.         do {
  313.         if (size(stack)<2) return `back;
  314.         poped = WS_pop(stack);
  315.         y2debug("poped=%1", poped);
  316.         current = select(poped, 1, nil);
  317.         stack = (list) select(poped, 0, nil);
  318.         special = WS_special(aliases, (string) current);
  319.         y2debug("special=%1", special);
  320.         } while (special);
  321.     }
  322.  
  323.     else {
  324.         y2debug("ret=%1", ret);
  325.         current = WS_next(sequence, (string) current, (symbol) ret);
  326.         y2debug("current=%1", current);
  327.         if (current == nil)
  328.         return (symbol) WS_error(sformat("Next not found: %1", current));
  329.     }
  330.     }
  331.  
  332.     /* Not reached */
  333.     return nil;
  334. }
  335.  
  336. /* EOF */
  337. }
  338.