uninstall good

This commit is contained in:
David Rose 2009-12-20 18:29:25 +00:00
parent 38d3eda196
commit fd6e2fc82a
11 changed files with 419 additions and 195 deletions

View File

@ -70,7 +70,8 @@ get_download_url_prefix() const {
// Function: P3DHost::get_descriptive_name
// Access: Public
// Description: Returns the descriptive name provided for this host,
// if any. This will be available after
// if any. Returns the url if no descriptive name is
// provided. This will be available after
// read_contents_file() has been called.
////////////////////////////////////////////////////////////////////
inline const string &P3DHost::

View File

@ -37,6 +37,8 @@ P3DHost(const string &host_url) :
}
_download_url_prefix = _host_url_prefix;
_descriptive_name = _host_url;
_xcontents = NULL;
_contents_seq = 0;
}
@ -449,6 +451,37 @@ add_mirror(string mirror_url) {
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DHost::uninstall
// Access: Public
// Description: Removes the host directory and all its contents
// from the user's hard disk.
////////////////////////////////////////////////////////////////////
void P3DHost::
uninstall() {
if (_host_dir.empty()) {
nout << "Cannot uninstall " << _descriptive_name << ": host directory not yet known.\n";
return;
}
// First, explicitly uninstall each of our packages.
Packages::iterator mi;
for (mi = _packages.begin(); mi != _packages.end(); ++mi) {
PackageMap &package_map = (*mi).second;
PackageMap::iterator pi;
for (pi = package_map.begin(); pi != package_map.end(); ++pi) {
P3DPackage *package = (*pi).second;
package->uninstall();
}
}
// Then, uninstall the host itself.
nout << "Uninstalling " << _descriptive_name << " from " << _host_dir << "\n";
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
inst_mgr->delete_directory_recursively(_host_dir);
}
////////////////////////////////////////////////////////////////////
// Function: P3DHost::determine_host_dir
// Access: Private

View File

@ -64,6 +64,8 @@ public:
void choose_random_mirrors(vector<string> &result, int num_mirrors);
void add_mirror(string mirror_url);
void uninstall();
private:
void determine_host_dir(const string &host_dir_basename);

View File

@ -421,6 +421,10 @@ set_p3d_filename(const string &p3d_filename, const int &p3d_offset) {
////////////////////////////////////////////////////////////////////
void P3DInstance::
set_wparams(const P3DWindowParams &wparams) {
if (is_failed()) {
return;
}
_got_wparams = true;
_wparams = wparams;
@ -1080,6 +1084,12 @@ start_download(P3DDownload *download, bool add_request) {
assert(download->get_download_id() == 0);
assert(!download->get_url().empty());
if (is_failed()) {
// Can't download anything more after failure.
download->cancel();
return 0;
}
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
int download_id = inst_mgr->get_unique_id();
@ -1239,6 +1249,11 @@ splash_button_clicked_sub_thread() {
////////////////////////////////////////////////////////////////////
void P3DInstance::
splash_button_clicked_main_thread() {
if (is_failed()) {
// Can't click the button after we've failed.
return;
}
if (!_p3d_trusted) {
auth_button_clicked();
} else if (_session == NULL) {
@ -1329,7 +1344,7 @@ auth_finished_main_thread() {
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstance::uninstall
// Function: P3DInstance::uninstall_packages
// Access: Public
// Description: Stops the instance (if it is running) and deletes any
// packages referenced by the instance. This is
@ -1337,23 +1352,39 @@ auth_finished_main_thread() {
// P3DMainObject::call_uninstall().
////////////////////////////////////////////////////////////////////
void P3DInstance::
uninstall() {
if (_session != NULL) {
_session->set_failed();
_session->shutdown();
}
uninstall_packages() {
Packages::const_iterator pi;
for (pi = _packages.begin(); pi != _packages.end(); ++pi) {
P3DPackage *package = (*pi);
package->uninstall();
package->remove_instance(this);
}
_packages.clear();
}
_auto_install = false;
_instance_window_opened = false;
set_failed();
////////////////////////////////////////////////////////////////////
// Function: P3DInstance::uninstall_host
// Access: Public
// Description: Stops the instance (if it is running) and deletes all
// packages downloaded from any of the host(s)
// referenced by the instance. This is a more
// aggressive uninstall than uninstall_packages(). This
// is normally called by JavaScript, via
// P3DMainObject::call_uninstall().
////////////////////////////////////////////////////////////////////
void P3DInstance::
uninstall_host() {
set<P3DHost *> hosts;
Packages::const_iterator pi;
for (pi = _packages.begin(); pi != _packages.end(); ++pi) {
P3DPackage *package = (*pi);
hosts.insert(package->get_host());
}
set<P3DHost *>::iterator hi;
for (hi = hosts.begin(); hi != hosts.end(); ++hi) {
P3DHost *host = (*hi);
host->uninstall();
}
}
////////////////////////////////////////////////////////////////////
@ -2283,9 +2314,9 @@ handle_script_request(const string &operation, P3D_object *object,
////////////////////////////////////////////////////////////////////
void P3DInstance::
set_failed() {
_failed = true;
set_button_image(IT_none);
set_background_image(IT_failed);
_failed = true;
make_splash_window();
}
@ -2312,7 +2343,7 @@ make_splash_window() {
make_visible = false;
}
if (_failed) {
if (is_failed()) {
// But, if we've failed to launch somehow, we need to let the user
// know.
make_visible = true;
@ -2423,6 +2454,11 @@ make_splash_window() {
////////////////////////////////////////////////////////////////////
void P3DInstance::
set_background_image(ImageType image_type) {
if (is_failed()) {
// Can't change the background again after we've failed.
return;
}
if (image_type != _current_background_image) {
nout << "setting background to " << _image_type_names[image_type]
<< ", splash_window = " << _splash_window << "\n";
@ -2455,6 +2491,11 @@ set_background_image(ImageType image_type) {
////////////////////////////////////////////////////////////////////
void P3DInstance::
set_button_image(ImageType image_type) {
if (is_failed()) {
// Can't set the button again after we've failed.
return;
}
if (image_type != _current_button_image) {
nout << "setting button to " << _image_type_names[image_type] << "\n";
// Remove the previous image.
@ -2659,6 +2700,10 @@ start_next_download() {
////////////////////////////////////////////////////////////////////
void P3DInstance::
mark_download_complete() {
if (_failed) {
return;
}
if (!_download_complete) {
_download_complete = true;
_panda_script_object->set_bool_property("downloadComplete", true);

View File

@ -116,7 +116,8 @@ public:
void auth_finished_sub_thread();
void auth_finished_main_thread();
void uninstall();
void uninstall_packages();
void uninstall_host();
private:
class ImageDownload : public P3DFileDownload {

View File

@ -24,6 +24,21 @@ is_initialized() const {
return _is_initialized;
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::reconsider_runtime_environment
// Access: Public
// Description: Recreates the runtime environment if a previous call
// to uninstall_all() removed it. Does nothing if the
// runtime environment is already correctly set up.
////////////////////////////////////////////////////////////////////
inline void P3DInstanceManager::
reconsider_runtime_environment() {
assert(_is_initialized);
if (!_created_runtime_environment) {
create_runtime_environment();
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::verify_contents
// Access: Public

View File

@ -58,6 +58,7 @@ P3DInstanceManager() {
init_xml();
_is_initialized = false;
_created_runtime_environment = false;
_api_version = 0;
_next_temp_filename_counter = 1;
_unique_id = 0;
@ -187,36 +188,51 @@ initialize(int api_version, const string &contents_filename,
const string &log_basename, bool trusted_environment,
bool console_environment) {
_api_version = api_version;
_trusted_environment = trusted_environment;
_console_environment = console_environment;
_host_url = host_url;
_verify_contents = verify_contents;
_platform = platform;
if (_platform.empty()) {
_platform = DTOOL_PLATFORM;
}
_log_directory = log_directory;
_log_basename = log_basename;
_trusted_environment = trusted_environment;
_console_environment = console_environment;
_host_url = host_url;
if (_host_url.empty()) {
_host_url = PANDA_PACKAGE_HOST_URL;
}
_root_dir = find_root_dir();
if (_platform.empty()) {
_platform = DTOOL_PLATFORM;
}
// Allow the caller (e.g. panda3d.exe) to specify a log directory.
_log_directory = log_directory;
// Or, allow the developer to compile one in.
#ifdef P3D_PLUGIN_LOG_DIRECTORY
if (_log_directory.empty()) {
_log_directory = P3D_PLUGIN_LOG_DIRECTORY;
}
#endif
#ifdef P3D_PLUGIN_LOG_BASENAME2
if (_log_basename.empty()) {
_log_basename = P3D_PLUGIN_LOG_BASENAME2;
}
#endif
if (_log_basename.empty()) {
_log_basename = "p3dcore";
}
_root_dir = find_root_dir();
if (_root_dir.empty()) {
cerr << "Could not find root directory.\n";
return false;
}
// Allow the caller (e.g. panda3d.exe) to specify a log directory.
// Or, allow the developer to compile one in.
// Failing that, we write logfiles to Panda3D/log.
if (_log_directory.empty()) {
_log_directory = _root_dir + "/log";
}
mkdir_complete(_log_directory, cerr);
// Ensure that the log directory ends with a slash.
if (!_log_directory.empty() && _log_directory[_log_directory.size() - 1] != '/') {
@ -227,126 +243,11 @@ initialize(int api_version, const string &contents_filename,
}
// Construct the logfile pathname.
_log_basename = log_basename;
#ifdef P3D_PLUGIN_LOG_BASENAME2
if (_log_basename.empty()) {
_log_basename = P3D_PLUGIN_LOG_BASENAME2;
}
#endif
if (_log_basename.empty()) {
_log_basename = "p3dcore";
}
_log_pathname = _log_directory;
_log_pathname += _log_basename;
_log_pathname += ".log";
logfile.close();
logfile.clear();
logfile.open(_log_pathname.c_str(), ios::out | ios::trunc);
if (logfile) {
logfile.setf(ios::unitbuf);
nout_stream = &logfile;
}
// Determine the temporary directory.
#ifdef _WIN32
char buffer_1[MAX_PATH];
// Figuring out the correct path for temporary files is a real mess
// on Windows. We should be able to use GetTempPath(), but that
// relies on $TMP or $TEMP being defined, and it appears that
// Mozilla clears these environment variables for the plugin, which
// forces GetTempPath() into $USERPROFILE instead. This is really
// an inappropriate place for temporary files, so, GetTempPath()
// isn't a great choice.
// We could use SHGetSpecialFolderPath() instead to get us the path
// to "Temporary Internet Files", which is acceptable. The trouble
// is, if we happen to be running in "Protected Mode" on Vista, this
// folder isn't actually writable by us! On Vista, we're supposed
// to use IEGetWriteableFolderPath() instead, but *this* function
// doesn't exist on XP and below. Good Lord.
// We could go through a bunch of LoadLibrary() calls to try to find
// the right path, like we do in find_root_dir(), but I'm just tired
// of doing all that nonsense. We'll use a two-stage trick instead.
// We'll check for $TEMP or $TMP being defined specifically, and if
// they are, we'll use GetTempPath(); otherwise, we'll fall back to
// SHGetSpecialFolderPath().
if (getenv("TEMP") != NULL || getenv("TMP") != NULL) {
if (GetTempPath(MAX_PATH, buffer_1) != 0) {
_temp_directory = buffer_1;
}
}
if (_temp_directory.empty()) {
if (SHGetSpecialFolderPath(NULL, buffer_1, CSIDL_INTERNET_CACHE, true)) {
_temp_directory = buffer_1;
// That just *might* return a non-writable folder, if we're in
// Protected Mode. We'll test this with GetTempFileName().
char temp_buffer[MAX_PATH];
if (!GetTempFileName(_temp_directory.c_str(), "p3d", 0, temp_buffer)) {
nout << "GetTempFileName failed on " << _temp_directory
<< ", switching to GetTempPath\n";
_temp_directory.clear();
} else {
DeleteFile(temp_buffer);
}
}
}
// If both of the above failed, we'll fall back to GetTempPath()
// once again as a last resort, which is supposed to return
// *something* that works, even if $TEMP and $TMP are undefined.
if (_temp_directory.empty()) {
if (GetTempPath(MAX_PATH, buffer_1) != 0) {
_temp_directory = buffer_1;
}
}
// Also insist that the temp directory is fully specified.
size_t needs_size_2 = GetFullPathName(_temp_directory.c_str(), 0, NULL, NULL);
char *buffer_2 = new char[needs_size_2];
if (GetFullPathName(_temp_directory.c_str(), needs_size_2, buffer_2, NULL) != 0) {
_temp_directory = buffer_2;
}
delete[] buffer_2;
// And make sure the directory actually exists.
mkdir_complete(_temp_directory, nout);
#else
_temp_directory = "/tmp/";
#endif // _WIN32
// Ensure that the temp directory ends with a slash.
if (!_temp_directory.empty() && _temp_directory[_temp_directory.size() - 1] != '/') {
#ifdef _WIN32
if (_temp_directory[_temp_directory.size() - 1] != '\\')
#endif
_temp_directory += "/";
}
nout << "_root_dir = " << _root_dir
<< ", _temp_directory = " << _temp_directory
<< ", platform = " << _platform
<< ", contents_filename = " << contents_filename
<< ", host_url = " << host_url
<< ", verify_contents = " << verify_contents
<< "\n";
if (_root_dir.empty()) {
nout << "Could not find root directory.\n";
return false;
}
// Make the certificate directory.
_certs_dir = _root_dir + "/certs";
if (!mkdir_complete(_certs_dir, nout)) {
nout << "Couldn't mkdir " << _certs_dir << "\n";
}
create_runtime_environment();
_is_initialized = true;
if (!_verify_contents &&
@ -373,6 +274,7 @@ set_plugin_version(int major, int minor, int sequence,
bool official, const string &distributor,
const string &coreapi_host_url,
time_t coreapi_timestamp) {
reconsider_runtime_environment();
_plugin_major_version = major;
_plugin_minor_version = minor;
_plugin_sequence_version = sequence;
@ -389,6 +291,7 @@ set_plugin_version(int major, int minor, int sequence,
////////////////////////////////////////////////////////////////////
void P3DInstanceManager::
set_super_mirror(const string &super_mirror_url) {
reconsider_runtime_environment();
if (!super_mirror_url.empty()) {
nout << "super_mirror = " << super_mirror_url << "\n";
}
@ -410,6 +313,7 @@ P3DInstance *P3DInstanceManager::
create_instance(P3D_request_ready_func *func,
const P3D_token tokens[], size_t num_tokens,
int argc, const char *argv[], void *user_data) {
reconsider_runtime_environment();
P3DInstance *inst = new P3DInstance(func, tokens, num_tokens, argc, argv,
user_data);
inst->ref();
@ -961,6 +865,43 @@ cert_to_der(X509 *cert) {
return result;
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::uninstall_all
// Access: Public
// Description: Stops all active instances and removes *all*
// downloaded files from all hosts, and empties the
// current user's Panda3D directory as much as possible.
//
// This cannot remove the coreapi dll or directory on
// Windows.
////////////////////////////////////////////////////////////////////
void P3DInstanceManager::
uninstall_all() {
Instances::iterator ii;
for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
P3DInstance *inst = (*ii);
inst->uninstall_host();
}
Hosts::iterator hi;
for (hi = _hosts.begin(); hi != _hosts.end(); ++hi) {
P3DHost *host = (*hi).second;
host->uninstall();
}
// Close the logfile so we can remove that too.
logfile.close();
if (!_root_dir.empty()) {
// This won't be able to delete the coreapi directory on Windows,
// because we're running that DLL right now. But it will delete
// everything else.
delete_directory_recursively(_root_dir);
}
_created_runtime_environment = false;
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::get_global_ptr
// Access: Public, Static
@ -1112,6 +1053,82 @@ scan_directory_recursively(const string &dirname,
return true;
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::delete_directory_recursively
// Access: Public, Static
// Description: Deletes all of the files and directories in the named
// directory and below, like rm -rf. Use with extreme
// caution.
////////////////////////////////////////////////////////////////////
void P3DInstanceManager::
delete_directory_recursively(const string &root_dir) {
vector<string> contents, dirname_contents;
if (!scan_directory_recursively(root_dir, contents, dirname_contents)) {
// Maybe it's just a single file, not a directory. Delete it.
#ifdef _WIN32
// Windows can't delete a file if it's read-only.
chmod(root_dir.c_str(), 0644);
#endif
int result = unlink(root_dir.c_str());
if (result == 0) {
nout << "Deleted " << root_dir << "\n";
} else {
if (access(root_dir.c_str(), F_OK) == 0) {
nout << "Could not delete " << root_dir << "\n";
}
}
return;
}
vector<string>::iterator ci;
for (ci = contents.begin(); ci != contents.end(); ++ci) {
string filename = (*ci);
string pathname = root_dir + "/" + filename;
#ifdef _WIN32
// Windows can't delete a file if it's read-only.
chmod(pathname.c_str(), 0644);
#endif
int result = unlink(pathname.c_str());
if (result == 0) {
nout << " Deleted " << filename << "\n";
} else {
nout << " Could not delete " << filename << "\n";
}
}
// Now delete all of the directories too. They're already in
// reverse order, so we remove deeper directories first.
for (ci = dirname_contents.begin(); ci != dirname_contents.end(); ++ci) {
string filename = (*ci);
string pathname = root_dir + "/" + filename;
#ifdef _WIN32
chmod(pathname.c_str(), 0755);
#endif
int result = rmdir(pathname.c_str());
if (result == 0) {
nout << " Removed directory " << filename << "\n";
} else {
nout << " Could not remove directory " << filename << "\n";
}
}
// Finally, delete the root directory itself.
string pathname = root_dir;
#ifdef _WIN32
chmod(pathname.c_str(), 0755);
#endif
int result = rmdir(pathname.c_str());
if (result == 0) {
nout << "Removed directory " << root_dir << "\n";
} else {
if (access(pathname.c_str(), F_OK) == 0) {
nout << "Could not remove directory " << root_dir << "\n";
}
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::remove_file_from_list
// Access: Public, Static
@ -1185,6 +1202,121 @@ append_safe_dir(string &root, const string &basename) {
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::create_runtime_environment
// Access: Private
// Description: Called during initialize, or after a previous call to
// uninstall_all(), to make sure all needed
// directories exist and the logfile is open.
////////////////////////////////////////////////////////////////////
void P3DInstanceManager::
create_runtime_environment() {
mkdir_complete(_log_directory, cerr);
logfile.close();
logfile.clear();
logfile.open(_log_pathname.c_str(), ios::out | ios::trunc);
if (logfile) {
logfile.setf(ios::unitbuf);
nout_stream = &logfile;
}
// Determine the temporary directory.
#ifdef _WIN32
char buffer_1[MAX_PATH];
// Figuring out the correct path for temporary files is a real mess
// on Windows. We should be able to use GetTempPath(), but that
// relies on $TMP or $TEMP being defined, and it appears that
// Mozilla clears these environment variables for the plugin, which
// forces GetTempPath() into $USERPROFILE instead. This is really
// an inappropriate place for temporary files, so, GetTempPath()
// isn't a great choice.
// We could use SHGetSpecialFolderPath() instead to get us the path
// to "Temporary Internet Files", which is acceptable. The trouble
// is, if we happen to be running in "Protected Mode" on Vista, this
// folder isn't actually writable by us! On Vista, we're supposed
// to use IEGetWriteableFolderPath() instead, but *this* function
// doesn't exist on XP and below. Good Lord.
// We could go through a bunch of LoadLibrary() calls to try to find
// the right path, like we do in find_root_dir(), but I'm just tired
// of doing all that nonsense. We'll use a two-stage trick instead.
// We'll check for $TEMP or $TMP being defined specifically, and if
// they are, we'll use GetTempPath(); otherwise, we'll fall back to
// SHGetSpecialFolderPath().
if (getenv("TEMP") != NULL || getenv("TMP") != NULL) {
if (GetTempPath(MAX_PATH, buffer_1) != 0) {
_temp_directory = buffer_1;
}
}
if (_temp_directory.empty()) {
if (SHGetSpecialFolderPath(NULL, buffer_1, CSIDL_INTERNET_CACHE, true)) {
_temp_directory = buffer_1;
// That just *might* return a non-writable folder, if we're in
// Protected Mode. We'll test this with GetTempFileName().
char temp_buffer[MAX_PATH];
if (!GetTempFileName(_temp_directory.c_str(), "p3d", 0, temp_buffer)) {
nout << "GetTempFileName failed on " << _temp_directory
<< ", switching to GetTempPath\n";
_temp_directory.clear();
} else {
DeleteFile(temp_buffer);
}
}
}
// If both of the above failed, we'll fall back to GetTempPath()
// once again as a last resort, which is supposed to return
// *something* that works, even if $TEMP and $TMP are undefined.
if (_temp_directory.empty()) {
if (GetTempPath(MAX_PATH, buffer_1) != 0) {
_temp_directory = buffer_1;
}
}
// Also insist that the temp directory is fully specified.
size_t needs_size_2 = GetFullPathName(_temp_directory.c_str(), 0, NULL, NULL);
char *buffer_2 = new char[needs_size_2];
if (GetFullPathName(_temp_directory.c_str(), needs_size_2, buffer_2, NULL) != 0) {
_temp_directory = buffer_2;
}
delete[] buffer_2;
// And make sure the directory actually exists.
mkdir_complete(_temp_directory, nout);
#else
_temp_directory = "/tmp/";
#endif // _WIN32
// Ensure that the temp directory ends with a slash.
if (!_temp_directory.empty() && _temp_directory[_temp_directory.size() - 1] != '/') {
#ifdef _WIN32
if (_temp_directory[_temp_directory.size() - 1] != '\\')
#endif
_temp_directory += "/";
}
nout << "_root_dir = " << _root_dir
<< ", _temp_directory = " << _temp_directory
<< ", platform = " << _platform
<< ", host_url = " << _host_url
<< ", verify_contents = " << _verify_contents
<< "\n";
// Make the certificate directory.
_certs_dir = _root_dir + "/certs";
if (!mkdir_complete(_certs_dir, nout)) {
nout << "Couldn't mkdir " << _certs_dir << "\n";
}
_created_runtime_environment = true;
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::append_safe_dir_component
// Access: Private, Static

View File

@ -60,6 +60,7 @@ public:
bool console_environment);
inline bool is_initialized() const;
inline void reconsider_runtime_environment();
inline bool get_verify_contents() const;
inline void reset_verify_contents();
@ -126,6 +127,8 @@ public:
string get_cert_dir(X509 *cert);
static string cert_to_der(X509 *cert);
void uninstall_all();
static P3DInstanceManager *get_global_ptr();
static void delete_global_ptr();
@ -135,11 +138,13 @@ public:
vector<string> &filename_contents,
vector<string> &dirname_contents,
const string &prefix = "");
static void delete_directory_recursively(const string &root_dir);
static bool remove_file_from_list(vector<string> &contents, const string &filename);
static void append_safe_dir(string &root, const string &basename);
private:
void create_runtime_environment();
static void append_safe_dir_component(string &root, const string &component);
private:
@ -151,6 +156,7 @@ private:
private:
bool _is_initialized;
bool _created_runtime_environment;
int _api_version;
string _host_url;
string _root_dir;

View File

@ -451,9 +451,29 @@ P3D_object *P3DMainObject::
call_uninstall(P3D_object *params[], int num_params) {
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
// Get the first parameter, the uninstall mode.
string mode;
if (num_params > 0) {
int size = P3D_OBJECT_GET_STRING(params[0], NULL, 0);
char *buffer = new char[size];
P3D_OBJECT_GET_STRING(params[0], buffer, size);
mode = string(buffer, size);
delete[] buffer;
}
if (mode == "all") {
nout << "uninstall all\n";
inst_mgr->uninstall_all();
return inst_mgr->new_bool_object(true);
}
if (_inst != NULL) {
nout << "uninstall for " << _inst << "\n";
_inst->uninstall();
nout << "uninstall " << mode << " for " << _inst << "\n";
if (mode == "host") {
_inst->uninstall_host();
} else {
_inst->uninstall_packages();
}
return inst_mgr->new_bool_object(true);
}

View File

@ -217,56 +217,23 @@ uninstall() {
nout << "Uninstalling package " << _package_name << " from " << _package_dir << "\n";
// First, make sure that all instances that are sharing this package
// are stopped, so there will be no access conflicts preventing us
// from removing the files. This is particularly important on
// Windows.
Instances::iterator ii;
for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
P3DInstance *inst = (*ii);
P3DSession *session = inst->get_session();
if (session != NULL) {
nout << "Stopping session " << session << "\n";
session->shutdown();
}
inst->set_failed();
}
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
vector<string> contents, dirname_contents;
inst_mgr->scan_directory_recursively(_package_dir, contents,
dirname_contents);
vector<string>::iterator ci;
for (ci = contents.begin(); ci != contents.end(); ++ci) {
string filename = (*ci);
string pathname = _package_dir + "/" + filename;
#ifdef _WIN32
// Windows can't delete a file if it's read-only.
chmod(pathname.c_str(), 0644);
#endif
int result = unlink(pathname.c_str());
if (result == 0) {
nout << " Deleted " << filename << "\n";
} else {
nout << " Could not delete " << filename << "\n";
}
}
// Now delete all of the directories too. They're already in
// reverse order, so we remove deeper directories first.
for (ci = dirname_contents.begin(); ci != dirname_contents.end(); ++ci) {
string filename = (*ci);
string pathname = _package_dir + "/" + filename;
#ifdef _WIN32
chmod(pathname.c_str(), 0755);
#endif
int result = rmdir(pathname.c_str());
if (result == 0) {
nout << " Removed directory " << filename << "\n";
} else {
nout << " Could not remove directory " << filename << "\n";
}
}
// Finally, delete the package directory itself.
string pathname = _package_dir;
#ifdef _WIN32
chmod(pathname.c_str(), 0755);
#endif
int result = rmdir(pathname.c_str());
if (result == 0) {
nout << "Removed directory " << _package_dir << "\n";
} else {
nout << "Could not remove directory " << _package_dir << "\n";
}
inst_mgr->delete_directory_recursively(_package_dir);
_info_ready = false;
_ready = false;

View File

@ -96,6 +96,8 @@ P3DSession::
////////////////////////////////////////////////////////////////////
void P3DSession::
shutdown() {
set_failed();
if (_p3dpython_started) {
// Tell the process we're going away.
TiXmlDocument doc;