home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2007 January, February, March & April
/
Chip-Cover-CD-2007-02.iso
/
boot
/
i386
/
root
/
usr
/
share
/
YaST2
/
clients
/
inst_source.ycp
< prev
next >
Wrap
Text File
|
2006-11-29
|
20KB
|
661 lines
/**
* Module: inst_source.ycp
*
* Author: Cornelius Schumacher <cschum@suse.de>
*
* Purpose:
* Adding, removing and prioritizing of installation sources for packagemanager.
*
*/
{
textdomain "packager";
import "Confirm";
import "Mode";
import "Installation";
import "PackageCallbacksInit";
import "PackageLock";
import "PackageSystem";
import "Report";
import "SLP";
import "Stage";
// SourceManager overlaps quite a bit with inst_source,
// so far we only use it for ZMD sync, TODO refactor better
import "SourceManager";
import "SuSEFirewall";
import "Wizard";
import "Label";
import "Popup";
import "AddOnProduct";
import "Sequencer";
// Do not sync the changes to ZENworks even if rug is present
// This is handy for repairing an already out-of-sync situation
boolean have_rug = (integer)SCR::Read (.target.size, "/usr/bin/rug") >= 0;
boolean norug = !have_rug || WFM::Args(0) == "norug";
// constant Plaindir
string plaindir_type = "Plaindir";
Wizard::CreateDialog();
Wizard::SetDesktopIcon("sw_source");
// dialog caption
Wizard::SetContents(_("Initializing..."), `Empty (), "", false, true);
// check whether running as root
if (! Confirm::MustBeRoot () || ! PackageLock::Check ())
{
UI::CloseDialog ();
return (any)`abort;
}
PackageCallbacksInit::InitPackageCallbacks ();
// constructor of Product is needed in order to initialize the product
// macro. Takes a lot of time because whole package manager target
// is initialized
import "Product";
include "packager/inst_source_dialogs.ycp";
integer numSources = 0;
list<map<string,any> > sourceStatesIn = [];
list<map<string,any> > sourceStatesOut = [];
list<integer> sourcesToDelete = [];
/**
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 ) ``{
integer id = source[ "SrcId" ]:0;
map generalData = Pkg::SourceGeneralData( id );
map productData = Pkg::SourceProductData( id );
y2milestone("generalData: %1", generalData);
y2milestone("productData: %1", productData);
term item = `item(
`id( index ),
// corresponds to the "Enable/Disable" button
source[ "enabled" ]:true ? _("On") : _("Off"),
source["autorefresh"]:true ? _("On") : _("Off"),
// translators: unknown name for a given source
productData[ "label" ]:generalData[ "type" ]: _("unknown"),
generalData[ "url" ]:""
);
return item;
}
/**
* Fill sources table with entries from the InstSrcManager agent.
*/
define void fillTable() ``{
y2milestone ("Filling source table");
list items = [];
numSources = size( sourceStatesOut );
integer i = 0;
while ( i < numSources ) {
items = add( items, createItem( i, sourceStatesOut[ i ]:$[] ) );
i = i + 1;
}
UI::ChangeWidget( `id( `table ), `Items, items );
}
boolean LicenseAccepted (integer id) {
Wizard::CreateDialog ();
boolean ret = AddOnProduct::AcceptedLicenseAndInfoFile (id);
UI::CloseDialog ();
return ret;
}
define symbol createSource( string url ) ``{
y2milestone("createSource: %1", url);
if ( url != "" )
{
// for Plaindir source we have to use SourceCreateType() binding
boolean plaindir = false;
map parsed = URL::Parse(url);
string scheme = parsed["scheme"]:"";
if (scheme == "pkg")
{
parsed["scheme"] = "dir";
url = URL::Build(parsed);
plaindir = true;
}
// check if SMB/CIFS share can be mounted
if (scheme == "smb" && SCR::Read(.target.size, "/sbin/mount.cifs") < 0)
{
y2milestone("SMB/CIFS share cannot be mounted, installing missing 'cifs-mount' package...");
// install cifs-mount package
PackageSystem::CheckAndInstallPackages(["cifs-mount"]);
}
list<integer> newSources = (plaindir) ?
[ Pkg::SourceCreateType(url, "", plaindir_type) ] :
Pkg::SourceScan( url, "" );
if ( size( newSources ) == 0 )
{
// message part 1
string _msg1 = sformat( _("Unable to create installation source
from URL '%1'."), url );
/* FIXME Pkg::LastErrorId always returns 'ok'
string err = Pkg::LastErrorId();
if ( err != "ok" ) {
if ( err == "instsrc_duplicate" )
// message part 2 alt. 1
_msg2 = _("A catalog for this product already exists.");
else
}
*/
// message part 2 alt. 2 followed by description
string _msg2 = _("Details:") + "\n" + Pkg::LastError() + "\n" +
// message part 3
_("Try again?");
boolean tryagain = Popup::YesNo( _msg1 + "\n" + _msg2 );
if ( tryagain ) return `again;
else return `cancel;
}
else
{
list<integer> prod_sources = filter (integer s, newSources, {
map src_data = Pkg::SourceGeneralData (s);
string src_type = src_data["type"]:"";
return (src_type == "YaST" || src_type == "YUM" || src_type == plaindir_type);
});
if (size (prod_sources) == 0)
{
if (! Popup::AnyQuestion (
Popup::NoHeadline (),
// continue-back popup
_("There is no product information available at the given location.
If you expected to address a product, return back and enter
the correct location.
To make rpm packages located at the specified location available
in the packages selection, continue."),
Label::ContinueButton (),
Label::BackButton (),
`focus_yes))
{
return `again;
}
}
foreach( integer id, newSources, ``{
if (! LicenseAccepted (id))
{
Pkg::SourceDelete (id);
}
else
{
map src_data = Pkg::SourceGeneralData (id);
boolean auto_refresh = src_data["autorefresh"]:false;
map<string, any> sourceState = $[ "SrcId": id, "enabled": true, "autorefresh" : auto_refresh ];
sourceStatesOut = add( sourceStatesOut, sourceState );
}
} );
return `ok;
}
}
}
/**
* Find which sources have to be added or deleted to ZENworks.
* #182992: formerly we did not consider the enabled attribute.
* But ZENworks cannot completely disable a source (unsubscribing a
* catalog merely decreases its priority) so we consider a disabled source
* 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;
}
define void deleteSource( integer index ) ``{
integer srcid = sourceStatesOut[index, "SrcId"]:-1;
if( srcid != -1)
sourcesToDelete = add( sourcesToDelete, srcid );
sourceStatesOut = remove( sourceStatesOut, index );
}
boolean Write() {
boolean success = Pkg::SourceEditSet( sourceStatesOut );
// we must sync before the sources are deleted from zypp
// otherwise we will not get their details
list<integer> added = newSources (sourceStatesIn, sourceStatesOut);
list<integer> deleted = newSources (sourceStatesOut, sourceStatesIn);
boolean have_rug = !norug && (integer)SCR::Read (.target.size, "/usr/bin/rug") >= 0;
boolean any_changed = added != [] || deleted != []; // #217697
if (success && have_rug && any_changed) {
UI::OpenDialog (
`VBox (
`Label (SourceManager::SyncLabel ()),
`PushButton (`id (`abort), Label::AbortButton ())
));
boolean syncok = SourceManager::SyncAddedAndDeleted (added, deleted);
UI::CloseDialog ();
if (!syncok)
{
// yes/no popup
if (!Popup::YesNo (_("Source synchronization with ZMD failed.
Save changes anyway?")))
success = false;
}
}
else {
y2milestone ("No rug, not syncing");
}
foreach( integer id, sourcesToDelete, ``{
success = success && Pkg::SourceDelete(id);
});
// store in the persistent libzypp storage
success = success && Pkg::SourceSaveAll(); // #176013
return success;
}
symbol SummaryDialog () {
y2milestone ("Running Summary dialog");
list items = [];
// pusg button
string replaceButtonLabel = _("&Replace...");
// pusg button
string refreshButtonLabel = _("Re&fresh Now...");
// pusg button
string enableButtonLabel = _("Enab&le or Disable");
// push button
string refreshOnOffButtonLabel = _("Refre&sh On or Off");
term contents =
`VBox(
`HBox(
`Table( `id( `table ),/* `opt( `keepSorting ),*/
// table header
`header( _("Status"),
// table header
_("Refresh"),
// table header
_("Name"),
// table header
_("URL") ),
items ),
`HSpacing()
),
// TODO Help
`Left (`CheckBox (`id (`zmdsync),
// Checkbox label
_("Synchronize Changes with &ZENworks"),
!norug)),
`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 (),
// menu button label
`MenuButton (`opt(`key_F6), _("Source Settings"), [
`item(`id(`enable), enableButtonLabel),
`item(`id(`refresh_on_off), refreshOnOffButtonLabel),
`item(`id(`refresh), refreshButtonLabel )
])
),
`VSpacing( 0.5 )
);
// dialog caption
string title = _("Configured Software Catalogs");
// string title = _("Media Containing the Software Catalog");
// help
string help_text = _("<p>
In this dialog, manage configured software catalogs.</p>");
help_text = help_text + _("<p>
<b>Adding a New Catalog</b><br>
To add a new catalog, use <b>Add</b> and specify the software catalog.
</p>");
// help, continued
help_text = help_text + _("<p>
To install packages from <b>CD</b>,
have the &product; CD set or the DVD available.
</p>
");
// help, continued
help_text = help_text + _("<p>
The &product; CDs can be copied to the <b>hard disk</b>.
Then use that as the installation source.
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>Network</b> installation requires a working network connection.
Configure YaST2's \"Network Devices\" module first,
if required. Specify the directory where the packages from
the first CD are located, such as /data1/CD1.
Only the base path is
required if packages are not divided, for example, /usr/full-i386.
The directory must be listed in the file <i>/etc/exports</i>
on the NFS server.
</p>
");
// help, continued
help_text = help_text + _("<p>
<b>Modifying a Catalog</b>
To change a catalog media, use <b>Edit</b>. To remove a catalog, use
<b>Delete</b>. To enable or disable the catalog, set refreshing on the
initialization time on or off, or refresh it immediatelly, use
<b>Source Settings</b>.");
// help, continued
help_text = help_text + _("<p>
<b>Synchronize Changes with ZENworks</b> will call <tt>rug</tt>
to perform the changes also in that package management system.</p>");
Wizard::SetNextButton(`next, Label::FinishButton() );
Wizard::SetContents(title, contents, help_text, false, true);
Wizard::HideBackButton();
UI::ChangeWidget (`id (`zmdsync), `Enabled, have_rug);
fillTable();
symbol input = nil;
integer current = -1;
string url = "";
boolean exit = false;
repeat {
if ( current >= 0 ) {
UI::ChangeWidget( `id( `table ), `CurrentItem, current );
}
input = (symbol)Wizard::UserInput();
y2debug( "Input: %1", input );
symbol createResult = `again;
if (input == `add)
{
return `add;
}
if ( input == `next )
{
norug = ! (boolean) UI::QueryWidget (`id (`zmdsync), `Value);
// store the new state
boolean success = Write();
if ( !success ) {
// popup message part 1
string _msg1 = _("Unable to save changes to installation source
configuration.");
string details = Pkg::LastError();
// 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 == `back)
{
// popup headline
string headline = _("Abort Catalog Configuration");
// popup message
string msg = _("Abort the catalog configuration?
All changes will be lost.");
if ( Popup::YesNoHeadline( headline, msg ) ) {
exit = true;
}
}
else
{
current = (integer) UI::QueryWidget( `id( `table ), `CurrentItem );
y2debug( "Current item: %1", current );
map<string, any> sourceState = sourceStatesOut[ current ]:$[];
integer id = sourceState[ "SrcId" ]:-1;
if ( id < 0 ) {
y2internal( "Unable to determine source id" );
continue;
}
if ( input == `replace )
{
map generalData = Pkg::SourceGeneralData( id );
string url = generalData[ "url" ]:"";
boolean auto_refresh = sourceState["autorefresh"]:true;
boolean plaindir = generalData["type"]:"YaST" == plaindir_type;
do {
// change schema if the source type is plaindir
// to show the right popup dialog
if (plaindir)
{
map parsed = URL::Parse(url);
parsed["scheme"] = "pkg";
url = URL::Build(parsed);
}
url = editUrl( url );
if ( size( url ) == 0 ) break;
createResult = createSource( url );
if ( createResult == `ok ) {
deleteSource( current );
fillTable();
}
} while ( createResult == `again );
}
else if ( input == `refresh )
{
Pkg::SourceRefreshNow (id);
fillTable ();
/* map generalData = Pkg::SourceGeneralData( id );
string url = generalData[ "url" ]:"";
do {
// url = editUrl( url );
if ( size( url ) == 0 ) break;
deleteSource( current );
createResult = createSource( url );
if ( createResult == `ok ) {
fillTable();
}
} while ( createResult == `again );*/
}
else if ( input == `delete )
{
// yes-no popup
if ( Popup::YesNo( _("Delete the selected catalog from the list?") ) )
{
deleteSource( current );
fillTable();
}
}
else if ( input == `enable )
{
boolean state = sourceState[ "enabled" ]:true;
state = !state;
// corresponds to the "Enable/Disable" button
string newstate = ( state ? _("On") : _("Off") );
UI::ChangeWidget( `id( `table ), `Item( current, 0 ), newstate );
sourceState[ "enabled" ] = state;
sourceStatesOut[ current ] = sourceState;
}
else if ( input == `refresh_on_off )
{
integer source_id = sourceState["SrcId"]:0;
map src_data = Pkg::SourceGeneralData (source_id);
string type = src_data["type"]:"UnitedLinux";
boolean state = sourceState[ "autorefresh" ]:true;
if (type == "PlainDir" && ! state)
{
// popup message
Popup::Message (_("For the selected source, refresh
cannot be set."));
}
else
{
state = !state;
}
// corresponds to the "Enable/Disable" button
string newstate = ( state ? _("On") : _("Off") );
UI::ChangeWidget( `id( `table ), `Item( current, 1 ), newstate );
sourceState["autorefresh"] = state;
sourceStatesOut[ current ] = sourceState;
}
}
} until ( exit );
UI::CloseDialog();
y2debug( "Return: %1", input );
return input;
}
symbol StoreSource () {
string url = SourceDialogs::GetURL ();
if (url == "slp://")
{
string service = SourceManager::AddSourceTypeSLP ();
y2milestone ("Trying to add source '%1'", service);
if (service != nil)
{
// add the installation source
symbol createResult = createSource(service);
y2milestone ("Adding source result: %1", createResult);
return `next;
}
return `back;
}
if (createSource(url) == `again)
return `back;
return `next;
}
boolean restore = Pkg::SourceStartManager( false );
if( ! restore )
{
// #210514 (L3): unconditionally removing the sources is BAD.
// Usually it is just a temporary error because of misconfigured proxy.
boolean cleanup = Popup::AnyQuestion( // [1]
Label::ErrorMsg(),
// Error popup (part 1)
_("There were errors when restoring the source configuration.
Not all sources are available for configuration.
") + Pkg::LastError() + "\n\n" +
// Error popup (part 2): Yes/No question.
// "immediately" is important: because of stupid design [2],
// they will be removed even if the user then chooses Abort :(
_("Do you want to immediately remove these sources?"),
Label::YesButton(), Label::NoButton(), `focus_no);
// Notes irrelevant for translators:
// [1]: we want the focus on "No"; Popup::YesNo is too specialized
// [2]: using SourceManager and not just PersistentStorage in inst_source
// delete the broken sources from the persistent store
if (cleanup) {
Pkg::SourceCleanupBroken();
}
}
sourceStatesIn = Pkg::SourceEditGet();
y2milestone( "Found sources: %1", sourceStatesIn);
sourceStatesOut = sourceStatesIn;
map<string,any> aliases = $[
"summary" : ``(SummaryDialog ()),
"type" : ``(SourceDialogs::TypeDialog ()),
"edit" : ``(SourceDialogs::EditDialog ()),
"store" : ``(StoreSource ())
];
map sequence = $[
"ws_start" : "summary",
"summary" : $[
`add : "type",
`edit : "edit",
`abort : `abort,
`next : `next,
],
"type" : $[
`next : "edit",
`finish : "store",
`abort : `abort,
],
"edit" : $[
`next : "store",
`abort : `abort,
],
"store" : $[
`next : "summary",
`abort : `abort,
],
];
y2milestone ("Starting source sequence");
symbol ret = Sequencer::Run (aliases, sequence);
if (ret == `next && Mode::normal ())
ret = `restart_menu;
UI::CloseDialog ();
return ret;
} // EOF