Connect output progress tracking callbacks inside execute_command() (#760709)

All the output progress tracking callbacks for execution of ext2/3/4 and
ntfs file system specific commands followed this pattern:

    sigc::connection c = signal_progress.connect( sigc::mem_fun( *this, &ext2::..._progress ) );
    bool success = ! execute_command( ... );
    c.disconnect();
    return success;

Instead, pass the callback slot and a flag into execute_command() and
connect the callback inside.  This simplifies the pattern to:

    return ! execute_command( ...|EXEC_PROGRESS_STDOUT,
                              sigc::mem_fun( *this, &ext2::..._progress ) );

Note that as the progress tracking callbacks are only registered against
updates to the relevant stream from the tracked commands they won't be
called when the other stream is updated any more.

Also note that signal_progress is a member of the FileSystem class and
derived objects so lives as long as GParted is running, therefore the
progress tracking callbacks need explicitly disconnecting at the end of
execute_command().  However signal_update is a member of the PipeCapture
class of which the output and error local variables in execute_command()
are types.  Therefore there is no need to explicitly disconnect the
signal_update callbacks as they will be destructed along with the
callback slots when they go out of scope at the end of the
execute_command() method.

Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific
             copy methods
This commit is contained in:
Mike Fleetwood 2016-01-23 09:27:38 +00:00 committed by Curtis Gedak
parent 27e30a570f
commit c00927c23d
4 changed files with 57 additions and 38 deletions

View File

@ -25,19 +25,23 @@
#include <fstream>
#include <sys/stat.h>
#include <sigc++/slot.h>
namespace GParted
{
enum ExecFlags
{
EXEC_NONE = 1 << 0,
EXEC_CHECK_STATUS = 1 << 1, // Set the status of the command in the operation
// details based on the exit status being zero or
// non-zero. Must either use this flag when calling
// ::execute_command() or call ::set_status()
// afterwards.
EXEC_CANCEL_SAFE = 1 << 2
EXEC_NONE = 1 << 0,
EXEC_CHECK_STATUS = 1 << 1, // Set the status of the command in the operation
// details based on the exit status being zero or
// non-zero. Must either use this flag when calling
// ::execute_command() or call ::set_status()
// afterwards.
EXEC_CANCEL_SAFE = 1 << 2,
EXEC_PROGRESS_STDOUT = 1 << 3, // Run progress tracking callback after reading new
// data on stdout from command.
EXEC_PROGRESS_STDERR = 1 << 4 // Same but for stderr.
};
inline ExecFlags operator|( ExecFlags lhs, ExecFlags rhs )
@ -77,8 +81,18 @@ public:
virtual bool remove( const Partition & partition, OperationDetail & operationdetail ) { return true; };
protected:
typedef sigc::slot<void, OperationDetail *> StreamSlot;
// Use sigc::slot<> class default constructor, via StreamSlot typedef, to create
// an empty, unconnected slot to use as the default stream_progress_slot parameter
// for when none is provided.
// References:
// * How to set default parameter as class object in c++?
// http://stackoverflow.com/questions/12121645/how-to-set-default-parameter-as-class-object-in-c
// * C++ function, what default value can I give for an object?
// http://stackoverflow.com/questions/9909444/c-function-what-default-value-can-i-give-for-an-object
int execute_command( const Glib::ustring & command, OperationDetail & operationdetail,
ExecFlags flags = EXEC_NONE );
ExecFlags flags = EXEC_NONE, StreamSlot stream_progress_slot = StreamSlot() );
void set_status( OperationDetail & operationdetail, bool success );
void execute_command_eof();
Glib::ustring mk_temp_dir( const Glib::ustring & infix, OperationDetail & operationdetail ) ;

View File

@ -23,6 +23,7 @@
#include <gtkmm/main.h>
#include <signal.h>
#include <fcntl.h>
#include <sigc++/slot.h>
namespace GParted
{
@ -80,7 +81,7 @@ static void setup_child()
}
int FileSystem::execute_command( const Glib::ustring & command, OperationDetail & operationdetail,
ExecFlags flags )
ExecFlags flags, StreamSlot stream_progress_slot )
{
operationdetail.add_child( OperationDetail( command, STATUS_EXECUTE, FONT_BOLD_ITALIC ) );
Glib::Pid pid;
@ -122,13 +123,24 @@ int FileSystem::execute_command( const Glib::ustring & command, OperationDetail
outputcapture.signal_update.connect( sigc::bind( sigc::ptr_fun( update_command_output ),
children[children.size() - 2],
&output ) );
outputcapture.signal_update.connect( sigc::bind( sigc::mem_fun( *this, &FileSystem::update_command_progress ),
&operationdetail ) );
errorcapture.signal_update.connect( sigc::bind( sigc::ptr_fun( update_command_output ),
children[children.size() - 1],
&error ) );
errorcapture.signal_update.connect( sigc::bind( sigc::mem_fun( *this, &FileSystem::update_command_progress ),
&operationdetail ) );
sigc::connection c;
if ( flags & EXEC_PROGRESS_STDOUT && ! stream_progress_slot.empty() )
{
// Call progress tracking callback when stdout updates
outputcapture.signal_update.connect( sigc::bind( sigc::mem_fun( *this, &FileSystem::update_command_progress ),
&operationdetail ) );
c = signal_progress.connect( stream_progress_slot );
}
else if ( flags & EXEC_PROGRESS_STDERR && ! stream_progress_slot.empty() )
{
// Call progress tracking callback when stderr updates
errorcapture.signal_update.connect( sigc::bind( sigc::mem_fun( *this, &FileSystem::update_command_progress ),
&operationdetail ) );
c = signal_progress.connect( stream_progress_slot );
}
outputcapture.connect_signal();
errorcapture.connect_signal();
@ -148,6 +160,9 @@ int FileSystem::execute_command( const Glib::ustring & command, OperationDetail
}
close( out );
close( err );
if ( c.connected() )
c.disconnect();
operationdetail.stop_progressbar();
return exit_status;
}

View File

@ -228,12 +228,10 @@ bool ext2::write_uuid( const Partition & partition, OperationDetail & operationd
bool ext2::create( const Partition & new_partition, OperationDetail & operationdetail )
{
sigc::connection c = signal_progress.connect( sigc::mem_fun( *this, &ext2::create_progress ) );
bool ret = ! execute_command( mkfs_cmd + " -F -L \"" + new_partition.get_filesystem_label() + "\" " +
new_partition.get_path(),
operationdetail, EXEC_CHECK_STATUS|EXEC_CANCEL_SAFE );
c.disconnect();
return ret;
return ! execute_command( mkfs_cmd + " -F -L \"" + new_partition.get_filesystem_label() + "\" " +
new_partition.get_path(),
operationdetail, EXEC_CHECK_STATUS|EXEC_CANCEL_SAFE|EXEC_PROGRESS_STDOUT,
sigc::mem_fun( *this, &ext2::create_progress ) );
}
bool ext2::resize( const Partition & partition_new, OperationDetail & operationdetail, bool fill_partition )
@ -244,18 +242,15 @@ bool ext2::resize( const Partition & partition_new, OperationDetail & operationd
str_temp += " " + Utils::num_to_str( floor( Utils::sector_to_unit(
partition_new .get_sector_length(), partition_new .sector_size, UNIT_KIB ) ) ) + "K";
sigc::connection c = signal_progress.connect( sigc::mem_fun( *this, &ext2::resize_progress ) );
bool ret = ! execute_command( str_temp, operationdetail, EXEC_CHECK_STATUS );
c.disconnect();
return ret;
return ! execute_command( str_temp, operationdetail, EXEC_CHECK_STATUS|EXEC_PROGRESS_STDOUT,
sigc::mem_fun( *this, &ext2::resize_progress ) );
}
bool ext2::check_repair( const Partition & partition, OperationDetail & operationdetail )
{
sigc::connection c = signal_progress.connect( sigc::mem_fun( *this, &ext2::check_repair_progress ) );
exit_status = execute_command( fsck_cmd + " -f -y -v -C 0 " + partition.get_path(), operationdetail,
EXEC_CANCEL_SAFE );
c.disconnect();
EXEC_CANCEL_SAFE|EXEC_PROGRESS_STDOUT,
sigc::mem_fun( *this, &ext2::check_repair_progress ) );
bool success = ( exit_status == 0 || exit_status == 1 || exit_status == 2 );
set_status( operationdetail, success );
return success;
@ -274,10 +269,8 @@ bool ext2::move( const Partition & partition_new,
cmd = image_cmd + " -ra -p -O " + offset + " " + partition_new.get_path();
fs_block_size = partition_old.fs_block_size;
sigc::connection c = signal_progress.connect( sigc::mem_fun( *this, &ext2::copy_progress ) );
bool success = ! execute_command( cmd, operationdetail, EXEC_CHECK_STATUS|EXEC_CANCEL_SAFE );
c.disconnect();
return success;
return ! execute_command( cmd, operationdetail, EXEC_CHECK_STATUS|EXEC_CANCEL_SAFE|EXEC_PROGRESS_STDERR,
sigc::mem_fun( *this, &ext2::copy_progress ) );
}
bool ext2::copy( const Partition & src_part,
@ -285,11 +278,9 @@ bool ext2::copy( const Partition & src_part,
OperationDetail & operationdetail )
{
fs_block_size = src_part.fs_block_size;
sigc::connection c = signal_progress.connect( sigc::mem_fun( *this, &ext2::copy_progress ) );
bool success = ! execute_command( image_cmd + " -ra -p " + src_part.get_path() + " " + dest_part.get_path(),
operationdetail, EXEC_CHECK_STATUS|EXEC_CANCEL_SAFE );
c.disconnect();
return success;
return ! execute_command( image_cmd + " -ra -p " + src_part.get_path() + " " + dest_part.get_path(),
operationdetail, EXEC_CHECK_STATUS|EXEC_CANCEL_SAFE|EXEC_PROGRESS_STDERR,
sigc::mem_fun( *this, &ext2::copy_progress ) );
}
//Private methods

View File

@ -234,9 +234,9 @@ bool ntfs::resize( const Partition & partition_new, OperationDetail & operationd
//real resize
operationdetail .add_child( OperationDetail( _("real resize") ) ) ;
sigc::connection c = signal_progress.connect( sigc::mem_fun( *this, &ntfs::resize_progress ) );
if ( ! execute_command( cmd + " " + partition_new.get_path(),
operationdetail.get_last_child(), EXEC_CHECK_STATUS ) )
operationdetail.get_last_child(), EXEC_CHECK_STATUS|EXEC_PROGRESS_STDOUT,
sigc::mem_fun( *this, &ntfs::resize_progress ) ) )
{
operationdetail .get_last_child() .set_status( STATUS_SUCCES ) ;
return_value = true ;
@ -245,7 +245,6 @@ bool ntfs::resize( const Partition & partition_new, OperationDetail & operationd
{
operationdetail .get_last_child() .set_status( STATUS_ERROR ) ;
}
c.disconnect();
}
else
{