Răsfoiți Sursa

some cleanup

David Rose 16 ani în urmă
părinte
comite
936ff2455e

+ 4 - 6
direct/src/plugin/p3dInstance.cxx

@@ -1155,7 +1155,7 @@ report_package_info_ready(P3DPackage *package) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DInstance::
 void P3DInstance::
 start_next_download() {
 start_next_download() {
-  while (_download_package_index < _downloading_packages.size()) {
+  while (_download_package_index < (int)_downloading_packages.size()) {
     P3DPackage *package = _downloading_packages[_download_package_index];
     P3DPackage *package = _downloading_packages[_download_package_index];
     if (package->get_failed()) {
     if (package->get_failed()) {
       // Too bad.  TODO: fail.
       // Too bad.  TODO: fail.
@@ -1211,12 +1211,10 @@ start_next_download() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DInstance::
 void P3DInstance::
 report_package_progress(P3DPackage *package, double progress) {
 report_package_progress(P3DPackage *package, double progress) {
-  if (_download_package_index >= _downloading_packages.size() ||
+  if (_download_package_index >= (int)_downloading_packages.size() ||
       package != _downloading_packages[_download_package_index]) {
       package != _downloading_packages[_download_package_index]) {
-    // Got a report from an unexpected package.
-    nout << "Got download progress report from " << package->get_package_name()
-         << ", not at download head (head is " << _download_package_index
-         << ")\n";
+    // Quietly ignore a download progress report from an unexpected
+    // package.
     return;
     return;
   }
   }
 
 

+ 0 - 1
direct/src/plugin/p3dInstanceManager.cxx

@@ -22,7 +22,6 @@
 #include "p3dNoneObject.h"
 #include "p3dNoneObject.h"
 #include "p3dBoolObject.h"
 #include "p3dBoolObject.h"
 #include "find_root_dir.h"
 #include "find_root_dir.h"
-#include "mkdir_complete.h"
 #include "fileSpec.h"
 #include "fileSpec.h"
 #include "get_tinyxml.h"
 #include "get_tinyxml.h"
 
 

+ 1 - 1
direct/src/plugin/p3dPackage.cxx

@@ -45,7 +45,7 @@ P3DPackage(const string &package_name,
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
 
 
   _package_fullname = _package_name;
   _package_fullname = _package_name;
-  _package_dir = inst_mgr->get_root_dir() + string("/") + _package_name;
+  _package_dir = inst_mgr->get_root_dir() + string("/packages/") + _package_name;
   if (!_package_platform.empty()) {
   if (!_package_platform.empty()) {
     _package_fullname += string("_") + _package_platform;
     _package_fullname += string("_") + _package_platform;
     _package_dir += string("/") + _package_platform;
     _package_dir += string("/") + _package_platform;

+ 52 - 10
direct/src/plugin/p3dSession.cxx

@@ -25,6 +25,9 @@
 #include "p3dConcreteSequence.h"
 #include "p3dConcreteSequence.h"
 #include "p3dConcreteStruct.h"
 #include "p3dConcreteStruct.h"
 #include "binaryXml.h"
 #include "binaryXml.h"
+#include "mkdir_complete.h"
+
+#include <ctype.h>
 
 
 #ifndef _WIN32
 #ifndef _WIN32
 #include <fcntl.h>
 #include <fcntl.h>
@@ -49,6 +52,7 @@ P3DSession(P3DInstance *inst) {
   _session_key = inst->get_session_key();
   _session_key = inst->get_session_key();
   _python_version = inst->get_python_version();
   _python_version = inst->get_python_version();
 
 
+  _start_dir = inst_mgr->get_root_dir() + "/start";
   _p3dpython_running = false;
   _p3dpython_running = false;
 
 
   _started_read_thread = false;
   _started_read_thread = false;
@@ -660,6 +664,28 @@ start_p3dpython(P3DInstance *inst) {
 
 
   _python_root_dir = inst->_panda3d->get_package_dir();
   _python_root_dir = inst->_panda3d->get_package_dir();
 
 
+  mkdir_complete(_start_dir, nout);
+
+  // Build up a search path that includes all of the required packages
+  // that have already been installed.
+  string search_path;
+  size_t pi = 0;
+  assert(pi < inst->_packages.size());
+  search_path = inst->_packages[pi]->get_package_dir();
+  ++pi;
+  while (pi < inst->_packages.size()) {
+#ifdef _WIN32
+    search_path += ';';
+#else
+    search_path += ':';
+#endif  // _WIN32
+
+    search_path += inst->_packages[pi]->get_package_dir();
+    ++pi;
+  }
+
+  nout << "Search path is " << search_path << "\n";
+
   string p3dpython = P3D_PLUGIN_P3DPYTHON;
   string p3dpython = P3D_PLUGIN_P3DPYTHON;
   if (p3dpython.empty()) {
   if (p3dpython.empty()) {
     p3dpython = _python_root_dir + "/p3dpython";
     p3dpython = _python_root_dir + "/p3dpython";
@@ -692,42 +718,58 @@ start_p3dpython(P3DInstance *inst) {
 
 
   // Define some new environment variables.
   // Define some new environment variables.
   env += "PATH=";
   env += "PATH=";
-  env += _python_root_dir;
+  env += search_path;
   env += '\0';
   env += '\0';
 
 
   env += "LD_LIBRARY_PATH=";
   env += "LD_LIBRARY_PATH=";
-  env += _python_root_dir;
+  env += search_path;
   env += '\0';
   env += '\0';
 
 
   env += "DYLD_LIBRARY_PATH=";
   env += "DYLD_LIBRARY_PATH=";
-  env += _python_root_dir;
+  env += search_path;
   env += '\0';
   env += '\0';
 
 
   env += "PYTHONPATH=";
   env += "PYTHONPATH=";
-  env += _python_root_dir;
+  env += search_path;
   env += '\0';
   env += '\0';
 
 
   env += "PYTHONHOME=";
   env += "PYTHONHOME=";
   env += _python_root_dir;
   env += _python_root_dir;
   env += '\0';
   env += '\0';
 
 
-  env += "PRC_DIR=";
-  env += _python_root_dir;
+  env += "PRC_PATH=";
+  env += search_path;
   env += '\0';
   env += '\0';
 
 
-  env += "PANDA_PRC_DIR=";
-  env += _python_root_dir;
+  env += "PANDA_PRC_PATH=";
+  env += search_path;
   env += '\0';
   env += '\0';
+    
+  // Define each package's root directory in an environment variable
+  // named after the package, for the convenience of the packages in
+  // setting up their config files.
+  for (size_t pi = 0; pi < inst->_packages.size(); ++pi) {
+    P3DPackage *package = inst->_packages[pi];
+    const string package_name = package->get_package_name();
+    for (string::const_iterator si = package_name.begin();
+         si != package_name.end();
+         ++si) {
+      env += toupper(*si);
+    }
+    env += string("_ROOT=");
+    env += package->get_package_dir();
+    env += '\0';
+  }
 
 
   nout << "Attempting to start python from " << p3dpython << "\n";
   nout << "Attempting to start python from " << p3dpython << "\n";
 #ifdef _WIN32
 #ifdef _WIN32
   _p3dpython_handle = win_create_process
   _p3dpython_handle = win_create_process
-    (p3dpython, _python_root_dir, env, _output_filename,
+    (p3dpython, _start_dir, env, _output_filename,
      _pipe_read, _pipe_write);
      _pipe_read, _pipe_write);
   bool started_p3dpython = (_p3dpython_handle != INVALID_HANDLE_VALUE);
   bool started_p3dpython = (_p3dpython_handle != INVALID_HANDLE_VALUE);
 #else
 #else
   _p3dpython_pid = posix_create_process
   _p3dpython_pid = posix_create_process
-    (p3dpython, _python_root_dir, env, _output_filename,
+    (p3dpython, _start_dir, env, _output_filename,
      _pipe_read, _pipe_write);
      _pipe_read, _pipe_write);
   bool started_p3dpython = (_p3dpython_pid > 0);
   bool started_p3dpython = (_p3dpython_pid > 0);
 #endif
 #endif

+ 1 - 0
direct/src/plugin/p3dSession.h

@@ -92,6 +92,7 @@ private:
   string _python_version;
   string _python_version;
   string _output_filename;
   string _output_filename;
   string _python_root_dir;
   string _python_root_dir;
+  string _start_dir;
 
 
   typedef map<int, P3DInstance *> Instances;
   typedef map<int, P3DInstance *> Instances;
   Instances _instances;
   Instances _instances;

+ 51 - 27
direct/src/plugin_standalone/panda3d.cxx

@@ -56,13 +56,17 @@ int Panda3D::
 run(int argc, char *argv[]) {
 run(int argc, char *argv[]) {
   extern char *optarg;
   extern char *optarg;
   extern int optind;
   extern int optind;
-  const char *optstr = "u:p:fl:t:s:o:h";
 
 
+  // We prefix a "+" sign to tell gnu getopt not to parse options
+  // following the first not-option parameter.  (These will be passed
+  // into the sub-process.)
+  const char *optstr = "+mu:p:ft:s:o:h";
+
+  bool allow_multiple = false;
   string download_url = P3D_PLUGIN_DOWNLOAD;
   string download_url = P3D_PLUGIN_DOWNLOAD;
   string this_platform = DTOOL_PLATFORM;
   string this_platform = DTOOL_PLATFORM;
   bool force_download = false;
   bool force_download = false;
 
 
-  Filename output_filename;
   P3D_window_type window_type = P3D_WT_toplevel;
   P3D_window_type window_type = P3D_WT_toplevel;
   int win_x = 0, win_y = 0;
   int win_x = 0, win_y = 0;
   int win_width = 0, win_height = 0;
   int win_width = 0, win_height = 0;
@@ -71,6 +75,10 @@ run(int argc, char *argv[]) {
 
 
   while (flag != EOF) {
   while (flag != EOF) {
     switch (flag) {
     switch (flag) {
+    case 'm':
+      allow_multiple = true;
+      break;
+
     case 'u':
     case 'u':
       download_url = optarg;
       download_url = optarg;
       break;
       break;
@@ -83,10 +91,6 @@ run(int argc, char *argv[]) {
       force_download = true;
       force_download = true;
       break;
       break;
 
 
-    case 'l':
-      output_filename = Filename::from_os_specific(optarg);
-      break;
-
     case 't':
     case 't':
       if (strcmp(optarg, "toplevel") == 0) {
       if (strcmp(optarg, "toplevel") == 0) {
         window_type = P3D_WT_toplevel;
         window_type = P3D_WT_toplevel;
@@ -118,6 +122,7 @@ run(int argc, char *argv[]) {
 
 
     case 'h':
     case 'h':
     case '?':
     case '?':
+    case '+':
     default:
     default:
       usage();
       usage();
       return 1;
       return 1;
@@ -143,7 +148,24 @@ run(int argc, char *argv[]) {
     return 1;
     return 1;
   }
   }
 
 
-  int num_instances = argc - 1;
+  int num_instance_filenames, num_instance_args;
+  char **instance_filenames, **instance_args;
+
+  if (allow_multiple) {
+    // With -m, the remaining arguments are all instance filenames.
+    num_instance_filenames = argc - 1;
+    instance_filenames = argv + 1;
+    num_instance_args = 0;
+    instance_args = argv + argc;
+
+  } else {
+    // Without -m, there is one instance filename, and everything else
+    // gets delivered to that instance.
+    num_instance_filenames = 1;
+    instance_filenames = argv + 1;
+    num_instance_args = argc - 2;
+    instance_args = argv + 2;
+  }
 
 
   P3D_window_handle parent_window;
   P3D_window_handle parent_window;
   if (window_type == P3D_WT_embedded) {
   if (window_type == P3D_WT_embedded) {
@@ -168,8 +190,8 @@ run(int argc, char *argv[]) {
 #endif
 #endif
 
 
     // Subdivide the window into num_x_spans * num_y_spans sub-windows.
     // Subdivide the window into num_x_spans * num_y_spans sub-windows.
-    int num_y_spans = int(sqrt((double)num_instances));
-    int num_x_spans = (num_instances + num_y_spans - 1) / num_y_spans;
+    int num_y_spans = int(sqrt((double)num_instance_filenames));
+    int num_x_spans = (num_instance_filenames + num_y_spans - 1) / num_y_spans;
     
     
     int inst_width = win_width / num_x_spans;
     int inst_width = win_width / num_x_spans;
     int inst_height = win_height / num_y_spans;
     int inst_height = win_height / num_y_spans;
@@ -177,7 +199,7 @@ run(int argc, char *argv[]) {
     for (int yi = 0; yi < num_y_spans; ++yi) {
     for (int yi = 0; yi < num_y_spans; ++yi) {
       for (int xi = 0; xi < num_x_spans; ++xi) {
       for (int xi = 0; xi < num_x_spans; ++xi) {
         int i = yi * num_x_spans + xi;
         int i = yi * num_x_spans + xi;
-        if (i >= num_instances) {
+        if (i >= num_instance_filenames) {
           continue;
           continue;
         }
         }
 
 
@@ -186,20 +208,20 @@ run(int argc, char *argv[]) {
         int inst_y = win_y + yi * inst_height;
         int inst_y = win_y + yi * inst_height;
 
 
         P3D_instance *inst = create_instance
         P3D_instance *inst = create_instance
-          (argv[i + 1], P3D_WT_embedded, 
+          (instance_filenames[i], P3D_WT_embedded, 
            inst_x, inst_y, inst_width, inst_height, parent_window,
            inst_x, inst_y, inst_width, inst_height, parent_window,
-           output_filename);
+           instance_args, num_instance_args);
         _instances.insert(inst);
         _instances.insert(inst);
       }
       }
     }
     }
 
 
   } else {
   } else {
     // Not an embedded window.  Create each window with the same parameters.
     // Not an embedded window.  Create each window with the same parameters.
-    for (int i = 0; i < num_instances; ++i) {
+    for (int i = 0; i < num_instance_filenames; ++i) {
       P3D_instance *inst = create_instance
       P3D_instance *inst = create_instance
-        (argv[i + 1], window_type, 
+        (instance_filenames[i], window_type, 
          win_x, win_y, win_width, win_height, parent_window,
          win_x, win_y, win_width, win_height, parent_window,
-         output_filename);
+         instance_args, num_instance_args);
       _instances.insert(inst);
       _instances.insert(inst);
     }
     }
   }
   }
@@ -579,12 +601,8 @@ make_parent_window(P3D_window_handle &parent_window,
 P3D_instance *Panda3D::
 P3D_instance *Panda3D::
 create_instance(const string &arg, P3D_window_type window_type,
 create_instance(const string &arg, P3D_window_type window_type,
                 int win_x, int win_y, int win_width, int win_height,
                 int win_x, int win_y, int win_width, int win_height,
-                P3D_window_handle parent_window,
-                const Filename &output_filename) {
-
-  string os_output_filename = output_filename.to_os_specific();
+                P3D_window_handle parent_window, char **args, int num_args) {
   P3D_token tokens[] = {
   P3D_token tokens[] = {
-    { "output_filename", os_output_filename.c_str() },
     { "src", arg.c_str() },
     { "src", arg.c_str() },
   };
   };
   int num_tokens = sizeof(tokens) / sizeof(P3D_token);
   int num_tokens = sizeof(tokens) / sizeof(P3D_token);
@@ -645,18 +663,24 @@ void Panda3D::
 usage() {
 usage() {
   cerr
   cerr
     << "\nUsage:\n"
     << "\nUsage:\n"
-    << "   panda3d [opts] file.p3d [file_b.p3d file_c.p3d ...]\n\n"
+    << "   panda3d [opts] file.p3d [args]\n\n"
+    << "   panda3d -m [opts] file_a.p3d file_b.p3d [file_c.p3d ...]\n\n"
   
   
     << "This program is used to execute a Panda3D application bundle stored\n"
     << "This program is used to execute a Panda3D application bundle stored\n"
-    << "in a .p3d file.  Normally you only run one p3d bundle at a time,\n"
-    << "but it is possible to run multiple bundles simultaneously.\n\n"
+    << "in a .p3d file.  In the first form, without a -m option, it\n"
+    << "executes one application; remaining arguments following the\n"
+    << "application name are passed into the application.  In the second\n"
+    << "form, with a -m option, it can execute multiple applications\n"
+    << "simultaneously, though in this form arguments cannot be passed into\n"
+    << "the applications.\n\n"
 
 
     << "Options:\n\n"
     << "Options:\n\n"
 
 
-    << "  -l output.log\n"
-    << "    Specify the name of the file to receive the log output of the\n"
-    << "    plugin process(es).  The default is to send this output to the\n"
-    << "    console.\n\n"
+    << "  -m\n"
+    << "    Indicates that multiple application filenames will be passed on\n"
+    << "    the command line.  All applications will be run at the same\n"
+    << "    time, but additional arguments may not be passed to any of the\n"
+    << "    applictions.\n\n"
 
 
     << "  -t [toplevel|embedded|fullscreen|hidden]\n"
     << "  -t [toplevel|embedded|fullscreen|hidden]\n"
     << "    Specify the type of graphic window to create.  If you specify\n"
     << "    Specify the type of graphic window to create.  If you specify\n"

+ 1 - 1
direct/src/plugin_standalone/panda3d.h

@@ -59,7 +59,7 @@ private:
                                 int win_x, int win_y, int win_width, 
                                 int win_x, int win_y, int win_width, 
                                 int win_height,
                                 int win_height,
                                 P3D_window_handle parent_window,
                                 P3D_window_handle parent_window,
-                                const Filename &output_filename);
+                                char **args, int num_args);
   void delete_instance(P3D_instance *instance);
   void delete_instance(P3D_instance *instance);
 
 
   void usage();
   void usage();

+ 122 - 82
direct/src/showutil/Packager.py

@@ -9,6 +9,7 @@ import glob
 import marshal
 import marshal
 import new
 import new
 import string
 import string
+import types
 from direct.showbase import Loader
 from direct.showbase import Loader
 from direct.showutil import FreezeTool
 from direct.showutil import FreezeTool
 from direct.directnotify.DirectNotifyGlobal import *
 from direct.directnotify.DirectNotifyGlobal import *
@@ -31,11 +32,13 @@ class Packager:
     class PackFile:
     class PackFile:
         def __init__(self, package, filename,
         def __init__(self, package, filename,
                      newName = None, deleteTemp = False,
                      newName = None, deleteTemp = False,
-                     compress = None, extract = None, executable = None):
+                     explicit = False, compress = None, extract = None,
+                     executable = None):
             assert isinstance(filename, Filename)
             assert isinstance(filename, Filename)
             self.filename = Filename(filename)
             self.filename = Filename(filename)
             self.newName = newName
             self.newName = newName
             self.deleteTemp = deleteTemp
             self.deleteTemp = deleteTemp
+            self.explicit = explicit
             self.compress = compress
             self.compress = compress
             self.extract = extract
             self.extract = extract
             self.executable = executable
             self.executable = executable
@@ -58,7 +61,7 @@ class Packager:
 
 
             if self.executable:
             if self.executable:
                 # Look up the filename along the system PATH, if necessary.
                 # Look up the filename along the system PATH, if necessary.
-                self.filename.resolveFilename(packager.dllPath)
+                self.filename.resolveFilename(packager.executablePath)
 
 
             # Convert the filename to an unambiguous filename for
             # Convert the filename to an unambiguous filename for
             # searching.
             # searching.
@@ -73,19 +76,27 @@ class Packager:
             if self.newName in package.skipFilenames:
             if self.newName in package.skipFilenames:
                 return True
                 return True
 
 
-            basename = Filename(self.newName).getBasename()
-            if not package.packager.caseSensitive:
-                basename = basename.lower()
-            if basename in package.packager.excludeSystemFiles:
-                return True
-
-            for exclude in package.packager.excludeSystemGlobs:
-                if exclude.matches(basename):
-                    return True
+            if not self.explicit:
+                # Make sure it's not one of our auto-excluded system
+                # files.  (But only make this check if this file was
+                # not explicitly added.)
 
 
-            for exclude in package.excludedFilenames:
-                if exclude.matches(self.filename):
+                basename = Filename(self.newName).getBasename()
+                if not package.packager.caseSensitive:
+                    basename = basename.lower()
+                if basename in package.packager.excludeSystemFiles:
                     return True
                     return True
+                for exclude in package.packager.excludeSystemGlobs:
+                    if exclude.matches(basename):
+                        return True
+
+                # Also check if it was explicitly excluded.  As above,
+                # omit this check for an explicitly-added file: if you
+                # both include and exclude a file, the file is
+                # included.
+                for exclude in package.excludedFilenames:
+                    if exclude.matches(self.filename):
+                        return True
 
 
             return False
             return False
                 
                 
@@ -115,12 +126,15 @@ class Packager:
             self.version = None
             self.version = None
             self.platform = None
             self.platform = None
             self.p3dApplication = False
             self.p3dApplication = False
-            self.displayName = None
             self.compressionLevel = 0
             self.compressionLevel = 0
             self.importedMapsDir = 'imported_maps'
             self.importedMapsDir = 'imported_maps'
             self.mainModule = None
             self.mainModule = None
             self.requires = []
             self.requires = []
 
 
+            # This is the set of config variables assigned to the
+            # package.
+            self.configs = {}
+
             # This is the set of files and modules, already included
             # This is the set of files and modules, already included
             # by required packages, that we can skip.
             # by required packages, that we can skip.
             self.skipFilenames = {}
             self.skipFilenames = {}
@@ -369,7 +383,7 @@ class Packager:
                     filename = Filename.fromOsSpecific(filename)
                     filename = Filename.fromOsSpecific(filename)
                     filename.resolveFilename(path)
                     filename.resolveFilename(path)
                     self.addFile(filename, newName = filename.getBasename(),
                     self.addFile(filename, newName = filename.getBasename(),
-                                 executable = True)
+                                 explicit = False, executable = True)
                     
                     
         def __parseDependenciesWindows(self, tempFile):
         def __parseDependenciesWindows(self, tempFile):
             """ Reads the indicated temporary file, the output from
             """ Reads the indicated temporary file, the output from
@@ -451,7 +465,7 @@ class Packager:
                     filename = Filename.fromOsSpecific(filename)
                     filename = Filename.fromOsSpecific(filename)
                     filename.resolveFilename(path)
                     filename.resolveFilename(path)
                     self.addFile(filename, newName = filename.getBasename(),
                     self.addFile(filename, newName = filename.getBasename(),
-                                 executable = True)
+                                 explicit = False, executable = True)
                     
                     
         def __parseDependenciesOSX(self, tempFile):
         def __parseDependenciesOSX(self, tempFile):
             """ Reads the indicated temporary file, the output from
             """ Reads the indicated temporary file, the output from
@@ -522,7 +536,7 @@ class Packager:
                     filename = Filename.fromOsSpecific(filename)
                     filename = Filename.fromOsSpecific(filename)
                     filename.resolveFilename(path)
                     filename.resolveFilename(path)
                     self.addFile(filename, newName = filename.getBasename(),
                     self.addFile(filename, newName = filename.getBasename(),
-                                 executable = True)
+                                 explicit = False, executable = True)
                     
                     
         def __parseDependenciesPosix(self, tempFile):
         def __parseDependenciesPosix(self, tempFile):
             """ Reads the indicated temporary file, the output from
             """ Reads the indicated temporary file, the output from
@@ -560,7 +574,8 @@ class Packager:
                     newName += '/' + filename.getBasename()
                     newName += '/' + filename.getBasename()
                 # Sometimes the PYTHONPATH has the wrong case in it.
                 # Sometimes the PYTHONPATH has the wrong case in it.
                 filename.makeTrueCase()
                 filename.makeTrueCase()
-                self.addFile(filename, newName = newName, extract = True)
+                self.addFile(filename, newName = newName,
+                             explicit = False, extract = True)
             freezer.extras = []
             freezer.extras = []
 
 
 
 
@@ -579,11 +594,14 @@ class Packager:
             if self.version:
             if self.version:
                 xpackage.SetAttribute('version', self.version)
                 xpackage.SetAttribute('version', self.version)
 
 
-            if self.displayName:
-                xpackage.SetAttribute('display_name', self.displayName)
-
             xpackage.SetAttribute('main_module', self.mainModule)
             xpackage.SetAttribute('main_module', self.mainModule)
 
 
+            for variable, value in self.configs.items():
+                if isinstance(value, types.UnicodeType):
+                    xpackage.SetAttribute(variable, value.encode('utf-8'))
+                else:
+                    xpackage.SetAttribute(variable, str(value))
+
             for package in self.requires:
             for package in self.requires:
                 xrequires = TiXmlElement('requires')
                 xrequires = TiXmlElement('requires')
                 xrequires.SetAttribute('name', package.packageName)
                 xrequires.SetAttribute('name', package.packageName)
@@ -628,8 +646,11 @@ class Packager:
             if self.version:
             if self.version:
                 xpackage.SetAttribute('version', self.version)
                 xpackage.SetAttribute('version', self.version)
 
 
-            if self.displayName:
-                xpackage.SetAttribute('display_name', self.displayName)
+            for variable, value in self.configs.items():
+                if isinstance(value, types.UnicodeType):
+                    xpackage.SetAttribute(variable, value.encode('utf-8'))
+                else:
+                    xpackage.SetAttribute(variable, str(value))
 
 
             for package in self.requires:
             for package in self.requires:
                 xrequires = TiXmlElement('requires')
                 xrequires = TiXmlElement('requires')
@@ -872,7 +893,8 @@ class Packager:
                     self.importedMapsDir, filename.getBasenameWoExtension(),
                     self.importedMapsDir, filename.getBasenameWoExtension(),
                     uniqueId, filename.getExtension())
                     uniqueId, filename.getExtension())
 
 
-            self.addFile(filename, newName = newName, compress = False)
+            self.addFile(filename, newName = newName, explicit = False,
+                         compress = False)
 
 
         def addComponent(self, file):
         def addComponent(self, file):
             if file.platformSpecific:
             if file.platformSpecific:
@@ -916,24 +938,25 @@ class Packager:
         self.persistDir = None
         self.persistDir = None
 
 
         # A search list of directories and/or URL's to search for
         # A search list of directories and/or URL's to search for
-        # installed packages.
-        self.installSearch = []
+        # installed packages.  We query it from a config variable
+        # initially, but we may also be extending it at runtime.
+        self.installSearch = ConfigVariableSearchPath('pdef-path')
 
 
         # The system PATH, for searching dll's and exe's.
         # The system PATH, for searching dll's and exe's.
-        self.dllPath = DSearchPath()
+        self.executablePath = DSearchPath()
         if PandaSystem.getPlatform().startswith('win'):
         if PandaSystem.getPlatform().startswith('win'):
-            self.addWindowsSearchPath(self.dllPath, "PATH")
+            self.addWindowsSearchPath(self.executablePath, "PATH")
         elif PandaSystem.getPlatform().startswith('osx'):
         elif PandaSystem.getPlatform().startswith('osx'):
-            self.addPosixSearchPath(self.dllPath, "DYLD_LIBRARY_PATH")
-            self.addPosixSearchPath(self.dllPath, "LD_LIBRARY_PATH")
-            self.addPosixSearchPath(self.dllPath, "PATH")
-            self.dllPath.appendDirectory('/lib')
-            self.dllPath.appendDirectory('/usr/lib')
+            self.addPosixSearchPath(self.executablePath, "DYLD_LIBRARY_PATH")
+            self.addPosixSearchPath(self.executablePath, "LD_LIBRARY_PATH")
+            self.addPosixSearchPath(self.executablePath, "PATH")
+            self.executablePath.appendDirectory('/lib')
+            self.executablePath.appendDirectory('/usr/lib')
         else:
         else:
-            self.addPosixSearchPath(self.dllPath, "LD_LIBRARY_PATH")
-            self.addPosixSearchPath(self.dllPath, "PATH")
-            self.dllPath.appendDirectory('/lib')
-            self.dllPath.appendDirectory('/usr/lib')
+            self.addPosixSearchPath(self.executablePath, "LD_LIBRARY_PATH")
+            self.addPosixSearchPath(self.executablePath, "PATH")
+            self.executablePath.appendDirectory('/lib')
+            self.executablePath.appendDirectory('/usr/lib')
 
 
         # The platform string.
         # The platform string.
         self.platform = PandaSystem.getPlatform()
         self.platform = PandaSystem.getPlatform()
@@ -1286,6 +1309,32 @@ class Packager:
         value = ExecutionEnvironment.expandString(value.strip())
         value = ExecutionEnvironment.expandString(value.strip())
         ExecutionEnvironment.setEnvironmentVariable(variable, value)
         ExecutionEnvironment.setEnvironmentVariable(variable, value)
 
 
+    def parse_model_path(self, words):
+        """
+        model_path directory
+        """
+        newName = None
+
+        try:
+            command, dirName = words
+        except ValueError:
+            raise ArgumentError
+
+        getModelPath().appendDirectory(Filename.fromOsSpecific(dirName))
+
+    def parse_reset_model_path(self, words):
+        """
+        reset_model_path
+        """
+        newName = None
+
+        try:
+            (command,) = words
+        except ValueError:
+            raise ArgumentError
+
+        getModelPath().clear()
+
     def parse_begin_package(self, words):
     def parse_begin_package(self, words):
         """
         """
         begin_package packageName [version=v]
         begin_package packageName [version=v]
@@ -1338,20 +1387,23 @@ class Packager:
 
 
         self.endPackage(packageName, p3dApplication = True)
         self.endPackage(packageName, p3dApplication = True)
 
 
-    def parse_display_name(self, words):
+    def parse_config(self, words):
         """
         """
-        display_name "name"
+        config variable=value
         """
         """
-
+        
         try:
         try:
-            command, displayName = words
+            command, assign = words
         except ValueError:
         except ValueError:
-            raise ArgumentError
-
-        if not self.currentPackage:
-            raise OutsideOfPackageError
+            raise ArgumentNumber
+        
+        try:
+            variable, value = assign.split('=', 1)
+        except ValueError:
+            raise PackagerError, 'Equals sign required in assignment'
 
 
-        self.currentPackage.displayName = displayName
+        variable = variable.strip()
+        self.config(variable, value)
 
 
     def parse_require(self, words):
     def parse_require(self, words):
         """
         """
@@ -1368,32 +1420,6 @@ class Packager:
         version = args.get('version', None)
         version = args.get('version', None)
         self.require(packageName, version = version)
         self.require(packageName, version = version)
 
 
-    def parse_model_path(self, words):
-        """
-        model_path directory
-        """
-        newName = None
-
-        try:
-            command, dirName = words
-        except ValueError:
-            raise ArgumentError
-
-        getModelPath().appendDirectory(Filename.fromOsSpecific(dirName))
-
-    def parse_reset_model_path(self, words):
-        """
-        reset_model_path
-        """
-        newName = None
-
-        try:
-            (command,) = words
-        except ValueError:
-            raise ArgumentError
-
-        getModelPath().clear()
-
     def parse_module(self, words):
     def parse_module(self, words):
         """
         """
         module moduleName [newName]
         module moduleName [newName]
@@ -1624,10 +1650,10 @@ class Packager:
             return package
             return package
 
 
         # Look on the searchlist.
         # Look on the searchlist.
-        for path in self.installSearch:
-            package = self.__scanPackageDir(path, packageName, platform, version, requires = requires)
+        for dirname in self.installSearch.getDirectories():
+            package = self.__scanPackageDir(dirname, packageName, platform, version, requires = requires)
             if not package:
             if not package:
-                package = self.__scanPackageDir(path, packageName, None, version, requires = requires)
+                package = self.__scanPackageDir(dirname, packageName, None, version, requires = requires)
 
 
             if package:
             if package:
                 package = self.packages.setdefault((package.packageName, package.platform, package.version), package)
                 package = self.packages.setdefault((package.packageName, package.platform, package.version), package)
@@ -1727,9 +1753,9 @@ class Packager:
         if not requires:
         if not requires:
             return True
             return True
 
 
-        # Really, we only check the panda3d package for now.  The
-        # other packages will list this as a dependency, and this is
-        # all that matters.
+        # Really, we only check the panda3d package.  The other
+        # packages will list this as a dependency, and this is all
+        # that matters.
 
 
         panda1 = self.__findPackageInList('panda3d', [package] + package.requires)
         panda1 = self.__findPackageInList('panda3d', [package] + package.requires)
         panda2 = self.__findPackageInList('panda3d', requires)
         panda2 = self.__findPackageInList('panda3d', requires)
@@ -1760,6 +1786,17 @@ class Packager:
 
 
         return None
         return None
 
 
+    def config(self, variable, value):
+        """ Sets the indicated p3d config variable to the given value.
+        This will be written into the p3d_info.xml file at the top of
+        the application, or to the package desc file for a package
+        file. """
+
+        if not self.currentPackage:
+            raise OutsideOfPackageError
+
+        self.currentPackage.configs[variable] = value
+
     def require(self, packageName, version = None):
     def require(self, packageName, version = None):
         """ Indicates a dependency on the named package, supplied as
         """ Indicates a dependency on the named package, supplied as
         a name.
         a name.
@@ -1878,7 +1915,7 @@ class Packager:
             basename = freezer.generateCode(basename, compileToExe = compileToExe)
             basename = freezer.generateCode(basename, compileToExe = compileToExe)
 
 
             package.addFile(Filename(basename), newName = dirname + basename,
             package.addFile(Filename(basename), newName = dirname + basename,
-                            deleteTemp = True, extract = True)
+                            deleteTemp = True, explicit = True, extract = True)
             package.addExtensionModules()
             package.addExtensionModules()
             if not package.platform:
             if not package.platform:
                 package.platform = PandaSystem.getPlatform()
                 package.platform = PandaSystem.getPlatform()
@@ -1924,6 +1961,7 @@ class Packager:
         files = glob.glob(filename.toOsSpecific())
         files = glob.glob(filename.toOsSpecific())
         if not files:
         if not files:
             files = [filename.toOsSpecific()]
             files = [filename.toOsSpecific()]
+        explicit = (len(files) == 1)
 
 
         newName = None
         newName = None
         prefix = ''
         prefix = ''
@@ -1946,7 +1984,7 @@ class Packager:
                 
                 
             self.currentPackage.addFile(
             self.currentPackage.addFile(
                 filename, newName = name, extract = extract,
                 filename, newName = name, extract = extract,
-                executable = executable)
+                explicit = explicit, executable = executable)
 
 
     def exclude(self, filename):
     def exclude(self, filename):
         """ Marks the indicated filename as not to be included.  The
         """ Marks the indicated filename as not to be included.  The
@@ -1996,7 +2034,8 @@ class Packager:
         # It's a file name.  Add it.
         # It's a file name.  Add it.
         ext = filename.getExtension()
         ext = filename.getExtension()
         if ext == 'py':
         if ext == 'py':
-            self.currentPackage.addFile(filename, newName = newName)
+            self.currentPackage.addFile(filename, newName = newName,
+                                        explicit = False)
         else:
         else:
             if ext == 'pz':
             if ext == 'pz':
                 # Strip off an implicit .pz extension.
                 # Strip off an implicit .pz extension.
@@ -2006,4 +2045,5 @@ class Packager:
                 ext = newFilename.getExtension()
                 ext = newFilename.getExtension()
 
 
             if ext in self.knownExtensions:
             if ext in self.knownExtensions:
-                self.currentPackage.addFile(filename, newName = newName)
+                self.currentPackage.addFile(filename, newName = newName,
+                                            explicit = False)

+ 1 - 1
direct/src/showutil/packp3d.py

@@ -78,7 +78,7 @@ def makePackedApp(args):
         elif option == '-r':
         elif option == '-r':
             requires.append(value)
             requires.append(value)
         elif option == '-s':
         elif option == '-s':
-            packager.installSearch.append(Filename.fromOsSpecific(value))
+            packager.installSearch.appendDirectory(Filename.fromOsSpecific(value))
         elif option == '-x':
         elif option == '-x':
             versionIndependent = True
             versionIndependent = True
         elif option == '-h':
         elif option == '-h':

+ 2 - 2
direct/src/showutil/ppackage.py

@@ -83,7 +83,7 @@ for opt, arg in opts:
     if opt == '-i':
     if opt == '-i':
         packager.installDir = Filename.fromOsSpecific(arg)
         packager.installDir = Filename.fromOsSpecific(arg)
     elif opt == '-s':
     elif opt == '-s':
-        packager.installSearch.append(Filename.fromOsSpecific(arg))
+        packager.installSearch.appendDirectory(Filename.fromOsSpecific(arg))
     elif opt == '-d':
     elif opt == '-d':
         packager.persistDir = Filename.fromOsSpecific(arg)
         packager.persistDir = Filename.fromOsSpecific(arg)
     elif opt == '-p':
     elif opt == '-p':
@@ -108,7 +108,7 @@ packageDef = Filename.fromOsSpecific(args[0])
 
 
 if not packager.installDir:
 if not packager.installDir:
     packager.installDir = Filename('install')
     packager.installDir = Filename('install')
-packager.installSearch = [packager.installDir] + packager.installSearch
+packager.installSearch.prependDirectory(packager.installDir)
 
 
 packager.setup()
 packager.setup()
 packages = packager.readPackageDef(packageDef)
 packages = packager.readPackageDef(packageDef)

+ 52 - 31
direct/src/showutil/runp3d.py

@@ -65,6 +65,8 @@ class AppRunner(DirectObject):
         self.windowOpened = False
         self.windowOpened = False
         self.windowPrc = None
         self.windowPrc = None
 
 
+        self.fullDiskAccess = False
+
         self.Undefined = Undefined
         self.Undefined = Undefined
         self.ConcreteStruct = ConcreteStruct
         self.ConcreteStruct = ConcreteStruct
 
 
@@ -139,22 +141,36 @@ class AppRunner(DirectObject):
 
 
         vfs = VirtualFileSystem.getGlobalPtr()
         vfs = VirtualFileSystem.getGlobalPtr()
 
 
-        # Clear *all* the mount points, including "/", so that we no
-        # longer access the disk directly.
-        vfs.unmountAll()
-
-        # Make sure the directories on our standard Python path are mounted
-        # read-only, so we can still load Python.
-        for dirname in sys.path:
-            vfs.mount(dirname, dirname, vfs.MFReadOnly)
-
-        # Also mount some standard directories read-write (temporary and
-        # app-data directories).
-        tdir = Filename.temporary('', '')
-        for dirname in set([ tdir.getDirname(),
-                             Filename.getTempDirectory().cStr(),
-                             Filename.getUserAppdataDirectory().cStr(),
-                             Filename.getCommonAppdataDirectory().cStr() ]):
+        # Unmount directories we don't need.  This doesn't provide
+        # actual security, since it only disables this stuff for users
+        # who go through the vfs; a malicious programmer can always
+        # get to the underlying true file I/O operations.  Still, it
+        # can help prevent honest developers from accidentally getting
+        # stuck where they don't belong.
+        if not self.fullDiskAccess:
+            # Clear *all* the mount points, including "/", so that we
+            # no longer access the disk directly.
+            vfs.unmountAll()
+
+            # Make sure the directories on our standard Python path
+            # are mounted read-only, so we can still load Python.
+            # Note: read-only actually doesn't have any effect on the
+            # vfs right now; careless application code can still write
+            # to these directories inadvertently.
+            for dirname in sys.path:
+                vfs.mount(dirname, dirname, vfs.MFReadOnly)
+
+            # Also mount some standard directories read-write
+            # (temporary and app-data directories).
+            tdir = Filename.temporary('', '')
+            for dirname in set([ tdir.getDirname(),
+                                 Filename.getTempDirectory().cStr(),
+                                 Filename.getUserAppdataDirectory().cStr(),
+                                 Filename.getCommonAppdataDirectory().cStr() ]):
+                vfs.mount(dirname, dirname, 0)
+
+            # And we might need the current working directory.
+            dirname = ExecutionEnvironment.getCwd()
             vfs.mount(dirname, dirname, 0)
             vfs.mount(dirname, dirname, 0)
 
 
         # Now set up Python to import this stuff.
         # Now set up Python to import this stuff.
@@ -257,12 +273,30 @@ class AppRunner(DirectObject):
             raise ArgumentError, "No such file: %s" % (p3dFilename)
             raise ArgumentError, "No such file: %s" % (p3dFilename)
 
 
         fname.makeAbsolute()
         fname.makeAbsolute()
-        self.initPackedAppEnvironment()
-
         mf = Multifile()
         mf = Multifile()
         if not mf.openRead(fname):
         if not mf.openRead(fname):
             raise ArgumentError, "Not a Panda Multifile: %s" % (p3dFilename)
             raise ArgumentError, "Not a Panda Multifile: %s" % (p3dFilename)
 
 
+        # Now load the p3dInfo file.
+        self.p3dInfo = None
+        self.p3dPackage = None
+        i = mf.findSubfile('p3d_info.xml')
+        if i >= 0:
+            stream = mf.openReadSubfile(i)
+            self.p3dInfo = readXmlStream(stream)
+            mf.closeReadSubfile(stream)
+        if self.p3dInfo:
+            self.p3dPackage = self.p3dInfo.FirstChildElement('package')
+
+        if self.p3dPackage:
+            fullDiskAccess = self.p3dPackage.Attribute('full_disk_access')
+            try:
+                self.fullDiskAccess = int(fullDiskAccess)
+            except ValueError:
+                pass
+
+        self.initPackedAppEnvironment()
+
         # Mount the Multifile under /mf, by convention.
         # Mount the Multifile under /mf, by convention.
         vfs.mount(mf, MultifileRoot, vfs.MFReadOnly)
         vfs.mount(mf, MultifileRoot, vfs.MFReadOnly)
 
 
@@ -278,19 +312,6 @@ class AppRunner(DirectObject):
                 data = open(pathname, 'r').read()
                 data = open(pathname, 'r').read()
                 loadPrcFileData(pathname, data)
                 loadPrcFileData(pathname, data)
 
 
-        # Now load the p3dInfo file.
-        self.p3dInfo = None
-        self.p3dPackage = None
-        i = mf.findSubfile('p3d_info.xml')
-        if i >= 0:
-            stream = mf.openReadSubfile(i)
-            self.p3dInfo = readXmlStream(stream)
-            mf.closeReadSubfile(stream)
-        if self.p3dInfo:
-            p3dPackage = self.p3dInfo.FirstChild('package')
-            if p3dPackage:
-                self.p3dPackage = p3dPackage.ToElement()
-
         self.gotP3DFilename = True
         self.gotP3DFilename = True
 
 
         # Send this call to the main thread; don't call it directly.
         # Send this call to the main thread; don't call it directly.