ACC SHELL
/**
* Module: PackageSlideShow.ycp
*
* Purpose: Module to access slides from installation repository
*
* Author: Stefan Hundhammer <sh@suse.de>
* Stanislav Visnovsky <visnov@suse.cz>
*
*/
{
module "PackageSlideShow";
textdomain "packager";
import "Slides";
import "SlideShow";
import "String";
import "Mode";
global list<list<integer> > total_sizes_per_cd_per_src = []; // total sizes per inst-src: [ [42, 43, 44], [12, 13, 14] ]
global list<list<integer> > remaining_sizes_per_cd_per_src = []; // remaining sizes
global list<list<integer> > remaining_times_per_cd_per_src = []; // remaining times
global list<string> inst_src_names = []; // a list of strings identifying each repository
global list<list<integer> > total_pkg_count_per_cd_per_src = []; // number of pkgs per inst-src: [ [7, 5, 3], [2, 3, 4] ]
global list<list<integer> > remaining_pkg_count_per_cd_per_src = []; // remaining number of pkgs
global map<integer,integer> srcid_to_current_src_no = $[];
// the string is follwed by a media number, e.g. "Medium 1"
global string media_type = _("Medium");
global integer total_size_installed = 0;
global integer total_size_to_install = 0;
global integer min_time_per_cd = 10; // const - minimum time displayed per CD if there is something to install
global integer max_time_per_cd = 7200; // const - seconds to cut off predicted time (it's bogus anyway)
global integer size_column = 1; // const - column number for remaining size per CD
global integer pkg_count_column = 2; // const - column number for remaining number of packages per CD
global integer time_column = 3; // const - column number for remaining time per CD
global integer current_src_no = -1; // 1..n
global integer current_cd_no = -1; // 1..n
global integer next_src_no = -1;
global integer next_cd_no = -1;
global boolean last_cd = false;
global integer total_cd_count = 0;
global boolean unit_is_seconds = false; // begin with package sizes
global integer bytes_per_second = 1;
global boolean init_pkg_data_complete = false;
boolean debug = false; // more debugging info
string provide_name = ""; // currently downlaoded package name
string provide_size = ""; // currently downlaoded package size
// package summary
// package counters
integer installed_packages = 0;
integer updated_packages = 0;
integer removed_packages = 0;
integer total_downloaded = 0;
integer total_installed = 0;
// package list (only used in installed system)
list<string> installed_packages_list = [];
list<string> updated_packages_list = [];
list<string> removed_packages_list = [];
// integer avg_download_rate = 0;
integer current_provide_size = 0;
integer current_install_size = 0;
string current_pkg_name = "";
boolean updating = false;
void ResetPackageSummary()
{
installed_packages = 0;
updated_packages = 0;
removed_packages = 0;
total_downloaded = 0;
total_installed = 0;
// avg_download_rate = 0;
// temporary values
current_provide_size = 0;
current_install_size = 0;
current_pkg_name = "";
updating = false;
}
global map<string,any> GetPackageSummary()
{
return $[
"installed" : installed_packages,
"updated" : updated_packages,
"removed" : removed_packages,
"installed_list" : installed_packages_list,
"updated_list" : updated_packages_list,
"removed_list" : removed_packages_list,
"downloaded_bytes" : total_downloaded,
"installed_bytes" : total_installed,
];
}
/*****************************************************************************/
/*************** Formatting functions and helpers ***************************/
/*****************************************************************************/
/**
* Get version info for a package (without build no.)
*
* @param pkg_name name of the package without path and ".rpm" extension
* @return version string
**/
global string StripReleaseNo( string pkg_name )
{
integer build_no_pos = findlastof (pkg_name, "-" ); // find trailing build no.
if ( build_no_pos != nil && build_no_pos > 0 )
{
// cut off trailing build no.
pkg_name = substring( pkg_name , 0, build_no_pos );
}
return pkg_name;
}
/**
* Get package file name from path
*
* @param pkg_name location of the package
* @return string package file name
**/
global string StripPath(string pkg_name)
{
if (pkg_name == nil)
{
return nil;
}
integer file_pos = findlastof(pkg_name, "/");
if (file_pos != nil && file_pos > 0 )
{
// return just the file name
pkg_name = substring(pkg_name, file_pos + 1);
}
return pkg_name;
}
/**
* set media type "CD" or "DVD"
*/
global void SetMediaType (string new_media_type)
{
media_type = new_media_type;
}
/**
* Sum up all list items
**/
integer ListSum( list<integer> sizes )
{
integer sum = 0;
foreach( integer item, sizes, ``{
if ( item != -1 )
sum = sum + item;
});
return sum;
}
/**
* Sum up all positive list items, but cut off individual items at a maximum value.
* Negative return values indicate overflow of any individual item at "max_cutoff".
* In this case, the absolute value of the return value is "max_cutoff" * number of overflows.
* (e.g. >2hour + >2hours + 1:13:20 => >4hours
**/
integer ListSumCutOff( list<integer> sizes, integer max_cutoff )
{
integer overflow = 0;
integer sum = 0;
foreach( integer item, sizes, ``{
if ( item > 0 )
{
if ( item > max_cutoff )
{
overflow = overflow + 1;
}
else
{
sum = sum + item;
}
}
});
if (overflow > 0)
{
sum = -overflow * max_cutoff;
}
return sum;
}
integer TotalRemainingSize()
{
return ListSum( flatten( remaining_sizes_per_cd_per_src ) );
}
integer TotalRemainingTime()
{
return ListSumCutOff( flatten( remaining_times_per_cd_per_src ),
max_time_per_cd );
}
integer TotalRemainingPkgCount()
{
return ListSum( flatten( remaining_pkg_count_per_cd_per_src ) );
}
integer TotalInstalledSize()
{
return total_size_to_install - TotalRemainingSize();
}
/**
* Format an integer seconds value with min:sec or hours:min:sec
*
* Negative values are interpreted as overflow - ">" is prepended and the
* absolute value is used.
**/
string FormatTimeShowOverflow( integer seconds )
{
string text = "";
if ( seconds < 0 ) // Overflow (indicated by negative value)
{
// When data throughput goes downhill (stalled network connection etc.),
// cut off the predicted time at a reasonable maximum.
// "%1" is a predefined maximum time.
text = sformat( _(">%1"), String::FormatTime( -seconds ) );
}
else
{
text = String::FormatTime( seconds );
}
return text;
}
/**
* Format number of remaining bytes to be installed as string.
* @param remaining bytes remaining, -1 for 'done'
* @return string human readable remaining time or byte / kB/ MB size
**/
string FormatRemainingSize( integer remaining )
{
if ( remaining < 0 )
{
// Nothing more to install from this CD (very concise - little space!!)
return _("Done.");
}
if ( remaining == 0 )
{
return "";
}
return String::FormatSize( remaining );
}
/**
* Format number of remaining packages to be installed as string.
* @param remaining bytes remaining, -1 for 'done'
* @return string human readable remaining time or byte / kB/ MB size
**/
string FormatRemainingCount( integer remaining )
{
if ( remaining < 0 )
{
// Nothing more to install from this CD (very concise - little space!!)
return _("Done.");
}
if ( remaining == 0 )
{
return "";
}
return sformat( "%1", remaining );
}
string FormatNextMedia()
{
string text = "";
if ( next_src_no >= 0 && next_cd_no >= 0 )
{
string next_media_name = sformat( "%1 %2 %3",
inst_src_names[ next_src_no ]:"",
media_type, next_cd_no+1 );
if ( unit_is_seconds )
{
// Status line informing about the next CD that will be used
// %1: Media type ("CD" / "DVD", ???)
// %2: Media name ("SuSE Linux Professional CD 2" )
// %3: Time remaining until this media will be needed
text = sformat( _("Next %1: %2 -- %3"), media_type, next_media_name,
String::FormatTime( remaining_times_per_cd_per_src[ current_src_no-1, current_cd_no-1 ]: 1) );
}
else
{
// Status line informing about the next CD that will be used
// %1: Media type ("CD" / "DVD", ???)
// %2: Media name ("SuSE Linux Professional CD 2" )
text = sformat( _("Next %1: %2"), media_type, next_media_name );
}
}
return text;
}
/*****************************************************************************/
/*********************** Computing Helpers **********************************/
/*****************************************************************************/
/**
* Perform sanity check for correct initialzation etc.
* @param silent don't complain in log file
* @return true if OK, false if any error
**/
boolean SanityCheck( boolean silent )
{
return true; // FIXME!
if ( ! init_pkg_data_complete )
{
if ( ! silent )
{
y2error( "PackageSlideShow::SanityCheck(): Slide show not correctly initialized: " +
"PackageSlideShow::InitPkgData() never called!" );
}
return false;
}
if ( current_src_no < 1 || current_cd_no < 1 )
{
// nothing to install but something is going to be deleted, so it's OK
if (Pkg::IsAnyResolvable(`package, `to_remove))
{
return true;
}
else if (!silent)
{
y2error(-1, "PackageSlideShow::SanityCheck(): Illegal values for current_src_no (%1) or current_cd_no (%2)",
current_src_no, current_cd_no );
y2milestone( "total sizes: %1", total_sizes_per_cd_per_src );
}
return false;
}
return true;
}
/**
* Update internal bookkeeping: subtract size of one package from the
* global list of remaining sizes per CD
**/
void SubtractPackageSize( integer pkg_size )
{
integer remaining = remaining_sizes_per_cd_per_src [ current_src_no-1, current_cd_no-1 ]: 1;
remaining = remaining - pkg_size;
total_size_installed = total_size_installed + pkg_size;
if ( remaining <= 0 )
{
// -1 is the indicator for "done with this CD" - not to be
// confused with 0 for "nothing to install from this CD".
remaining = -1;
}
remaining_sizes_per_cd_per_src [ current_src_no-1, current_cd_no-1 ] = remaining;
remaining_pkg_count_per_cd_per_src [ current_src_no-1, current_cd_no-1 ] =
remaining_pkg_count_per_cd_per_src [ current_src_no-1, current_cd_no-1 ]:0 -1;
if ( unit_is_seconds )
{
integer seconds = 0;
if ( remaining > 0 && bytes_per_second > 0 )
seconds = remaining / bytes_per_second;
remaining_times_per_cd_per_src [ current_src_no-1, current_cd_no-1 ] = seconds;
}
if ( debug )
y2milestone( "SubtractPackageSize( %1 ) -> %2", pkg_size, remaining_sizes_per_cd_per_src);
}
/**
* Initialize internal pacakge data, such as remaining package sizes and
* times. This may not be called before the pkginfo server is up and
* running, so this cannot be reliably done from the constructor in all
* cases.
* @param force true to force reinitialization
**/
global void InitPkgData(boolean force)
{
if ( init_pkg_data_complete && ! force)
return;
ResetPackageSummary();
// Reinititalize some globals (in case this is a second run)
total_size_installed = 0;
//total_time_elapsed = 0;
//start_time = -1;
current_src_no = -1; // 1..n
current_cd_no = -1; // 1..n
next_src_no = -1;
next_cd_no = -1;
last_cd = false;
unit_is_seconds = false; // begin with package sizes
bytes_per_second = 1;
list< list > src_list = Pkg::PkgMediaNames();
inst_src_names = maplist( list src, src_list, ``(src[0]:"CD") );
y2milestone ("Media names: %1", inst_src_names);
integer index = 0;
srcid_to_current_src_no = listmap( list src, src_list, {
index = index + 1;
return $[src[1]:-1 : index];
});
y2milestone ("Repository mapping information: %1", srcid_to_current_src_no );
total_sizes_per_cd_per_src = Pkg::PkgMediaSizes();
total_pkg_count_per_cd_per_src = Pkg::PkgMediaCount();
total_size_to_install = ListSum( flatten( total_sizes_per_cd_per_src ) );
y2milestone("total_size_to_install: %1", total_size_to_install);
remaining_sizes_per_cd_per_src = (list<list <integer> >) eval (total_sizes_per_cd_per_src);
remaining_pkg_count_per_cd_per_src = (list<list <integer> >) eval (total_pkg_count_per_cd_per_src);
total_cd_count = size( flatten( total_sizes_per_cd_per_src ) );
init_pkg_data_complete = true;
// reset the history log
SlideShow::inst_log = "";
y2milestone( "PackageSlideShow::InitPkgData() done; total_sizes_per_cd_per_src: %1", total_sizes_per_cd_per_src );
y2milestone( "PackageSlideShow::InitPkgData(): pkg: %1", total_pkg_count_per_cd_per_src );
// RebuildDialog(true);
}
/**
* Try to figure out what media will be needed next
* and set next_src_no and next_cd_no accordingly.
**/
void FindNextMedia()
{
// Normally we would have to use current_cd_no+1,
// but since this uses 1..n and we need 0..n-1
// for array subscripts anyway, use it as it is.
next_cd_no = current_cd_no;
next_src_no = current_src_no-1;
last_cd = false;
while ( next_src_no < size( remaining_sizes_per_cd_per_src ) )
{
list<integer> remaining_sizes = remaining_sizes_per_cd_per_src[ next_src_no ]: [];
while ( next_cd_no < size( remaining_sizes ) )
{
if ( remaining_sizes[ next_cd_no ]:0 > 0 )
{
if ( debug )
y2milestone( "Next media: src: %1 CD: %2", next_src_no, next_cd_no );
return;
}
else
{
next_cd_no = next_cd_no + 1;
}
}
next_src_no = next_src_no + 1;
}
if ( debug )
y2milestone( "No next media - all done" );
next_src_no = -1;
next_cd_no = -1;
last_cd = true;
}
/**
* Set the current repository and CD number. Must be called for each CD change.
* src_no: 1...n
* cd_no: 1...n
**/
global void SetCurrentCdNo( integer src_no, integer cd_no )
{
if (cd_no == 0)
{
y2milestone("medium number 0, using medium number 1");
cd_no = 1;
}
y2milestone("SetCurrentCdNo() - src: %1 , CD: %2", src_no, cd_no);
current_src_no = srcid_to_current_src_no[src_no]:-1;
current_cd_no = cd_no;
SlideShow::CheckForSlides();
FindNextMedia();
if ( Slides::HaveSlides() && Slides::HaveSlideSupport() )
{
if ( ! SlideShow::HaveSlideWidget() )
{
SlideShow::RebuildDialog();
if ( SlideShow::user_switched_to_details )
SlideShow::SwitchToDetailsView();
}
if ( ! SlideShow::user_switched_to_details ) // Don't override explicit user request!
{
SlideShow::SwitchToSlideView();
}
}
else
{
if ( ! SlideShow::ShowingDetails() )
SlideShow::RebuildDialog();
}
}
/**
* Recalculate remaining times per CD based on package sizes remaining
* and data rate so far. Recalculation is only done each 'recalc_interval'
* seconds unless 'force_recalc' is set to 'true'.
*
* @param force_recalc force recalculation even if timeout not reached yet
* @return true if recalculated, false if not
**/
boolean RecalcRemainingTimes( boolean force_recalc )
{
if ( ! force_recalc
&& time() < SlideShow::next_recalc_time )
{
// Nothing to do (yet) - simply return
return false;
}
// Actually do recalculation
integer elapsed = SlideShow::total_time_elapsed;
if ( SlideShow::start_time >= 0 )
{
elapsed = elapsed + time() - SlideShow::start_time;
}
if ( elapsed == 0 )
{
// Called too early - no calculation possible yet.
// This happens regularly during initialization, so an error
// message wouldn't be a good idea here.
return false;
}
// This is the real thing.
integer real_bytes_per_second = total_size_installed / elapsed;
// But this turns out to be way to optimistic - RPM gets slower and
// slower while installing. So let's add some safety margin to make
// sure initial estimates are on the pessimistic side - the
// installation being faster than initially estimated will be a
// pleasant surprise to the user. Most users don't like it the other
// way round.
//
// The "pessimistic factor" progressively decreases as the installation
// proceeds. It begins with about 1.7, i.e. the data transfer rate is
// halved to what it looks like initially. It decreases to 1.0 towards
// the end.
float pessimistic_factor = 1.0;
if ( total_size_to_install > 0 )
pessimistic_factor = 1.7 - tofloat( total_size_installed ) / tofloat( total_size_to_install );
bytes_per_second = tointeger( tofloat( real_bytes_per_second ) / pessimistic_factor + 0.5 );
if ( bytes_per_second < 1 )
bytes_per_second = 1;
remaining_times_per_cd_per_src = [];
// Recalculate remaining times for the individual CDs
foreach ( list<integer> remaining_sizes_list, remaining_sizes_per_cd_per_src,
``{
list<integer> remaining_times_list = [];
integer remaining_time = -1;
foreach ( integer remaining_size, remaining_sizes_list,
``{
remaining_time = remaining_size;
if ( remaining_size > 0 )
{
remaining_time = remaining_size / bytes_per_second;
if ( remaining_time < min_time_per_cd )
{
// It takes at least this long for the CD drive to spin up and
// for RPM to do _anything_. Times below this values are
// ridiculously unrealistic.
remaining_time = min_time_per_cd;
}
else if ( remaining_time > max_time_per_cd ) // clip off at 2 hours
{
// When data throughput goes downhill (stalled network connection etc.),
// cut off the predicted time at a reasonable maximum.
remaining_time = max_time_per_cd;
}
}
remaining_times_list = add( remaining_times_list, remaining_time );
});
remaining_times_per_cd_per_src = add( remaining_times_per_cd_per_src, remaining_times_list );
});
// Recalculate slide interval
if ( Slides::HaveSlides() )
{
integer slides_remaining = size( Slides::slides ) - SlideShow::current_slide_no - 1;
if ( slides_remaining > 0 )
{
// The remaining time for the rest of the slides depends on the
// remaining time for the current CD only: This is where the
// slide images and texts reside. Normally, only CD1 has slides
// at all, i.e. the slide show must be finished when CD1 is
// done.
//
// In addition to that, take elapsed time for current slide
// into account so all slides get about the same time.
integer time_remaining = remaining_times_per_cd_per_src[current_src_no-1, current_cd_no-1]:1 + time() - SlideShow::slide_start_time;
SlideShow::slide_interval = time_remaining / slides_remaining;
y2debug( "New slide interval: %1 - slides remaining: %2 - remaining time: %3",
SlideShow::slide_interval, slides_remaining, time_remaining );
if ( SlideShow::slide_interval < SlideShow::slide_min_interval )
{
SlideShow::slide_interval = SlideShow::slide_min_interval;
y2debug( "Resetting slide interval to min slide interval: %1", SlideShow::slide_interval );
}
if ( SlideShow::slide_interval > SlideShow::slide_max_interval )
{
SlideShow::slide_interval = SlideShow::slide_max_interval;
y2debug( "Resetting slide interval to max slide interval: %1", SlideShow::slide_interval );
}
}
}
SlideShow::next_recalc_time = time() + SlideShow::recalc_interval;
return true;
}
/**
* Switch unit to seconds if necessary and recalc everything accordingly.
* @return true if just switched from sizes to seconds, false otherwise
**/
boolean SwitchToSecondsIfNecessary()
{
if ( unit_is_seconds
|| time() < SlideShow::start_time + SlideShow::initial_recalc_delay )
{
return false; // no need to switch
}
RecalcRemainingTimes( true ); // force recalculation
unit_is_seconds = true;
return true; // just switched
}
/*****************************************************************************/
/****************** Callbacks and progress bars *****************************/
/*****************************************************************************/
/**
* Update progress widgets for the current CD: Label and ProgressBar.
* Use global statistics variables for that.
**/
global void UpdateCurrentCdProgress(boolean silent_check)
{
if ( ! SanityCheck( silent_check ) ) return;
if ( ! UI::WidgetExists(`cdStatisticsTable) ) return;
//
// Update table entries for current CD
//
integer remaining = remaining_sizes_per_cd_per_src [ current_src_no-1, current_cd_no-1 ]:0;
UI::ChangeWidget(`id(`cdStatisticsTable ),
`Item( sformat( "cd(%1,%2)", current_src_no-1, current_cd_no-1), size_column ),
FormatRemainingSize( remaining ) );
UI::ChangeWidget(`id(`cdStatisticsTable ),
`Item( sformat( "cd(%1,%2)", current_src_no-1, current_cd_no-1), pkg_count_column ),
FormatRemainingCount( remaining_pkg_count_per_cd_per_src [ current_src_no-1, current_cd_no-1 ]:0 ) );
if ( unit_is_seconds )
{
// Convert 'remaining' from size (bytes) to time (seconds)
remaining = remaining / bytes_per_second;
if ( remaining <= 0 )
remaining = 0;
if ( remaining > max_time_per_cd ) // clip off at 2 hours
{
// When data throughput goes downhill (stalled network connection etc.),
// cut off the predicted time at a reasonable maximum.
remaining = -max_time_per_cd;
}
UI::ChangeWidget(`id(`cdStatisticsTable ),
`Item( sformat( "cd(%1,%2)", current_src_no-1, current_cd_no-1), time_column ),
FormatTimeShowOverflow( remaining ) );
}
//
// Update "total" table entries
//
UI::ChangeWidget(`id( `cdStatisticsTable ),
`Item( "total", size_column ),
FormatRemainingSize( TotalRemainingSize() ) );
UI::ChangeWidget(`id( `cdStatisticsTable ),
`Item( "total", pkg_count_column ),
FormatRemainingCount( TotalRemainingPkgCount() ) );
if ( unit_is_seconds )
{
UI::ChangeWidget(`id( `cdStatisticsTable ), `Item( "total", time_column ),
FormatTimeShowOverflow( TotalRemainingTime() ) );
}
}
/**
* Update progress widgets
**/
void UpdateTotalProgress(boolean silent_check)
{
integer total_size_to_install_kB = total_size_to_install >> 10;
// avoid division by zero
if (total_size_to_install_kB <= 0)
{
total_size_to_install_kB = 1;
}
SlideShow::StageProgress( ( TotalInstalledSize() >> 10 ) * 100 / total_size_to_install_kB, nil /*, SlideShow::GetProgressLabel()*/ );
UpdateCurrentCdProgress(silent_check);
if ( UI::WidgetExists(`nextMedia ) )
{
string nextMedia = FormatNextMedia();
if ( nextMedia != "" || last_cd )
{
UI::ChangeWidget(`nextMedia, `Value, nextMedia );
UI::RecalcLayout();
last_cd = false;
}
}
}
/**
* Returns a table widget item list for CD statistics
**/
list<term> CdStatisticsTableItems()
{
list<term> itemList = [];
//
// Add "Total" item - at the top so it is visible by default even if there are many items
//
{
// List column header for total remaining MB and time to install
string caption = _("Total");
integer remaining = TotalRemainingSize();
string rem_size = FormatRemainingSize( remaining );
string rem_count = FormatRemainingCount( TotalRemainingPkgCount() );
string rem_time = "";
if ( unit_is_seconds && bytes_per_second > 0 )
{
rem_time = FormatTimeShowOverflow( TotalRemainingTime() );
}
itemList = add( itemList, SlideShow::TableItem( "total", caption, " " + rem_size, " " + rem_count, " " + rem_time ) );
}
//
// Now go through all repositories
//
integer src_no = 0;
foreach ( list<integer> inst_src, remaining_sizes_per_cd_per_src, ``{
y2milestone( "src #%1: %2", src_no, inst_src );
if (ListSum(inst_src) > 0) // Ignore repositories from where there is nothing is to install
{
// Add heading for this repository
itemList = add( itemList, SlideShow::TableItem( sformat( "src(%1)", src_no ),
inst_src_names[ src_no ]:"", "", "", "" ) );
integer cd_no = 0;
foreach ( integer remaining, inst_src, ``{
if ( remaining > 0
|| ( src_no+1 == current_src_no && cd_no+1 == current_cd_no ) ) // suppress current CD
{
string caption = sformat( "%1 %2", media_type, cd_no+1 ); // "CD 1" - column #0
string rem_size = FormatRemainingSize( remaining ); // column #1
string rem_count = FormatRemainingCount( remaining_pkg_count_per_cd_per_src[ src_no, cd_no ]:0 );
string rem_time = "";
if ( unit_is_seconds && bytes_per_second > 0 )
{
remaining = remaining / bytes_per_second;
rem_time = String::FormatTime( remaining ); // column #2
if ( remaining > max_time_per_cd ) // clip off at 2 hours
{
// When data throughput goes downhill (stalled network connection etc.),
// cut off the predicted time at a reasonable maximum.
// "%1" is a predefined maximum time.
rem_time = FormatTimeShowOverflow( -max_time_per_cd );
}
}
itemList = add( itemList,
SlideShow::TableItem( sformat("cd(%1,%2)", src_no, cd_no ), // ID
caption, " " + rem_size, " " + rem_count, " " + rem_time ) );
}
cd_no = cd_no + 1;
});
}
src_no = src_no + 1;
});
if ( debug )
{
y2milestone( "Remaining: %1", remaining_sizes_per_cd_per_src );
y2milestone( "CD table item list:\n%1", itemList );
}
return itemList;
}
/**
* Progress display update
* This is called via the packager's progress callbacks.
*
* @param pkg_percent package percentage
**/
global void UpdateCurrentPackageProgress(integer pkg_percent)
{
SlideShow::SubProgress( pkg_percent, nil );
}
// update the download rate
global void UpdateCurrentPackageRateProgress(integer pkg_percent, integer bps_avg, integer bps_current)
{
// avg_download_rate = bps_avg;
if( ! SlideShow::ShowingDetails() ) return;
string new_text = nil; // no update of the label
if (bps_current > 0)
{
// do not show the average download rate if the space is limited
if (SlideShow::textmode && SlideShow::display_width < 100)
{
bps_avg = -1;
}
new_text = String::FormatRateMessage(provide_name + " - %1", bps_avg, bps_current);
new_text = sformat(_("Downloading %1 (download size %2)"), new_text, provide_size);
}
SlideShow::SubProgress( pkg_percent, new_text );
}
global void DoneProvide( integer error, string reason, string name )
{
if (error == 0)
{
total_downloaded = total_downloaded + current_provide_size;
}
}
/**
* Update progress widgets for all CDs.
* Uses global statistics variables.
**/
global void UpdateAllCdProgress(boolean silent_check)
{
if ( ! SanityCheck( silent_check ) ) return;
if ( unit_is_seconds )
RecalcRemainingTimes( true ); // force
SlideShow::UpdateTable( CdStatisticsTableItems() );
}
/**
* Return a CD's progress bar ID
* @param src_no number of the repository (from 0 on)
* @param cd_no number of the CD within that repository (from 0 on)
**/
string CdProgressId( integer src_no, integer cd_no )
{
return sformat( "Src %1 CD %2", src_no, cd_no );
}
/**
* package start display update
* - this is called at the end of a new package
*
* @param pkg_name package name
* @param deleting Flag: deleting (true) or installing (false) package?
**/
global void SlideDisplayDone ( string pkg_name,
integer pkg_size,
boolean deleting )
{
if ( ! deleting )
{
SubtractPackageSize( pkg_size );
if (SwitchToSecondsIfNecessary()
|| RecalcRemainingTimes( false ) ) // no forced recalculation
{
y2debug( "Updating progress for all CDs" );
UpdateAllCdProgress(false);
}
else
{
UpdateCurrentCdProgress(false);
}
UpdateTotalProgress(false);
if (updating)
{
updated_packages = updated_packages + 1;
if (Mode::normal())
{
updated_packages_list = add(updated_packages_list, current_pkg_name);
}
}
else
{
installed_packages = installed_packages + 1;
if (Mode::normal())
{
installed_packages_list = add(installed_packages_list, current_pkg_name);
}
}
total_installed = total_installed + current_install_size;
} // ! deleting
else
{
removed_packages = removed_packages + 1;
if (Mode::normal())
{
removed_packages_list = add(removed_packages_list, current_pkg_name);
}
}
}
/**
* package start display update
* - this is called at the beginning of a new package
*
* @param pkg_name package name
* @param pkg_summary package summary (short description)
* @param deleting Flag: deleting (true) or installing (false) package?
**/
global void SlideDisplayStart( string pkg_name,
string pkg_summary,
integer pkg_size,
boolean deleting )
{
if ( ! SanityCheck( false ) ) return;
// remove path
pkg_name = StripPath(pkg_name);
// remove release and .rpm suffix
// pkg_name = StripReleaseNo( pkg_name ); // bug #154872
if ( deleting )
{
pkg_size = -1;
// This is a kind of misuse of insider knowledge: If there are packages to delete, this
// deletion comes first, and only then packages are installed. This, however, greatly
// distorts the estimated times based on data throughput so far: While packages are
// deleted, throughput is zero, and estimated times rise to infinity (they are cut off
// at max_time_per_cd to hide this). So we make sure the time spent deleting packages is
// not counted for estimating remaining times - reset the timer.
//
// Note: This will begin to fail when some day packages are deleted in the middle of the
// installaton process.
SlideShow::ResetTimer();
}
if ( pkg_summary == nil )
pkg_summary = "";
string msg = "";
if ( deleting )
{
// Heading for the progress bar for the current package
// while it is deleted. "%1" is the package name.
msg = sformat( _("Deleting %1"), pkg_name );
current_pkg_name = pkg_name;
}
else
{
updating = Pkg::PkgInstalled(current_pkg_name);
// package installation - summary text
// %1 is RPM name, %2 is installed (unpacked) size (e.g. 6.20MB)
msg = sformat( _("Installing %1 (installed size %2)"), pkg_name, String::FormatSize( pkg_size ) );
current_install_size = pkg_size;
}
//
// Update package progress bar
//
SlideShow::SubProgress( 0, msg );
// Update global progress bar
string rem_string = "";
integer tot_rem_t = TotalRemainingTime();
rem_string = ( unit_is_seconds && bytes_per_second > 0 && tot_rem_t > 0) ?
sformat("%1 / %2", FormatRemainingSize(TotalRemainingSize()), FormatTimeShowOverflow(tot_rem_t))
: FormatRemainingSize(TotalRemainingSize());
SlideShow::SetGlobalProgressLabel( SlideShow::CurrentStageDescription() + sformat(_(" (Remaining: %1, %2 packages)"), rem_string, TotalRemainingPkgCount()));
//
// Update (user visible) installation log
//
SlideShow::AppendMessageToInstLog(msg);
//
// Update the current slide if applicable
//
if ( SlideShow::ShowingSlide() )
{
SlideShow::ChangeSlideIfNecessary();
}
}
global void SlideGenericProvideStart (string pkg_name, integer sz,
string pattern, boolean remote)
{
if ( ! SanityCheck( false ) ) return;
if ( ! SlideShow::ShowingDetails() ) return;
string provide_msg = "";
if (remote)
{
provide_name = pkg_name;
provide_size = String::FormatSize(sz);
provide_msg = sformat(_("Downloading %1 (download size %2)"), provide_name, provide_size);
}
else
{
provide_msg = pkg_name;
}
SlideShow::SubProgress( 0, provide_msg );
//
// Update (user visible) installation log
// for remote download only
//
if( ! remote ) return;
y2milestone( "Package '%1' is remote", pkg_name );
// message in the installatino log, %1 is package name,
// %2 is package size
SlideShow::AppendMessageToInstLog( sformat (pattern, pkg_name, String::FormatSize (sz)) );
}
global void SlideDeltaApplyStart (string pkg_name) {
if ( ! SanityCheck( false ) ) return;
if ( ! SlideShow::ShowingDetails() ) return;
SlideShow::SubProgress( 0, pkg_name );
SlideShow::AppendMessageToInstLog( sformat (_("Applying delta RPM: %1"), pkg_name) );
}
/**
* Package providal start
*/
global void SlideProvideStart (string pkg_name, integer sz, boolean remote)
{
current_provide_size = remote ? sz : 0;
current_pkg_name = pkg_name;
if (remote)
{
// message in the installatino log, %1 is package name,
// %2 is package size
SlideGenericProvideStart (pkg_name, sz, _("Downloading %1 (download size %2)"),
remote);
}
}
}
ACC SHELL 2018