ACC SHELL
/**
* Module: repositories.ycp
*
* Author: Cornelius Schumacher <cschum@suse.de>
* Ladislav Slezak <lslezak@suse.cz>
*
* Purpose:
* Adding, removing and prioritizing of repositories for packagemanager.
*
* $Id: repositories.ycp 62077 2010-05-31 19:42:12Z lslezak $
*
*/
{
textdomain "packager";
import "Confirm";
import "Mode";
import "PackageCallbacks";
import "PackageLock";
import "Report";
// SourceManager overlaps quite a bit with inst_source,
// so far we only use it for ZMD sync, TODO refactor better
import "SourceManager";
import "SourceDialogs";
import "Wizard";
import "Label";
import "Popup";
import "Sequencer";
import "CommandLine";
import "Progress";
import "Directory";
import "URL";
include "packager/inst_source_dialogs.ycp";
include "packager/key_manager_dialogs.ycp";
include "packager/repositories_include.ycp";
boolean full_mode = false;
// cache for textmode value
boolean text_mode = nil;
boolean textmode()
{
if (text_mode == nil)
{
text_mode = Mode::commandline() ? true : UI::GetDisplayInfo()["TextMode"]:false;
}
return text_mode;
}
list<integer> sourcesToDelete = [];
list<integer> reposFromDeletedServices = [];
// default (minimal) priority of a repository
const integer default_priority = 99;
const string priority_label = _("&Priority");
const string keeppackages_label = _("Keep Downloaded Packages");
// current view:
// selected service (or empty) if all services are selected
string displayed_service = "";
// service/repository view flag
boolean repository_view = true;
void RemoveDeletedAddNewRepos () {
list<map<string,any> > ret = [];
list <integer> current_sources = Pkg::SourceGetCurrent (false);
list <integer> known_repos = [];
list <integer> deleted_repos = [];
// sources deleted during this script run
foreach (map<string,any> one_source, sourceStatesIn, {
integer src_id = tointeger (one_source["SrcId"]:nil);
if (src_id != nil) deleted_repos = add (deleted_repos, src_id);
});
// sources is a copy of sourceStatesOut
foreach (map<string,any> one_source, sourceStatesOut, {
integer src_id = tointeger (one_source["SrcId"]:nil);
if (contains (current_sources, src_id)) {
if (src_id != nil) known_repos = add (known_repos, src_id);
ret = add (ret, one_source);
} else {
y2milestone ("Source %1 has been removed already", one_source);
}
});
foreach (integer one_srcid, current_sources, {
// already known repository
if (contains (known_repos, one_srcid)) return;
// already deleted repository
if (contains (deleted_repos, one_srcid)) return;
// already deleted repository
if (contains (SourceManager::just_removed_sources, one_srcid)) return;
// repository has been added recently (by some external functionality
// that doesn't use these internal variables)
map <string,any> generalData = Pkg::SourceGeneralData (one_srcid);
generalData["enabled"] = true;
generalData["SrcId"] = one_srcid;
y2milestone ("New repository found: %1", generalData);
ret = add (ret, generalData);
});
sourceStatesOut = ret;
}
string PriorityToString(integer priority)
{
string ret = tostring(priority);
// pad to 3 characters
integer rest = 3 - size(ret);
while(rest > 0) {
ret = " " + ret;
rest = rest - 1;
}
if (priority == default_priority)
{
ret = ret + " (" + _("Default") + ")";
}
return ret;
}
list<map<string,any> > ReposFromService(string service, list<map<string,any> > input)
{
return filter(map<string,any> repo, input,
{
return repo["service"]:"" == service;
}
);
}
/**
Create a table item from a map as returned by the InstSrcManager agent.
@param source The map describing the source as returned form the agent.
@return An item suitable for addition to a Table.
*/
define term createItem( integer index, map source, boolean repository_mode ) ``{
integer id = source[ "SrcId" ]:0;
map generalData = Pkg::SourceGeneralData( id );
y2milestone("generalData(%1): %2", id, generalData);
string name = repository_mode ? (haskey(source, "name") ?
source["name"]:"" :
// unkown name (alias) of the source
generalData[ "alias" ]:generalData[ "type" ]: _("Unknown Name"))
: source["name"]:"";
integer priority = source["priority"]:default_priority;
string url = repository_mode ? generalData["url"]:"" : source["url"]:"";
string service_alias = source["service"]:"";
string service_name = service_alias != "" ? Pkg::ServiceGet(service_alias)["name"]:"" : "";
term item = repository_mode ?
`item(
`id( index ),
PriorityToString(priority),
// corresponds to the "Enable/Disable" button
source[ "enabled" ]:true ? UI::Glyph (`CheckMark) : "",
source[ "autorefresh" ]:true ? UI::Glyph (`CheckMark) : "",
// translators: unknown name for a given source
name,
service_name,
url
)
: `item(
`id( index ),
// corresponds to the "Enable/Disable" button
source[ "enabled" ]:true ? UI::Glyph (`CheckMark) : "",
source[ "autorefresh" ]:true ? UI::Glyph (`CheckMark) : "",
// translators: unknown name for a given source
name,
url
);
return item;
}
map<string,any> getSourceInfo (integer index, map source) {
integer id = source[ "SrcId" ]:0;
map generalData = Pkg::SourceGeneralData( id );
y2milestone("generalData(%1): %2", id, generalData);
// get the editable propertis from 'source' parameter,
// get the fixed propertis from the package manager
map<string,any> out = $[
"enabled" : source["enabled"]:true,
"autorefresh" : source["autorefresh"]:true,
"name" : source["name"]:_("Unknown Name"),
"url" : generalData[ "url" ]:"",
"type" : generalData["type"]:"",
"priority" : source["priority"]:default_priority,
"service" : source["service"]:"",
"keeppackages" : source["keeppackages"]:false,
];
return out;
}
/**
* Fill sources table with entries from the InstSrcManager agent.
*/
define void fillTable(boolean repo_mode, string service_name)
{
y2milestone ("Filling repository table: repository mode: %1, service: %2", repo_mode, service_name);
list items = [];
if (repo_mode)
{
// because Online Repositories / Community Repositories don't use
// these internal data maps
RemoveDeletedAddNewRepos();
}
list<map<string,any> > itemList = repo_mode ? sourceStatesOut : serviceStatesOut;
// displaye only repositories from the selected service
if (repo_mode && service_name != "")
{
itemList = ReposFromService(service_name, itemList);
}
integer numItems = size(itemList);
integer i = 0;
while ( i < numItems ) {
items = add( items, createItem( i, itemList[ i ]:$[], repo_mode ) );
i = i + 1;
}
y2milestone("New table content: %1", items);
UI::ChangeWidget( `id( `table ), `Items, items );
}
string repoInfoRichText(string name, string raw_url, string category)
{
string schema = tolower(URL::Parse(raw_url)["scheme"]:"");
string icon_tag = "<IMG SRC=\"" + Directory::icondir + "/22x22/apps/"
+ ((schema == "cd" || schema == "dvd" || schema == "iso") ? "yast-cd_update.png" : "yast-http-server.png")
+ "\"> ";
if (raw_url == "")
{
raw_url = _("Unknown");
}
string url = sformat (_("URL: %1"), raw_url);
return sformat("<P>%1<B><BIG>%2</BIG></B></P><P>%3<BR>%4</P>", icon_tag, name, url, category);
}
term repoInfoTerm()
{
return textmode() ?
`VBox (
`Left(`Heading(`id(`name), `opt(`hstretch), "")),
`Left(`Label(`id(`url), `opt(`hstretch), "")),
`Left(`Label(`id(`category), `opt(`hstretch), ""))
)
:
`VSquash(`MinHeight(4, `RichText(`id(`repo_info), "")));
}
void fillRepoInfo(integer index, map source, boolean repo_mode, string service_name)
{
map<string,any> info = repo_mode ? getSourceInfo (index, source) : source;
if (repo_mode)
{
y2milestone("getSourceInfo(%1, %2): %3", index, source, info);
}
// heading - in case repo name not found
string name = info["name"]:_("Unknown repository name");
// label to be used instead of URL if not found
string url = sformat (_("URL: %1"), info["url"]:_("Unknown") );
// label, %1 is repo category (eg. YUM)
string category = sformat (_("Category: %1"), info["type"]:_("Unknown"));
// label, %1 is repo category (eg. YUM)
string service = info["service"]:"";
if (service != "")
{
map service_info = Pkg::ServiceGet(service);
service = sformat (_("Service: %1"), service_info["name"]:"");
}
// don't display category for services
if (!repo_mode)
{
category = "";
}
if (textmode())
{
UI::ChangeWidget(`id(`name), `Label, name);
UI::ChangeWidget(`id(`url), `Label, url);
UI::ChangeWidget(`id(`category), `Label, category);
}
else
{
UI::ChangeWidget(`id(`repo_info), `Value, repoInfoRichText(name, info["url"]:"", category));
}
UI::ChangeWidget (`id (`enable), `Value, info["enabled"]:true);
UI::ChangeWidget (`id (`autorefresh), `Value, info["autorefresh"]:true);
if (repo_mode)
{
// priority and keeppackages are displayed only for repositories
UI::ChangeWidget (`id (`priority), `Value, info["priority"]:default_priority);
UI::ChangeWidget (`id (`keeppackages), `Value, info["keeppackages"]:false);
}
}
void clearRepoInfo()
{
if (textmode())
{
UI::ChangeWidget(`id(`name), `Label, "");
UI::ChangeWidget(`id(`url), `Label, "");
UI::ChangeWidget(`id(`category), `Label, "");
}
else
{
UI::ChangeWidget(`id(`repo_info), `Value, "");
}
UI::ChangeWidget (`id (`enable), `Value, false);
UI::ChangeWidget (`id (`autorefresh), `Value, false);
if (UI::WidgetExists(`id(`priority)))
{
// priority is displayed only for repositories
UI::ChangeWidget (`id (`priority), `Value, default_priority);
}
}
void fillCurrentRepoInfo () {
integer selected = (integer)UI::QueryWidget (`id (`table), `CurrentItem);
if (selected == nil)
{
clearRepoInfo();
return;
}
map data = (repository_view) ?
((displayed_service == "") ? sourceStatesOut[selected]:$[] :
ReposFromService(displayed_service, sourceStatesOut)[selected]:$[]
)
: serviceStatesOut[selected]:$[];
fillRepoInfo (selected, data, repository_view, displayed_service);
}
/**
* Find which repositories have to be added or deleted to ZENworks.
* #182992: formerly we did not consider the enabled attribute.
* But ZENworks cannot completely disable a repository (unsubscribing a
* repository merely decreases its priority) so we consider a disabled repository
* like a deleted one.
* @param statesOld sourceStates{In or Out}
* @param statesNew sourceStates{In or Out}
* @return the list of SrcId's that are enabled in statesNew
* but are not enabled in statesOld
*/
list<integer> newSources (list<map<string,any> > statesOld,
list<map<string,any> > statesNew) {
y2milestone ("From %1 To %2", statesOld, statesNew);
list<integer> ret = [];
map<integer, boolean> seen = listmap (
map<string, any> src, statesOld,
``( $[(src["SrcId"]:-1) : (src["enabled"]:true) ] ));
foreach (map<string, any> src, statesNew, {
integer newid = src["SrcId"]:-1;
boolean newena = src["enabled"]:true;
if (newena && ! seen[newid]:false)
ret = add (ret, newid);
});
y2milestone ("Difference %1", ret);
return ret;
}
list<string> newServices (list<map<string,any> > statesOld,
list<map<string,any> > statesNew) {
y2milestone ("Services from %1 To %2", statesOld, statesNew);
list<string> ret = [];
list<string> seen = maplist (
map<string, any> srv, statesOld,
{
return srv["alias"]:"";
}
);
foreach (map<string, any> srv, statesNew, {
string alias = srv["alias"]:"";
y2milestone("Checking %1", alias);
if (!contains(seen, alias))
{
ret = add (ret, alias);
}
});
y2milestone ("Difference %1", ret);
return ret;
}
define void deleteSource( integer index ) ``{
integer srcid = sourceStatesOut[index, "SrcId"]:-1;
if (srcid != -1) {
sourcesToDelete = add (sourcesToDelete, srcid);
SourceManager::just_removed_sources = add (SourceManager::just_removed_sources, srcid);
}
sourceStatesOut = remove( sourceStatesOut, index );
}
define void deleteService(integer index)
{
y2milestone("Removing service: %1", index);
serviceStatesOut = remove(serviceStatesOut, index);
}
boolean Write() {
boolean success = true;
// evaluate removed and new services
list<string> deleted_services = newServices(serviceStatesOut, serviceStatesIn);
y2milestone("Deleted services: %1", deleted_services);
list<string> added_services = newServices(serviceStatesIn, serviceStatesOut);
y2milestone("Added services: %1", added_services);
foreach(string alias, deleted_services,
{
y2milestone("Removing service %1", alias);
success = success && Pkg::ServiceDelete(alias);
}
);
y2milestone("New service config: %1", serviceStatesOut);
foreach(map<string,any> s, serviceStatesOut,
{
string alias = s["alias"]:"";
if (contains(added_services, alias))
{
y2milestone("Adding service %1", alias);
string new_url = s["url"]:"";
if (new_url != "")
{
y2milestone("aliases: %1", Pkg::ServiceAliases());
success = success && Pkg::ServiceAdd(alias, new_url);
// set enabled and autorefresh flags
success = success && Pkg::ServiceSet(alias, s);
}
else
{
y2error("Empty URL for service %1", alias);
}
}
else
{
y2milestone("Modifying service %1", alias);
success = success && Pkg::ServiceSet(alias, s);
}
}
);
y2milestone("New repo config: %1", sourceStatesOut);
success = success && Pkg::SourceEditSet( sourceStatesOut );
// we must sync before the repositories are deleted from zypp
// otherwise we will not get their details
list<integer> added = newSources (sourceStatesIn, sourceStatesOut);
list<integer> deleted = newSources (sourceStatesOut, sourceStatesIn);
foreach( integer id, sourcesToDelete, ``{
if (contains(reposFromDeletedServices, id))
{
y2milestone("Repository %1 has been already removed (belongs to a deleted service)", id);
}
else
{
success = success && Pkg::SourceDelete(id);
}
});
boolean refresh_enabled = contains(WFM::Args(), "refresh-enabled");
foreach(map<string,any> src_state, sourceStatesOut,
{
integer srcid = src_state["SrcId"]:-1;
if (refresh_enabled && contains(added, srcid))
{
y2milestone("Refreshing enabled repository: %1", srcid);
src_state["do_refresh"] = true;
}
if (src_state["do_refresh"]:false)
{
y2milestone("Downloading metadata for source %1", srcid);
success = success && Pkg::SourceRefreshNow(srcid);
}
}
);
success = success && KeyManager::Write();
// store repositories and services in the persistent libzypp storage
success = success && Pkg::SourceSaveAll(); // #176013
return success;
}
list<term> buildList()
{
list<term> ret = [
`item(`id(`all_repositories), _("All repositories"), repository_view),
`item(`id(`all_services), _("All services"), !repository_view && displayed_service == "")
];
foreach(map<string,any> srv_state, serviceStatesOut,
{
term t = `item(`id(srv_state["alias"]:""), sformat(_("Service '%1'"), srv_state["name"]:""), repository_view && displayed_service == srv_state["alias"]:"");
ret = add(ret, t);
}
);
return ret;
}
term RepoFilterWidget()
{
// combobox label
return `ComboBox(`id(`service_filter), `opt(`notify), _("View"), buildList());
}
void UpdateCombobox()
{
UI::ReplaceWidget(`id(`filter_rp), RepoFilterWidget());
}
// return table widget definition
// layout of the table depends on the current mode (services do not have priorities)
term TableWidget(boolean repository_mode)
{
term tabheader = repository_mode ?
`header(
// table header - priority of the repository - keep the translation as short as possible!
_("Priority"),
// table header - is the repo enabled? - keep the translation as short as possible!
`Center(_("Enabled")),
// table header - is autorefresh enabled for the repo?
// keep the translation as short as possible!
`Center(_("Autorefresh")),
// table header - name of the repo
_("Name"),
// table header - service to which the repo belongs
_("Service"),
// table header - URL of the repo
_("URL") )
:
`header(
// table header - is the repo enabled? - keep the translation as short as possible!
`Center(_("Enabled")),
// table header - is autorefresh enabled for the repo?
// keep the translation as short as possible!
`Center(_("Autorefresh")),
// table header - name of the repo
_("Name"),
// table header - URL of the repo
_("URL") );
return `Table(`id(`table),`opt(`notify, `immediate), tabheader, []);
}
void ReplaceWidgets(boolean repo_mode)
{
y2milestone("Replacing the table widget");
UI::ReplaceWidget(`id(`tabrp), TableWidget(repo_mode));
UI::ReplaceWidget(`id(`priorp), repo_mode ? `IntField(`id(`priority), `opt(`notify), priority_label, 0, 200, default_priority) : `Empty());
UI::ReplaceWidget(`id(`keeppkg_rp), repo_mode ? `CheckBox(`id(`keeppackages), `opt(`notify), keeppackages_label) : `Empty());
}
void RemoveReposFromService(string service_alias)
{
// delete the repositories belonging to the service
list<map<string,any> > repos = ReposFromService(service_alias, sourceStatesOut);
y2milestone("Removing repos from service alias=%1: %2", service_alias, repos);
foreach(map<string,any> repo, repos,
{
integer srcid = repo["SrcId"]:-1;
if (srcid != -1) {
sourcesToDelete = add (sourcesToDelete, srcid);
SourceManager::just_removed_sources = add (SourceManager::just_removed_sources, srcid);
}
sourceStatesOut = filter (map<string,any> srcstate, sourceStatesOut,
{
if (srcstate["SrcId"]:-1 == srcid)
{
y2milestone("Removing repository %1", srcstate);
reposFromDeletedServices = add(reposFromDeletedServices, srcid);
return false;
}
return true;
}
);
}
);
}
void SetReposStatusFromService(string service_alias, boolean enable)
{
// delete the repositories belonging to the service
list<map<string,any> > repos = ReposFromService(service_alias, sourceStatesOut);
y2milestone("%1 repos from service alias=%2: %3", enable ? "Enabling" : "Disabling", service_alias, repos);
foreach(map<string,any> repo, repos,
{
integer srcid = repo["SrcId"]:-1;
sourceStatesOut = maplist (map<string,any> srcstate, sourceStatesOut,
{
if (srcstate["SrcId"]:-1 == srcid)
{
y2milestone("%1 repository %2", enable ? "Enabling" : "Disabling", srcstate);
srcstate["enabled"] = enable;
}
return srcstate;
}
);
}
);
}
any SummaryDialog () {
y2milestone ("Running Summary dialog");
// push button - change URL of the selected repository
string replaceButtonLabel = _("&Replace...");
// push button - refresh the selected repository now
string refreshButtonLabel = _("Re&fresh Selected");
// push button - disable/enable the selected repository
string enableButtonLabel = _("Status &On or Off");
// push button - disable/enable automatic refresh of the selected repository
string refreshOnOffButtonLabel = _("Refre&sh On or Off");
// push button - set name of the selected repository
string setAliasButtonLabel = _("Set &Name...");
term contents =
`VBox(
`Right(`ReplacePoint(`id(`filter_rp), RepoFilterWidget())),
`VWeight(1, `ReplacePoint(`id(`tabrp), TableWidget(repository_view))),
repoInfoTerm(),
// label
`Left (`Label (_("Properties"))),
`HBox(
`HSquash(
`VBox(
// check box
`Left (`CheckBox (`id (`enable), `opt(`notify), _("&Enabled"))),
// check box
`Left (`CheckBox (`id (`autorefresh), `opt(`notify), _("Automatically &Refresh")))
)
),
`HSpacing(1),
`HSquash(
`Bottom(
// check box
`ReplacePoint(`id(`keeppkg_rp), `CheckBox(`id(`keeppackages), `opt(`notify), keeppackages_label))
)
),
`HSpacing(1),
`HSquash(`ReplacePoint(`id(`priorp), `IntField(`id(`priority), `opt(`notify), priority_label, 0, 200, default_priority))),
`HStretch()
),
`VSpacing (0.4),
`HBox(
`PushButton (`id (`add), `opt(`key_F3),
Label::AddButton ()),
`PushButton(`id(`replace), `opt(`key_F4),
Label::EditButton ()),
`PushButton (`id(`delete), `opt(`key_F5),
Label::DeleteButton ()),
`HStretch (),
// push button label
`PushButton (`id (`key_mgr), _("&GPG Keys...")),
// menu button label
`MenuButton (`id(`menu_button), `opt(`key_F6), _("Refresh"), [
`item(`id(`refresh), refreshButtonLabel ),
// menu button label
`item(`id(`autorefresh_all), _("Refresh All Autor&efreshed")),
// menu button label
`item(`id(`refresh_enabled), _("Refresh All &Enabled"))
])
)
);
// dialog caption
string title = _("Configured Software Repositories");
// help
string help_text = _("<p>
In this dialog, manage configured software repositories and services.</p>");
help_text = help_text + _("<P>A <B>service</B> or <B>Repository Index Service (RIS) </B> is a protocol for package repository management. A service can offer one or more software repositories which can be dynamically changed by the service administrator.</P>");
help_text = help_text + _("<p>
<b>Adding a New Repository or a Service</b><br>
To add a new repository, use <b>Add</b> and specify the software repository or service.
Yast will automatically detect whether a service or a repository is available at the entered location.
</p>");
// help, continued
help_text = help_text + _("<p>
To install packages from <b>CD</b>,
have the CD set or the DVD available.
</p>
");
// help, continued
help_text = help_text + _("<p>
The CDs can be copied to <b>hard disk</b>
and then used as a repository.
Insert the path name where the first
CD is located, for example, /data1/<b>CD1</b>.
Only the base path is required if all CDs are copied
into one directory.
</p>
");
// help, continued
help_text = help_text + _("<p>
<b>Modifying Status of a Repository or a Service</b><br>
To change a repository location, use <b>Edit</b>. To remove a repository, use
<b>Delete</b>. To enable or disable the repository or to change the refresh status at initialization time, select the repository in the table and use the check boxes below.
</p>
");
// help text, continued
help_text = help_text + _("<P><B>Priority of a Repository</B><BR>
Priority of a repository is an integer value between 0 (the highest priority) and 200 (the lowest priority). Default priority is 99. If a package is available in more repositories the repository with the highest priority is used.</P>");
// help text, continued
help_text = help_text + _("<P>Select the appropriate option on top of the window for navigation in repositories and services.</P>");
// help text, continued
help_text = help_text + _("<P><B>Keep Downloaded Packages</B><BR>Check this option to keep downloaded packages in a local cache so they can be reused later when the packages are reinstalled. If unchecked the downloaded packages are deleted after installation.</P>") + _("<P>The default local cache is located in directory <B>/var/cache/zypp/packages</B>, the location can be changed in <B>/etc/zypp/zypp.conf</B> file.</P>");
Wizard::SetNextButton(`next, Label::OKButton() );
Wizard::SetAbortButton(`abort, Label::CancelButton() );
Wizard::SetContents(title, contents, help_text, false, true);
Wizard::HideBackButton();
fillTable(repository_view, displayed_service);
fillCurrentRepoInfo();
symbol input = nil;
integer current = -1;
string url = "";
boolean exit = false;
repeat {
if ( current != nil && current >= 0 ) {
UI::ChangeWidget( `id( `table ), `CurrentItem, current );
fillCurrentRepoInfo ();
}
current = -1;
map event = UI::WaitForEvent();
input = event["ID"]:`nothing;
y2debug( "Input: %1", input );
if (input == `table && event["EventReason"]:"" == "Activated")
input = `enable;
symbol createResult = `again;
if (input == `add)
{
return `add;
}
if ( input == `next )
{
// store the new state
boolean success = Write();
if ( !success ) {
// popup message part 1
string _msg1 = _("Unable to save changes to the repository
configuration.");
string details = Pkg::LastError();
y2milestone("LastError: %1", details);
// popup message part 2 followed by other info
string _msg2 = details != "" ? (_("Details:") + "\n" + details)
: "";
// popup message part 3
_msg2 = _msg2 + "\n" + _("Try again?");
boolean tryagain = Popup::YesNo( _msg1 + "\n" + _msg2 );
if ( !tryagain ) exit = true;
} else {
exit = true;
}
}
// Wizard::UserInput returns `back instead of `cancel when window is closed by WM
else if (input == `abort || input == `cancel)
{
// handle cancel as abort
input = `abort;
// no change, do not confirm exit
if (sourceStatesOut == sourceStatesIn)
{
exit = true;
}
else
{
// popup headline
string headline = _("Abort Repository Configuration");
// popup message
string msg = _("Abort the repository configuration?
All changes will be lost.");
if ( Popup::YesNoHeadline( headline, msg ) )
{
exit = true;
}
}
}
else if (input == `key_mgr)
{
exit = true;
//return `key_mgr;
// start the GPG key manager
//RunGPGKeyMgmt();
}
else if (input == `service_filter)
{
// handle the combobox events here...
any current_item = UI::QueryWidget(`id(`service_filter), `Value);
// rebuild the dialog if needed
y2milestone("Current combobox item: %1", current_item);
boolean update_table_widget = false;
if (current_item == `all_repositories)
{
update_table_widget = !repository_view || displayed_service != "";
y2milestone("Switching to repository view");
repository_view = true;
displayed_service = "";
}
else if (current_item == `all_services)
{
update_table_widget = repository_view;
y2milestone("Switching to service view");
repository_view = false;
// display all services
displayed_service = "";
}
else if (is(current_item, string))
{
// switch to the selected repository
y2milestone("Switching to service %1", current_item);
repository_view = true;
// display the selected service
displayed_service = (string)current_item;
// FIXME: always update the table?
update_table_widget = true;
}
// update table widget
if (update_table_widget)
{
ReplaceWidgets(repository_view);
}
// update table content
fillTable(repository_view, displayed_service);
fillCurrentRepoInfo();
// update the current item
current = (integer) UI::QueryWidget( `id( `table ), `CurrentItem );
}
else
{
current = (integer) UI::QueryWidget( `id( `table ), `CurrentItem );
y2debug( "Current item: %1", current );
map<string, any> sourceState = $[];
// global_current - 'current' that points to global sourceStatesOut
integer global_current = -1;
if (repository_view)
{
if (displayed_service == "")
{
sourceState = sourceStatesOut[ current ]:$[];
global_current = current;
}
else
{
if (current != nil)
{
list<map<string,any> > sources_from_service = ReposFromService(displayed_service, sourceStatesOut);
sourceState = sources_from_service[current]:$[];
find(map<string,any> s, sourceStatesOut,
{
global_current = global_current + 1;
return s["SrcId"]:nil == sourceState["SrcId"]:-1;
}
);
y2milestone("global_current: %1", global_current);
}
}
}
integer id = sourceState[ "SrcId" ]:-1;
if ( id < 0 && repository_view && displayed_service == "") {
y2internal("Unable to determine repository id, broken repository?");
continue;
}
if ( input == `replace )
{
if (repository_view)
{
map generalData = Pkg::SourceGeneralData( id );
string url = generalData[ "url" ]:"";
string old_url = url;
boolean plaindir = generalData["type"]:"YaST" == plaindir_type;
SourceDialogs::SetRepoName (sourceState["name"]:"");
do {
url = SourceDialogs::EditPopupType(url, plaindir);
if ( size( url ) == 0 ) break;
boolean same_url = (url == old_url);
y2debug("same_url: %1 (old: %2, new: %3)", same_url, old_url, url);
// special check for cd:// and dvd:// repositories
if (!same_url)
{
map new_url_parsed = URL::Parse(url);
map old_url_parsed = URL::Parse(old_url);
string new_url_scheme = tolower(new_url_parsed["scheme"]:"");
string old_url_scheme = tolower(old_url_parsed["scheme"]:"");
// ignore cd:// <-> dvd:// changes if the path is not changed
if ((new_url_scheme == "cd" || new_url_scheme == "dvd")
&& (old_url_scheme == "cd" || old_url_scheme == "dvd"))
{
// compare only directories, ignore e.g. ?device=/dev/sr0 options
if (new_url_parsed["path"]:"" == old_url_parsed["path"]:"")
{
Pkg::SourceChangeUrl(sourceState[ "SrcId" ]:-1, url);
same_url = true;
}
}
}
if (!same_url || plaindir != SourceDialogs::IsPlainDir())
{
y2milestone ("URL or plaindir flag changed, recreating the source");
// copy the refresh flag
createResult = createSource( url, SourceDialogs::IsPlainDir(), sourceState["do_refresh"]:false, SourceDialogs::GetRepoName ());
if ( createResult == `ok ) {
// restore the origonal properties (enabled, autorefresh, keeppackages)
// the added repository is at the end of the list
integer idx = size(sourceStatesOut) - 1;
map<string, any> addedSource = sourceStatesOut[idx]:$[];
y2milestone("Orig repo: %1", sourceState);
y2milestone("Added repo: %1", addedSource);
if (addedSource != $[])
{
boolean auto_refresh = sourceState["autorefresh"]:true;
boolean keeppackages = sourceState["keeppackages"]:false;
boolean enabled = sourceState["enabled"]:true;
integer priority = sourceState["priority"]:default_priority;
y2milestone("Restoring the original properties: enabled: %1, autorefresh: %2, keeppackages: %3, priority: %4", enabled, auto_refresh, keeppackages, priority);
// set the original properties
addedSource["autorefresh"] = auto_refresh;
addedSource["keeppackages"] = keeppackages;
addedSource["enabled"] = enabled;
addedSource["priority"] = priority;
// get the ID of the old repo and mark it for removal
integer srcid = sourceStatesOut[global_current, "SrcId"]:-1;
if (srcid != -1)
{
sourcesToDelete = add (sourcesToDelete, srcid);
SourceManager::just_removed_sources = add (SourceManager::just_removed_sources, srcid);
}
// replace the data
sourceStatesOut[global_current] = addedSource;
// remove the duplicate at the end
sourceStatesOut = remove(sourceStatesOut, idx);
// refresh only the name and URL in the table
UI::ChangeWidget(`id(`table), `Cell( global_current, 3), addedSource["name"]:"");
UI::ChangeWidget(`id(`table), `Cell( global_current, 5), url);
fillCurrentRepoInfo();
}
}
}
else
{
y2milestone ("URL is the same, not recreating the source");
string new_name = SourceDialogs::GetRepoName();
if (new_name != sourceState["name"]:"")
{
sourceState["name"] = new_name;
sourceStatesOut[ global_current ] = sourceState;
// update only the name cell in the table
UI::ChangeWidget(`id(`table), `Cell( global_current, 3), new_name);
fillCurrentRepoInfo();
}
else
{
y2milestone("The repository name has not been changed");
}
createResult = `ok;
}
} while ( createResult == `again );
}
else // service view
{
map <string, any> service_info = serviceStatesOut[current]:$[];
y2milestone("Editing service %1...", current);
string url = service_info["url"]:"";
string old_url = url;
SourceDialogs::SetRepoName(service_info["name"]:"");
do {
url = SourceDialogs::EditPopupService(url);
if ( size( url ) == 0 ) break;
if (url != old_url)
{
y2milestone ("URL of the service has been changed, recreating the service");
// createSource() can potentially create a repository instead of a service
// Probe for a service first must be done before creating a new service
string service_type = Pkg::ServiceProbe(url);
y2milestone("Probed service type: %1", service_type);
if (service_type != nil && service_type != "NONE")
{
createResult = createSource(url, false /*plaindir*/, false /*do_refresh*/, SourceDialogs::GetRepoName());
if ( createResult == `ok )
{
deleteService( current );
fillTable(repository_view, displayed_service);
fillCurrentRepoInfo();
// refresh also the combobox widget
UpdateCombobox();
}
}
else
{
Report::Error(sformat(_("There is no service at URL:
%1"), url));
}
}
else
{
y2milestone ("URL is the same, not recreating the service");
string entered_service_name = SourceDialogs::GetRepoName();
string old_service_name = service_info["name"]:"";
if (old_service_name != entered_service_name)
{
y2milestone("Updating name of the service to '%1'", entered_service_name);
service_info["name"] = entered_service_name;
serviceStatesOut[ current ] = service_info;
fillTable(repository_view, displayed_service);
fillCurrentRepoInfo();
createResult = `ok;
// update the reference
sourceStatesOut = maplist(map<string,any> src_state, sourceStatesOut,
{
if (src_state["service"]:"" == old_service_name)
{
src_state["service"] = entered_service_name;
}
return src_state;
}
);
// refresh also the combobox widget
UpdateCombobox();
}
}
} while ( createResult == `again );
}
}
else if ( input == `refresh )
{
if (repository_view)
{
Pkg::SourceRefreshNow (id);
if (full_mode && sourceState["enabled"]:false)
{
// force loading of the resolvables
Pkg::SourceSetEnabled(id, false);
Pkg::SourceSetEnabled(id, true);
}
}
else
{
// refresh a service
string service_alias = (serviceStatesOut[current]:$[])["alias"]:"";
y2milestone("Refreshing service %1...", service_alias);
Pkg::ServiceRefresh(service_alias);
}
}
else if ( input == `autorefresh_all || input == `refresh_enabled)
{
y2milestone("Refreshing all %1 %2%3...", input == `refresh_enabled ? "enabled" : "autorefreshed",
repository_view ? "repositories" : "services",
repository_view && displayed_service != "" ? " from service " + displayed_service : "");
boolean refresh_autorefresh_only = input == `autorefresh_all;
integer to_refresh = 0;
list<map<string,any> > data = (repository_view) ?
(displayed_service == "" ? sourceStatesOut : ReposFromService(displayed_service, sourceStatesOut))
: serviceStatesOut;
y2internal("data: %1", data);
foreach(map<string,any> src_state, data,
{
if (src_state["enabled"]:false && (!refresh_autorefresh_only || src_state["autorefresh"]:false))
{
string url = repository_view ?
(Pkg::SourceGeneralData(src_state["SrcId"]:-1)["url"]:"")
: src_state["url"]:"";
string schema = tolower(substring(url, 0, 3));
if (schema != "cd:" && schema != "dvd")
{
to_refresh = to_refresh + 1;
}
}
}
);
y2milestone("%1 %2 will be refreshed", to_refresh, repository_view ? "repositories" : "services");
if (to_refresh > 0)
{
Wizard::CreateDialog ();
// TODO: add help text
Progress::New(repository_view ? _("Refreshing Repositories") : _("Refreshing Services"),
"", to_refresh + 1, [ repository_view ? _("Refresh Repositories") : _("Refresh Services") ],
[], "");
foreach(map<string,any> src_state, data,
{
if (src_state["enabled"]:false && (!refresh_autorefresh_only || src_state["autorefresh"]:false))
{
string name = src_state["name"]:"";
if (repository_view)
{
integer srcid = src_state["SrcId"]:-1;
string url = Pkg::SourceGeneralData(src_state["SrcId"]:-1)["url"]:"";
string schema = tolower(substring(url, 0, 3));
if (schema != "cd:" && schema != "dvd")
{
y2milestone("Autorefreshing repository %1 (%2)", srcid, name);
// progress bar label
Progress::Title(sformat(_("Refreshing Repository %1..."), name));
Pkg::SourceRefreshNow(srcid);
if (full_mode && src_state["enabled"]:false)
{
// force loading of the resolvables
Pkg::SourceSetEnabled(srcid, false);
Pkg::SourceSetEnabled(srcid, true);
}
Progress::NextStep();
}
else
{
y2milestone("Skipping a CD/DVD repository %1 (%2)", srcid, name);
}
}
else
{
string service_alias = src_state["alias"]:"";
// refreshing services
// progress bar label
Progress::Title(sformat(_("Refreshing Service %1..."), name));
y2milestone("Refreshing service %1 (alias: %2)...", name, service_alias);
Pkg::ServiceRefresh(service_alias);
}
}
}
);
Progress::Finish();
Wizard::CloseDialog();
}
}
else if ( input == `delete )
{
if (repository_view)
{
// yes-no popup
if ( Popup::YesNo( _("Delete the selected repository from the list?") ) )
{
deleteSource(global_current);
fillTable(repository_view, displayed_service);
fillCurrentRepoInfo();
}
}
else
{
string selected_service = (serviceStatesOut[current]:$[])["name"]:"";
// yes-no popup
if ( Popup::YesNo(sformat(_("Delete service %1\nand its repositories?"), selected_service)))
{
string service_alias = (serviceStatesOut[current]:$[])["alias"]:"";
RemoveReposFromService(service_alias);
deleteService( current );
fillTable(repository_view, displayed_service);
fillCurrentRepoInfo();
// refresh also the combobox widget
UpdateCombobox();
}
}
}
else if (input == `enable)
{
if (repository_view)
{
boolean state = sourceState[ "enabled" ]:true;
state = !state;
// corresponds to the "Enable/Disable" button
string newstate = ( state ? UI::Glyph (`CheckMark) : "");
UI::ChangeWidget( `id( `table ), `Item( current, 1 ), newstate );
sourceState[ "enabled" ] = state;
sourceStatesOut[ global_current ] = sourceState;
if (full_mode)
{
Pkg::SourceSetEnabled(sourceState["SrcId"]:-1, state);
}
}
else
{
map<string,any> srv = serviceStatesOut[current]:$[];
y2milestone("Selected service: %1", srv);
boolean state = srv["enabled"]:false;
state = !state;
// disable/enable the repositories belonging to the service
string service_alias = (serviceStatesOut[current]:$[])["alias"]:"";
SetReposStatusFromService(service_alias, state);
// update the table
string newstate = ( state ? UI::Glyph (`CheckMark) : "");
UI::ChangeWidget( `id( `table ), `Item( current, 0 ), newstate );
// store the change
srv["enabled"] = state;
serviceStatesOut[current] = srv;
}
}
else if ( input == `autorefresh)
{
if (repository_view)
{
integer source_id = sourceState["SrcId"]:0;
map src_data = Pkg::SourceGeneralData (source_id);
string type = src_data["type"]:"";
boolean state = sourceState[ "autorefresh" ]:true;
if (type == "PlainDir" && ! state)
{
// popup message
Popup::Message (_("For the selected repository, refresh
cannot be set."));
}
else
{
state = !state;
string newstate = (state ? UI::Glyph(`CheckMark) : "");
UI::ChangeWidget(`id(`table), `Item(current, 2), newstate);
}
sourceState["autorefresh"] = state;
sourceStatesOut[ global_current ] = sourceState;
}
else
{
map<string,any> srv = serviceStatesOut[current]:$[];
y2milestone("Selected service: %1", srv);
boolean state = srv["autorefresh"]:false;
state = !state;
// update the table
string newstate = ( state ? UI::Glyph (`CheckMark) : "");
UI::ChangeWidget( `id( `table ), `Item( current, 1 ), newstate );
// store the change
srv["autorefresh"] = state;
serviceStatesOut[current] = srv;
}
// do not refresh the item in the table
current = -1;
}
else if (input == `priority)
{
if (repository_view)
{
// refresh the value in the table
integer new_priority = (integer)UI::QueryWidget(`id(`priority), `Value);
y2debug("New priority: %1", new_priority);
UI::ChangeWidget( `id( `table ), `Item( current, 0 ), PriorityToString(new_priority));
sourceState[ "priority" ] = new_priority;
sourceStatesOut[ global_current ] = sourceState;
// do not refresh the item in the table
current = -1;
}
else
{
y2error("Ignoring event `priority: the widget should NOT be displayed in service mode!");
}
}
else if (input == `keeppackages)
{
if (repository_view)
{
// refresh the value in the table
boolean new_keep = (boolean)UI::QueryWidget(`id(`keeppackages), `Value);
y2internal("New keep packages option: %1", new_keep);
sourceState[ "keeppackages" ] = new_keep;
sourceStatesOut[ global_current ] = sourceState;
// do not refresh the item in the table
current = -1;
}
else
{
y2error("Ignoring event `keeppackages: the widget should NOT be displayed in service mode!");
}
}
else if (input != `table)
{
y2warning("Unknown user input: %1", input);
}
}
} until ( exit );
y2debug( "Return: %1", input );
return input;
}
list<map<string,any> > SortReposByPriority(list<map<string,any> > repos)
{
// check the input
if (repos == nil)
{
return repos;
}
// sort the maps by "repos" key (in ascending order)
list<map<string,any> > ret = sort(map<string,any> repo1, map<string,any> repo2, repos, {return repo1["priority"]:default_priority < repo2["priority"]:default_priority;});
y2milestone("SortReposByPriority: %1 -> %2", repos, ret);
return ret;
}
// remember the original selected URL scheme
string selected_url_scheme = "";
symbol StartTypeDialog()
{
string seturl = selected_url_scheme;
if (seturl != nil && seturl != "")
{
seturl = selected_url_scheme + "://";
}
symbol ret = TypeDialogOpts(true, seturl);
if (ret == `back)
{
selected_url_scheme = "";
}
else
{
selected_url_scheme = URL::Parse(SourceDialogs::GetRawURL())["scheme"]:"";
y2milestone("Selected URL scheme: %1", selected_url_scheme);
if (selected_url_scheme == nil || selected_url_scheme == "")
{
selected_url_scheme = "url";
}
}
return ret;
}
boolean KnownURL(string url)
{
string scheme = tolower(URL::Parse(url)["scheme"]:"");
// alway create CD/DVD repository
if (scheme == "cd" || scheme == "dvd")
{
return false;
}
boolean ret = false;
foreach (map<string,any> src, sourceStatesOut,
{
integer src_id = tointeger(src["SrcId"]:nil);
map generalData = Pkg::SourceGeneralData(src_id);
string src_url = generalData["url"]:"";
if (src_url == url)
{
ret = true;
}
}
);
y2milestone("URL exists: %1", ret);
return ret;
}
symbol StartEditDialog()
{
y2milestone("Edit URL with protocol %1", selected_url_scheme);
symbol ret = nil;
do
{
ret = SourceDialogs::EditDialogProtocol(selected_url_scheme);
if (ret == `next)
{
string url = SourceDialogs::GetURL();
boolean known_url = KnownURL(url);
if (known_url)
{
// popup question, %1 is repository URL
if (!Popup::AnyQuestion("",
sformat(_("Repository %1
has been already added. Each repository should be added only once.
Really add the repository again?"), URL::HidePassword(url)),
Label::YesButton(),
Label::NoButton(),
`focus_no
)
)
{
// ask again
ret = nil;
}
}
}
}
while (ret == nil);
y2milestone("Result: %1", ret);
return ret;
}
symbol StartStoreSource()
{
symbol ret = StoreSource();
if (ret == `next || ret == `abort || ret == `close)
{
y2milestone("Resetting selected URL scheme");
selected_url_scheme = "";
}
return ret;
}
// main function - start the workflow
symbol StartInstSource()
{
Wizard::CreateDialog();
Wizard::SetDesktopIcon("sw_source");
if (!full_mode)
{
// dialog caption
Wizard::SetContents(_("Initializing..."), `Empty (), "", false, true);
Pkg::TargetInit("/", true);
}
// check whether running as root
if (! Confirm::MustBeRoot () || !PackageLock::Connect(false)["connected"]:false)
{
UI::CloseDialog ();
return `abort;
}
if (!full_mode)
{
PackageCallbacks::InitPackageCallbacks ();
}
// read repositories & services
boolean restore = (!full_mode) ? Pkg::SourceRestore() : true;
y2milestone("Known services: %1", Pkg::ServiceAliases());
if( ! restore )
{
boolean cont = Popup::AnyQuestionRichText(
Label::ErrorMsg(),
// Error popup
_("<p>There were errors while restoring the repository configuration.</p>\n") + "<p>" + Pkg::LastError() + "</p>",
50, 15,
Label::ContinueButton(), Label::CancelButton(), `focus_no
);
// really continue?
if (!cont) {
return `abort;
}
}
// read known GPG keys
KeyManager::Read();
sourceStatesIn = SortReposByPriority(Pkg::SourceEditGet());
y2milestone( "Found repositories: %1", sourceStatesIn);
sourceStatesOut = sourceStatesIn;
list<string> srv_aliases = Pkg::ServiceAliases();
// get the current services
foreach(string srv_alias, srv_aliases,
{
serviceStatesIn = add(serviceStatesIn, Pkg::ServiceGet(srv_alias));
}
);
y2milestone("Loaded services: %1", serviceStatesIn);
serviceStatesOut = serviceStatesIn;
map<string,any> aliases = $[
"summary" : ``(SummaryDialog ()),
"type" : ``(StartTypeDialog()),
"edit" : ``(StartEditDialog ()),
"store" : ``(StartStoreSource ()),
"keymgr" : [``(RunGPGKeyMgmt(false)), true]
];
map sequence = $[
"ws_start" : "summary",
"summary" : $[
`add : "type",
`edit : "edit",
`key_mgr : "keymgr",
`abort : `abort,
`next : `next,
],
"keymgr" : $[
`next : "summary",
`abort : "summary"
],
"type" : $[
`next : "edit",
`finish : "store",
`abort : `abort,
],
"edit" : $[
`next : "store",
`abort : `abort,
],
"store" : $[
`next : "summary",
`abort : `abort,
],
];
y2milestone ("Starting repository sequence");
symbol ret = Sequencer::Run (aliases, sequence);
UI::CloseDialog ();
return ret;
}
map cmdline_description = $[
"id" : "inst_source",
/* Command line help text for the repository module, %1 is "zypper" */
"help" : sformat(_("Installation Repositories - this module doesn't support the command line interface, use '%1' instead."), "zypper"),
"guihandler" : StartInstSource,
];
if (WFM::Args() == [ `sw_single_mode ])
{
y2milestone("Started from sw_single, switching the mode");
full_mode = true;
any ret = StartInstSource();
// load objects from the new repositories
if (ret != `abort)
{
Pkg::SourceLoad();
}
return ret;
}
if (WFM::Args() == [ "refresh-enabled" ])
{
y2milestone("Refresh enabled option set");
return StartInstSource();
}
return CommandLine::Run(cmdline_description);
} // EOF
ACC SHELL 2018