Show total size before download and add option to check for free space

The downloader now shows total size to be downloaded
Added --check-free-space option to check if there is enough free space and abort if not enough is available
This commit is contained in:
Sude 2023-04-03 14:52:09 +03:00
parent 9cd85f69cb
commit 546982c717
5 changed files with 106 additions and 15 deletions

View File

@ -47,6 +47,7 @@ struct DownloadConfig
bool bSaveChangelogs; bool bSaveChangelogs;
bool bSaveSerials; bool bSaveSerials;
bool bAutomaticXMLCreation; bool bAutomaticXMLCreation;
bool bFreeSpaceCheck;
bool bInstallers; bool bInstallers;
bool bExtras; bool bExtras;

View File

@ -92,6 +92,7 @@ namespace Util
curl_off_t CurlWriteMemoryCallback(char *ptr, curl_off_t size, curl_off_t nmemb, void *userp); curl_off_t CurlWriteMemoryCallback(char *ptr, curl_off_t size, curl_off_t nmemb, void *userp);
curl_off_t CurlWriteChunkMemoryCallback(void *contents, curl_off_t size, curl_off_t nmemb, void *userp); curl_off_t CurlWriteChunkMemoryCallback(void *contents, curl_off_t size, curl_off_t nmemb, void *userp);
curl_off_t CurlReadChunkMemoryCallback(void *contents, curl_off_t size, curl_off_t nmemb, ChunkMemoryStruct *userp); curl_off_t CurlReadChunkMemoryCallback(void *contents, curl_off_t size, curl_off_t nmemb, ChunkMemoryStruct *userp);
std::string makeSizeString(const unsigned long long& iSizeInBytes);
template<typename ... Args> std::string formattedString(const std::string& format, Args ... args) template<typename ... Args> std::string formattedString(const std::string& format, Args ... args)
{ {

View File

@ -290,6 +290,7 @@ int main(int argc, char *argv[])
("include-hidden-products", bpo::value<bool>(&Globals::globalConfig.bIncludeHiddenProducts)->zero_tokens()->default_value(false), "Include games that have been set hidden in account page") ("include-hidden-products", bpo::value<bool>(&Globals::globalConfig.bIncludeHiddenProducts)->zero_tokens()->default_value(false), "Include games that have been set hidden in account page")
("size-only", bpo::value<bool>(&Globals::globalConfig.bSizeOnly)->zero_tokens()->default_value(false), "Don't check the hashes of the files whose size matches that on the server") ("size-only", bpo::value<bool>(&Globals::globalConfig.bSizeOnly)->zero_tokens()->default_value(false), "Don't check the hashes of the files whose size matches that on the server")
("verbosity", bpo::value<int>(&Globals::globalConfig.iMsgLevel)->default_value(0), "Set message verbosity level\n -1 = Less verbose\n 0 = Default\n 1 = Verbose\n 2 = Debug") ("verbosity", bpo::value<int>(&Globals::globalConfig.iMsgLevel)->default_value(0), "Set message verbosity level\n -1 = Less verbose\n 0 = Default\n 1 = Verbose\n 2 = Debug")
("check-free-space", bpo::value<bool>(&Globals::globalConfig.dlConf.bFreeSpaceCheck)->zero_tokens()->default_value(false), "Check for available free space before starting download")
; ;
options_cli_no_cfg_hidden.add_options() options_cli_no_cfg_hidden.add_options()

View File

@ -735,6 +735,30 @@ void Downloader::download()
if (!dlQueue.empty()) if (!dlQueue.empty())
{ {
unsigned long long totalSizeBytes = iTotalRemainingBytes.load();
std::cout << "Total size: " << Util::makeSizeString(totalSizeBytes) << std::endl;
if (Globals::globalConfig.dlConf.bFreeSpaceCheck)
{
boost::filesystem::path path = boost::filesystem::absolute(Globals::globalConfig.dirConf.sDirectory);
while(!boost::filesystem::exists(path) && !path.empty())
{
path = path.parent_path();
}
if(boost::filesystem::exists(path) && !path.empty())
{
boost::filesystem::space_info space = boost::filesystem::space(path);
if (space.available < totalSizeBytes)
{
std::cerr << "Not enough free space in " << boost::filesystem::canonical(path) << " ("
<< Util::makeSizeString(space.available) << ")"<< std::endl;
exit(1);
}
}
}
// Limit thread count to number of items in download queue // Limit thread count to number of items in download queue
unsigned int iThreads = std::min(Globals::globalConfig.iThreads, static_cast<unsigned int>(dlQueue.size())); unsigned int iThreads = std::min(Globals::globalConfig.iThreads, static_cast<unsigned int>(dlQueue.size()));
@ -3871,10 +3895,30 @@ void Downloader::galaxyInstallGameById(const std::string& product_id, int build_
dlQueueGalaxy.push(items[i]); dlQueueGalaxy.push(items[i]);
} }
double totalSizeMB = static_cast<double>(totalSize)/1024/1024;
std::cout << game_title << std::endl; std::cout << game_title << std::endl;
std::cout << "Files: " << items.size() << std::endl; std::cout << "Files: " << items.size() << std::endl;
std::cout << "Total size installed: " << totalSizeMB << " MB" << std::endl; std::cout << "Total size installed: " << Util::makeSizeString(totalSize) << std::endl;
if (Globals::globalConfig.dlConf.bFreeSpaceCheck)
{
boost::filesystem::path path = boost::filesystem::absolute(install_path);
while(!boost::filesystem::exists(path) && !path.empty())
{
path = path.parent_path();
}
if(boost::filesystem::exists(path) && !path.empty())
{
boost::filesystem::space_info space = boost::filesystem::space(path);
if (space.available < totalSize)
{
std::cerr << "Not enough free space in " << boost::filesystem::canonical(path) << " ("
<< Util::makeSizeString(space.available) << ")"<< std::endl;
exit(1);
}
}
}
// Limit thread count to number of items in download queue // Limit thread count to number of items in download queue
unsigned int iThreads = std::min(Globals::globalConfig.iThreads, static_cast<unsigned int>(dlQueueGalaxy.size())); unsigned int iThreads = std::min(Globals::globalConfig.iThreads, static_cast<unsigned int>(dlQueueGalaxy.size()));
@ -5166,19 +5210,6 @@ void Downloader::galaxyInstallGame_MojoSetupHack(const std::string& product_id)
} }
} }
// Create directories
for (std::uintmax_t i = 0; i < vZipDirectories.size(); ++i)
{
if (!boost::filesystem::exists(vZipDirectories[i].filepath))
{
if (!boost::filesystem::create_directories(vZipDirectories[i].filepath))
{
std::cerr << "Failed to create directory " << vZipDirectories[i].filepath << std::endl;
return;
}
}
}
// Set start and end offsets for split files // Set start and end offsets for split files
// Create map of split files for combining them later // Create map of split files for combining them later
splitFilesMap mSplitFiles; splitFilesMap mSplitFiles;
@ -5216,10 +5247,12 @@ void Downloader::galaxyInstallGame_MojoSetupHack(const std::string& product_id)
} }
// Add files to download queue // Add files to download queue
uintmax_t totalSize = 0;
for (std::uintmax_t i = 0; i < vZipFiles.size(); ++i) for (std::uintmax_t i = 0; i < vZipFiles.size(); ++i)
{ {
dlQueueGalaxy_MojoSetupHack.push(vZipFiles[i]); dlQueueGalaxy_MojoSetupHack.push(vZipFiles[i]);
iTotalRemainingBytes.fetch_add(vZipFiles[i].comp_size); iTotalRemainingBytes.fetch_add(vZipFiles[i].comp_size);
totalSize += vZipFiles[i].uncomp_size;
} }
// Add symlinks to download queue // Add symlinks to download queue
@ -5227,6 +5260,45 @@ void Downloader::galaxyInstallGame_MojoSetupHack(const std::string& product_id)
{ {
dlQueueGalaxy_MojoSetupHack.push(vZipFilesSymlink[i]); dlQueueGalaxy_MojoSetupHack.push(vZipFilesSymlink[i]);
iTotalRemainingBytes.fetch_add(vZipFilesSymlink[i].comp_size); iTotalRemainingBytes.fetch_add(vZipFilesSymlink[i].comp_size);
totalSize += vZipFilesSymlink[i].uncomp_size;
}
std::cout << game.title << std::endl;
std::cout << "Files: " << dlQueueGalaxy_MojoSetupHack.size() << std::endl;
std::cout << "Total size installed: " << Util::makeSizeString(totalSize) << std::endl;
if (Globals::globalConfig.dlConf.bFreeSpaceCheck)
{
boost::filesystem::path path = boost::filesystem::absolute(install_path);
while(!boost::filesystem::exists(path) && !path.empty())
{
path = path.parent_path();
}
if(boost::filesystem::exists(path) && !path.empty())
{
boost::filesystem::space_info space = boost::filesystem::space(path);
if (space.available < totalSize)
{
std::cerr << "Not enough free space in " << boost::filesystem::canonical(path) << " ("
<< Util::makeSizeString(space.available) << ")"<< std::endl;
exit(1);
}
}
}
// Create directories
for (std::uintmax_t i = 0; i < vZipDirectories.size(); ++i)
{
if (!boost::filesystem::exists(vZipDirectories[i].filepath))
{
if (!boost::filesystem::create_directories(vZipDirectories[i].filepath))
{
std::cerr << "Failed to create directory " << vZipDirectories[i].filepath << std::endl;
return;
}
}
} }
// Limit thread count to number of items in download queue // Limit thread count to number of items in download queue

View File

@ -893,3 +893,19 @@ curl_off_t Util::CurlReadChunkMemoryCallback(void *contents, curl_off_t size, cu
return realsize; return realsize;
} }
std::string Util::makeSizeString(const unsigned long long& iSizeInBytes)
{
auto units = { "B", "kB", "MB", "GB", "TB", "PB" };
std::string size_unit = "B";
double iSize = static_cast<double>(iSizeInBytes);
for (auto unit : units)
{
size_unit = unit;
if (iSize < 1024)
break;
iSize /= 1024;
}
return formattedString("%0.2f %s", iSize, size_unit.c_str());
}