2018-03-28 09:36:36 +00:00
# include "PresetUpdater.hpp"
2018-04-12 18:04:48 +00:00
# include <algorithm>
2018-03-28 09:36:36 +00:00
# include <thread>
2018-04-24 16:06:42 +00:00
# include <unordered_map>
2018-04-23 09:16:47 +00:00
# include <ostream>
2018-04-13 13:08:58 +00:00
# include <stdexcept>
# include <boost/format.hpp>
2018-03-28 09:36:36 +00:00
# include <boost/algorithm/string.hpp>
2018-04-11 11:12:08 +00:00
# include <boost/filesystem.hpp>
2018-03-28 09:36:36 +00:00
# include <boost/filesystem/fstream.hpp>
2018-12-20 16:44:24 +00:00
# include <boost/lexical_cast.hpp>
2018-04-17 09:54:59 +00:00
# include <boost/log/trivial.hpp>
2018-03-28 09:36:36 +00:00
# include <wx/app.h>
2018-04-12 18:04:48 +00:00
# include <wx/msgdlg.h>
2018-04-17 14:59:53 +00:00
# include "libslic3r/libslic3r.h"
2018-03-28 09:36:36 +00:00
# include "libslic3r/Utils.hpp"
# include "slic3r/GUI/GUI.hpp"
2018-11-26 13:41:58 +00:00
# include "slic3r/GUI/I18N.hpp"
2018-03-28 09:36:36 +00:00
# include "slic3r/GUI/PresetBundle.hpp"
2018-04-24 16:06:42 +00:00
# include "slic3r/GUI/UpdateDialogs.hpp"
# include "slic3r/GUI/ConfigWizard.hpp"
2018-11-26 13:41:58 +00:00
# include "slic3r/GUI/GUI_App.hpp"
2018-03-28 09:36:36 +00:00
# include "slic3r/Utils/Http.hpp"
2018-04-12 18:04:48 +00:00
# include "slic3r/Config/Version.hpp"
# include "slic3r/Config/Snapshot.hpp"
2018-03-28 09:36:36 +00:00
namespace fs = boost : : filesystem ;
2018-04-12 18:04:48 +00:00
using Slic3r : : GUI : : Config : : Index ;
using Slic3r : : GUI : : Config : : Version ;
using Slic3r : : GUI : : Config : : Snapshot ;
using Slic3r : : GUI : : Config : : SnapshotDB ;
2018-03-28 09:36:36 +00:00
namespace Slic3r {
enum {
SLIC3R_VERSION_BODY_MAX = 256 ,
} ;
2018-04-13 13:08:58 +00:00
static const char * INDEX_FILENAME = " index.idx " ;
static const char * TMP_EXTENSION = " .download " ;
2018-04-12 18:04:48 +00:00
2018-04-24 16:06:42 +00:00
struct Update
2018-04-17 14:59:53 +00:00
{
2018-04-24 16:06:42 +00:00
fs : : path source ;
fs : : path target ;
Version version ;
2019-05-13 16:38:48 +00:00
std : : string vendor ;
std : : string changelog_url ;
Update ( fs : : path & & source , fs : : path & & target , const Version & version , std : : string vendor , std : : string changelog_url )
: source ( std : : move ( source ) )
, target ( std : : move ( target ) )
, version ( version )
, vendor ( std : : move ( vendor ) )
, changelog_url ( std : : move ( changelog_url ) )
2018-04-24 16:06:42 +00:00
{ }
2018-04-17 14:59:53 +00:00
2018-04-24 16:06:42 +00:00
friend std : : ostream & operator < < ( std : : ostream & os , const Update & self ) {
os < < " Update( " < < self . source . string ( ) < < " -> " < < self . target . string ( ) < < ' ) ' ;
return os ;
2018-04-17 14:59:53 +00:00
}
} ;
2018-04-24 16:06:42 +00:00
struct Incompat
2018-04-12 18:04:48 +00:00
{
2018-04-24 16:06:42 +00:00
fs : : path bundle ;
2018-04-12 18:04:48 +00:00
Version version ;
2019-05-13 16:38:48 +00:00
std : : string vendor ;
2018-04-12 18:04:48 +00:00
2019-05-13 16:38:48 +00:00
Incompat ( fs : : path & & bundle , const Version & version , std : : string vendor )
: bundle ( std : : move ( bundle ) )
, version ( version )
, vendor ( std : : move ( vendor ) )
2018-04-12 18:04:48 +00:00
{ }
2018-04-24 16:06:42 +00:00
friend std : : ostream & operator < < ( std : : ostream & os , const Incompat & self ) {
os < < " Incompat( " < < self . bundle . string ( ) < < ' ) ' ;
2018-04-23 09:16:47 +00:00
return os ;
}
2018-04-12 18:04:48 +00:00
} ;
2018-04-24 16:06:42 +00:00
struct Updates
{
std : : vector < Incompat > incompats ;
std : : vector < Update > updates ;
} ;
2018-04-12 18:04:48 +00:00
2019-02-14 14:28:18 +00:00
static Semver get_slic3r_version ( )
{
auto res = Semver : : parse ( SLIC3R_VERSION ) ;
if ( ! res ) {
const char * error = " Could not parse Slic3r version string: " SLIC3R_VERSION ;
BOOST_LOG_TRIVIAL ( error ) < < error ;
throw std : : runtime_error ( error ) ;
}
return * res ;
}
2019-02-14 15:51:41 +00:00
wxDEFINE_EVENT ( EVT_SLIC3R_VERSION_ONLINE , wxCommandEvent ) ;
2018-04-12 18:04:48 +00:00
2018-03-28 09:36:36 +00:00
struct PresetUpdater : : priv
{
2019-02-14 14:28:18 +00:00
const Semver ver_slic3r ;
2018-04-13 13:08:58 +00:00
std : : vector < Index > index_db ;
bool enabled_version_check ;
bool enabled_config_update ;
std : : string version_check_url ;
2018-04-17 15:11:56 +00:00
bool had_config_update ;
2018-03-28 09:36:36 +00:00
fs : : path cache_path ;
2018-04-12 18:04:48 +00:00
fs : : path rsrc_path ;
fs : : path vendor_path ;
2018-03-28 09:36:36 +00:00
bool cancel ;
std : : thread thread ;
2018-09-20 23:33:41 +00:00
priv ( ) ;
2018-03-28 09:36:36 +00:00
2018-04-13 13:08:58 +00:00
void set_download_prefs ( AppConfig * app_config ) ;
bool get_file ( const std : : string & url , const fs : : path & target_path ) const ;
void prune_tmps ( ) const ;
void sync_version ( ) const ;
2018-12-20 16:44:24 +00:00
void sync_config ( const std : : set < VendorProfile > vendors ) ;
2018-04-12 18:04:48 +00:00
void check_install_indices ( ) const ;
2018-04-23 11:58:03 +00:00
Updates get_config_updates ( ) const ;
2018-04-18 09:40:43 +00:00
void perform_updates ( Updates & & updates , bool snapshot = true ) const ;
2018-06-11 15:34:06 +00:00
static void copy_file ( const fs : : path & from , const fs : : path & to ) ;
2018-03-28 09:36:36 +00:00
} ;
2019-02-14 14:28:18 +00:00
PresetUpdater : : priv : : priv ( )
: ver_slic3r ( get_slic3r_version ( ) )
, had_config_update ( false )
, cache_path ( fs : : path ( Slic3r : : data_dir ( ) ) / " cache " )
, rsrc_path ( fs : : path ( resources_dir ( ) ) / " profiles " )
, vendor_path ( fs : : path ( Slic3r : : data_dir ( ) ) / " vendor " )
, cancel ( false )
2018-04-13 13:08:58 +00:00
{
2018-09-20 23:33:41 +00:00
set_download_prefs ( GUI : : wxGetApp ( ) . app_config ) ;
2018-04-13 13:08:58 +00:00
check_install_indices ( ) ;
2018-12-20 16:44:24 +00:00
index_db = Index : : load_db ( ) ;
2018-04-13 13:08:58 +00:00
}
2018-04-23 09:16:47 +00:00
// Pull relevant preferences from AppConfig
2018-04-13 13:08:58 +00:00
void PresetUpdater : : priv : : set_download_prefs ( AppConfig * app_config )
{
enabled_version_check = app_config - > get ( " version_check " ) = = " 1 " ;
2018-04-25 15:43:01 +00:00
version_check_url = app_config - > version_check_url ( ) ;
2018-05-15 10:14:26 +00:00
enabled_config_update = app_config - > get ( " preset_update " ) = = " 1 " & & ! app_config - > legacy_datadir ( ) ;
2018-04-13 13:08:58 +00:00
}
2018-03-28 09:36:36 +00:00
2018-04-23 09:16:47 +00:00
// Downloads a file (http get operation). Cancels if the Updater is being destroyed.
2018-04-13 13:08:58 +00:00
bool PresetUpdater : : priv : : get_file ( const std : : string & url , const fs : : path & target_path ) const
2018-03-28 09:36:36 +00:00
{
2018-04-13 13:08:58 +00:00
bool res = false ;
fs : : path tmp_path = target_path ;
2018-04-20 09:05:00 +00:00
tmp_path + = ( boost : : format ( " .%1%%2% " ) % get_current_pid ( ) % TMP_EXTENSION ) . str ( ) ;
2018-04-23 09:16:47 +00:00
BOOST_LOG_TRIVIAL ( info ) < < boost : : format ( " Get: `%1%` \n \t -> `%2%` \n \t via tmp path `%3%` " )
% url
% target_path . string ( )
% tmp_path . string ( ) ;
2018-04-13 13:08:58 +00:00
Http : : get ( url )
. on_progress ( [ this ] ( Http : : Progress , bool & cancel ) {
if ( cancel ) { cancel = true ; }
} )
2018-04-23 09:16:47 +00:00
. on_error ( [ & ] ( std : : string body , std : : string error , unsigned http_status ) {
( void ) body ;
BOOST_LOG_TRIVIAL ( error ) < < boost : : format ( " Error getting: `%1%`: HTTP %2%, %3% " )
% url
% http_status
2018-04-24 16:06:42 +00:00
% error ;
2018-04-23 09:16:47 +00:00
} )
2018-06-06 08:52:19 +00:00
. on_complete ( [ & ] ( std : : string body , unsigned /* http_status */ ) {
2018-04-13 13:08:58 +00:00
fs : : fstream file ( tmp_path , std : : ios : : out | std : : ios : : binary | std : : ios : : trunc ) ;
file . write ( body . c_str ( ) , body . size ( ) ) ;
2018-04-16 14:52:11 +00:00
file . close ( ) ;
2018-04-13 13:08:58 +00:00
fs : : rename ( tmp_path , target_path ) ;
res = true ;
} )
. perform_sync ( ) ;
return res ;
}
2018-04-23 09:16:47 +00:00
// Remove leftover paritally downloaded files, if any.
2018-04-13 13:08:58 +00:00
void PresetUpdater : : priv : : prune_tmps ( ) const
{
2019-02-03 14:30:37 +00:00
for ( auto & dir_entry : boost : : filesystem : : directory_iterator ( cache_path ) )
if ( is_plain_file ( dir_entry ) & & dir_entry . path ( ) . extension ( ) = = TMP_EXTENSION ) {
BOOST_LOG_TRIVIAL ( debug ) < < " Cache prune: " < < dir_entry . path ( ) . string ( ) ;
fs : : remove ( dir_entry . path ( ) ) ;
2018-04-13 13:08:58 +00:00
}
}
2018-04-23 09:16:47 +00:00
// Get Slic3rPE version available online, save in AppConfig.
2018-04-13 13:08:58 +00:00
void PresetUpdater : : priv : : sync_version ( ) const
{
if ( ! enabled_version_check ) { return ; }
2019-04-15 14:14:19 +00:00
BOOST_LOG_TRIVIAL ( info ) < < boost : : format ( " Downloading %1% online version from: `%2%` " ) % SLIC3R_APP_NAME % version_check_url ;
2018-04-23 09:16:47 +00:00
2018-04-13 13:08:58 +00:00
Http : : get ( version_check_url )
2018-03-28 09:36:36 +00:00
. size_limit ( SLIC3R_VERSION_BODY_MAX )
. on_progress ( [ this ] ( Http : : Progress , bool & cancel ) {
cancel = this - > cancel ;
} )
2018-04-23 09:16:47 +00:00
. on_error ( [ & ] ( std : : string body , std : : string error , unsigned http_status ) {
( void ) body ;
BOOST_LOG_TRIVIAL ( error ) < < boost : : format ( " Error getting: `%1%`: HTTP %2%, %3% " )
% version_check_url
% http_status
2018-04-24 16:06:42 +00:00
% error ;
2018-04-23 09:16:47 +00:00
} )
2018-06-06 08:52:19 +00:00
. on_complete ( [ & ] ( std : : string body , unsigned /* http_status */ ) {
2018-03-28 09:36:36 +00:00
boost : : trim ( body ) ;
2019-04-15 14:14:19 +00:00
BOOST_LOG_TRIVIAL ( info ) < < boost : : format ( " Got %1% online version: `%2%`. Sending to GUI thread... " ) % SLIC3R_APP_NAME % body ;
2019-02-14 14:28:18 +00:00
2019-02-14 15:51:41 +00:00
wxCommandEvent * evt = new wxCommandEvent ( EVT_SLIC3R_VERSION_ONLINE ) ;
evt - > SetString ( GUI : : from_u8 ( body ) ) ;
GUI : : wxGetApp ( ) . QueueEvent ( evt ) ;
2018-03-28 09:36:36 +00:00
} )
. perform_sync ( ) ;
2018-04-13 13:08:58 +00:00
}
2018-03-28 09:36:36 +00:00
2018-04-23 09:16:47 +00:00
// Download vendor indices. Also download new bundles if an index indicates there's a new one available.
// Both are saved in cache.
2018-12-20 16:44:24 +00:00
void PresetUpdater : : priv : : sync_config ( const std : : set < VendorProfile > vendors )
2018-04-13 13:08:58 +00:00
{
2018-04-23 09:16:47 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " Syncing configuration cache " ;
2018-04-13 13:08:58 +00:00
if ( ! enabled_config_update ) { return ; }
2018-03-28 09:36:36 +00:00
// Donwload vendor preset bundles
2018-12-20 16:44:24 +00:00
for ( auto & index : index_db ) {
2018-03-28 09:36:36 +00:00
if ( cancel ) { return ; }
2018-04-13 13:08:58 +00:00
const auto vendor_it = vendors . find ( VendorProfile ( index . vendor ( ) ) ) ;
2018-04-23 09:16:47 +00:00
if ( vendor_it = = vendors . end ( ) ) {
BOOST_LOG_TRIVIAL ( warning ) < < " No such vendor: " < < index . vendor ( ) ;
continue ;
}
2018-04-13 13:08:58 +00:00
const VendorProfile & vendor = * vendor_it ;
2018-04-23 09:16:47 +00:00
if ( vendor . config_update_url . empty ( ) ) {
BOOST_LOG_TRIVIAL ( info ) < < " Vendor has no config_update_url: " < < vendor . name ;
continue ;
}
2018-04-13 13:08:58 +00:00
// Download a fresh index
2018-04-23 09:16:47 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " Downloading index for vendor: " < < vendor . name ;
2018-04-13 13:08:58 +00:00
const auto idx_url = vendor . config_update_url + " / " + INDEX_FILENAME ;
2018-12-20 16:44:24 +00:00
const std : : string idx_path = ( cache_path / ( vendor . id + " .idx " ) ) . string ( ) ;
const std : : string idx_path_temp = idx_path + " -update " ;
if ( ! get_file ( idx_url , idx_path_temp ) ) { continue ; }
2018-04-13 13:08:58 +00:00
if ( cancel ) { return ; }
// Load the fresh index up
2018-12-20 16:44:24 +00:00
{
Index new_index ;
try {
new_index . load ( idx_path_temp ) ;
2018-12-22 09:02:42 +00:00
} catch ( const std : : exception & /* err */ ) {
2018-12-20 16:44:24 +00:00
BOOST_LOG_TRIVIAL ( error ) < < boost : : format ( " Failed loading a downloaded index %1% for vendor %2%: invalid index? " ) % idx_path_temp % vendor . name ;
continue ;
}
if ( new_index . version ( ) < index . version ( ) ) {
2019-02-14 14:28:18 +00:00
BOOST_LOG_TRIVIAL ( warning ) < < boost : : format ( " The downloaded index %1% for vendor %2% is older than the active one. Ignoring the downloaded index. " ) % idx_path_temp % vendor . name ;
2018-12-20 16:44:24 +00:00
continue ;
}
Slic3r : : rename_file ( idx_path_temp , idx_path ) ;
index = std : : move ( new_index ) ;
if ( cancel )
return ;
}
2018-03-28 09:36:36 +00:00
2018-04-13 13:08:58 +00:00
// See if a there's a new version to download
2018-12-20 16:44:24 +00:00
const auto recommended_it = index . recommended ( ) ;
if ( recommended_it = = index . end ( ) ) {
2018-05-01 08:35:07 +00:00
BOOST_LOG_TRIVIAL ( error ) < < boost : : format ( " No recommended version for vendor: %1%, invalid index? " ) % vendor . name ;
2018-04-23 09:16:47 +00:00
continue ;
}
2019-02-14 14:28:18 +00:00
2018-04-13 13:08:58 +00:00
const auto recommended = recommended_it - > config_version ;
2018-03-28 09:36:36 +00:00
2018-06-19 16:26:38 +00:00
BOOST_LOG_TRIVIAL ( debug ) < < boost : : format ( " Got index for vendor: %1%: current version: %2%, recommended version: %3% " )
2018-04-23 09:16:47 +00:00
% vendor . name
% vendor . config_version . to_string ( )
% recommended . to_string ( ) ;
2018-04-13 13:08:58 +00:00
if ( vendor . config_version > = recommended ) { continue ; }
// Download a fresh bundle
2018-04-23 09:16:47 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " Downloading new bundle for vendor: " < < vendor . name ;
2018-04-13 13:08:58 +00:00
const auto bundle_url = ( boost : : format ( " %1%/%2%.ini " ) % vendor . config_update_url % recommended . to_string ( ) ) . str ( ) ;
const auto bundle_path = cache_path / ( vendor . id + " .ini " ) ;
if ( ! get_file ( bundle_url , bundle_path ) ) { continue ; }
if ( cancel ) { return ; }
2018-03-28 09:36:36 +00:00
}
}
2018-04-23 09:16:47 +00:00
// Install indicies from resources. Only installs those that are either missing or older than in resources.
2018-04-12 18:04:48 +00:00
void PresetUpdater : : priv : : check_install_indices ( ) const
{
2018-04-23 09:16:47 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " Checking if indices need to be installed from resources... " ;
2019-02-03 14:30:37 +00:00
for ( auto & dir_entry : boost : : filesystem : : directory_iterator ( rsrc_path ) )
if ( is_idx_file ( dir_entry ) ) {
const auto & path = dir_entry . path ( ) ;
2018-04-12 18:04:48 +00:00
const auto path_in_cache = cache_path / path . filename ( ) ;
if ( ! fs : : exists ( path_in_cache ) ) {
2018-04-23 09:16:47 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " Install index from resources: " < < path . filename ( ) ;
2018-06-11 15:34:06 +00:00
copy_file ( path , path_in_cache ) ;
2018-04-17 08:28:32 +00:00
} else {
Index idx_rsrc , idx_cache ;
idx_rsrc . load ( path ) ;
idx_cache . load ( path_in_cache ) ;
if ( idx_cache . version ( ) < idx_rsrc . version ( ) ) {
2018-04-23 09:16:47 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " Update index from resources: " < < path . filename ( ) ;
2018-06-11 15:34:06 +00:00
copy_file ( path , path_in_cache ) ;
2018-04-17 08:28:32 +00:00
}
2018-04-12 18:04:48 +00:00
}
}
}
2018-04-23 09:16:47 +00:00
// Generates a list of bundle updates that are to be performed
2018-04-23 11:58:03 +00:00
Updates PresetUpdater : : priv : : get_config_updates ( ) const
2018-04-12 18:04:48 +00:00
{
Updates updates ;
2018-04-23 11:58:03 +00:00
2018-04-23 09:16:47 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " Checking for cached configuration updates... " ;
2018-04-12 18:04:48 +00:00
for ( const auto idx : index_db ) {
2018-04-24 16:06:42 +00:00
auto bundle_path = vendor_path / ( idx . vendor ( ) + " .ini " ) ;
2018-04-12 18:04:48 +00:00
if ( ! fs : : exists ( bundle_path ) ) {
2018-04-23 09:16:47 +00:00
BOOST_LOG_TRIVIAL ( info ) < < " Bundle not present for index, skipping: " < < idx . vendor ( ) ;
2018-04-12 18:04:48 +00:00
continue ;
}
// Perform a basic load and check the version
2019-05-13 16:38:48 +00:00
auto vp = VendorProfile : : from_ini ( bundle_path , false ) ;
2018-04-12 18:04:48 +00:00
2018-07-21 07:32:45 +00:00
// Getting a recommended version from the latest index, wich may have been downloaded
// from the internet, or installed / updated from the installation resources.
2018-04-12 18:04:48 +00:00
const auto recommended = idx . recommended ( ) ;
if ( recommended = = idx . end ( ) ) {
2018-05-01 08:35:07 +00:00
BOOST_LOG_TRIVIAL ( error ) < < boost : : format ( " No recommended version for vendor: %1%, invalid index? " ) % idx . vendor ( ) ;
2018-04-12 18:04:48 +00:00
}
2019-02-22 10:36:58 +00:00
const auto ver_current = idx . find ( vp . config_version ) ;
const bool ver_current_found = ver_current ! = idx . end ( ) ;
if ( ! ver_current_found ) {
auto message = ( boost : : format ( " Preset bundle `%1%` version not found in index: %2% " ) % idx . vendor ( ) % vp . config_version . to_string ( ) ) . str ( ) ;
BOOST_LOG_TRIVIAL ( error ) < < message ;
GUI : : show_error ( nullptr , GUI : : from_u8 ( message ) ) ;
}
BOOST_LOG_TRIVIAL ( debug ) < < boost : : format ( " Vendor: %1%, version installed: %2%%3%, version cached: %4% " )
2018-04-23 09:16:47 +00:00
% vp . name
2019-02-22 10:36:58 +00:00
% vp . config_version . to_string ( )
% ( ver_current_found ? " " : " (not found in index!) " )
2018-04-24 16:06:42 +00:00
% recommended - > config_version . to_string ( ) ;
2018-04-23 09:16:47 +00:00
2019-02-22 10:36:58 +00:00
if ( ver_current_found & & ! ver_current - > is_current_slic3r_supported ( ) ) {
2018-04-23 09:16:47 +00:00
BOOST_LOG_TRIVIAL ( warning ) < < " Current Slic3r incompatible with installed bundle: " < < bundle_path . string ( ) ;
2019-05-13 16:38:48 +00:00
updates . incompats . emplace_back ( std : : move ( bundle_path ) , * ver_current , vp . name ) ;
2019-02-22 10:36:58 +00:00
} else if ( recommended - > config_version > vp . config_version ) {
2018-04-12 18:04:48 +00:00
// Config bundle update situation
2018-04-23 11:58:03 +00:00
// Check if the update is already present in a snapshot
const auto recommended_snap = SnapshotDB : : singleton ( ) . snapshot_with_vendor_preset ( vp . name , recommended - > config_version ) ;
if ( recommended_snap ! = SnapshotDB : : singleton ( ) . end ( ) ) {
BOOST_LOG_TRIVIAL ( info ) < < boost : : format ( " Bundle update %1% %2% already found in snapshot %3%, skipping... " )
% vp . name
% recommended - > config_version . to_string ( )
% recommended_snap - > id ;
continue ;
}
2018-06-19 16:26:38 +00:00
auto path_src = cache_path / ( idx . vendor ( ) + " .ini " ) ;
2018-07-21 07:32:45 +00:00
auto path_in_rsrc = rsrc_path / ( idx . vendor ( ) + " .ini " ) ;
2018-06-19 16:26:38 +00:00
if ( ! fs : : exists ( path_src ) ) {
if ( ! fs : : exists ( path_in_rsrc ) ) {
BOOST_LOG_TRIVIAL ( warning ) < < boost : : format ( " Index for vendor %1% indicates update, but bundle found in neither cache nor resources " )
2018-07-21 07:32:45 +00:00
% idx . vendor ( ) ;
2018-06-19 16:26:38 +00:00
continue ;
} else {
path_src = std : : move ( path_in_rsrc ) ;
2018-07-21 07:32:45 +00:00
path_in_rsrc . clear ( ) ;
2018-06-19 16:26:38 +00:00
}
2018-04-13 13:08:58 +00:00
}
2018-07-21 07:32:45 +00:00
auto new_vp = VendorProfile : : from_ini ( path_src , false ) ;
bool found = false ;
2018-06-19 16:26:38 +00:00
if ( new_vp . config_version = = recommended - > config_version ) {
2019-05-13 16:38:48 +00:00
updates . updates . emplace_back ( std : : move ( path_src ) , std : : move ( bundle_path ) , * recommended , vp . name , vp . changelog_url ) ;
2018-07-21 07:32:45 +00:00
found = true ;
} else if ( ! path_in_rsrc . empty ( ) & & fs : : exists ( path_in_rsrc ) ) {
new_vp = VendorProfile : : from_ini ( path_in_rsrc , false ) ;
if ( new_vp . config_version = = recommended - > config_version ) {
2019-05-13 16:38:48 +00:00
updates . updates . emplace_back ( std : : move ( path_in_rsrc ) , std : : move ( bundle_path ) , * recommended , vp . name , vp . changelog_url ) ;
2018-07-21 07:32:45 +00:00
found = true ;
}
}
if ( ! found )
2018-06-19 16:26:38 +00:00
BOOST_LOG_TRIVIAL ( warning ) < < boost : : format ( " Index for vendor %1% indicates update (%2%) but the new bundle was found neither in cache nor resources " )
2018-05-02 15:13:39 +00:00
% idx . vendor ( )
2018-06-19 16:26:38 +00:00
% recommended - > config_version . to_string ( ) ;
2018-04-12 18:04:48 +00:00
}
}
return updates ;
}
2018-04-18 09:40:43 +00:00
void PresetUpdater : : priv : : perform_updates ( Updates & & updates , bool snapshot ) const
2018-04-16 14:52:11 +00:00
{
2018-04-24 16:06:42 +00:00
if ( updates . incompats . size ( ) > 0 ) {
if ( snapshot ) {
BOOST_LOG_TRIVIAL ( info ) < < " Taking a snapshot... " ;
2018-09-20 23:33:41 +00:00
SnapshotDB : : singleton ( ) . take_snapshot ( * GUI : : wxGetApp ( ) . app_config , Snapshot : : SNAPSHOT_DOWNGRADE ) ;
2018-04-24 16:06:42 +00:00
}
2018-04-23 09:16:47 +00:00
2018-04-24 16:06:42 +00:00
BOOST_LOG_TRIVIAL ( info ) < < boost : : format ( " Deleting %1% incompatible bundles " ) % updates . incompats . size ( ) ;
for ( const auto & incompat : updates . incompats ) {
BOOST_LOG_TRIVIAL ( info ) < < ' \t ' < < incompat ;
fs : : remove ( incompat . bundle ) ;
}
2018-04-18 09:40:43 +00:00
}
2018-04-24 16:06:42 +00:00
else if ( updates . updates . size ( ) > 0 ) {
if ( snapshot ) {
BOOST_LOG_TRIVIAL ( info ) < < " Taking a snapshot... " ;
2018-09-20 23:33:41 +00:00
SnapshotDB : : singleton ( ) . take_snapshot ( * GUI : : wxGetApp ( ) . app_config , Snapshot : : SNAPSHOT_UPGRADE ) ;
2018-04-24 16:06:42 +00:00
}
2018-04-16 14:52:11 +00:00
2018-04-24 16:06:42 +00:00
BOOST_LOG_TRIVIAL ( info ) < < boost : : format ( " Performing %1% updates " ) % updates . updates . size ( ) ;
2018-04-23 09:16:47 +00:00
2018-04-24 16:06:42 +00:00
for ( const auto & update : updates . updates ) {
BOOST_LOG_TRIVIAL ( info ) < < ' \t ' < < update ;
2018-04-16 14:52:11 +00:00
2018-06-11 15:34:06 +00:00
copy_file ( update . source , update . target ) ;
2018-04-16 14:52:11 +00:00
2018-04-24 16:06:42 +00:00
PresetBundle bundle ;
bundle . load_configbundle ( update . target . string ( ) , PresetBundle : : LOAD_CFGBNDLE_SYSTEM ) ;
2018-04-16 14:52:11 +00:00
2018-05-18 12:58:24 +00:00
BOOST_LOG_TRIVIAL ( info ) < < boost : : format ( " Deleting %1% conflicting presets " )
% ( bundle . prints . size ( ) + bundle . filaments . size ( ) + bundle . printers . size ( ) ) ;
2018-04-24 16:06:42 +00:00
auto preset_remover = [ ] ( const Preset & preset ) {
2018-05-18 12:58:24 +00:00
BOOST_LOG_TRIVIAL ( info ) < < ' \t ' < < preset . file ;
2018-04-24 16:06:42 +00:00
fs : : remove ( preset . file ) ;
} ;
for ( const auto & preset : bundle . prints ) { preset_remover ( preset ) ; }
for ( const auto & preset : bundle . filaments ) { preset_remover ( preset ) ; }
for ( const auto & preset : bundle . printers ) { preset_remover ( preset ) ; }
2018-05-16 17:41:35 +00:00
// Also apply the `obsolete_presets` property, removing obsolete ini files
2018-05-18 12:58:24 +00:00
BOOST_LOG_TRIVIAL ( info ) < < boost : : format ( " Deleting %1% obsolete presets " )
% ( bundle . obsolete_presets . prints . size ( ) + bundle . obsolete_presets . filaments . size ( ) + bundle . obsolete_presets . printers . size ( ) ) ;
2018-05-16 17:41:35 +00:00
auto obsolete_remover = [ ] ( const char * subdir , const std : : string & preset ) {
auto path = fs : : path ( Slic3r : : data_dir ( ) ) / subdir / preset ;
path + = " .ini " ;
2018-05-18 12:58:24 +00:00
BOOST_LOG_TRIVIAL ( info ) < < ' \t ' < < path . string ( ) ;
2018-05-16 17:41:35 +00:00
fs : : remove ( path ) ;
} ;
for ( const auto & name : bundle . obsolete_presets . prints ) { obsolete_remover ( " print " , name ) ; }
for ( const auto & name : bundle . obsolete_presets . filaments ) { obsolete_remover ( " filament " , name ) ; }
2018-11-19 10:10:22 +00:00
for ( const auto & name : bundle . obsolete_presets . sla_prints ) { obsolete_remover ( " sla_print " , name ) ; }
for ( const auto & name : bundle . obsolete_presets . sla_materials /*filaments*/ ) { obsolete_remover ( " sla_material " , name ) ; }
2018-05-16 17:41:35 +00:00
for ( const auto & name : bundle . obsolete_presets . printers ) { obsolete_remover ( " printer " , name ) ; }
2018-04-24 16:06:42 +00:00
}
2018-04-16 14:52:11 +00:00
}
}
2018-06-11 15:34:06 +00:00
void PresetUpdater : : priv : : copy_file ( const fs : : path & source , const fs : : path & target )
{
static const auto perms = fs : : owner_read | fs : : owner_write | fs : : group_read | fs : : others_read ; // aka 644
// Make sure the file has correct permission both before and after we copy over it
2018-06-11 16:30:40 +00:00
if ( fs : : exists ( target ) ) {
fs : : permissions ( target , perms ) ;
}
2018-06-11 15:34:06 +00:00
fs : : copy_file ( source , target , fs : : copy_option : : overwrite_if_exists ) ;
fs : : permissions ( target , perms ) ;
}
2018-04-12 18:04:48 +00:00
2018-09-20 23:33:41 +00:00
PresetUpdater : : PresetUpdater ( ) :
p ( new priv ( ) )
2018-04-13 13:08:58 +00:00
{ }
2018-03-28 09:36:36 +00:00
// Public
PresetUpdater : : ~ PresetUpdater ( )
{
if ( p & & p - > thread . joinable ( ) ) {
2018-04-23 09:16:47 +00:00
// This will stop transfers being done by the thread, if any.
// Cancelling takes some time, but should complete soon enough.
2018-03-28 09:36:36 +00:00
p - > cancel = true ;
p - > thread . join ( ) ;
}
}
2018-04-17 14:59:53 +00:00
void PresetUpdater : : sync ( PresetBundle * preset_bundle )
2018-03-28 09:36:36 +00:00
{
2018-09-20 23:33:41 +00:00
p - > set_download_prefs ( GUI : : wxGetApp ( ) . app_config ) ;
2018-04-13 13:08:58 +00:00
if ( ! p - > enabled_version_check & & ! p - > enabled_config_update ) { return ; }
2018-03-28 09:36:36 +00:00
// Copy the whole vendors data for use in the background thread
// Unfortunatelly as of C++11, it needs to be copied again
// into the closure (but perhaps the compiler can elide this).
std : : set < VendorProfile > vendors = preset_bundle - > vendors ;
p - > thread = std : : move ( std : : thread ( [ this , vendors ] ( ) {
2018-04-13 13:08:58 +00:00
this - > p - > prune_tmps ( ) ;
this - > p - > sync_version ( ) ;
this - > p - > sync_config ( std : : move ( vendors ) ) ;
2018-03-28 09:36:36 +00:00
} ) ) ;
}
2018-04-17 14:59:53 +00:00
void PresetUpdater : : slic3r_update_notify ( )
{
2018-04-23 09:16:47 +00:00
if ( ! p - > enabled_version_check ) { return ; }
if ( p - > had_config_update ) {
BOOST_LOG_TRIVIAL ( info ) < < " New Slic3r version available, but there was a configuration update, notification won't be displayed " ;
return ;
}
2018-04-17 14:59:53 +00:00
2018-09-20 23:33:41 +00:00
auto * app_config = GUI : : wxGetApp ( ) . app_config ;
2018-04-20 12:53:11 +00:00
const auto ver_online_str = app_config - > get ( " version_online " ) ;
const auto ver_online = Semver : : parse ( ver_online_str ) ;
const auto ver_online_seen = Semver : : parse ( app_config - > get ( " version_online_seen " ) ) ;
2018-04-17 14:59:53 +00:00
2018-04-20 12:53:11 +00:00
if ( ver_online ) {
// Only display the notification if the version available online is newer AND if we haven't seen it before
2019-02-14 14:28:18 +00:00
if ( * ver_online > p - > ver_slic3r & & ( ! ver_online_seen | | * ver_online_seen < * ver_online ) ) {
GUI : : MsgUpdateSlic3r notification ( p - > ver_slic3r , * ver_online ) ;
2018-04-20 12:53:11 +00:00
notification . ShowModal ( ) ;
if ( notification . disable_version_check ( ) ) {
app_config - > set ( " version_check " , " 0 " ) ;
p - > enabled_version_check = false ;
}
2018-04-17 14:59:53 +00:00
}
2019-05-13 16:38:48 +00:00
2018-04-20 12:53:11 +00:00
app_config - > set ( " version_online_seen " , ver_online_str ) ;
2018-04-17 14:59:53 +00:00
}
}
2018-04-24 16:06:42 +00:00
bool PresetUpdater : : config_update ( ) const
2018-04-11 11:12:08 +00:00
{
2018-04-24 16:06:42 +00:00
if ( ! p - > enabled_config_update ) { return true ; }
2018-04-13 13:08:58 +00:00
2018-04-23 11:58:03 +00:00
auto updates = p - > get_config_updates ( ) ;
2018-04-24 16:06:42 +00:00
if ( updates . incompats . size ( ) > 0 ) {
BOOST_LOG_TRIVIAL ( info ) < < boost : : format ( " %1% bundles incompatible. Asking for action... " ) % updates . incompats . size ( ) ;
2018-04-24 16:40:06 +00:00
std : : unordered_map < std : : string , wxString > incompats_map ;
2018-04-24 16:06:42 +00:00
for ( const auto & incompat : updates . incompats ) {
2018-07-23 10:34:07 +00:00
const auto min_slic3r = incompat . version . min_slic3r_version ;
const auto max_slic3r = incompat . version . max_slic3r_version ;
wxString restrictions ;
if ( min_slic3r ! = Semver : : zero ( ) & & max_slic3r ! = Semver : : inf ( ) ) {
restrictions = wxString : : Format ( _ ( L ( " requires min. %s and max. %s " ) ) ,
min_slic3r . to_string ( ) ,
max_slic3r . to_string ( )
) ;
} else if ( min_slic3r ! = Semver : : zero ( ) ) {
restrictions = wxString : : Format ( _ ( L ( " requires min. %s " ) ) , min_slic3r . to_string ( ) ) ;
} else {
restrictions = wxString : : Format ( _ ( L ( " requires max. %s " ) ) , max_slic3r . to_string ( ) ) ;
}
2019-05-13 16:38:48 +00:00
incompats_map . emplace ( std : : make_pair ( incompat . vendor , std : : move ( restrictions ) ) ) ;
2018-04-24 16:06:42 +00:00
}
2018-04-12 18:04:48 +00:00
2018-06-22 13:27:04 +00:00
p - > had_config_update = true ; // This needs to be done before a dialog is shown because of OnIdle() + CallAfter() in Perl
2018-04-24 16:06:42 +00:00
GUI : : MsgDataIncompatible dlg ( std : : move ( incompats_map ) ) ;
const auto res = dlg . ShowModal ( ) ;
if ( res = = wxID_REPLACE ) {
BOOST_LOG_TRIVIAL ( info ) < < " User wants to re-configure... " ;
p - > perform_updates ( std : : move ( updates ) ) ;
GUI : : ConfigWizard wizard ( nullptr , GUI : : ConfigWizard : : RR_DATA_INCOMPAT ) ;
2018-10-01 13:09:31 +00:00
if ( ! wizard . run ( GUI : : wxGetApp ( ) . preset_bundle , this ) ) {
2018-04-24 16:06:42 +00:00
return false ;
}
2018-10-01 13:09:31 +00:00
GUI : : wxGetApp ( ) . load_current_presets ( ) ;
2018-04-24 16:06:42 +00:00
} else {
BOOST_LOG_TRIVIAL ( info ) < < " User wants to exit Slic3r, bye... " ;
return false ;
}
}
else if ( updates . updates . size ( ) > 0 ) {
BOOST_LOG_TRIVIAL ( info ) < < boost : : format ( " Update of %1% bundles available. Asking for confirmation ... " ) % updates . updates . size ( ) ;
2018-04-12 18:04:48 +00:00
2019-05-13 16:38:48 +00:00
std : : vector < GUI : : MsgUpdateConfig : : Update > updates_msg ;
2018-04-24 16:06:42 +00:00
for ( const auto & update : updates . updates ) {
2019-05-13 16:38:48 +00:00
std : : string changelog_url = update . version . config_version . prerelease ( ) = = nullptr ? update . changelog_url : std : : string ( ) ;
updates_msg . emplace_back ( update . vendor , update . version . config_version , update . version . comment , std : : move ( changelog_url ) ) ;
2018-04-12 18:04:48 +00:00
}
2018-04-11 11:12:08 +00:00
2018-06-22 13:27:04 +00:00
p - > had_config_update = true ; // Ditto, see above
2019-05-13 16:38:48 +00:00
GUI : : MsgUpdateConfig dlg ( updates_msg ) ;
2018-04-24 16:06:42 +00:00
2018-04-12 18:04:48 +00:00
const auto res = dlg . ShowModal ( ) ;
2018-04-25 13:20:46 +00:00
if ( res = = wxID_OK ) {
2018-04-23 09:16:47 +00:00
BOOST_LOG_TRIVIAL ( debug ) < < " User agreed to perform the update " ;
2018-04-17 14:59:53 +00:00
p - > perform_updates ( std : : move ( updates ) ) ;
2018-06-06 08:52:19 +00:00
// Reload global configuration
2018-09-20 23:33:41 +00:00
auto * app_config = GUI : : wxGetApp ( ) . app_config ;
2018-10-01 13:09:31 +00:00
GUI : : wxGetApp ( ) . preset_bundle - > load_presets ( * app_config ) ;
GUI : : wxGetApp ( ) . load_current_presets ( ) ;
2018-04-23 09:16:47 +00:00
} else {
BOOST_LOG_TRIVIAL ( info ) < < " User refused the update " ;
2018-04-16 14:52:11 +00:00
}
2018-04-23 09:16:47 +00:00
} else {
BOOST_LOG_TRIVIAL ( info ) < < " No configuration updates available. " ;
2018-04-16 14:52:11 +00:00
}
2018-04-24 16:06:42 +00:00
return true ;
2018-04-16 14:52:11 +00:00
}
2018-04-12 18:04:48 +00:00
2018-04-24 16:06:42 +00:00
void PresetUpdater : : install_bundles_rsrc ( std : : vector < std : : string > bundles , bool snapshot ) const
2018-04-16 14:52:11 +00:00
{
Updates updates ;
2018-04-12 18:04:48 +00:00
2018-04-23 09:16:47 +00:00
BOOST_LOG_TRIVIAL ( info ) < < boost : : format ( " Installing %1% bundles from resources ... " ) % bundles . size ( ) ;
2018-04-16 14:52:11 +00:00
for ( const auto & bundle : bundles ) {
auto path_in_rsrc = p - > rsrc_path / bundle ;
auto path_in_vendors = p - > vendor_path / bundle ;
2019-05-13 16:38:48 +00:00
updates . updates . emplace_back ( std : : move ( path_in_rsrc ) , std : : move ( path_in_vendors ) , Version ( ) , " " , " " ) ;
2018-04-11 11:12:08 +00:00
}
2018-04-16 14:52:11 +00:00
2018-04-18 09:40:43 +00:00
p - > perform_updates ( std : : move ( updates ) , snapshot ) ;
2018-04-11 11:12:08 +00:00
}
2018-03-28 09:36:36 +00:00
}