2017-12-29 17:11:11 +01:00
# include "../include/installationmanager.hpp"
# include <unistd.h>
# include <sstream>
# include <deque>
2018-02-22 14:31:59 +01:00
# include <curl/curl.h>
# include <curl/easy.h>
# include <sys/stat.h> // fstat
# include <sys/types.h> // fstat
# include <cstdio>
# include <fstream>
2017-12-29 17:11:11 +01:00
# include "../include/exceptionhandler.hpp"
# include "../include/query.hpp"
2018-02-22 14:31:59 +01:00
# include "../include/paths.hpp"
# include "../include/csv.hpp"
2017-12-29 17:11:11 +01:00
# include "../include/rapidjson/istreamwrapper.h"
# include "../include/rapidjson/error/en.h"
# include "../include/rapidjson/filereadstream.h"
2018-02-22 14:31:59 +01:00
# include "../include/rapidjson/filewritestream.h"
# include "../include/rapidjson/ostreamwrapper.h"
# include "../include/rapidjson/writer.h"
2017-12-29 17:11:11 +01:00
InstallationManager : : InstallationManager ( const std : : string & hd , const std : : string & mod )
: _hd ( hd ) , _mod ( std : : move ( mod ) ) { }
void InstallationManager : : execute ( )
{
_version_query ( ) ;
/* --PACKPREINSTALLATION*/
/* TEMPORARY JSON */
const std : : string fp = _hd + " / " + _mod + " / " + _ver + " /modconfig.json " ;
_grab_json ( std : : move ( fp ) , _cfg ) ;
/* TEMPORARY JSON */
_campaign_query ( ) ;
std : : cout < < " \n " < < " You have selected: " < < " \n " ;
_print_selection ( 2 ) ;
2018-02-22 14:31:59 +01:00
/*
* PACKS SELECTION
*/
2017-12-29 17:11:11 +01:00
_pack_query ( ) ;
2018-02-22 14:31:59 +01:00
/*
* SELECTION SUMMARY
*/
2017-12-29 17:11:11 +01:00
_print_title ( " SELECTION SUMMARY " ) ;
2018-02-22 14:31:59 +01:00
/* Print campaign, turn, and pack selection */
2017-12-29 17:11:11 +01:00
_print_selection ( 3 ) ;
std : : cout < < " \n " ;
2018-02-22 14:31:59 +01:00
/* Final confirmation */
2017-12-29 17:11:11 +01:00
const Query < bool > query_final = { " Are you sure you want to install this selection? " } ;
if ( ! query_final . execute ( _cfg ) )
{
2018-02-22 14:31:59 +01:00
exit ( EXIT_SUCCESS ) ;
2017-12-29 17:11:11 +01:00
}
2018-02-22 14:31:59 +01:00
/*
* INSTALLATION
*/
2017-12-29 17:11:11 +01:00
std : : cout < < " Installing " < < _modname < < " version " < < _ver < < " ... \n " ;
2018-02-22 14:31:59 +01:00
_installall ( ) ;
std : : cout < < " Installation complete! \n " ;
2017-12-29 17:11:11 +01:00
}
void InstallationManager : : _version_query ( )
{
/* TEMPORARY JSON */
const std : : string fp = _hd + " / " + _mod + " /modinfo.json " ;
rapidjson : : Document modlist ;
_grab_json ( std : : move ( fp ) , modlist ) ;
/* TEMPORARY JSON */
/* Printing mod info */
std : : cout < < " Name: " < < modlist [ " name " ] . GetString ( ) < < " \n "
< < " Author: " < < modlist [ " author " ] . GetString ( ) < < " \n "
< < " Latest version: " < < modlist [ " versions " ] [ 0 ] . GetString ( ) < < " \n "
< < " Available versions: " ;
2018-02-22 14:31:59 +01:00
/* List available versions */
2017-12-29 17:11:11 +01:00
for ( rapidjson : : SizeType i = 0 ; i < modlist [ " versions " ] . Size ( ) ; i + + )
{
if ( i ! = 0 )
{
std : : cout < < " , " ;
}
std : : cout < < modlist [ " versions " ] [ i ] . GetString ( ) ;
}
std : : cout < < " \n " ;
2018-02-22 14:31:59 +01:00
/*
* PRE - INSTALLATION PROCESS
*/
2017-12-29 17:11:11 +01:00
2018-02-22 14:31:59 +01:00
/* VERSION */
/* Name and version confirmation */
2017-12-29 17:11:11 +01:00
const Query < bool > query_verify = { " Are you sure you want to install " + std : : string ( modlist [ " name " ] . GetString ( ) ) + " version " + modlist [ " versions " ] [ 0 ] . GetString ( ) + " ? " } ;
/* Asks user for mod version */
if ( query_verify . execute ( modlist ) )
{
2018-02-22 14:31:59 +01:00
/* Set mod name and version */
2017-12-29 17:11:11 +01:00
_modname = modlist [ " name " ] . GetString ( ) ;
_ver = modlist [ " versions " ] [ 0 ] . GetString ( ) ;
}
else
{
2018-02-22 14:31:59 +01:00
/* If more than 1 version, request for version */
2017-12-29 17:11:11 +01:00
if ( modlist [ " versions " ] . Size ( ) > 1 )
{
const Query < std : : string > query_version = { " Please specify the version you would like to install " , " versions " } ;
_ver = query_version . execute ( modlist ) ;
}
else
{
std : : cout < < " Exiting installation! " < < " \n " ;
2018-02-22 14:31:59 +01:00
exit ( EXIT_SUCCESS ) ;
2017-12-29 17:11:11 +01:00
}
}
}
void InstallationManager : : _campaign_query ( )
{
_print_title ( " CAMPAIGN SELECTION " ) ;
for ( rapidjson : : SizeType i = 0 ; i < _cfg [ " campaigns " ] . Size ( ) ; i + + )
{
std : : cout < < " [ " < < ( i + 1 ) < < " ] " < < _cfg [ " campaigns " ] [ i ] [ " name " ] . GetString ( ) < < " \n "
< < " Description: " < < _cfg [ " campaigns " ] [ i ] [ " desc " ] . GetString ( ) < < " \n " < < " \n " ;
}
/* CAMPAIGN SELECTION */
const Query < int > query_campaign = { " Please select your campaign " , " campaigns " } ;
_campaigns = query_campaign . execute ( _cfg ) - 1 ;
/* TURN SELECTION */
const Query < int > query_turns = { " Please select your preferred turns per year " , " turns " } ;
_turns = query_turns . execute ( _cfg ) - 1 ;
}
void InstallationManager : : _pack_query ( )
{
_print_title ( " PACK SELECTION " ) ;
const Query < bool > query_pack = { " Do you want to install this pack? " } ;
for ( rapidjson : : SizeType i = 0 ; i < _cfg [ " packs " ] . Size ( ) ; i + + )
{
std : : cout < < " \n " < < _cfg [ " packs " ] [ i ] [ " name " ] . GetString ( ) < < " \n "
< < _cfg [ " packs " ] [ i ] [ " desc " ] . GetString ( ) < < " \n " ;
_packs . push_back ( query_pack . execute ( _cfg ) ) ;
std : : cin . clear ( ) ;
}
}
void InstallationManager : : _grab_json ( const std : : string & path , rapidjson : : Document & d )
{
if ( ( access ( path . c_str ( ) , F_OK ) ! = 0 ) )
{
throw ExceptionHandler ( INVALID_ARGUMENT_ERROR ) ;
}
/*
std : : ifstream ifs ( path . c_str ( ) ) ;
rapidjson : : IStreamWrapper isw ( ifs ) ;
d . ParseStream ( isw ) ;
if ( d . ParseStream < 0 > ( isw ) . HasParseError ( ) )
{
std : : cerr < < " Failed to parse via string stream! " < < " \n " ;
std : : cerr < < " RapidJson ERROR: " ;
std : : cerr < < GetParseError_En ( d . GetParseError ( ) ) < < " \n " ;
std : : cerr < < " Filepath: " < < path < < " \n " ;
throw ExceptionHandler ( CUSTOM_ERROR , " Failed to parse JSON file! " ) ;
}
else
{
d . ParseStream ( isw ) ;
return 0 ;
}
if ( d . Parse < 0 > ( path . c_str ( ) ) . HasParseError ( ) )
{
std : : cerr < < " Failed to parse via string! " < < " \n " ;
std : : cerr < < " RapidJson ERROR: " ;
std : : cerr < < GetParseError_En ( d . GetParseError ( ) ) < < " \n " ;
std : : cerr < < " Filepath: " < < path < < " \n " ;
throw ExceptionHandler ( CUSTOM_ERROR , " Failed to parse JSON file! " ) ;
}
{
d . Parse ( path . c_str ( ) ) ;
return 0 ;
}
*/
char readBuffer [ 65536 ] ;
FILE * fp = fopen ( path . c_str ( ) , " r " ) ;
rapidjson : : FileReadStream is ( fp , readBuffer , sizeof ( readBuffer ) ) ;
if ( d . ParseStream < 0 > ( is ) . HasParseError ( ) )
{
std : : cerr < < " Failed to parse via file stream! " < < " \n " ;
std : : cerr < < " RapidJson ERROR: " ;
std : : cerr < < GetParseError_En ( d . GetParseError ( ) ) < < " \n " ;
std : : cerr < < " Filepath: " < < path < < " \n " ;
throw ExceptionHandler ( CUSTOM_ERROR , " Failed to parse JSON file! " ) ;
}
else
{
d . ParseStream ( is ) ;
}
}
void InstallationManager : : _print_title ( const std : : string & str )
{
std : : cout < < str < < " \n " ;
for ( auto i : str )
{
std : : cout < < " = " ;
}
std : : cout < < " \n " ;
}
void InstallationManager : : _print_selection ( const int i )
{
std : : deque < std : : string > print ;
switch ( i )
{
case 3 :
{
std : : stringstream ss ;
std : : vector < std : : string > packs ;
for ( rapidjson : : SizeType i = 0 ; i < _cfg [ " packs " ] . Size ( ) ; i + + )
{
if ( _packs [ i ] )
{
packs . push_back ( _cfg [ " packs " ] [ i ] [ " name " ] . GetString ( ) ) ;
}
}
ss < < " Packs: " ;
for ( auto it = packs . begin ( ) ; it ! = packs . end ( ) ; + + it )
{
ss < < * it ;
if ( it ! = ( packs . end ( ) - 1 ) )
{
ss < < " , " ;
}
}
ss < < " \n " ;
print . push_front ( ss . str ( ) ) ;
}
case 2 :
{
print . push_front ( " Turns: " + std : : string ( _cfg [ " turns " ] [ _turns ] [ " name " ] . GetString ( ) ) + " \n " ) ;
}
case 1 :
{
print . push_front ( " Campaign: " + std : : string ( _cfg [ " campaigns " ] [ _campaigns ] [ " name " ] . GetString ( ) ) + " \n " ) ;
}
}
for ( auto & i : print ) std : : cout < < i ;
}
2018-02-22 14:31:59 +01:00
size_t write_data ( void * ptr , size_t size , size_t nmemb , FILE * stream ) {
size_t written = fwrite ( ptr , size , nmemb , stream ) ;
return written ;
}
void InstallationManager : : _download ( const std : : string & tmp , const std : : string & dwn )
{
CURL * curl ;
FILE * fp ;
CURLcode res ;
curl = curl_easy_init ( ) ;
if ( curl )
{
fp = fopen ( tmp . c_str ( ) , " wb " ) ;
curl_easy_setopt ( curl , CURLOPT_URL , dwn . c_str ( ) ) ;
curl_easy_setopt ( curl , CURLOPT_WRITEFUNCTION , write_data ) ;
curl_easy_setopt ( curl , CURLOPT_WRITEDATA , fp ) ;
res = curl_easy_perform ( curl ) ;
/* always cleanup */
curl_easy_cleanup ( curl ) ;
fclose ( fp ) ;
}
else
{
throw ExceptionHandler ( CUSTOM_ERROR , " Failed to download " + dwn ) ;
}
}
/*
* Downloads from a url : MOD + file
* To a temporary location : TMP + path + file
* To be moved to path + file
*/
void InstallationManager : : _install ( const std : : string & file , const std : : string & path , const std : : string & fp )
{
/* Constant strings */
static const std : : string PREFIX = " https://gitlab.com/tw-lmm/etw/ " ;
static const std : : string BINDER = " /raw/master/ " ;
static const std : : string MOD = PREFIX + _mod + BINDER + _ver + " / " ;
static const std : : string TMP = " /tmp/etw_lmm/ " ;
const std : : string temp = TMP + file ;
const std : : string download = MOD + path + file ;
std : : cout < < " temp: " < < temp < < " \n "
< < " download: " < < download < < " \n "
< < " fp: " < < fp < < " \n " ;
/* Checks if directory /tmp/etw_lmm/ exists */
struct stat tmp ;
if ( stat ( TMP . c_str ( ) , & tmp ) ! = 0 )
{
mkdir ( TMP . c_str ( ) , 0700 ) ;
}
_download ( temp , download ) ;
if ( access ( fp . c_str ( ) , F_OK ) < 0 )
{
if ( std : : remove ( fp . c_str ( ) ) )
{
throw ExceptionHandler ( CUSTOM_ERROR , " Cannot remove file " + fp + " ! " ) ;
}
}
if ( rename ( temp . c_str ( ) , fp . c_str ( ) ) < 0 )
{
throw ExceptionHandler ( CUSTOM_ERROR , " Cannot move file " + file + " ! " ) ;
}
if ( std : : remove ( temp . c_str ( ) ) < 0 )
{
throw ExceptionHandler ( CUSTOM_ERROR , " Cannot remove file " + temp + " ! " ) ;
}
}
void InstallationManager : : _installall ( )
{
/* Install manifest */
std : : vector < std : : string > installed ;
/*
* CAMPAIGN - DEPENDENCIES
*/
std : : cout < < " Installing campaign dependencies... \n " ;
for ( rapidjson : : SizeType i = 0 ; _cfg [ " campaign_default " ] . Size ( ) ; i + + )
{
const std : : string fp = _hd + STEAM_PREFIX + std : : string ( _cfg [ " campaign_default " ] [ i ] [ " path " ] . GetString ( ) ) + std : : string ( _cfg [ " campaign_default " ] [ i ] [ " file " ] . GetString ( ) ) ;
std : : cout < < " Downloading " < < std : : string ( _cfg [ " campaign_default " ] [ i ] [ " file " ] . GetString ( ) ) < < " \n " ;
_install ( std : : string ( _cfg [ " campaign_default " ] [ i ] [ " file " ] . GetString ( ) ) ,
std : : string ( _cfg [ " campaigns " ] [ _campaigns ] [ " id " ] . GetString ( ) ) + " /default/ " ,
fp ) ;
installed . push_back ( std : : move ( fp ) ) ;
}
/*
* CAMPAIGN - TURNS
*/
std : : cout < < " Installing campaign preferences... \n " ;
const std : : string LUA = " scripting.lua " ;
const std : : string ESF = " startpos.esf " ;
// const std::string CAMPAIGN = std::string(_cfg["campaigns"][_campaigns]["id"].GetString()) + "/" + std::to_string((_turns+1)*2) + "_turns/main/";
const std : : string fp_lua = _hd + STEAM_PREFIX + MAIN_CAMPAIGN + " / " + LUA ;
const std : : string fp_esf = _hd + STEAM_PREFIX + MAIN_CAMPAIGN + " / " + ESF ;
_install ( LUA ,
std : : string ( _cfg [ " campaigns " ] [ _campaigns ] [ " id " ] . GetString ( ) ) + " / " + std : : string ( _cfg [ " turns " ] [ _turns ] [ " id " ] . GetString ( ) ) + " /main/ " ,
fp_lua ) ;
installed . push_back ( std : : move ( fp_lua ) ) ;
_install ( ESF ,
std : : string ( _cfg [ " campaigns " ] [ _campaigns ] [ " id " ] . GetString ( ) ) + " / " + std : : string ( _cfg [ " turns " ] [ _turns ] [ " id " ] . GetString ( ) ) + " /main/ " ,
fp_esf ) ;
installed . push_back ( std : : move ( fp_esf ) ) ;
/*
* DATA PACKS
*/
std : : cout < < " Installing packs... \n " ;
for ( auto b : _packs )
{
rapidjson : : SizeType i = 0 ;
if ( b )
{
if ( _cfg [ " packs " ] [ i ] [ " files " ] . Size ( ) > 1 )
{
for ( rapidjson : : SizeType j = 0 ; j < _cfg [ " packs " ] [ i ] [ " files " ] . Size ( ) ; j + + )
{
const std : : string fp = _hd + STEAM_PREFIX + " data/ " + std : : string ( _cfg [ " packs " ] [ i ] [ " files " ] [ j ] . GetString ( ) ) ;
_install ( std : : string ( _cfg [ " packs " ] [ i ] [ " files " ] [ j ] . GetString ( ) ) ,
" data/ " ,
fp ) ;
installed . push_back ( std : : move ( fp ) ) ;
}
}
else
{
const std : : string fp = _hd + STEAM_PREFIX + " data/ " + std : : string ( _cfg [ " packs " ] [ i ] [ " files " ] [ 0 ] . GetString ( ) ) ;
_install ( std : : string ( _cfg [ " packs " ] [ i ] [ " files " ] [ 0 ] . GetString ( ) ) ,
" data/ " ,
fp ) ;
installed . push_back ( std : : move ( fp ) ) ;
}
}
i + + ;
}
/* Logging installed files into installed.json */
/*rapidjson::Document json;
json . Parse ( _hd + INSTALLED . GetPath ( ) ) ;
rapidjson : : Value json_paths ( kArrayType ) ;
rapidjson : : Document : : AllocatorType & allocator = json . GetAllocator ( ) ;
for ( auto & i : installed )
{
json_paths . PushBack ( i , allocator ) ;
}
std : : ofstream ofs ( _hd + INSTALLED . GetPath ( ) ) ;
rapidjson : : OStreamWrapper osw ( ofs ) ;
rapidjson : : Writer < OStreamWrapper > writer ( osw ) ;
json . Accept ( writer ) ; */
const std : : string fp = _hd + INSTALLED . GetPath ( ) ;
CSV csv ( std : : move ( fp ) ) ;
csv . Write ( ) ;
csv . Update ( ) ;
}