2017-01-28 04:49:09 +08:00
# include "pch.h"
2016-09-19 11:50:08 +08:00
# include "vcpkg_Commands.h"
2017-01-26 11:32:50 +08:00
# include "vcpkglib.h"
2016-09-19 11:50:08 +08:00
# include "vcpkg_System.h"
2016-10-01 07:49:30 +08:00
# include "vcpkg_Input.h"
2017-01-27 06:25:36 +08:00
# include "vcpkg_Dependencies.h"
2017-04-01 16:09:34 +08:00
# include "vcpkg_Util.h"
2016-09-19 11:50:08 +08:00
2017-01-13 14:03:57 +08:00
namespace vcpkg : : Commands : : Remove
2016-09-19 11:50:08 +08:00
{
2017-04-04 07:24:44 +08:00
using Dependencies : : PackageSpecWithRemovePlan ;
2017-04-04 07:23:46 +08:00
using Dependencies : : RemovePlanType ;
2017-04-04 07:21:46 +08:00
using Dependencies : : RequestType ;
using Update : : OutdatedPackage ;
2017-01-27 06:25:36 +08:00
2016-09-19 11:50:08 +08:00
static void delete_directory ( const fs : : path & directory )
{
std : : error_code ec ;
fs : : remove_all ( directory , ec ) ;
if ( ! ec )
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : success , " Cleaned up %s " , directory . string ( ) ) ;
2016-09-19 11:50:08 +08:00
}
if ( fs : : exists ( directory ) )
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " Some files in %s were unable to be removed. Close any editors operating in this directory and retry. " , directory . string ( ) ) ;
2016-09-19 11:50:08 +08:00
}
}
2017-04-04 07:29:11 +08:00
static void remove_package ( const VcpkgPaths & paths , const PackageSpec & spec , StatusParagraphs * status_db )
2016-12-01 17:49:24 +08:00
{
2017-04-11 04:03:34 +08:00
StatusParagraph & pkg = * * status_db - > find ( spec . name ( ) , spec . triplet ( ) ) ;
2017-01-31 08:46:39 +08:00
2017-04-04 06:42:26 +08:00
pkg . want = Want : : PURGE ;
2017-04-04 06:25:34 +08:00
pkg . state = InstallState : : HALF_INSTALLED ;
2016-12-01 17:49:24 +08:00
write_update ( paths , pkg ) ;
std : : fstream listfile ( paths . listfile_path ( pkg . package ) , std : : ios_base : : in | std : : ios_base : : binary ) ;
if ( listfile )
{
std : : vector < fs : : path > dirs_touched ;
std : : string suffix ;
while ( std : : getline ( listfile , suffix ) )
{
if ( ! suffix . empty ( ) & & suffix . back ( ) = = ' \r ' )
suffix . pop_back ( ) ;
std : : error_code ec ;
auto target = paths . installed / suffix ;
auto status = fs : : status ( target , ec ) ;
if ( ec )
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : error , " failed: %s " , ec . message ( ) ) ;
2016-12-01 17:49:24 +08:00
continue ;
}
if ( fs : : is_directory ( status ) )
{
dirs_touched . push_back ( target ) ;
}
else if ( fs : : is_regular_file ( status ) )
{
fs : : remove ( target , ec ) ;
if ( ec )
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : error , " failed: %s: %s " , target . u8string ( ) , ec . message ( ) ) ;
2016-12-01 17:49:24 +08:00
}
}
else if ( ! fs : : status_known ( status ) )
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " Warning: unknown status: %s " , target . u8string ( ) ) ;
2016-12-01 17:49:24 +08:00
}
else
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " Warning: %s: cannot handle file type " , target . u8string ( ) ) ;
2016-12-01 17:49:24 +08:00
}
}
auto b = dirs_touched . rbegin ( ) ;
auto e = dirs_touched . rend ( ) ;
for ( ; b ! = e ; + + b )
{
if ( fs : : directory_iterator ( * b ) = = fs : : directory_iterator ( ) )
{
std : : error_code ec ;
fs : : remove ( * b , ec ) ;
if ( ec )
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : error , " failed: %s " , ec . message ( ) ) ;
2016-12-01 17:49:24 +08:00
}
}
}
listfile . close ( ) ;
fs : : remove ( paths . listfile_path ( pkg . package ) ) ;
}
2017-04-04 06:25:34 +08:00
pkg . state = InstallState : : NOT_INSTALLED ;
2016-12-01 17:49:24 +08:00
write_update ( paths , pkg ) ;
}
2017-04-04 07:24:44 +08:00
static void print_plan ( const std : : vector < PackageSpecWithRemovePlan > & plan )
2017-01-28 12:22:33 +08:00
{
2017-04-04 07:24:44 +08:00
std : : vector < const PackageSpecWithRemovePlan * > not_installed ;
std : : vector < const PackageSpecWithRemovePlan * > remove ;
2017-01-28 12:22:33 +08:00
2017-04-04 07:24:44 +08:00
for ( const PackageSpecWithRemovePlan & i : plan )
2017-01-28 12:22:33 +08:00
{
2017-04-07 08:28:49 +08:00
switch ( i . plan . plan_type )
2017-01-28 12:22:33 +08:00
{
2017-04-07 08:28:49 +08:00
case RemovePlanType : : NOT_INSTALLED :
not_installed . push_back ( & i ) ;
continue ;
case RemovePlanType : : REMOVE :
remove . push_back ( & i ) ;
continue ;
default :
Checks : : unreachable ( VCPKG_LINE_INFO ) ;
2017-01-28 12:22:33 +08:00
}
}
2017-04-07 09:57:17 +08:00
auto print_lambda = [ ] ( const PackageSpecWithRemovePlan * p ) { return to_output_string ( p - > plan . request_type , p - > spec . to_string ( ) ) ; } ;
2017-01-28 12:22:33 +08:00
if ( ! not_installed . empty ( ) )
{
2017-04-07 08:37:19 +08:00
std : : sort ( not_installed . begin ( ) , not_installed . end ( ) , & PackageSpecWithRemovePlan : : compare_by_name ) ;
2017-04-07 09:57:17 +08:00
System : : println ( " The following packages are not installed, so not removed: \n %s " , Strings : : join ( " \n " , not_installed , print_lambda ) ) ;
2017-01-28 12:22:33 +08:00
}
if ( ! remove . empty ( ) )
{
2017-04-07 08:37:19 +08:00
std : : sort ( remove . begin ( ) , remove . end ( ) , & PackageSpecWithRemovePlan : : compare_by_name ) ;
2017-04-07 09:57:17 +08:00
System : : println ( " The following packages will be removed: \n %s " , Strings : : join ( " \n " , remove , print_lambda ) ) ;
2017-01-28 12:22:33 +08:00
}
}
2017-04-11 04:00:33 +08:00
void perform_and_exit ( const VcpkgCmdArguments & args , const VcpkgPaths & paths , const Triplet & default_triplet )
2016-09-19 11:50:08 +08:00
{
2017-04-04 06:22:09 +08:00
static const std : : string OPTION_PURGE = " --purge " ;
static const std : : string OPTION_NO_PURGE = " --no-purge " ;
static const std : : string OPTION_RECURSE = " --recurse " ;
static const std : : string OPTION_DRY_RUN = " --dry-run " ;
static const std : : string OPTION_OUTDATED = " --outdated " ;
2017-01-13 14:03:57 +08:00
static const std : : string example = Commands : : Help : : create_example_string ( " remove zlib zlib:x64-windows curl boost " ) ;
2017-04-04 06:22:09 +08:00
const std : : unordered_set < std : : string > options = args . check_and_get_optional_command_arguments ( { OPTION_PURGE , OPTION_NO_PURGE , OPTION_RECURSE , OPTION_DRY_RUN , OPTION_OUTDATED } ) ;
2017-04-01 16:09:34 +08:00
2017-03-30 09:30:32 +08:00
StatusParagraphs status_db = database_load_check ( paths ) ;
2017-04-04 06:02:45 +08:00
std : : vector < PackageSpec > specs ;
2017-03-30 09:30:32 +08:00
if ( options . find ( OPTION_OUTDATED ) ! = options . cend ( ) )
2017-04-01 16:09:34 +08:00
{
2017-03-30 09:30:32 +08:00
args . check_exact_arg_count ( 0 , example ) ;
specs = Util : : fmap ( Update : : find_outdated_packages ( paths , status_db ) , [ ] ( auto & & outdated ) { return outdated . spec ; } ) ;
}
else
{
args . check_min_arg_count ( 1 , example ) ;
2017-04-11 04:00:33 +08:00
specs = Util : : fmap ( args . command_arguments , [ & ] ( auto & & arg ) { return Input : : check_and_get_package_spec ( arg , default_triplet , example ) ; } ) ;
2017-03-30 09:30:32 +08:00
for ( auto & & spec : specs )
2017-04-11 04:03:34 +08:00
Input : : check_triplet ( spec . triplet ( ) , paths ) ;
2017-03-30 09:30:32 +08:00
}
2017-04-01 16:09:34 +08:00
2017-04-04 06:22:09 +08:00
const bool alsoRemoveFolderFromPackages = options . find ( OPTION_NO_PURGE ) = = options . end ( ) ;
if ( options . find ( OPTION_PURGE ) ! = options . end ( ) & & ! alsoRemoveFolderFromPackages )
{
// User specified --purge and --no-purge
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : error , " Error: cannot specify both --no-purge and --purge. " ) ;
2017-04-04 06:22:09 +08:00
System : : print ( example ) ;
Checks : : exit_fail ( VCPKG_LINE_INFO ) ;
}
2017-03-30 09:30:32 +08:00
const bool isRecursive = options . find ( OPTION_RECURSE ) ! = options . cend ( ) ;
const bool dryRun = options . find ( OPTION_DRY_RUN ) ! = options . cend ( ) ;
2016-09-19 11:50:08 +08:00
2017-04-04 07:24:44 +08:00
const std : : vector < PackageSpecWithRemovePlan > remove_plan = Dependencies : : create_remove_plan ( specs , status_db ) ;
2017-03-14 08:38:04 +08:00
Checks : : check_exit ( VCPKG_LINE_INFO , ! remove_plan . empty ( ) , " Remove plan cannot be empty " ) ;
2017-01-27 09:53:45 +08:00
2017-01-28 12:22:33 +08:00
print_plan ( remove_plan ) ;
2017-04-04 07:24:44 +08:00
const bool has_non_user_requested_packages = std : : find_if ( remove_plan . cbegin ( ) , remove_plan . cend ( ) , [ ] ( const PackageSpecWithRemovePlan & package ) - > bool
2017-01-28 12:22:33 +08:00
{
2017-04-04 07:21:46 +08:00
return package . plan . request_type ! = RequestType : : USER_REQUESTED ;
2017-01-28 12:22:33 +08:00
} ) ! = remove_plan . cend ( ) ;
2017-03-30 09:30:32 +08:00
if ( has_non_user_requested_packages )
2017-01-28 12:22:33 +08:00
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " Additional packages (*) need to be removed to complete this operation. " ) ;
2017-03-30 09:30:32 +08:00
if ( ! isRecursive )
{
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : warning , " If you are sure you want to remove them, run the command with the --recurse option " ) ;
2017-03-30 09:30:32 +08:00
Checks : : exit_fail ( VCPKG_LINE_INFO ) ;
}
}
if ( dryRun )
{
Checks : : exit_success ( VCPKG_LINE_INFO ) ;
2017-01-28 12:22:33 +08:00
}
2017-04-04 07:24:44 +08:00
for ( const PackageSpecWithRemovePlan & action : remove_plan )
2016-09-19 11:50:08 +08:00
{
2017-04-08 07:17:54 +08:00
const std : : string display_name = action . spec . to_string ( ) ;
2017-02-04 10:25:43 +08:00
switch ( action . plan . plan_type )
2016-09-19 11:50:08 +08:00
{
2017-04-04 07:23:46 +08:00
case RemovePlanType : : NOT_INSTALLED :
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : success , " Package %s is not installed " , display_name ) ;
2017-02-04 10:25:43 +08:00
break ;
2017-04-04 07:23:46 +08:00
case RemovePlanType : : REMOVE :
2017-02-04 10:25:43 +08:00
System : : println ( " Removing package %s... " , display_name ) ;
remove_package ( paths , action . spec , & status_db ) ;
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : success , " Removing package %s... done " , display_name ) ;
2017-02-04 10:25:43 +08:00
break ;
2017-04-04 07:23:46 +08:00
case RemovePlanType : : UNKNOWN :
2017-02-04 10:25:43 +08:00
default :
2017-03-14 07:59:21 +08:00
Checks : : unreachable ( VCPKG_LINE_INFO ) ;
2016-09-19 11:50:08 +08:00
}
2017-01-31 04:34:36 +08:00
2017-02-04 10:25:43 +08:00
if ( alsoRemoveFolderFromPackages )
{
System : : println ( " Purging package %s... " , display_name ) ;
delete_directory ( paths . packages / action . spec . dir ( ) ) ;
2017-04-04 07:31:00 +08:00
System : : println ( System : : Color : : success , " Purging package %s... done " , display_name ) ;
2017-01-31 04:34:36 +08:00
}
2016-09-19 11:50:08 +08:00
}
2017-01-31 04:34:36 +08:00
2017-03-23 08:45:39 +08:00
Checks : : exit_success ( VCPKG_LINE_INFO ) ;
2016-09-19 11:50:08 +08:00
}
}