diff --git a/direct/src/p3d/HostInfo.py b/direct/src/p3d/HostInfo.py index 55392924a6..d6520b74ea 100644 --- a/direct/src/p3d/HostInfo.py +++ b/direct/src/p3d/HostInfo.py @@ -127,7 +127,7 @@ class HostInfo: platform, if one is provided by this host, or None if not. """ assert self.hasContentsFile - platforms = self.packages.get((name, version), {}) + platforms = self.packages.get((name, version or None), {}) if platform is not None: # In this case, we are looking for a specific platform diff --git a/direct/src/p3d/PackageInfo.py b/direct/src/p3d/PackageInfo.py index a3e0aa152a..0d29a84d71 100644 --- a/direct/src/p3d/PackageInfo.py +++ b/direct/src/p3d/PackageInfo.py @@ -1,4 +1,4 @@ -from pandac.PandaModules import Filename, URLSpec, DocumentSpec, Ramfile, TiXmlDocument, Multifile, Decompressor, EUOk, EUSuccess, VirtualFileSystem, Thread +from pandac.PandaModules import Filename, URLSpec, DocumentSpec, Ramfile, TiXmlDocument, Multifile, Decompressor, EUOk, EUSuccess, VirtualFileSystem, Thread, getModelPath from direct.p3d.FileSpec import FileSpec from direct.showbase import VFSImporter import os @@ -16,7 +16,9 @@ class PackageInfo: self.packageVersion = packageVersion self.platform = platform - self.packageDir = Filename(host.hostDir, '%s/%s' % (self.packageName, self.packageVersion)) + self.packageDir = Filename(host.hostDir, self.packageName) + if self.packageVersion: + self.packageDir = Filename(self.packageDir, self.packageVersion) # These will be filled in by HostInfo when the package is read # from contents.xml. @@ -362,7 +364,12 @@ class PackageInfo: if not foundOnPath: # Not already here; add it. - sys.path.append(root) + sys.path.insert(0, root) + + # Put it on the model-path, too. We do this indiscriminantly, + # because the Panda3D runtime won't be adding things to the + # model-path, so it shouldn't be already there. + getModelPath().prependDirectory(self.packageDir) # Also, find any toplevel Python packages, and add these as # shared packages. This will allow different packages diff --git a/direct/src/p3d/Packager.py b/direct/src/p3d/Packager.py index 9fb9bfe26c..9892b96471 100644 --- a/direct/src/p3d/Packager.py +++ b/direct/src/p3d/Packager.py @@ -306,6 +306,12 @@ class Packager: else: self.installMultifile() + if self.p3dApplication: + allowPythonDev = self.configs.get('allow_python_dev', 0) + if int(allowPythonDev): + print "\n*** Generating %s.p3d with allow_python_dev enabled ***\n" % (self.packageName) + + def considerPlatform(self): # Check to see if any of the files are platform-specific, # making the overall package platform-specific. @@ -1866,38 +1872,43 @@ class Packager: selected. """ - packageDir = Filename(rootDir, packageName) - basename = packageName + packages = [] if version: # A specific version package. - packageDir = Filename(packageDir, version) - basename += '.%s' % (version) + versionList = [version] else: - # Scan all versions. - packageDir = Filename(packageDir, '*') - basename += '.%s' % ('*') + # An unversioned package, or any old version. + versionList = [None, '*'] - if platform: - packageDir = Filename(packageDir, platform) - basename += '.%s' % (platform) + for version in versionList: + packageDir = Filename(rootDir, packageName) + basename = packageName - # Actually, the host means little for this search, since we're - # only looking in a local directory at this point. + if version: + # A specific or nonspecific version package. + packageDir = Filename(packageDir, version) + basename += '.%s' % (version) - basename += '.import.xml' - filename = Filename(packageDir, basename) - filelist = glob.glob(filename.toOsSpecific()) - if not filelist: - # It doesn't exist in the nested directory; try the root - # directory. - filename = Filename(rootDir, basename) + if platform: + packageDir = Filename(packageDir, platform) + basename += '.%s' % (platform) + + # 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()) + if not filelist: + # It doesn't exist in the nested directory; try the root + # directory. + filename = Filename(rootDir, basename) + filelist = glob.glob(filename.toOsSpecific()) - packages = [] - for file in filelist: - package = self.__readPackageImportDescFile(Filename.fromOsSpecific(file)) - packages.append(package) + for file in filelist: + package = self.__readPackageImportDescFile(Filename.fromOsSpecific(file)) + packages.append(package) self.__sortImportPackages(packages) for package in packages: @@ -1952,6 +1963,9 @@ class Packager: separating out numbers into separate numeric fields, so that version numbers sort numerically where appropriate. """ + if not version: + return ('',) + words = [] p = 0 while p < len(version): diff --git a/direct/src/p3d/packp3d.py b/direct/src/p3d/packp3d.py index 10a873e238..249aef87f8 100755 --- a/direct/src/p3d/packp3d.py +++ b/direct/src/p3d/packp3d.py @@ -40,6 +40,15 @@ Options: This option may be repeated as necessary. These directories may also be specified with the pdef-path Config.prc variable. + -D + Allow the application to be run with -D on the panda3d command + line, or equivalently, "python_dev=1" in the web tokens. If this + is allowed, then it will preserve the PYTHONPATH environment + variable from the user's environment, allowing Python files on + disk to shadow the same-named Python files within the p3d file, + for rapid iteration on the Python code. If the appliation is not + built with -D here, this option does nothing at runtime. + """ import sys @@ -57,13 +66,14 @@ class ArgumentError(StandardError): pass def makePackedApp(args): - opts, args = getopt.getopt(args, 'd:m:r:s:h') + opts, args = getopt.getopt(args, 'd:m:r:s:Dh') packager = Packager.Packager() root = Filename('.') main = None requires = [] + allowPythonDev = False for option, value in opts: if option == '-d': @@ -74,6 +84,8 @@ def makePackedApp(args): requires.append(value) elif option == '-s': packager.installSearch.appendDirectory(Filename.fromOsSpecific(value)) + elif option == '-D': + allowPythonDev = True elif option == '-h': print __doc__ % (os.path.split(sys.argv[0])[1]) sys.exit(1) @@ -120,6 +132,9 @@ def makePackedApp(args): for requireName in requires: packager.do_require(requireName) + if allowPythonDev: + packager.do_config(allow_python_dev = True) + packager.do_dir(root) packager.do_mainModule(mainModule) diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index 33e30452ef..57a89cb0fc 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/direct/src/plugin/p3dInstance.cxx @@ -72,6 +72,7 @@ P3DInstance(P3D_request_ready_func *func, P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); _instance_id = inst_mgr->get_unique_id(); _hidden = false; + _allow_python_dev = false; _session = NULL; _panda3d = NULL; _splash_window = NULL; @@ -881,13 +882,17 @@ scan_app_desc_file(TiXmlDocument *doc) { _log_basename = log_basename; } - int hidden = 0; - TiXmlElement *xconfig = xpackage->FirstChildElement("config"); if (xconfig != NULL) { + int hidden = 0; if (xconfig->QueryIntAttribute("hidden", &hidden) == TIXML_SUCCESS) { _hidden = (hidden != 0); } + + int allow_python_dev = 0; + if (xconfig->QueryIntAttribute("allow_python_dev", &allow_python_dev) == TIXML_SUCCESS) { + _allow_python_dev = (allow_python_dev != 0); + } } if (_hidden && _got_wparams) { diff --git a/direct/src/plugin/p3dInstance.h b/direct/src/plugin/p3dInstance.h index 30523c20bb..2ca71650f1 100644 --- a/direct/src/plugin/p3dInstance.h +++ b/direct/src/plugin/p3dInstance.h @@ -161,6 +161,7 @@ private: string _python_version; string _log_basename; bool _hidden; + bool _allow_python_dev; P3DSession *_session; diff --git a/direct/src/plugin/p3dPythonRun.cxx b/direct/src/plugin/p3dPythonRun.cxx index 1a22dbe88b..ca2ad9ec73 100755 --- a/direct/src/plugin/p3dPythonRun.cxx +++ b/direct/src/plugin/p3dPythonRun.cxx @@ -1048,9 +1048,12 @@ add_package_info(P3DCInstance *inst, TiXmlElement *xpackage) { const char *platform = xpackage->Attribute("platform"); const char *version = xpackage->Attribute("version"); const char *host = xpackage->Attribute("host"); - if (name == NULL || version == NULL || host == NULL) { + if (name == NULL || host == NULL) { return; } + if (version == NULL) { + version = ""; + } if (platform == NULL) { platform = ""; } diff --git a/direct/src/plugin/p3dSession.cxx b/direct/src/plugin/p3dSession.cxx index f54ab6b787..71a61fafb2 100644 --- a/direct/src/plugin/p3dSession.cxx +++ b/direct/src/plugin/p3dSession.cxx @@ -663,6 +663,12 @@ start_p3dpython(P3DInstance *inst) { mkdir_complete(start_dir, nout); } +#ifdef _WIN32 + char sep = ';'; +#else + char sep = ':'; +#endif // _WIN32 + // Build up a search path that includes all of the required packages // that have already been installed. We build this in reverse // order, so that the higher-order packages come first in the list; @@ -673,17 +679,52 @@ start_p3dpython(P3DInstance *inst) { search_path = inst->_packages[pi]->get_package_dir(); while (pi > 0) { --pi; -#ifdef _WIN32 - search_path += ';'; -#else - search_path += ':'; -#endif // _WIN32 - + search_path += sep; search_path += inst->_packages[pi]->get_package_dir(); } nout << "Search path is " << search_path << "\n"; + bool python_dev = false; + if (inst->_allow_python_dev) { + // If "allow_python_dev" is set in the instance's p3d_info.xml, + // *and* we have python_dev in the tokens, then we set python_dev + // true. + python_dev = (inst->get_fparams().lookup_token_int("python_dev") != 0); + } + + string python_path = search_path; + string prc_path = search_path; + + if (python_dev) { + // With python_dev true, we preserve the PYTHONPATH setting from + // the caller's environment; in fact, we put it in the front. + // This allows the caller's on-disk Python files to shadow the + // similar-named files in the p3d file, allowing easy iteration on + // the code in the p3d file. + const char *pypath = getenv("PYTHONPATH"); + if (pypath != (char *)NULL) { + python_path = pypath; + python_path += sep; + python_path += search_path; + } + + // We also preserve PRC_PATH. + const char *prcpath = getenv("PRC_PATH"); + if (prcpath == NULL) { + prcpath = getenv("PANDA_PRC_PATH"); + } + if (prcpath != (char *)NULL) { + prc_path = prcpath; + prc_path += sep; + prc_path += search_path; + } + + nout << "python_dev is true\n" + << "PYTHONPATH set to: " << python_path << "\n" + << "PRC_PATH set to: " << prc_path << "\n"; + } + string p3dpython = P3D_PLUGIN_P3DPYTHON; if (p3dpython.empty()) { p3dpython = _python_root_dir + "/p3dpython"; @@ -728,7 +769,7 @@ start_p3dpython(P3DInstance *inst) { env += '\0'; env += "PYTHONPATH="; - env += search_path; + env += python_path; env += '\0'; env += "PYTHONHOME="; @@ -736,11 +777,11 @@ start_p3dpython(P3DInstance *inst) { env += '\0'; env += "PRC_PATH="; - env += search_path; + env += prc_path; env += '\0'; env += "PANDA_PRC_PATH="; - env += search_path; + env += prc_path; env += '\0'; // Define each package's root directory in an environment variable diff --git a/direct/src/plugin_standalone/panda3d.cxx b/direct/src/plugin_standalone/panda3d.cxx index 4838bc18ca..26b4e3f1b3 100644 --- a/direct/src/plugin_standalone/panda3d.cxx +++ b/direct/src/plugin_standalone/panda3d.cxx @@ -64,7 +64,7 @@ run(int argc, char *argv[]) { // 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:fw:t:s:o:l:h"; + const char *optstr = "+mu:p:fw:t:s:o:l:Dh"; bool allow_multiple = false; string download_url = PANDA_PACKAGE_HOST_URL; @@ -136,6 +136,15 @@ run(int argc, char *argv[]) { _log_basename = "panda3d"; break; + case 'D': + { + P3D_token token; + token._keyword = "python_dev"; + token._value = "1"; + _tokens.push_back(token); + } + break; + case 'h': case '?': case '+': @@ -780,6 +789,14 @@ usage() { << " if a new version is available. Normally, this is done only\n" << " if contents.xml cannot be read.\n\n" + << " -D\n" + << " Request python_dev mode. This requires that the application was\n" + << " also built with -D on the packp3d command line. If so, this will\n" + << " preserve the PYTHONPATH environment variable from the user's\n" + << " environment, allowing Python files on disk to shadow the same-named\n" + << " Python files within the p3d file, for rapid iteration on the Python\n" + << " code.\n\n" + << " -u url\n" << " Specify the URL of the Panda3D download server. The default is\n" << " \"" << PANDA_PACKAGE_HOST_URL << "\" .\n\n"