ACC SHELL

Path : /usr/share/YaST2/clients/
File Upload :
Current File : //usr/share/YaST2/clients/inst_automatic_configuration.ycp

/**
 * File:	clients/inst_automatic_configuration.ycp
 * Package:	installation
 * Summary:	Automatic configuration instead of the second stage
 * Authors:	Lukas Ocilka <locilka@suse.cz>
 *
 * $Id: inst_automatic_configuration.ycp 58525 2009-09-04 12:20:57Z kmachalkova $
 *
 * @see http://visnov.blogspot.com/2008/02/getting-rid-of-2nd-stage-of.html
 */

{
    import "Mode";
    import "Stage";
    import "FileUtils";
    import "Directory";
    import "GetInstArgs";
    import "Wizard";
    import "Progress";
    // reads the control file
    // and sets sections of ProductFeatures
    import "ProductControl";
    import "ProductFeatures";
    import "InstError";

    textdomain "installation";

    if (GetInstArgs::going_back()) {
	// bnc #395098
	// There is no reason to go back as AC is non-interactive
	// and additionally there is nothing before AC to run
	y2milestone ("Returning `next, no reason to go back");
	return `next;
    }

    boolean test_mode = false;

    if (size (WFM::Args()) > 0 && is (WFM::Args(0), string)) {
	y2milestone ("Args: %1", WFM::Args());
	if (WFM::Args(0) == "test")
	    test_mode = true;
    }

    if (test_mode) Wizard::CreateDialog();

    y2milestone ("automatic_configuration started");

//    list <map <string, any> > proposal_scripts_to_call = [
//	$[
//	    "label":_("Finishing configuration..."),
//	    "type":"scripts",
//	    "items":["addon_update_sources", "inst_extrasources", "suseconfig", "save_hardware_status"]
//	],
//    ];

    list <map <string, any> > proposal_scripts_to_call = [];

    map <string, any> globals_features = ProductFeatures::GetSection ("globals");
    list <map> acc = (list <map>) globals_features["automatic_configuration"]:[];
    list <string> acc_ignore = (list <string>) globals_features["ac_redraw_and_ignore"]:[];

    if (acc == nil || acc == []) {
	y2warning ("No AC defined (%1), skipping...", acc);
	return `next;
    }

    map< string, list <string> > disabled_ac_items =  ProductControl::GetDisabledACItems();
    foreach (map one_step, acc, {
	map new_step = $[
	    "unique"	: one_step["unique_id"]:"",
	    "label"	: one_step["text_id"]:"",
	    "icon"	: one_step["icon"]:"yast",
	    "type"	: one_step["type"]:"scripts",
	    "items"	: maplist (string one_ic_item, (list <string>) one_step["ac_items"]:[], {
		return one_ic_item;
	    }),
	];

	// filter out the wrong ones
	new_step["items"] = filter (string one_item, new_step["items"]:[], {
	    if (one_item == nil || one_item == "") {
		y2error ("Wrong item '%1' came from %2", one_item, one_step);
		return false;
	    }

	    if ( haskey( disabled_ac_items, new_step["unique"]:"") &&
		 contains(disabled_ac_items[ new_step["unique"]:"" ]:[], one_item ) ) {
		y2milestone("Item %1 found among disabled items", one_item);
		return false;
	   } 

	    return true;
	});

	new_step["label"] = ProductControl::GetTranslatedText (new_step["label"]:"");

	if (new_step["label"]:"" == "" || new_step["label"]:nil == nil) {
	    y2error ("Unknown label text ID '%1', using fallback", new_step["label"]:"");
	    new_step["label"] = _("Creating automatic configuration...");
	}

	proposal_scripts_to_call = add (proposal_scripts_to_call, (map <string, any>) new_step);
    });

    /**
     * Prepares the list of installation scripts to be executed.
     * This comes from control file where scripts are mentioned without the leading
     * "inst_" but they are actually named that way ("inst_something").
     *
     * @example ["aa", "inst_bb"] -> ["inst_aa", "inst_bb"]
     */
    list <string> NormalizeScriptNames (list <string> names) {
	list <string> ret_names = [];

	foreach (string one_name, names, {
	    if (regexpmatch (one_name, "^inst_")) {
		ret_names = add (ret_names, one_name);
	    } else {
		ret_names = add (ret_names, "inst_" + one_name);
	    }
	});

	return ret_names;
    }

    /**
     * Similar to NormalizeScriptNames but it add "_proposal" instead if "inst_".
     *
     * @example ["aa", "bb_proposal"] -> ["aa_proposal", "bb_proposal"]
     */
    list <string> NormalizeProposalNames (list <string> names) {
	list <string> ret_names = [];

	foreach (string one_name, names, {
	    if (regexpmatch (one_name, "_proposal$")) {
		ret_names = add (ret_names, one_name);
	    } else {
		ret_names = add (ret_names, one_name + "_proposal");
	    }
	});

	return ret_names;
    }

    void HandleExceptions (string proposal_name) {
	if (proposal_name == "x11_proposal" || proposal_name == "x11") {
	    if (! UI::TextMode()) {
		y2milestone ("Printing >don't panic<!");
		SCR::Write (.dev.tty.stderr,
		    // TRANSLATORS: this message is displayed on console when X11 configuration
		    // switches from running X to console. Sometimes it looks like
		    // the installation has failed.
		    _("

******************************************************

 Do not panic!

 X11 Configuration must switch to console for a while
 to detect your videocard properly...

******************************************************
")
		);
	    }
	}
    }

    integer nr_of_steps = 0;

    void SetWizardContents () {
	Wizard::SetContents (
	    _("Automatic Configuration"),
	    `VBox (
		// faster progress
		`ReplacePoint(
		    `id ("rp_one_set_progress"),
		    `ProgressBar (
			`id ("one_set_progress"),
			_("Preparing configuration..."),
			100,
			0
		    )
		),
		// overall-autoconf progress
		`ProgressBar (
		    `id ("autoconf_progress"),
		    _("Creating automatic configuration..."),
		    nr_of_steps,
		    0
		)
	    ),
	    _("<p>Installation is currently writing the automatic configuration. Please wait...</p>"),
	    false, false
	);
    }

    integer current_sub_step = 0;
    integer current_step = 0;
    string current_client = "";
    boolean ac_redraw_and_ignore = nil;

    void DumpACUIError () {
	y2error ("AC progress widgets missing");
	y2warning ("---------------------- UI DUMP ----------------------");
	UI::DumpWidgetTree();
	y2warning ("---------------------- UI DUMP ----------------------");
    }

    string last_client = nil;

    void NextStep () {
	// If a Progress is missing, it's recreated and an error is reported
	if (last_client == nil) last_client = current_client;
	ac_redraw_and_ignore = (last_client == nil ? false : contains (acc_ignore, last_client));

	current_sub_step = current_sub_step + 1;
	current_step = current_step + 1;

	// BNC #483211: It might happen that some client close the dialog
	if (! UI::WidgetExists (`id (`next)) && ! UI::WidgetExists (`id (`back)) && ! UI::WidgetExists (`id (`abort))) {
	    y2error ("There is no Wizard dialog open! Creating one...");
	    Wizard::OpenNextBackStepsDialog();
	    DumpACUIError();
	    InstError::ShowErrorPopupWithLogs (
		sformat (_("An error has occured while calling '%1' AC script."), last_client)
	    );
	}

	// BNC #483211: It might happen that some client changes the dialog
	if (! UI::WidgetExists (`id ("one_set_progress")) || ! UI::WidgetExists (`id ("autoconf_progress"))) {
	    if (ac_redraw_and_ignore == true) {
		y2warning ("There is no Automatic Configuration dialog, adjusting the current one... (ignored)");
	    } else {
		DumpACUIError();
		y2error ("There is no Automatic Configuration dialog, adjusting the current one...");
		InstError::ShowErrorPopupWithLogs (
		    sformat (_("An error has occured while calling '%1' AC script."), last_client)
		);
	    }

	    // Redraw after showing an error
	    SetWizardContents();
	}

	if (UI::WidgetExists (`id ("one_set_progress")))
	    UI::ChangeWidget (`id ("one_set_progress"), `Value, current_sub_step);
	else
	    y2error ("Widget one_set_progress doesn't exist");

	if (UI::WidgetExists (`id ("autoconf_progress")))
	    UI::ChangeWidget (`id ("autoconf_progress"), `Value, current_step);
	else
	    y2error ("Widget autoconf_progress doesn't exist");
    }

    void DummyFunction () {
	sleep (random (1600));
    }

    void CallScripts (list <string> scripts_to_call) {
	y2milestone ("Scripts to call: %1", scripts_to_call);

	scripts_to_call = NormalizeScriptNames (scripts_to_call);

	foreach (string one_script, scripts_to_call, {
	    y2milestone ("Calling script %1", one_script);
	    current_client = one_script;
	    NextStep();
	    boolean progress_before = Progress::set (false);

	    any result = (
		test_mode ?
		    DummyFunction()
		    :
		    WFM::CallFunction (one_script, [ $["AutomaticConfiguration":true] ])
	    );

	    Progress::set (progress_before);
	    y2milestone ("Script %1 returned %2", one_script, result);
	    last_client = one_script;
	});
    }

    void CallProposals (list <string> proposals_to_call) {
	y2milestone ("Scripts to call: %1", proposals_to_call);

	proposals_to_call = NormalizeProposalNames (proposals_to_call);

	foreach (string one_proposal, proposals_to_call, {
	    y2milestone ("Calling script %1 MakeProposal", one_proposal);
	    current_client = one_proposal;
	    NextStep();
	    boolean progress_before = Progress::set (false);

	    HandleExceptions (one_proposal);
	    any result = (
		test_mode ?
		    DummyFunction()
		    :
		    WFM::CallFunction (one_proposal, ["MakeProposal", $[ "AutomaticConfiguration":true ]])
	    );

	    Progress::set (progress_before);
	    y2milestone ("Script %1 returned %2", one_proposal, result);
	    last_client = one_proposal;
	});

	foreach (string one_proposal, proposals_to_call, {
	    y2milestone ("Calling script %1 Write", one_proposal);
	    current_client = one_proposal;
	    NextStep();
	    boolean progress_before = Progress::set (false);

	    any result = (
		test_mode ?
		    DummyFunction()
		    :
		    WFM::CallFunction (one_proposal, ["Write", $[ "AutomaticConfiguration":true ]])
	    );

	    y2milestone ("Script %1 returned %2", one_proposal, result);
	    last_client = one_proposal;
	});
    }

    foreach (map one_autoconf_call, proposal_scripts_to_call, {
	nr_of_steps = nr_of_steps +
	    // Proposals have two steps, scripts only one
	    ((one_autoconf_call["type"]:"" == "proposals" ? 2:1) * size (one_autoconf_call["items"]:[]));
    });

    SetWizardContents();

    // items per step
    integer nr_of_items = 0;

    foreach (map one_autoconf_call, proposal_scripts_to_call, {
	if (one_autoconf_call["icon"]:"" != "") {
	    Wizard::SetTitleIcon (one_autoconf_call["icon"]:"");
	} else {
	    // generic YaST icon fallback
	    Wizard::SetTitleIcon ("yast");
	}

	string type = one_autoconf_call["type"]:"";

	nr_of_items = ((one_autoconf_call["type"]:"" == "proposals" ? 2:1) * size (one_autoconf_call["items"]:[]));
	string label = one_autoconf_call["label"]:_("Automatic configuration...");

	y2milestone ("Steps: %1, Label: %2", nr_of_steps, label);

	switch (type) {
	    case "scripts":
		CallScripts (one_autoconf_call["items"]:[]);
		break;
	    case "proposals":
		CallProposals (one_autoconf_call["items"]:[]);
		break;
	    y2error ("Unknown script type '%1'", type);
	}
    });

    y2milestone ("automatic_configuration finished");

    // Set to 100%
    UI::ChangeWidget (`id ("one_set_progress"), `Value, nr_of_items);
    UI::ChangeWidget (`id ("autoconf_progress"), `Value, nr_of_steps);

    if (test_mode) Wizard::CloseDialog();

    return `auto;
}

ACC SHELL 2018