mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 16:58:40 -04:00
wip: host support
This commit is contained in:
parent
494d61083e
commit
ae8c460b1b
@ -32,6 +32,7 @@
|
||||
p3dFileDownload.h p3dFileDownload.I \
|
||||
p3dFileParams.h p3dFileParams.I \
|
||||
p3dFloatObject.h \
|
||||
p3dHost.h p3dHost.I \
|
||||
p3dInstance.h p3dInstance.I \
|
||||
p3dInstanceManager.h p3dInstanceManager.I \
|
||||
p3dIntObject.h \
|
||||
@ -62,6 +63,7 @@
|
||||
p3dFileDownload.cxx \
|
||||
p3dFileParams.cxx \
|
||||
p3dFloatObject.cxx \
|
||||
p3dHost.cxx \
|
||||
p3dInstance.cxx \
|
||||
p3dInstanceManager.cxx \
|
||||
p3dIntObject.cxx \
|
||||
|
@ -24,6 +24,17 @@ get_filename() const {
|
||||
return _filename;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FileSpec::set_filename
|
||||
// Access: Private
|
||||
// Description: Changes the relative path to this file on disk,
|
||||
// within the package root directory.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline void FileSpec::
|
||||
set_filename(const string &filename) {
|
||||
_filename = filename;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FileSpec::get_pathname
|
||||
// Access: Private
|
||||
|
@ -32,6 +32,7 @@ public:
|
||||
void load_xml(TiXmlElement *element);
|
||||
|
||||
inline const string &get_filename() const;
|
||||
inline void set_filename(const string &filename);
|
||||
inline string get_pathname(const string &package_dir) const;
|
||||
inline size_t get_size() const;
|
||||
|
||||
|
73
direct/src/plugin/p3dHost.I
Normal file
73
direct/src/plugin/p3dHost.I
Normal file
@ -0,0 +1,73 @@
|
||||
// Filename: p3dHost.I
|
||||
// Created by: drose (21Aug09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DHost::get_host_dir
|
||||
// Access: Public
|
||||
// Description: Returns the local directory into which files
|
||||
// downloaded from this host will be installed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline const string &P3DHost::
|
||||
get_host_dir() const {
|
||||
return _host_dir;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DHost::get_host_url
|
||||
// Access: Public
|
||||
// Description: Returns the root URL of this particular host, as
|
||||
// passed from the package file. This is a unique
|
||||
// string that identifies each host.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline const string &P3DHost::
|
||||
get_host_url() const {
|
||||
return _host_url;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DHost::get_host_url_prefix
|
||||
// Access: Public
|
||||
// Description: Returns the root URL of this host, for constructing
|
||||
// full URL sequences. This is the same as
|
||||
// get_host_url(), except it is guaranteed to end in a
|
||||
// slash character.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline const string &P3DHost::
|
||||
get_host_url_prefix() const {
|
||||
return _host_url_prefix;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DHost::get_descriptive_name
|
||||
// Access: Public
|
||||
// Description: Returns the descriptive name provided for this host,
|
||||
// if any. This will be available after
|
||||
// read_contents_file() has been called.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline const string &P3DHost::
|
||||
get_descriptive_name() const {
|
||||
return _descriptive_name;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DHost::has_contents_file
|
||||
// Access: Public
|
||||
// Description: Returns true if a contents.xml file has been
|
||||
// successfully read for this host, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline bool P3DHost::
|
||||
has_contents_file() const {
|
||||
return (_xcontents != NULL);
|
||||
}
|
265
direct/src/plugin/p3dHost.cxx
Normal file
265
direct/src/plugin/p3dHost.cxx
Normal file
@ -0,0 +1,265 @@
|
||||
// Filename: p3dHost.cxx
|
||||
// Created by: drose (21Aug09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "p3dHost.h"
|
||||
#include "p3dInstanceManager.h"
|
||||
#include "p3dPackage.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DHost::Constructor
|
||||
// Access: Private
|
||||
// Description: Use P3DInstanceManager::get_host() to construct a new
|
||||
// P3DHost.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DHost::
|
||||
P3DHost(P3DInstanceManager *inst_mgr, const string &host_url) :
|
||||
_host_url(host_url)
|
||||
{
|
||||
_host_dir = inst_mgr->get_root_dir();
|
||||
_host_dir += "/host"; // TODO.
|
||||
|
||||
// Ensure that the download URL ends with a slash.
|
||||
_host_url_prefix = _host_url;
|
||||
if (!_host_url_prefix.empty() && _host_url_prefix[_host_url_prefix.size() - 1] != '/') {
|
||||
_host_url_prefix += "/";
|
||||
}
|
||||
|
||||
_xcontents = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DHost::Destructor
|
||||
// Access: Private
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DHost::
|
||||
~P3DHost() {
|
||||
if (_xcontents != NULL) {
|
||||
delete _xcontents;
|
||||
}
|
||||
|
||||
Packages::iterator pi;
|
||||
for (pi = _packages.begin(); pi != _packages.end(); ++pi) {
|
||||
delete (*pi).second;
|
||||
}
|
||||
_packages.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DHost::read_contents_file
|
||||
// Access: Public
|
||||
// Description: Reads the contents.xml file in the indicated
|
||||
// filename. On success, copies the contents.xml file
|
||||
// into the standard location (if it's not there
|
||||
// already).
|
||||
//
|
||||
// Returns true on success, false on failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DHost::
|
||||
read_contents_file(const string &contents_filename) {
|
||||
TiXmlDocument doc(contents_filename.c_str());
|
||||
if (!doc.LoadFile()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TiXmlElement *xcontents = doc.FirstChildElement("contents");
|
||||
if (xcontents == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_xcontents != NULL) {
|
||||
delete _xcontents;
|
||||
}
|
||||
_xcontents = (TiXmlElement *)xcontents->Clone();
|
||||
|
||||
string standard_filename = _host_dir + "/contents.xml";
|
||||
if (standardize_filename(standard_filename) !=
|
||||
standardize_filename(contents_filename)) {
|
||||
copy_file(contents_filename, standard_filename);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DHost::get_package
|
||||
// Access: Public
|
||||
// Description: Returns a (possibly shared) pointer to the indicated
|
||||
// package.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DPackage *P3DHost::
|
||||
get_package(const string &package_name, const string &package_version) {
|
||||
string key = package_name + "_" + package_version;
|
||||
Packages::iterator pi = _packages.find(key);
|
||||
if (pi != _packages.end()) {
|
||||
return (*pi).second;
|
||||
}
|
||||
|
||||
P3DPackage *package =
|
||||
new P3DPackage(this, package_name, package_version);
|
||||
bool inserted = _packages.insert(Packages::value_type(key, package)).second;
|
||||
assert(inserted);
|
||||
|
||||
return package;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DHost::get_package_desc_file
|
||||
// Access: Public
|
||||
// Description: Fills the indicated FileSpec with the hash
|
||||
// information for the package's desc file, and also
|
||||
// determines the package's platform. Returns true if
|
||||
// successful, false if the package is unknown. This
|
||||
// requires has_contents_file() to return true in order
|
||||
// to be successful.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DHost::
|
||||
get_package_desc_file(FileSpec &desc_file, // out
|
||||
string &package_platform, // out
|
||||
const string &package_name, // in
|
||||
const string &package_version) { // in
|
||||
if (_xcontents == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
|
||||
// Scan the contents data for the indicated package. First, we look
|
||||
// for a platform-specific version.
|
||||
TiXmlElement *xpackage = _xcontents->FirstChildElement("package");
|
||||
while (xpackage != NULL) {
|
||||
const char *name = xpackage->Attribute("name");
|
||||
const char *platform = xpackage->Attribute("platform");
|
||||
const char *version = xpackage->Attribute("version");
|
||||
if (name != NULL && platform != NULL && version != NULL &&
|
||||
package_name == name &&
|
||||
inst_mgr->get_platform() == platform &&
|
||||
package_version == version) {
|
||||
// Here's the matching package definition.
|
||||
desc_file.load_xml(xpackage);
|
||||
package_platform = platform;
|
||||
return true;
|
||||
}
|
||||
|
||||
xpackage = xpackage->NextSiblingElement("package");
|
||||
}
|
||||
|
||||
// Look again, this time looking for a non-platform-specific version.
|
||||
xpackage = _xcontents->FirstChildElement("package");
|
||||
while (xpackage != NULL) {
|
||||
const char *name = xpackage->Attribute("name");
|
||||
const char *platform = xpackage->Attribute("platform");
|
||||
const char *version = xpackage->Attribute("version");
|
||||
if (platform == NULL) {
|
||||
platform = "";
|
||||
}
|
||||
if (name != NULL && version != NULL &&
|
||||
package_name == name &&
|
||||
*platform == '\0' &&
|
||||
package_version == version) {
|
||||
// Here's the matching package definition.
|
||||
desc_file.load_xml(xpackage);
|
||||
package_platform = platform;
|
||||
return true;
|
||||
}
|
||||
|
||||
xpackage = xpackage->NextSiblingElement("package");
|
||||
}
|
||||
|
||||
// Couldn't find the named package.
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DHost::standardize_filename
|
||||
// Access: Private, Static
|
||||
// Description: Attempts to change the filename into some standard
|
||||
// form for comparison with other filenames. On a
|
||||
// case-insensitive filesystem, this converts the
|
||||
// filename to lowercase. On Windows, it further
|
||||
// replaces forward slashes with backslashes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string P3DHost::
|
||||
standardize_filename(const string &filename) {
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
string new_filename;
|
||||
for (string::const_iterator si = filename.begin();
|
||||
si != filename.end();
|
||||
++si) {
|
||||
char ch = *si;
|
||||
#ifdef _WIN32
|
||||
if (ch == '/') {
|
||||
ch = '\\';
|
||||
}
|
||||
#endif // _WIN32
|
||||
new_filename += tolower(ch);
|
||||
}
|
||||
return new_filename;
|
||||
#else // _WIN32 || __APPLE__
|
||||
return filename;
|
||||
#endif // _WIN32 || __APPLE__
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DHost::copy_file
|
||||
// Access: Private, Static
|
||||
// Description: Copies the data in the file named by from_filename
|
||||
// into the file named by to_filename.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DHost::
|
||||
copy_file(const string &from_filename, const string &to_filename) {
|
||||
ifstream in(from_filename.c_str(), ios::in | ios::binary);
|
||||
|
||||
// Copy to a temporary file first, in case (a) the filenames
|
||||
// actually refer to the same file, or (b) in case we have different
|
||||
// processes writing to the same file, and (c) to prevent
|
||||
// partially overwriting the file should something go wrong.
|
||||
ostringstream strm;
|
||||
strm << to_filename << ".t";
|
||||
#ifdef _WIN32
|
||||
strm << GetCurrentProcessId() << "_" << GetCurrentThreadId();
|
||||
#else
|
||||
strm << getpid();
|
||||
#endif
|
||||
string temp_filename = strm.str();
|
||||
ofstream out(temp_filename.c_str(), ios::out | ios::binary);
|
||||
|
||||
static const size_t buffer_size = 4096;
|
||||
char buffer[buffer_size];
|
||||
|
||||
in.read(buffer, buffer_size);
|
||||
size_t count = in.gcount();
|
||||
while (count != 0) {
|
||||
out.write(buffer, count);
|
||||
if (out.fail()) {
|
||||
unlink(temp_filename.c_str());
|
||||
return false;
|
||||
}
|
||||
in.read(buffer, buffer_size);
|
||||
count = in.gcount();
|
||||
}
|
||||
out.close();
|
||||
|
||||
if (!in.eof()) {
|
||||
unlink(temp_filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rename(temp_filename.c_str(), to_filename.c_str()) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
unlink(temp_filename.c_str());
|
||||
return false;
|
||||
}
|
71
direct/src/plugin/p3dHost.h
Normal file
71
direct/src/plugin/p3dHost.h
Normal file
@ -0,0 +1,71 @@
|
||||
// Filename: p3dHost.h
|
||||
// Created by: drose (21Aug09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef P3DHOST_H
|
||||
#define P3DHOST_H
|
||||
|
||||
#include "p3d_plugin_common.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
class FileSpec;
|
||||
class P3DInstanceManager;
|
||||
class P3DPackage;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : P3DHost
|
||||
// Description : Represents a particular download host serving up
|
||||
// Panda3D packages.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class P3DHost {
|
||||
private:
|
||||
P3DHost(P3DInstanceManager *inst_mgr, const string &host_url);
|
||||
~P3DHost();
|
||||
|
||||
public:
|
||||
inline const string &get_host_dir() const;
|
||||
inline const string &get_host_url() const;
|
||||
inline const string &get_host_url_prefix() const;
|
||||
inline const string &get_descriptive_name() const;
|
||||
|
||||
inline bool has_contents_file() const;
|
||||
bool read_contents_file(const string &contents_filename);
|
||||
|
||||
P3DPackage *get_package(const string &package_name,
|
||||
const string &package_version);
|
||||
bool get_package_desc_file(FileSpec &desc_file,
|
||||
string &package_platform,
|
||||
const string &package_name,
|
||||
const string &package_version);
|
||||
|
||||
private:
|
||||
static string standardize_filename(const string &filename);
|
||||
static bool copy_file(const string &from_filename, const string &to_filename);
|
||||
|
||||
private:
|
||||
string _host_dir;
|
||||
string _host_url;
|
||||
string _host_url_prefix;
|
||||
string _descriptive_name;
|
||||
TiXmlElement *_xcontents;
|
||||
|
||||
typedef map<string, P3DPackage *> Packages;
|
||||
Packages _packages;
|
||||
|
||||
friend class P3DInstanceManager;
|
||||
};
|
||||
|
||||
#include "p3dHost.I"
|
||||
|
||||
#endif
|
@ -884,12 +884,14 @@ scan_app_desc_file(TiXmlDocument *doc) {
|
||||
TiXmlElement *xrequires = xpackage->FirstChildElement("requires");
|
||||
while (xrequires != NULL) {
|
||||
const char *name = xrequires->Attribute("name");
|
||||
if (name != NULL) {
|
||||
const char *host_url = xrequires->Attribute("host");
|
||||
if (name != NULL && host_url != NULL) {
|
||||
const char *version = xrequires->Attribute("version");
|
||||
if (version == NULL) {
|
||||
version = "";
|
||||
}
|
||||
P3DPackage *package = inst_mgr->get_package(name, version);
|
||||
P3DHost *host = inst_mgr->get_host(host_url);
|
||||
P3DPackage *package = host->get_package(name, version);
|
||||
add_package(package);
|
||||
}
|
||||
|
||||
@ -1177,9 +1179,10 @@ make_splash_window() {
|
||||
if (!_fparams.has_token("splash_img")) {
|
||||
// No specific splash image is specified; get the default splash
|
||||
// image.
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
splash_image_url = inst_mgr->get_download_url();
|
||||
splash_image_url += "coreapi/splash.jpg";
|
||||
if (_panda3d != NULL) {
|
||||
splash_image_url = _panda3d->get_host()->get_host_url_prefix();
|
||||
splash_image_url += "coreapi/splash.jpg";
|
||||
}
|
||||
}
|
||||
|
||||
if (splash_image_url.empty()) {
|
||||
|
@ -36,18 +36,6 @@ get_root_dir() const {
|
||||
return _root_dir;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::get_download_url
|
||||
// Access: Public
|
||||
// Description: Returns the URL of the download server. All
|
||||
// downloadable files will be retrieved from various
|
||||
// subdirectories of this URL root.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline const string &P3DInstanceManager::
|
||||
get_download_url() const {
|
||||
return _download_url;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::get_platform
|
||||
// Access: Public
|
||||
@ -74,17 +62,6 @@ get_log_directory() const {
|
||||
return _log_directory;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::has_contents_file
|
||||
// Access: Public
|
||||
// Description: Returns true if a contents.xml file has been
|
||||
// successfully read, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline bool P3DInstanceManager::
|
||||
has_contents_file() const {
|
||||
return (_xcontents != NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::get_num_instances
|
||||
// Access: Public
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include "p3dInstanceManager.h"
|
||||
#include "p3dInstance.h"
|
||||
#include "p3dSession.h"
|
||||
#include "p3dPackage.h"
|
||||
#include "p3dHost.h"
|
||||
#include "p3d_plugin_config.h"
|
||||
#include "p3dWinSplashWindow.h"
|
||||
#include "p3dUndefinedObject.h"
|
||||
@ -51,7 +51,6 @@ P3DInstanceManager() {
|
||||
_is_initialized = false;
|
||||
_next_temp_filename_counter = 0;
|
||||
_unique_id = 0;
|
||||
_xcontents = NULL;
|
||||
|
||||
_notify_thread_continue = false;
|
||||
_started_notify_thread = false;
|
||||
@ -103,13 +102,15 @@ P3DInstanceManager::
|
||||
sigaction(SIGPIPE, &_old_sigpipe, NULL);
|
||||
#endif // _WIN32
|
||||
|
||||
if (_xcontents != NULL) {
|
||||
delete _xcontents;
|
||||
}
|
||||
|
||||
assert(_instances.empty());
|
||||
assert(_sessions.empty());
|
||||
|
||||
Hosts::iterator hi;
|
||||
for (hi = _hosts.begin(); hi != _hosts.end(); ++hi) {
|
||||
delete (*hi).second;
|
||||
}
|
||||
_hosts.clear();
|
||||
|
||||
// Delete any remaining temporary files.
|
||||
TempFilenames::iterator ti;
|
||||
for (ti = _temp_filenames.begin(); ti != _temp_filenames.end(); ++ti) {
|
||||
@ -145,7 +146,7 @@ P3DInstanceManager::
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::initialize
|
||||
// Access: Public
|
||||
// Description: Called by the host at application startup. It
|
||||
// Description: Called by the plugin host at application startup. It
|
||||
// returns true if the DLL is successfully initialized,
|
||||
// false if it should be immediately shut down and
|
||||
// redownloaded.
|
||||
@ -156,12 +157,7 @@ initialize(const string &contents_filename, const string &download_url,
|
||||
const string &log_basename) {
|
||||
|
||||
_root_dir = find_root_dir();
|
||||
_download_url = download_url;
|
||||
#ifdef P3D_PLUGIN_DOWNLOAD
|
||||
if (_download_url.empty()) {
|
||||
_download_url = P3D_PLUGIN_DOWNLOAD;
|
||||
}
|
||||
#endif
|
||||
|
||||
_platform = platform;
|
||||
if (_platform.empty()) {
|
||||
_platform = DTOOL_PLATFORM;
|
||||
@ -197,7 +193,7 @@ initialize(const string &contents_filename, const string &download_url,
|
||||
}
|
||||
delete[] buffer_2;
|
||||
|
||||
// Also make sure the directory actually exists.
|
||||
// And make sure the directory actually exists.
|
||||
mkdir_complete(_temp_directory, nout);
|
||||
|
||||
#else
|
||||
@ -216,11 +212,6 @@ initialize(const string &contents_filename, const string &download_url,
|
||||
}
|
||||
#endif
|
||||
|
||||
// Ensure that the download URL ends with a slash.
|
||||
if (!_download_url.empty() && _download_url[_download_url.size() - 1] != '/') {
|
||||
_download_url += "/";
|
||||
}
|
||||
|
||||
// Ensure that the temp directory ends with a slash.
|
||||
if (!_temp_directory.empty() && _temp_directory[_temp_directory.size() - 1] != '/') {
|
||||
#ifdef _WIN32
|
||||
@ -251,8 +242,6 @@ initialize(const string &contents_filename, const string &download_url,
|
||||
}
|
||||
|
||||
nout << "_root_dir = " << _root_dir
|
||||
<< ", contents = " << contents_filename
|
||||
<< ", download = " << _download_url
|
||||
<< ", platform = " << _platform
|
||||
<< "\n";
|
||||
|
||||
@ -263,9 +252,11 @@ initialize(const string &contents_filename, const string &download_url,
|
||||
|
||||
_is_initialized = true;
|
||||
|
||||
// Attempt to read the supplied contents.xml file.
|
||||
if (!contents_filename.empty()) {
|
||||
if (!read_contents_file(contents_filename)) {
|
||||
if (!download_url.empty() && !contents_filename.empty()) {
|
||||
// Attempt to pre-read the supplied contents.xml file, to avoid an
|
||||
// unnecessary download later.
|
||||
P3DHost *host = get_host(download_url);
|
||||
if (!host->read_contents_file(contents_filename)) {
|
||||
nout << "Couldn't read " << contents_filename << "\n";
|
||||
}
|
||||
}
|
||||
@ -273,42 +264,6 @@ initialize(const string &contents_filename, const string &download_url,
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::read_contents_file
|
||||
// Access: Public
|
||||
// Description: Reads the contents.xml file in the indicated
|
||||
// filename. On success, copies the contents.xml file
|
||||
// into the standard location (if it's not there
|
||||
// already).
|
||||
//
|
||||
// Returns true on success, false on failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DInstanceManager::
|
||||
read_contents_file(const string &contents_filename) {
|
||||
TiXmlDocument doc(contents_filename.c_str());
|
||||
if (!doc.LoadFile()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TiXmlElement *xcontents = doc.FirstChildElement("contents");
|
||||
if (xcontents == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_xcontents != NULL) {
|
||||
delete _xcontents;
|
||||
}
|
||||
_xcontents = (TiXmlElement *)xcontents->Clone();
|
||||
|
||||
string standard_filename = _root_dir + "/contents.xml";
|
||||
if (standardize_filename(standard_filename) !=
|
||||
standardize_filename(contents_filename)) {
|
||||
copy_file(contents_filename, standard_filename);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::create_instance
|
||||
// Access: Public
|
||||
@ -473,67 +428,23 @@ wait_request() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::get_package
|
||||
// Function: P3DInstanceManager::get_host
|
||||
// Access: Public
|
||||
// Description: Returns a (possibly shared) pointer to the indicated
|
||||
// package.
|
||||
// download host.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DPackage *P3DInstanceManager::
|
||||
get_package(const string &package_name, const string &package_version) {
|
||||
string package_platform = get_platform();
|
||||
string key = package_name + "_" + package_platform + "_" + package_version;
|
||||
Packages::iterator pi = _packages.find(key);
|
||||
if (pi != _packages.end()) {
|
||||
P3DHost *P3DInstanceManager::
|
||||
get_host(const string &host_url) {
|
||||
Hosts::iterator pi = _hosts.find(host_url);
|
||||
if (pi != _hosts.end()) {
|
||||
return (*pi).second;
|
||||
}
|
||||
|
||||
P3DPackage *package =
|
||||
new P3DPackage(package_name, package_platform, package_version);
|
||||
bool inserted = _packages.insert(Packages::value_type(key, package)).second;
|
||||
P3DHost *host = new P3DHost(this, host_url);
|
||||
bool inserted = _hosts.insert(Hosts::value_type(host_url, host)).second;
|
||||
assert(inserted);
|
||||
|
||||
return package;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::get_package_desc_file
|
||||
// Access: Public
|
||||
// Description: Fills the indicated FileSpec with the hash
|
||||
// information for the package's desc file. Returns
|
||||
// true if successful, false if the package is unknown.
|
||||
// This requires has_contents_file() to return true in
|
||||
// order to be successful.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DInstanceManager::
|
||||
get_package_desc_file(FileSpec &desc_file,
|
||||
const string &package_name,
|
||||
const string &package_version) {
|
||||
if (_xcontents == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
string package_platform = get_platform();
|
||||
|
||||
// Scan the contents data for the indicated package.
|
||||
TiXmlElement *xpackage = _xcontents->FirstChildElement("package");
|
||||
while (xpackage != NULL) {
|
||||
const char *name = xpackage->Attribute("name");
|
||||
const char *platform = xpackage->Attribute("platform");
|
||||
const char *version = xpackage->Attribute("version");
|
||||
if (name != NULL && platform != NULL && version != NULL &&
|
||||
package_name == name &&
|
||||
package_platform == platform &&
|
||||
package_version == version) {
|
||||
// Here's the matching package definition.
|
||||
desc_file.load_xml(xpackage);
|
||||
return true;
|
||||
}
|
||||
|
||||
xpackage = xpackage->NextSiblingElement("package");
|
||||
}
|
||||
|
||||
// Couldn't find the named package.
|
||||
return false;
|
||||
return host;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -698,89 +609,6 @@ delete_global_ptr() {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::standardize_filename
|
||||
// Access: Private, Static
|
||||
// Description: Attempts to change the filename into some standard
|
||||
// form for comparison with other filenames. On a
|
||||
// case-insensitive filesystem, this converts the
|
||||
// filename to lowercase. On Windows, it further
|
||||
// replaces forward slashes with backslashes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string P3DInstanceManager::
|
||||
standardize_filename(const string &filename) {
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
string new_filename;
|
||||
for (string::const_iterator si = filename.begin();
|
||||
si != filename.end();
|
||||
++si) {
|
||||
char ch = *si;
|
||||
#ifdef _WIN32
|
||||
if (ch == '/') {
|
||||
ch = '\\';
|
||||
}
|
||||
#endif // _WIN32
|
||||
new_filename += tolower(ch);
|
||||
}
|
||||
return new_filename;
|
||||
#else // _WIN32 || __APPLE__
|
||||
return filename;
|
||||
#endif // _WIN32 || __APPLE__
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::copy_file
|
||||
// Access: Private, Static
|
||||
// Description: Copies the data in the file named by from_filename
|
||||
// into the file named by to_filename.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DInstanceManager::
|
||||
copy_file(const string &from_filename, const string &to_filename) {
|
||||
ifstream in(from_filename.c_str(), ios::in | ios::binary);
|
||||
|
||||
// Copy to a temporary file first, in case (a) the filenames
|
||||
// actually refer to the same file, or (b) in case we have different
|
||||
// processes writing to the same file, and (c) to prevent
|
||||
// partially overwriting the file should something go wrong.
|
||||
ostringstream strm;
|
||||
strm << to_filename << ".t";
|
||||
#ifdef _WIN32
|
||||
strm << GetCurrentProcessId() << "_" << GetCurrentThreadId();
|
||||
#else
|
||||
strm << getpid();
|
||||
#endif
|
||||
string temp_filename = strm.str();
|
||||
ofstream out(temp_filename.c_str(), ios::out | ios::binary);
|
||||
|
||||
static const size_t buffer_size = 4096;
|
||||
char buffer[buffer_size];
|
||||
|
||||
in.read(buffer, buffer_size);
|
||||
size_t count = in.gcount();
|
||||
while (count != 0) {
|
||||
out.write(buffer, count);
|
||||
if (out.fail()) {
|
||||
unlink(temp_filename.c_str());
|
||||
return false;
|
||||
}
|
||||
in.read(buffer, buffer_size);
|
||||
count = in.gcount();
|
||||
}
|
||||
out.close();
|
||||
|
||||
if (!in.eof()) {
|
||||
unlink(temp_filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rename(temp_filename.c_str(), to_filename.c_str()) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
unlink(temp_filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstanceManager::nt_thread_run
|
||||
// Access: Private
|
||||
@ -791,12 +619,12 @@ nt_thread_run() {
|
||||
// The notify thread exists because we need to be able to send
|
||||
// asynchronous notifications of request events. These request
|
||||
// events were detected in the various read threads associated with
|
||||
// each session, but we can't call back into the host space from the
|
||||
// read thread, since if the host immediately response to a callback
|
||||
// by calling back into the p3d_plugin space, now we have our read
|
||||
// thread doing stuff in here that's not related to the read thread.
|
||||
// Even worse, some of the things it might need to do might require
|
||||
// a separate read thread to be running!
|
||||
// each session, but we can't call back into the plugin host space
|
||||
// from the read thread, since if the host immediately response to a
|
||||
// callback by calling back into the p3d_plugin space, now we have
|
||||
// our read thread doing stuff in here that's not related to the
|
||||
// read thread. Even worse, some of the things it might need to do
|
||||
// might require a separate read thread to be running!
|
||||
|
||||
_notify_ready.acquire();
|
||||
while (_notify_thread_continue) {
|
||||
|
@ -28,7 +28,7 @@
|
||||
|
||||
class P3DInstance;
|
||||
class P3DSession;
|
||||
class P3DPackage;
|
||||
class P3DHost;
|
||||
class FileSpec;
|
||||
class TiXmlElement;
|
||||
|
||||
@ -52,13 +52,9 @@ public:
|
||||
inline bool is_initialized() const;
|
||||
|
||||
inline const string &get_root_dir() const;
|
||||
inline const string &get_download_url() const;
|
||||
inline const string &get_platform() const;
|
||||
inline const string &get_log_directory() const;
|
||||
|
||||
inline bool has_contents_file() const;
|
||||
bool read_contents_file(const string &contents_filename);
|
||||
|
||||
P3DInstance *
|
||||
create_instance(P3D_request_ready_func *func,
|
||||
const P3D_token tokens[], size_t num_tokens,
|
||||
@ -74,11 +70,7 @@ public:
|
||||
P3DInstance *check_request();
|
||||
void wait_request();
|
||||
|
||||
P3DPackage *get_package(const string &package_name,
|
||||
const string &package_version);
|
||||
bool get_package_desc_file(FileSpec &desc_file,
|
||||
const string &package_name,
|
||||
const string &package_version);
|
||||
P3DHost *get_host(const string &host_url);
|
||||
|
||||
inline int get_num_instances() const;
|
||||
|
||||
@ -97,10 +89,6 @@ public:
|
||||
static P3DInstanceManager *get_global_ptr();
|
||||
static void delete_global_ptr();
|
||||
|
||||
private:
|
||||
static string standardize_filename(const string &filename);
|
||||
static bool copy_file(const string &from_filename, const string &to_filename);
|
||||
|
||||
private:
|
||||
// The notify thread. This thread runs only for the purpose of
|
||||
// generating asynchronous notifications of requests, to callers who
|
||||
@ -111,15 +99,12 @@ private:
|
||||
private:
|
||||
bool _is_initialized;
|
||||
string _root_dir;
|
||||
string _download_url;
|
||||
string _platform;
|
||||
string _log_directory;
|
||||
string _log_basename;
|
||||
string _log_pathname;
|
||||
string _temp_directory;
|
||||
|
||||
TiXmlElement *_xcontents;
|
||||
|
||||
P3D_object *_undefined_object;
|
||||
P3D_object *_none_object;
|
||||
P3D_object *_true_object;
|
||||
@ -131,8 +116,8 @@ private:
|
||||
typedef map<string, P3DSession *> Sessions;
|
||||
Sessions _sessions;
|
||||
|
||||
typedef map<string, P3DPackage *> Packages;
|
||||
Packages _packages;
|
||||
typedef map<string, P3DHost *> Hosts;
|
||||
Hosts _hosts;
|
||||
|
||||
typedef set<string> TempFilenames;
|
||||
TempFilenames _temp_filenames;
|
||||
|
@ -81,6 +81,17 @@ get_failed() const {
|
||||
return _failed;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPackage::get_host
|
||||
// Access: Public
|
||||
// Description: Returns the host server which offers this package for
|
||||
// download.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline P3DHost *P3DPackage::
|
||||
get_host() const {
|
||||
return _host;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPackage::get_package_dir
|
||||
// Access: Public
|
||||
|
@ -36,21 +36,14 @@ static const double extract_portion = 0.05;
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DPackage::
|
||||
P3DPackage(const string &package_name,
|
||||
const string &package_platform,
|
||||
P3DPackage(P3DHost *host, const string &package_name,
|
||||
const string &package_version) :
|
||||
_host(host),
|
||||
_package_name(package_name),
|
||||
_package_platform(package_platform),
|
||||
_package_version(package_version)
|
||||
{
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
|
||||
_package_fullname = _package_name;
|
||||
_package_dir = inst_mgr->get_root_dir() + string("/packages/") + _package_name;
|
||||
if (!_package_platform.empty()) {
|
||||
_package_fullname += string("_") + _package_platform;
|
||||
_package_dir += string("/") + _package_platform;
|
||||
}
|
||||
_package_dir = _host->get_host_dir() + string("/packages/") + _package_name;
|
||||
_package_fullname += string("_") + _package_version;
|
||||
_package_dir += string("/") + _package_version;
|
||||
|
||||
@ -169,16 +162,14 @@ begin_info_download() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPackage::
|
||||
download_contents_file() {
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
|
||||
if (inst_mgr->has_contents_file()) {
|
||||
if (_host->has_contents_file()) {
|
||||
// We've already got a contents.xml file; go straight to the
|
||||
// package desc file.
|
||||
download_desc_file();
|
||||
return;
|
||||
}
|
||||
|
||||
string url = inst_mgr->get_download_url();
|
||||
string url = _host->get_host_url_prefix();
|
||||
url += "contents.xml";
|
||||
|
||||
// Download contents.xml to a temporary filename first, in case
|
||||
@ -196,15 +187,13 @@ download_contents_file() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPackage::
|
||||
contents_file_download_finished(bool success) {
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
|
||||
if (!inst_mgr->has_contents_file()) {
|
||||
if (!success || !inst_mgr->read_contents_file(_temp_contents_file->get_filename())) {
|
||||
if (!_host->has_contents_file()) {
|
||||
if (!success || !_host->read_contents_file(_temp_contents_file->get_filename())) {
|
||||
nout << "Couldn't read " << *_temp_contents_file << "\n";
|
||||
|
||||
// Maybe we can read an already-downloaded contents.xml file.
|
||||
string standard_filename = inst_mgr->get_root_dir() + "/contents.xml";
|
||||
if (!inst_mgr->read_contents_file(standard_filename)) {
|
||||
string standard_filename = _host->get_host_dir() + "/contents.xml";
|
||||
if (!_host->read_contents_file(standard_filename)) {
|
||||
// Couldn't even read that. Fail.
|
||||
report_done(false);
|
||||
delete _temp_contents_file;
|
||||
@ -225,27 +214,31 @@ contents_file_download_finished(bool success) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPackage::download_desc_file
|
||||
// Access: Private
|
||||
// Description: Starts downloading the desc file for the package.
|
||||
// Description: Starts downloading the desc file for the package, if
|
||||
// it's needed; or read to local version if it's fresh
|
||||
// enough.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPackage::
|
||||
download_desc_file() {
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
|
||||
// Attempt to check the desc file for freshness. If it already
|
||||
// exists, and is consistent with the server contents file, we don't
|
||||
// need to re-download it.
|
||||
string root_dir = inst_mgr->get_root_dir() + "/packages";
|
||||
FileSpec desc_file;
|
||||
if (!inst_mgr->get_package_desc_file(desc_file, _package_name, _package_version)) {
|
||||
if (!_host->get_package_desc_file(desc_file, _package_platform,
|
||||
_package_name, _package_version)) {
|
||||
nout << "Couldn't find package " << _package_fullname
|
||||
<< " in contents file.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
} else if (desc_file.get_pathname(root_dir) != _desc_file_pathname) {
|
||||
nout << "Wrong pathname for desc file: "
|
||||
<< desc_file.get_pathname(root_dir)
|
||||
<< " instead of " << _desc_file_pathname << "\n";
|
||||
// The desc file might have a different path on the host server than
|
||||
// it has locally, because we strip out the platform locally.
|
||||
// Adjust desc_file to point to the local file.
|
||||
string url_filename = desc_file.get_filename();
|
||||
desc_file.set_filename(_desc_file_basename);
|
||||
assert (desc_file.get_pathname(_package_dir) == _desc_file_pathname);
|
||||
|
||||
} else if (!desc_file.full_verify(root_dir)) {
|
||||
if (!desc_file.full_verify(_package_dir)) {
|
||||
nout << _desc_file_pathname << " is stale.\n";
|
||||
|
||||
} else {
|
||||
@ -258,13 +251,8 @@ download_desc_file() {
|
||||
}
|
||||
|
||||
// The desc file is not current. Go download it.
|
||||
string url = inst_mgr->get_download_url();
|
||||
url += _package_name;
|
||||
if (!_package_platform.empty()) {
|
||||
url += "/" + _package_platform;
|
||||
}
|
||||
url += "/" + _package_version;
|
||||
url += "/" + _desc_file_basename;
|
||||
string url = _host->get_host_url_prefix();
|
||||
url += url_filename;
|
||||
|
||||
start_download(DT_desc_file, url, _desc_file_pathname, false);
|
||||
}
|
||||
@ -415,8 +403,7 @@ begin_data_download() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPackage::
|
||||
download_compressed_archive(bool allow_partial) {
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
string url = inst_mgr->get_download_url();
|
||||
string url = _host->get_host_url_prefix();
|
||||
url += _package_name;
|
||||
if (!_package_platform.empty()) {
|
||||
url += "/" + _package_platform;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "fileSpec.h"
|
||||
#include "get_tinyxml.h"
|
||||
|
||||
class P3DHost;
|
||||
class P3DInstance;
|
||||
class P3DTemporaryFile;
|
||||
|
||||
@ -31,23 +32,26 @@ class P3DTemporaryFile;
|
||||
// runtime, which consists of a bunch of dll's
|
||||
// downloaded in a single tar file, is a package.
|
||||
//
|
||||
// The plugin is responsible for managing these packages
|
||||
// on disk, downloading new versions when needed, and
|
||||
// removing stale versions to limit disk space waste.
|
||||
// The core API is responsible for managing these
|
||||
// packages on disk, downloading new versions when
|
||||
// needed, and removing stale versions to limit disk
|
||||
// space waste.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class P3DPackage {
|
||||
public:
|
||||
P3DPackage(const string &package_name,
|
||||
const string &package_platform,
|
||||
private:
|
||||
P3DPackage(P3DHost *host,
|
||||
const string &package_name,
|
||||
const string &package_version);
|
||||
~P3DPackage();
|
||||
|
||||
public:
|
||||
inline bool get_info_ready() const;
|
||||
inline size_t get_download_size() const;
|
||||
|
||||
inline void activate_download();
|
||||
inline bool get_ready() const;
|
||||
inline bool get_failed() const;
|
||||
inline P3DHost *get_host() const;
|
||||
inline const string &get_package_dir() const;
|
||||
inline const string &get_package_name() const;
|
||||
inline const string &get_package_version() const;
|
||||
@ -101,6 +105,8 @@ private:
|
||||
bool is_extractable(const string &filename) const;
|
||||
|
||||
private:
|
||||
P3DHost *_host;
|
||||
|
||||
string _package_name;
|
||||
string _package_version;
|
||||
string _package_platform;
|
||||
@ -132,6 +138,8 @@ private:
|
||||
|
||||
friend class Download;
|
||||
friend class P3DMultifileReader;
|
||||
|
||||
friend class P3DHost;
|
||||
};
|
||||
|
||||
#include "p3dPackage.I"
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
// There is only one P3DPythonRun object in any given process space.
|
||||
// Makes the statics easier to deal with, and we don't need multiple
|
||||
// instances of this think.
|
||||
// instances of this thing.
|
||||
P3DPythonRun *P3DPythonRun::_global_ptr = NULL;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "p3dFileDownload.cxx"
|
||||
#include "p3dFileParams.cxx"
|
||||
#include "p3dFloatObject.cxx"
|
||||
#include "p3dHost.cxx"
|
||||
#include "p3dInstance.cxx"
|
||||
#include "p3dInstanceManager.cxx"
|
||||
#include "p3dIntObject.cxx"
|
||||
|
@ -6,10 +6,9 @@
|
||||
/********************************** DO NOT EDIT ****************************/
|
||||
|
||||
/* The URL that is the root of the download server that this plugin
|
||||
should contact. The nppanda3d.dll file should be found at this
|
||||
location; as well as the contents.xml file that defines where the
|
||||
various Panda3D packages will be found. */
|
||||
#$[]define P3D_PLUGIN_DOWNLOAD "$[P3D_PLUGIN_DOWNLOAD]$[if $[notdir $[P3D_PLUGIN_DOWNLOAD]],/]"
|
||||
should contact. The contents.xml file that defines this particular
|
||||
"coreapi" package should be found at this location. */
|
||||
#$[]define PANDA_PACKAGE_HOST_URL "$[PANDA_PACKAGE_HOST_URL]"
|
||||
|
||||
/* The filename(s) to generate output to when the plugin is running.
|
||||
For debugging purposes only. */
|
||||
|
@ -108,7 +108,7 @@ void PPInstance::
|
||||
begin() {
|
||||
if (!is_plugin_loaded()) {
|
||||
// Go download the contents file, so we can download the core DLL.
|
||||
string url = P3D_PLUGIN_DOWNLOAD;
|
||||
string url = PANDA_PACKAGE_HOST_URL;
|
||||
if (!url.empty() && url[url.length() - 1] != '/') {
|
||||
url += '/';
|
||||
}
|
||||
@ -837,7 +837,7 @@ get_core_api(TiXmlElement *xplugin) {
|
||||
|
||||
} else {
|
||||
// The DLL file needs to be downloaded. Go get it.
|
||||
string url = P3D_PLUGIN_DOWNLOAD;
|
||||
string url = PANDA_PACKAGE_HOST_URL;
|
||||
if (!url.empty() && url[url.length() - 1] != '/') {
|
||||
url += '/';
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ run(int argc, char *argv[]) {
|
||||
const char *optstr = "+mu:p:ft:s:o:l:h";
|
||||
|
||||
bool allow_multiple = false;
|
||||
string download_url = P3D_PLUGIN_DOWNLOAD;
|
||||
string download_url = PANDA_PACKAGE_HOST_URL;
|
||||
string this_platform = DTOOL_PLATFORM;
|
||||
bool force_download = false;
|
||||
|
||||
@ -752,7 +752,7 @@ usage() {
|
||||
|
||||
<< " -u url\n"
|
||||
<< " Specify the URL of the Panda3D download server. The default is\n"
|
||||
<< " \"" << P3D_PLUGIN_DOWNLOAD << "\" .\n\n"
|
||||
<< " \"" << PANDA_PACKAGE_HOST_URL << "\" .\n\n"
|
||||
|
||||
<< " -p platform\n"
|
||||
<< " Specify the platform to masquerade as. The default is \""
|
||||
|
@ -133,8 +133,9 @@ class Packager:
|
||||
def __init__(self, packageName, packager):
|
||||
self.packageName = packageName
|
||||
self.packager = packager
|
||||
self.version = None
|
||||
self.platform = None
|
||||
self.version = None
|
||||
self.host = None
|
||||
self.p3dApplication = False
|
||||
self.compressionLevel = 0
|
||||
self.importedMapsDir = 'imported_maps'
|
||||
@ -672,6 +673,7 @@ class Packager:
|
||||
xrequires.SetAttribute('name', package.packageName)
|
||||
if package.version:
|
||||
xrequires.SetAttribute('version', package.version)
|
||||
xrequires.SetAttribute('host', package.host)
|
||||
xpackage.InsertEndChild(xrequires)
|
||||
|
||||
doc.InsertEndChild(xpackage)
|
||||
@ -699,6 +701,9 @@ class Packager:
|
||||
raise PackagerError, message
|
||||
|
||||
def writeDescFile(self):
|
||||
""" Makes the package.xml file that describes the package
|
||||
and its contents, for download. """
|
||||
|
||||
packageDescFullpath = Filename(self.packager.installDir, self.packageDesc)
|
||||
doc = TiXmlDocument(packageDescFullpath.toOsSpecific())
|
||||
decl = TiXmlDeclaration("1.0", "utf-8", "")
|
||||
@ -724,6 +729,7 @@ class Packager:
|
||||
xrequires.SetAttribute('platform', package.platform)
|
||||
if package.version:
|
||||
xrequires.SetAttribute('version', package.version)
|
||||
xrequires.SetAttribute('host', package.host)
|
||||
xpackage.InsertEndChild(xrequires)
|
||||
|
||||
xuncompressedArchive = self.getFileSpec(
|
||||
@ -743,6 +749,10 @@ class Packager:
|
||||
doc.SaveFile()
|
||||
|
||||
def writeImportDescFile(self):
|
||||
""" Makes the package_import.xml file that describes the
|
||||
package and its contents, for other packages and
|
||||
applications that may wish to "require" this one. """
|
||||
|
||||
packageImportDescFullpath = Filename(self.packager.installDir, self.packageImportDesc)
|
||||
doc = TiXmlDocument(packageImportDescFullpath.toOsSpecific())
|
||||
decl = TiXmlDeclaration("1.0", "utf-8", "")
|
||||
@ -754,6 +764,7 @@ class Packager:
|
||||
xpackage.SetAttribute('platform', self.platform)
|
||||
if self.version:
|
||||
xpackage.SetAttribute('version', self.version)
|
||||
xpackage.SetAttribute('host', self.host)
|
||||
|
||||
for package in self.requires:
|
||||
xrequires = TiXmlElement('requires')
|
||||
@ -762,6 +773,7 @@ class Packager:
|
||||
xrequires.SetAttribute('platform', package.platform)
|
||||
if package.version:
|
||||
xrequires.SetAttribute('version', package.version)
|
||||
xrequires.SetAttribute('host', package.host)
|
||||
xpackage.InsertEndChild(xrequires)
|
||||
|
||||
self.components.sort()
|
||||
@ -785,6 +797,7 @@ class Packager:
|
||||
self.packageName = xpackage.Attribute('name')
|
||||
self.platform = xpackage.Attribute('platform')
|
||||
self.version = xpackage.Attribute('version')
|
||||
self.host = xpackage.Attribute('host')
|
||||
|
||||
self.requires = []
|
||||
xrequires = xpackage.FirstChildElement('requires')
|
||||
@ -792,8 +805,11 @@ class Packager:
|
||||
packageName = xrequires.Attribute('name')
|
||||
platform = xrequires.Attribute('platform')
|
||||
version = xrequires.Attribute('version')
|
||||
host = xrequires.Attribute('host')
|
||||
if packageName:
|
||||
package = self.packager.findPackage(packageName, platform = platform, version = version, requires = self.requires)
|
||||
package = self.packager.findPackage(
|
||||
packageName, platform = platform, version = version,
|
||||
host = host, requires = self.requires)
|
||||
if package:
|
||||
self.requires.append(package)
|
||||
xrequires = xrequires.NextSiblingElement('requires')
|
||||
@ -1012,9 +1028,12 @@ class Packager:
|
||||
self.installDir = None
|
||||
self.persistDir = None
|
||||
|
||||
# A search list of directories and/or URL's to search for
|
||||
# installed packages. We query it from a config variable
|
||||
# initially, but we may also be extending it at runtime.
|
||||
# The download URL at which these packages will eventually be
|
||||
# hosted. This may also be changed with the "host" command.
|
||||
self.host = PandaSystem.getPackageHostUrl()
|
||||
self.hostDescriptiveName = None
|
||||
|
||||
# A search list for previously-built local packages.
|
||||
self.installSearch = ConfigVariableSearchPath('pdef-path')
|
||||
|
||||
# The system PATH, for searching dll's and exe's.
|
||||
@ -1195,23 +1214,8 @@ class Packager:
|
||||
# We must have an actual install directory.
|
||||
assert(self.installDir)
|
||||
|
||||
## # If the persist dir names an empty or nonexistent directory,
|
||||
## # we will be generating a brand new publish with no previous
|
||||
## # patches.
|
||||
## self.persistDir.makeDir()
|
||||
|
||||
## # Within the persist dir, we make a temporary holding dir for
|
||||
## # generating multifiles.
|
||||
## self.mfTempDir = Filename(self.persistDir, Filename('mftemp/'))
|
||||
## self.mfTempDir.makeDir()
|
||||
|
||||
## # We also need a temporary holding dir for squeezing py files.
|
||||
## self.pyzTempDir = Filename(self.persistDir, Filename('pyz/'))
|
||||
## self.pyzTempDir.makeDir()
|
||||
|
||||
## # Change to the persist directory so the temp files will be
|
||||
## # created there
|
||||
## os.chdir(self.persistDir.toOsSpecific())
|
||||
if not PandaSystem.getPackageVersionString() or not PandaSystem.getPackageHostUrl():
|
||||
raise PackagerError, 'This script must be run using a version of Panda3D that has been built\nfor distribution. Try using ppackage.p3d or packp3d.p3d instead.'
|
||||
|
||||
def __expandVariable(self, line, p):
|
||||
""" Given that line[p] is a dollar sign beginning a variable
|
||||
@ -1441,6 +1445,32 @@ class Packager:
|
||||
value = ExecutionEnvironment.expandString(value.strip())
|
||||
ExecutionEnvironment.setEnvironmentVariable(variable, value)
|
||||
|
||||
def parse_host(self, words):
|
||||
"""
|
||||
host "url" ["descriptive name"]
|
||||
"""
|
||||
|
||||
hostDescriptiveName = None
|
||||
try:
|
||||
if len(words) == 2:
|
||||
command, host = words
|
||||
else:
|
||||
command, host, hostDescriptiveName = words
|
||||
except ValueError:
|
||||
raise ArgumentNumber
|
||||
|
||||
if self.currentPackage:
|
||||
self.currentPackage.host = host
|
||||
else:
|
||||
# Outside of a package, the "host" command specifies the
|
||||
# host for all future packages.
|
||||
self.host = host
|
||||
|
||||
# The descriptive name, if specified, is kept until the end,
|
||||
# where it may be passed to make_contents by ppackage.py.
|
||||
if hostDescriptiveName:
|
||||
self.hostDescriptiveName = hostDescriptiveName
|
||||
|
||||
def parse_model_path(self, words):
|
||||
"""
|
||||
model_path directory
|
||||
@ -1469,10 +1499,10 @@ class Packager:
|
||||
|
||||
def parse_begin_package(self, words):
|
||||
"""
|
||||
begin_package packageName [version=v]
|
||||
begin_package packageName [version=v] [host=host]
|
||||
"""
|
||||
|
||||
args = self.__parseArgs(words, ['version'])
|
||||
args = self.__parseArgs(words, ['version', 'host'])
|
||||
|
||||
try:
|
||||
command, packageName = words
|
||||
@ -1480,8 +1510,10 @@ class Packager:
|
||||
raise ArgumentNumber
|
||||
|
||||
version = args.get('version', None)
|
||||
host = args.get('host', None)
|
||||
|
||||
self.beginPackage(packageName, version = version, p3dApplication = False)
|
||||
self.beginPackage(packageName, version = version, host = host,
|
||||
p3dApplication = False)
|
||||
|
||||
def parse_end_package(self, words):
|
||||
"""
|
||||
@ -1539,10 +1571,10 @@ class Packager:
|
||||
|
||||
def parse_require(self, words):
|
||||
"""
|
||||
require packageName [version=v]
|
||||
require packageName [version=v] [host=url]
|
||||
"""
|
||||
|
||||
args = self.__parseArgs(words, ['version'])
|
||||
args = self.__parseArgs(words, ['version', 'host'])
|
||||
|
||||
try:
|
||||
command, packageName = words
|
||||
@ -1550,7 +1582,8 @@ class Packager:
|
||||
raise ArgumentError
|
||||
|
||||
version = args.get('version', None)
|
||||
self.require(packageName, version = version)
|
||||
host = args.get('host', None)
|
||||
self.require(packageName, version = version, host = host)
|
||||
|
||||
def parse_module(self, words):
|
||||
"""
|
||||
@ -1798,7 +1831,8 @@ class Packager:
|
||||
del words[-1]
|
||||
|
||||
|
||||
def beginPackage(self, packageName, version = None, p3dApplication = False):
|
||||
def beginPackage(self, packageName, version = None, host = None,
|
||||
p3dApplication = False):
|
||||
""" Begins a new package specification. packageName is the
|
||||
basename of the package. Follow this with a number of calls
|
||||
to file() etc., and close the package with endPackage(). """
|
||||
@ -1806,20 +1840,33 @@ class Packager:
|
||||
if self.currentPackage:
|
||||
raise PackagerError, 'unmatched end_package %s' % (self.currentPackage.packageName)
|
||||
|
||||
# A special case for the Panda3D package. We enforce that the
|
||||
# version number matches what we've been compiled with.
|
||||
if host is None and not p3dApplication:
|
||||
# Every package that doesn't specify otherwise uses the
|
||||
# current download host.
|
||||
host = self.host
|
||||
|
||||
# A special case when building the "panda3d" package. We
|
||||
# enforce that the version number matches what we've been
|
||||
# compiled with.
|
||||
if packageName == 'panda3d':
|
||||
if version is None:
|
||||
version = PandaSystem.getPackageVersionString()
|
||||
else:
|
||||
if version != PandaSystem.getPackageVersionString():
|
||||
message = 'mismatched Panda3D version: requested %s, but Panda3D is built as %s' % (version, PandaSystem.getPackageVersionString())
|
||||
raise PackageError, message
|
||||
if host is None:
|
||||
host = PandaSystem.getPackageHostUrl()
|
||||
|
||||
if version != PandaSystem.getPackageVersionString():
|
||||
message = 'mismatched Panda3D version: requested %s, but Panda3D is built as %s' % (version, PandaSystem.getPackageVersionString())
|
||||
raise PackageError, message
|
||||
|
||||
if host != PandaSystem.getPackageHostUrl():
|
||||
message = 'mismatched Panda3D host: requested %s, but Panda3D is built as %s' % (host, PandaSystem.getPackageHostUrl())
|
||||
raise PackageError, message
|
||||
|
||||
package = self.Package(packageName, self)
|
||||
self.currentPackage = package
|
||||
|
||||
package.version = version
|
||||
package.host = host
|
||||
package.p3dApplication = p3dApplication
|
||||
|
||||
if package.p3dApplication:
|
||||
@ -1855,7 +1902,7 @@ class Packager:
|
||||
self.currentPackage = None
|
||||
|
||||
def findPackage(self, packageName, platform = None, version = None,
|
||||
requires = None):
|
||||
host = None, requires = None):
|
||||
""" Searches for the named package from a previous publish
|
||||
operation along the install search path.
|
||||
|
||||
@ -1872,25 +1919,32 @@ class Packager:
|
||||
platform = self.platform
|
||||
|
||||
# Is it a package we already have resident?
|
||||
package = self.packages.get((packageName, platform, version), None)
|
||||
package = self.packages.get((packageName, platform, version, host), None)
|
||||
if package:
|
||||
return package
|
||||
|
||||
# Look on the searchlist.
|
||||
for dirname in self.installSearch.getDirectories():
|
||||
package = self.__scanPackageDir(dirname, packageName, platform, version, requires = requires)
|
||||
package = self.__scanPackageDir(dirname, packageName, platform, version, host, requires = requires)
|
||||
if not package:
|
||||
package = self.__scanPackageDir(dirname, packageName, None, version, requires = requires)
|
||||
package = self.__scanPackageDir(dirname, packageName, None, version, host, requires = requires)
|
||||
|
||||
if package:
|
||||
package = self.packages.setdefault((package.packageName, package.platform, package.version), package)
|
||||
self.packages[(packageName, platform, version)] = package
|
||||
return package
|
||||
break
|
||||
|
||||
if not package:
|
||||
# Query the indicated host.
|
||||
package = self.__findPackageOnHost(packageName, platform, version, host, requires = requires)
|
||||
|
||||
if package:
|
||||
package = self.packages.setdefault((package.packageName, package.platform, package.version, package.host), package)
|
||||
self.packages[(packageName, platform, version, host)] = package
|
||||
return package
|
||||
|
||||
return None
|
||||
|
||||
def __scanPackageDir(self, rootDir, packageName, platform, version,
|
||||
requires = None):
|
||||
host, requires = None):
|
||||
""" Scans a directory on disk, looking for *_import.xml files
|
||||
that match the indicated packageName and optional version. If a
|
||||
suitable xml file is found, reads it and returns the assocated
|
||||
@ -1917,6 +1971,9 @@ class Packager:
|
||||
packageDir = Filename(packageDir, '*')
|
||||
basename += '_%s' % ('*')
|
||||
|
||||
# Actually, the host means little for this search, since we're
|
||||
# only looking in a local directory at this point.
|
||||
|
||||
basename += '_import.xml'
|
||||
filename = Filename(packageDir, basename)
|
||||
filelist = glob.glob(filename.toOsSpecific())
|
||||
@ -1934,6 +1991,10 @@ class Packager:
|
||||
|
||||
return None
|
||||
|
||||
def __findPackageOnHost(self, packageName, platform, version, host, requires = None):
|
||||
# TODO.
|
||||
return None
|
||||
|
||||
def __sortPackageImportFilelist(self, filelist):
|
||||
""" Given a list of *_import.xml filenames, sorts them in
|
||||
reverse order by version, so that the highest-numbered
|
||||
@ -1968,7 +2029,8 @@ class Packager:
|
||||
while p < len(version) and version[p] in string.digits:
|
||||
w += version[p]
|
||||
p += 1
|
||||
words.append(int(w))
|
||||
if w:
|
||||
words.append(int(w))
|
||||
|
||||
return tuple(words)
|
||||
|
||||
@ -2024,7 +2086,7 @@ class Packager:
|
||||
|
||||
self.currentPackage.configs[variable] = value
|
||||
|
||||
def require(self, packageName, version = None):
|
||||
def require(self, packageName, version = None, host = None):
|
||||
""" Indicates a dependency on the named package, supplied as
|
||||
a name.
|
||||
|
||||
@ -2035,13 +2097,17 @@ class Packager:
|
||||
if not self.currentPackage:
|
||||
raise OutsideOfPackageError
|
||||
|
||||
# A special case for the Panda3D package. We enforce that the
|
||||
# version number matches what we've been compiled with.
|
||||
# A special case when requiring the "panda3d" package. We
|
||||
# supply the version number what we've been compiled with as a
|
||||
# default.
|
||||
if packageName == 'panda3d':
|
||||
if version is None:
|
||||
version = PandaSystem.getPackageVersionString()
|
||||
if host is None:
|
||||
host = PandaSystem.getPackageHostUrl()
|
||||
|
||||
package = self.findPackage(packageName, version = version, requires = self.currentPackage.requires)
|
||||
package = self.findPackage(packageName, version = version, host = host,
|
||||
requires = self.currentPackage.requires)
|
||||
if not package:
|
||||
message = 'Unknown package %s, version "%s"' % (packageName, version)
|
||||
raise PackagerError, message
|
||||
@ -2059,20 +2125,14 @@ class Packager:
|
||||
if not self.currentPackage:
|
||||
raise OutsideOfPackageError
|
||||
|
||||
# A special case for the Panda3D package. We enforce that the
|
||||
# version number matches what we've been compiled with.
|
||||
# A special case when requiring the "panda3d" package. We
|
||||
# complain if the version number doesn't match what we've been
|
||||
# compiled with.
|
||||
if package.packageName == 'panda3d':
|
||||
if package.version != PandaSystem.getPackageVersionString():
|
||||
if not PandaSystem.getPackageVersionString():
|
||||
# We haven't been compiled with any particular
|
||||
# version of Panda. This is a warning, not an
|
||||
# error.
|
||||
print "Warning: requiring panda3d version %s, which may or may not match the current build of Panda. Recommend that you use only the official Panda3D build for making distributable applications to ensure compatibility." % (package.version)
|
||||
else:
|
||||
# This particular version of Panda doesn't match
|
||||
# the requested version. Again, a warning, not an
|
||||
# error.
|
||||
print "Warning: requiring panda3d version %s, which does not match the current build of Panda, which is version %s." % (package, PandaSystem.getPackageVersionString())
|
||||
print "Warning: requiring panda3d version %s, which does not match the current build of Panda, which is version %s." % (package, PandaSystem.getPackageVersionString())
|
||||
elif package.host != PandaSystem.getPackageHostUrl():
|
||||
print "Warning: requiring panda3d host %s, which does not match the current build of Panda, which is host %s." % (package, PandaSystem.getPackageHostUrl())
|
||||
|
||||
self.currentPackage.requirePackage(package)
|
||||
|
||||
|
@ -12,17 +12,24 @@ make_contents.py [opts]
|
||||
|
||||
Options:
|
||||
|
||||
-d stage_dir
|
||||
-i install_dir
|
||||
The full path to a local directory that contains the
|
||||
ready-to-be-published files, as populated by one or more
|
||||
iterations of the ppackage script. It is the user's
|
||||
responsibility to copy this directory structure to a server.
|
||||
|
||||
Specify the staging directory. This is a temporary directory on
|
||||
the local machine that contains a copy of the web server
|
||||
contents. The default is the current directory.
|
||||
-n "host descriptive name"
|
||||
Specifies a descriptive name of the download server that will
|
||||
host these contents. This name may be presented to the user when
|
||||
managing installed packages. If this option is omitted, the name
|
||||
is unchanged from the previous pass.
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import getopt
|
||||
import os
|
||||
import types
|
||||
|
||||
try:
|
||||
import hashlib
|
||||
@ -56,6 +63,7 @@ class FileSpec:
|
||||
class ContentsMaker:
|
||||
def __init__(self):
|
||||
self.installDir = None
|
||||
self.hostDescriptiveName = None
|
||||
|
||||
def build(self):
|
||||
if not self.installDir:
|
||||
@ -67,20 +75,56 @@ class ContentsMaker:
|
||||
if not self.packages:
|
||||
raise ArgumentError, "No packages found."
|
||||
|
||||
# Now write the contents.xml file.
|
||||
contentsFileBasename = 'contents.xml'
|
||||
contentsFilePathname = os.path.join(self.installDir, contentsFileBasename)
|
||||
contentsLine = None
|
||||
if self.hostDescriptiveName is not None:
|
||||
if self.hostDescriptiveName:
|
||||
contentsLine = '<contents descriptive_name="%s">' % (
|
||||
self.quoteString(self.hostDescriptiveName))
|
||||
else:
|
||||
contentsLine = self.readContentsLine(contentsFilePathname)
|
||||
if not contentsLine:
|
||||
contentsLine = '<contents>'
|
||||
|
||||
# Now write the contents.xml file.
|
||||
f = open(contentsFilePathname, 'w')
|
||||
print >> f, '<?xml version="1.0" ?>'
|
||||
print >> f, '<?xml version="1.0" encoding="utf-8" ?>'
|
||||
print >> f, ''
|
||||
print >> f, '<contents>'
|
||||
print >> f, contentsLine
|
||||
for type, packageName, packagePlatform, packageVersion, file in self.packages:
|
||||
print >> f, ' <%s name="%s" platform="%s" version="%s" %s />' % (
|
||||
type, packageName, packagePlatform or '', packageVersion, file.getParams())
|
||||
print >> f, '</contents>'
|
||||
f.close()
|
||||
|
||||
def readContentsLine(self, contentsFilePathname):
|
||||
""" Reads the previous iteration of contents.xml to get the
|
||||
previous top-level contents line, which contains the
|
||||
hostDescriptiveName. """
|
||||
|
||||
try:
|
||||
f = open(contentsFilePathname, 'r')
|
||||
except OSError:
|
||||
return None
|
||||
|
||||
for line in f.readlines():
|
||||
if line.startswith('<contents'):
|
||||
return line.rstrip()
|
||||
|
||||
return None
|
||||
|
||||
def quoteString(self, str):
|
||||
""" Correctly quotes a string for embedding in the xml file. """
|
||||
if isinstance(str, types.UnicodeType):
|
||||
str = str.encode('utf-8')
|
||||
str = str.replace('&', '&')
|
||||
str = str.replace('"', '"')
|
||||
str = str.replace('\'', ''')
|
||||
str = str.replace('<', '<')
|
||||
str = str.replace('>', '>')
|
||||
return str
|
||||
|
||||
def scanDirectory(self):
|
||||
""" Walks through all the files in the stage directory and
|
||||
looks for the package directory xml files. """
|
||||
@ -139,13 +183,16 @@ class ContentsMaker:
|
||||
|
||||
|
||||
def makeContents(args):
|
||||
opts, args = getopt.getopt(args, 'd:h')
|
||||
opts, args = getopt.getopt(args, 'i:n:h')
|
||||
|
||||
cm = ContentsMaker()
|
||||
cm.installDir = '.'
|
||||
for option, value in opts:
|
||||
if option == '-d':
|
||||
if option == '-i':
|
||||
cm.installDir = value
|
||||
|
||||
elif option == '-n':
|
||||
cm.hostDescriptiveName = value
|
||||
|
||||
elif option == '-h':
|
||||
print __doc__
|
||||
|
@ -119,15 +119,21 @@ def makePackedApp(args):
|
||||
packager.installDir = appDir
|
||||
getModelPath().appendDirectory(root)
|
||||
|
||||
packager.setup()
|
||||
packager.beginPackage(appBase, p3dApplication = True)
|
||||
for requireName in requires:
|
||||
packager.require(requireName)
|
||||
|
||||
packager.dir(root)
|
||||
packager.mainModule(mainModule)
|
||||
|
||||
packager.endPackage(appBase, p3dApplication = True)
|
||||
try:
|
||||
packager.setup()
|
||||
packager.beginPackage(appBase, p3dApplication = True)
|
||||
for requireName in requires:
|
||||
packager.require(requireName)
|
||||
|
||||
packager.dir(root)
|
||||
packager.mainModule(mainModule)
|
||||
|
||||
packager.endPackage(appBase, p3dApplication = True)
|
||||
except Packager.PackagerError:
|
||||
# Just print the error message and exit gracefully.
|
||||
inst = sys.exc_info()[1]
|
||||
print inst.args[0]
|
||||
sys.exit(1)
|
||||
|
||||
def main(appRunner):
|
||||
""" This function is called when this module is invoked as
|
||||
|
@ -38,12 +38,13 @@ Options:
|
||||
ready-to-be-published files into. This directory structure may
|
||||
contain multiple different packages from multiple different
|
||||
invocations of this script. It is the user's responsibility to
|
||||
copy this directory structure to a web host where it may be
|
||||
downloaded by the client.
|
||||
copy this directory structure to a server, which will have the
|
||||
URL specified by -u, below.
|
||||
|
||||
-s search_dir
|
||||
Additional directories to search for previously-built packages.
|
||||
This option may be repeated as necessary.
|
||||
This option may be repeated as necessary. These directories may
|
||||
also be specified with the pdef-path Config.prc variable.
|
||||
|
||||
-d persist_dir
|
||||
The full path to a local directory that retains persistant state
|
||||
@ -54,6 +55,21 @@ Options:
|
||||
empty, patches will not be created for this publish; but the
|
||||
directory structure will be populated for the next publish.
|
||||
|
||||
-u host_url
|
||||
Specifies the URL to the download server that will eventually
|
||||
host these packages (that is, the public URL of the install
|
||||
directory). This may also be overridden with a "host" command
|
||||
appearing within the pdef file. This is used for packages only;
|
||||
it is ignored for p3d applications, which are not specific to a
|
||||
particular host.
|
||||
|
||||
-n "host descriptive name"
|
||||
Specifies a descriptive name of the download server named by -u.
|
||||
This name may be presented to the user when managing installed
|
||||
packages. This may also be overridden with a "host" command
|
||||
appearing within the pdef file. This information is written to
|
||||
the contents.xml file at the top of the install directory.
|
||||
|
||||
-p platform
|
||||
Specify the platform to masquerade as. The default is whatever
|
||||
platform Panda has been built for. It is probably unwise to set
|
||||
@ -82,7 +98,7 @@ def usage(code, msg = ''):
|
||||
packager = Packager.Packager()
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'i:s:d:p:Hh')
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'i:s:d:p:u:n:Hh')
|
||||
except getopt.error, msg:
|
||||
usage(1, msg)
|
||||
|
||||
@ -95,6 +111,10 @@ for opt, arg in opts:
|
||||
packager.persistDir = Filename.fromOsSpecific(arg)
|
||||
elif opt == '-p':
|
||||
packager.platform = arg
|
||||
elif opt == '-u':
|
||||
package.host = arg
|
||||
elif opt == '-n':
|
||||
package.hostDescriptiveName = arg
|
||||
|
||||
elif opt == '-h':
|
||||
usage(0)
|
||||
@ -117,8 +137,14 @@ if not packager.installDir:
|
||||
packager.installDir = Filename('install')
|
||||
packager.installSearch.prependDirectory(packager.installDir)
|
||||
|
||||
packager.setup()
|
||||
packages = packager.readPackageDef(packageDef)
|
||||
try:
|
||||
packager.setup()
|
||||
packages = packager.readPackageDef(packageDef)
|
||||
except Packager.PackagerError:
|
||||
# Just print the error message and exit gracefully.
|
||||
inst = sys.exc_info()[1]
|
||||
print inst.args[0]
|
||||
sys.exit(1)
|
||||
|
||||
# Look to see if we built any true packages, or if all of them were
|
||||
# p3d files.
|
||||
@ -133,5 +159,6 @@ if anyPackages:
|
||||
# the root of the install directory.
|
||||
cm = make_contents.ContentsMaker()
|
||||
cm.installDir = packager.installDir.toOsSpecific()
|
||||
cm.hostDescriptiveName = packager.hostDescriptiveName
|
||||
cm.build()
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user