diff --git a/.travis.yml b/.travis.yml index 26088946eb..92732bb929 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,12 +4,12 @@ compiler: - clang before_script: - sudo apt-get install python-dev libpng-dev zlib1g-dev libssl-dev libx11-dev libgl1-mesa-dev libxrandr-dev libxxf86dga-dev libxcursor-dev bison flex libfreetype6-dev libvorbis-dev libjpeg-dev libopenal-dev libode-dev nvidia-cg-toolkit -script: python makepanda/makepanda.py --everything --git-commit $TRAVIS_COMMIT +script: python makepanda/makepanda.py --everything --git-commit $TRAVIS_COMMIT --installer notifications: irc: channels: - "chat.freenode.net#panda3d" on_success: change - on_failure: change + on_failure: always use_notice: true skip_join: true diff --git a/direct/src/autorestart/Sources.pp b/direct/src/autorestart/Sources.pp deleted file mode 100644 index a85fc78a17..0000000000 --- a/direct/src/autorestart/Sources.pp +++ /dev/null @@ -1,8 +0,0 @@ -#begin bin_target - // This program only compiles on Unix. - #define BUILD_TARGET $[UNIX_PLATFORM] - #define C++FLAGS -DWITHIN_PANDA - - #define TARGET autorestart - #define SOURCES autorestart.c -#end bin_target diff --git a/direct/src/autorestart/autorestart.c b/direct/src/autorestart/autorestart.c deleted file mode 100644 index bfcad109de..0000000000 --- a/direct/src/autorestart/autorestart.c +++ /dev/null @@ -1,901 +0,0 @@ -/* Filename: autorestart.c - * Created by: drose (05Sep02) - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * - * 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." - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifdef WITHIN_PANDA -#include "dtoolbase.h" -#endif - -#include -#include -#include -#include /* for strerror */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_LIBCURL -#include -#endif - -/* The maximum number of seconds to wait for a process to go away - after issuing SIGTERM. This is only used in watchdog mode, when -W - is provided on the command line. */ -#define MAX_WAITTERM_SEC 10 - -char **params = NULL; -char *logfile_name = NULL; -char *pidfile_name = NULL; -int dont_fork = 0; -char *watchdog_url = NULL; -int watchdog_start_sec = 0; -int watchdog_cycle_sec = 0; -int watchdog_timeout_sec = 0; -char *startup_username = NULL; -char *startup_groupname = NULL; -char *startup_chdir = NULL; -int logfile_fd = -1; -int stop_on_terminate = 0; -int stop_always = 0; -char *respawn_script = NULL; -int respawn_count_time = 0; - -/* If requested, delay these many seconds between restart attempts */ -int respawn_delay_time = 5; - - -/* We shouldn't respawn more than (spam_respawn_count - 1) times over - spam_respawn_time seconds. */ -int spam_respawn_count = 5; -int spam_respawn_time = 60; -int spam_restart_delay_time = 600; /* Optionally, do not exit if we spam too much; simply sleep for this many seconds*/ - - - -pid_t child_pid = 0; -pid_t watchdog_pid = 0; - -#define TIME_BUFFER_SIZE 128 - -/* Keep track of the frequency with which we respawn, so we can report - this to our respawn script. */ -typedef struct respawn_record_struct { - time_t _time; - struct respawn_record_struct *_next; -} respawn_record; - -respawn_record *respawns = NULL; - -int -record_respawn(time_t now) { - /* Records the respawning event in the respawn_record, and returns - the number of respawns in the last respawn_count_time - interval. */ - respawn_record *rec; - respawn_record *next; - int count; - - if (respawn_count_time <= 0) { - /* We're not tracking respawns if respawn_count_time is 0. */ - return 0; - } - - rec = (respawn_record *)malloc(sizeof(respawn_record)); - rec->_time = now; - rec->_next = respawns; - respawns = rec; - - /* Now walk through the rest of the list and count up the number of - respawn events until we reach a record more than - respawn_count_time seconds old. */ - count = 0; - while (rec->_next != NULL && - (now - rec->_time) <= respawn_count_time) { - rec = rec->_next; - count++; - } - - /* The remaining respawn records get removed. */ - next = rec->_next; - rec->_next = NULL; - while (next != NULL) { - rec = next; - next = rec->_next; - free(rec); - } - - return count; -} - -void -invoke_respawn_script(time_t now) { - char buffer[32]; - char *new_command; - int new_command_length; - - /* The process is about to be respawned; run the script that we were - given on the command line. */ - if (respawn_count_time <= 0) { - /* We're not counting respawn times, so just run the script - directly. */ - system(respawn_script); - - } else { - /* We are counting respawn times, so append that information as a - parameter to the command. */ - sprintf(buffer, " %d", record_respawn(now)); - new_command_length = strlen(respawn_script) + strlen(buffer); - new_command = (char *)malloc(new_command_length + 1); - strcpy(new_command, respawn_script); - strcat(new_command, buffer); - assert(strlen(new_command) == new_command_length); - - system(new_command); - - free(new_command); - } -} - -/* A callback function passed to libcurl that simply discards the data - retrieved from the server. We only care about the HTTP status. */ -size_t -watchdog_bitbucket(void *ptr, size_t size, size_t nmemb, void *userdata) { - return size * nmemb; -} - -/* Waits up to timeout_ms for a particular child to terminate. - Returns 0 if the timeout expires. */ -pid_t -waitpid_timeout(pid_t child_pid, int *status_ptr, int timeout_ms) { - pid_t result; - struct timeval now, tv; - int now_ms, start_ms, elapsed_ms; - - gettimeofday(&now, NULL); - start_ms = now.tv_sec * 1000 + now.tv_usec / 1000; - - result = waitpid(child_pid, status_ptr, WNOHANG); - while (result == 0) { - gettimeofday(&now, NULL); - now_ms = now.tv_sec * 1000 + now.tv_usec / 1000; - elapsed_ms = now_ms - start_ms; - - if (elapsed_ms > timeout_ms) { - /* Tired of waiting. */ - return 0; - } - - /* Yield the timeslice and wait some more. */ - tv.tv_sec = 0; - tv.tv_usec = 1; - select(0, NULL, NULL, NULL, &tv); - result = waitpid(child_pid, status_ptr, WNOHANG); - } - if (result == -1) { - perror("waitpid"); - } - - return result; -} - - -/* Poll the requested URL until a failure or timeout occurs, or until - the child terminates on its own. Returns 1 on HTTP failure or - timeout, 0 on self-termination. In either case, *status_ptr is - filled in with the status value returned by waitpid().*/ -int -do_watchdog(int *status_ptr) { -#ifndef HAVE_LIBCURL - fprintf(stderr, "Cannot watchdog; no libcurl available.\n"); - return 0; -#else /* HAVE_LIBCURL */ - - CURL *curl; - CURLcode res; - char error_buffer[CURL_ERROR_SIZE]; - pid_t wresult; - - // Before we start polling the URL, wait at least start milliseconds. - wresult = waitpid_timeout(child_pid, status_ptr, watchdog_start_sec * 1000); - if (wresult == child_pid) { - // The child terminated on its own before we got started. - return 0; - } - - curl = curl_easy_init(); - if (!curl) { - fprintf(stderr, "Cannot watchdog; curl failed to init.\n"); - return 0; - } - - curl_easy_setopt(curl, CURLOPT_URL, watchdog_url); - /*curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);*/ - curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, watchdog_timeout_sec * 1000); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, watchdog_bitbucket); - curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer); - curl_easy_setopt(curl, CURLOPT_USERAGENT, "autorestart"); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); - curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1); - curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1); - - res = curl_easy_perform(curl); - while (res == 0) { - /* 0: The HTTP request finished successfully (but might or might - not have returned an error code like a 404). */ - long http_response = 0; - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response); - if ((http_response / 100) != 2) { - /* Anything in the 200 range is deemed success. Anything else - is deemed failure. */ - fprintf(stderr, "%s returned %ld\n", watchdog_url, http_response); - break; - } - - wresult = waitpid_timeout(child_pid, status_ptr, watchdog_cycle_sec * 1000); - if (wresult == child_pid) { - /* The process terminated on its own. Return 0 to indicate this. */ - return 0; - } - - res = curl_easy_perform(curl); - } - - curl_easy_cleanup(curl); - - /* Failed to retrieve the watchdog URL. */ - if (res != 0) { - fprintf(stderr, "Failed to contact %s: %s\n", watchdog_url, error_buffer); - } - - /* Kill the child process and wait for it to go away. */ - kill(child_pid, SIGTERM); - - pid_t result = waitpid_timeout(child_pid, status_ptr, MAX_WAITTERM_SEC * 1000); - if (result != child_pid) { - if (result == -1) { - perror("waitpid"); - } else { - /* SIGTERM didn't make the process die. Try SIGKILL. */ - fprintf(stderr, "Force-killing child process\n"); - kill(child_pid, SIGKILL); - result = waitpid_timeout(child_pid, status_ptr, MAX_WAITTERM_SEC * 1000); - if (result == -1) { - perror("waitpid"); - } - } - } - - /* Return 1 to indicate we killed the child due to an HTTP error. */ - return 1; -#endif /* HAVE_LIBCURL */ -} - -void -exec_process() { - /* First, output the command line to the log file. */ - char **p; - for (p = params; *p != NULL; ++p) { - fprintf(stderr, "%s ", *p); - } - fprintf(stderr, "\n"); - execvp(params[0], params); - fprintf(stderr, "Cannot exec %s: %s\n", params[0], strerror(errno)); - - /* Exit with a status of 0, to indicate to the parent process that - we should stop. */ - exit(0); -} - -int -spawn_process() { - /* Spawns the child process. Returns true if the process terminated - by itself and should be respawned, false if it was explicitly - killed (or some other error condition exists), and it should not - respawn any more. */ - pid_t wresult; - int status; - int error_exit; - - child_pid = fork(); - if (child_pid < 0) { - /* Fork error. */ - perror("fork"); - return 0; - } - - if (child_pid == 0) { - /* Child. Exec the process. */ - fprintf(stderr, "Child pid is %d.\n", getpid()); - exec_process(); - /* Shouldn't get here. */ - exit(1); - } - - /* Parent. */ - - error_exit = 0; - - if (watchdog_url != NULL) { - /* If we're watchdogging, then go check the URL. This function - won't return until the URL fails or the child exits. */ - error_exit = do_watchdog(&status); - - } else { - /* If we're not watchdogging, then just wait for the child to - terminate, and diagnose the reason. */ - wresult = waitpid(child_pid, &status, 0); - if (wresult < 0) { - perror("waitpid"); - return 0; - } - } - - /* Now that we've returned from waitpid, clear the child pid number - so our signal handler doesn't get too confused. */ - child_pid = 0; - - if (error_exit) { - /* An HTTP error exit is a reason to respawn. */ - return 1; - - } else if (WIFSIGNALED(status)) { - int signal = WTERMSIG(status); - fprintf(stderr, "\nprocess caught signal %d.\n\n", signal); - /* A signal exit is a reason to respawn unless the signal is TERM - or KILL. */ - return !stop_on_terminate || (signal != SIGTERM && signal != SIGKILL); - - } else { - int exit_status = WEXITSTATUS(status); - fprintf(stderr, "\nprocess exited with status %d.\n\n", WEXITSTATUS(status)); - /* Normal exit is a reason to respawn if the status indicates failure. */ - return !stop_on_terminate || (exit_status != 0); - } -} - -void -sigterm_handler() { - pid_t wresult; - int status; - time_t now; - char time_buffer[TIME_BUFFER_SIZE]; - - now = time(NULL); - strftime(time_buffer, TIME_BUFFER_SIZE, "%T on %A, %d %b %Y", localtime(&now)); - - fprintf(stderr, "\nsigterm caught at %s; shutting down.\n", time_buffer); - if (child_pid == 0) { - fprintf(stderr, "no child process.\n\n"); - - } else { - kill(child_pid, SIGTERM); - - wresult = waitpid(child_pid, &status, 0); - if (wresult < 0) { - perror("waitpid"); - } else { - fprintf(stderr, "child process terminated.\n\n"); - } - } - exit(1); -} - -void -sighup_handler() { - time_t now; - char time_buffer[TIME_BUFFER_SIZE]; - - now = time(NULL); - strftime(time_buffer, TIME_BUFFER_SIZE, "%T on %A, %d %b %Y", localtime(&now)); - - fprintf(stderr, "\nsighup caught at %s.\n", time_buffer); - if (child_pid == 0) { - fprintf(stderr, "no child process.\n\n"); - - } else { - kill(child_pid, SIGHUP); - } -} - -void -sigalarm_handler() { - fprintf(stderr, "sleep epoch was complete.\n"); -} - -void -do_autorestart() { - char time_buffer[TIME_BUFFER_SIZE]; - time_t now; - time_t *spam_respawn = NULL; - int sri, num_sri; - struct sigaction sa; - - if (spam_respawn_count > 1) { - spam_respawn = (time_t *)malloc(sizeof(time_t) * spam_respawn_count); - } - - /* Make our process its own process group. */ - setpgid(0, 0); - - /* Set up a signal handler to trap SIGTERM. */ - sa.sa_handler = sigterm_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - if (sigaction(SIGTERM, &sa, NULL) < 0) { - perror("sigaction"); - } - - /* Set up a signal handler to trap SIGHUP. We pass this into the - child. */ - sa.sa_handler = sighup_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - if (sigaction(SIGHUP, &sa, NULL) < 0) { - perror("sigaction"); - } - - if (logfile_fd >= 0) { - /* If we have a logfile, dup it onto stdout and stderr. */ - dup2(logfile_fd, STDOUT_FILENO); - dup2(logfile_fd, STDERR_FILENO); - close(logfile_fd); - } - - /* Make sure stdin is closed. */ - close(STDIN_FILENO); - - now = time(NULL); - strftime(time_buffer, TIME_BUFFER_SIZE, "%T on %A, %d %b %Y", localtime(&now)); - fprintf(stderr, "autorestart begun at %s.\n", time_buffer); - - if (pidfile_name != NULL) { - unlink(pidfile_name); - FILE *pidfile = fopen(pidfile_name, "w"); - if (pidfile == NULL) { - fprintf(stderr, "Could not write pidfile %s\n", pidfile_name); - } else { - fprintf(pidfile, "%d\n", getpid()); - fclose(pidfile); - } - } - - sri = 1; - num_sri = 1; - if (spam_respawn_count > 1) { - spam_respawn[1] = now; - } - - while (spawn_process()) { - now = time(NULL); - - if (respawn_script != NULL) { - invoke_respawn_script(now); - } - - if (respawn_delay_time) { - sleep(respawn_delay_time); - } - - /* Make sure we're not respawning too fast. */ - if (spam_respawn_count > 1) { - sri = (sri + 1) % spam_respawn_count; - spam_respawn[sri] = now; - if (num_sri < spam_respawn_count) { - num_sri++; - } else { - time_t last = spam_respawn[(sri + 1) % spam_respawn_count]; - if (now - last < spam_respawn_time) - { - if(!spam_restart_delay_time) - { - fprintf(stderr, "respawning too fast, giving up.\n"); - break; - } - else - { - num_sri = 1; /* reset num_sri */ - fprintf(stderr, "respawning too fast, will sleep for %d seconds.\n", spam_restart_delay_time); - signal (SIGALRM, sigalarm_handler); - alarm(spam_restart_delay_time); - pause(); - signal (SIGALRM, SIG_IGN); - } - } - } - } - - if (stop_always) { - fprintf(stderr, "instructed to not autorestart, exiting.\n"); - break; - } - - strftime(time_buffer, TIME_BUFFER_SIZE, "%T on %A, %d %b %Y", localtime(&now)); - fprintf(stderr, "respawning at %s.\n", time_buffer); - } - - now = time(NULL); - strftime(time_buffer, TIME_BUFFER_SIZE, "%T on %A, %d %b %Y", localtime(&now)); - fprintf(stderr, "autorestart terminated at %s.\n", time_buffer); - exit(0); -} - -void -double_fork() { - pid_t child, grandchild, wresult; - int status; - - /* Fork once, then again, to disassociate the child from the command - shell process group. */ - child = fork(); - if (child < 0) { - /* Failure to fork. */ - perror("fork"); - exit(1); - } - - if (child == 0) { - /* Child. Fork again. */ - grandchild = fork(); - if (grandchild < 0) { - perror("fork"); - exit(1); - } - - if (grandchild == 0) { - /* Grandchild. Begin useful work. */ - do_autorestart(); - /* Shouldn't get here. */ - exit(1); - } - - /* Child. Report the new pid, then terminate gracefully. */ - fprintf(stderr, "Spawned, monitoring pid is %d.\n", grandchild); - exit(0); - } - - /* Parent. Wait for the child to terminate, then return. */ - wresult = waitpid(child, &status, 0); - if (wresult < 0) { - perror("waitpid"); - exit(1); - } - - if (!WIFEXITED(status)) { - if (WIFSIGNALED(status)) { - fprintf(stderr, "child caught signal %d unexpectedly.\n", WTERMSIG(status)); - } else { - fprintf(stderr, "child exited with status %d.\n", WEXITSTATUS(status)); - } - exit(1); - } -} - -void -usage() { - fprintf(stderr, - "\n" - "autorestart [opts] program [args . . . ]\n" - "autorestart -h\n\n"); -} - -void -help() { - usage(); - fprintf(stderr, - "This program is used to run a program as a background task and\n" - "automatically restart it should it terminate for any reason other\n" - "than normal exit or explicit user kill.\n\n" - - "If the program exits with a status of 0, indicating successful\n" - "completion, it is not restarted.\n\n" - - "If the program is terminated via a TERM or KILL signal (e.g. via\n" - "kill [pid] or kill -9 [pid]), it is assumed the user meant for the\n" - "process to stop, and it is not restarted.\n\n" - - "Options:\n\n" - - " -l logfilename\n" - " Route stdout and stderr from the child process into the indicated\n" - " log file.\n\n" - - " -p pidfilename\n" - " Write the pid of the monitoring process to the indicated pidfile.\n\n" - " -f\n" - " Don't fork autorestart itself; run it as a foreground process. \n" - " (Normally, autorestart forks itself to run as a background process.)\n" - " In this case, the file named by -p is not used.\n\n" - - " -n\n" - " Do not attempt to restart the process under any circumstance.\n" - " The program can still be used to execute a script on abnormal\n" - " process termination.\n\n" - - " -t\n" - " Stop on terminate: don't restart if the child process exits\n" - " normally or is killed with a SIGTERM. With this flag, the\n" - " child process will be restarted only if it exits with a\n" - " non-zero exit status, or if it is killed with a signal other\n" - " than SIGTERM. Without this flag, the default behavior is to\n" - " restart the child process if it exits for any reason.\n\n" - - " -r count,secs,sleep\n" - " Sleep 'sleep' seconds if the process respawns 'count' times\n" - " within 'secs' seconds. This is designed to prevent respawning\n" - " from using too many system resources if something is wrong with\n" - " the child process. The default value is %d,%d,%d. Use -r 0,0,0\n" - " to disable this feature.\n\n" - - " -s \"command\"\n" - " Run the indicated command or script each time the process is\n" - " respawned, using the system() call. This may be useful, for\n" - " instance, to notify an operator via email each time a respawn\n" - " occurs. If -c is also specified, an additional parameter will\n" - " be appended to the command, indicating the number of times the\n" - " respawn has occurred in the given time interval.\n\n" - - " -c secs\n" - " Specifies the number of seconds over which to count respawn events\n" - " for the purposes of passing an argument to the script named with\n" - " -s.\n\n" - - " -d secs\n" - " Specifies the number of seconds to delay for between restarts.\n" - " The default is %d.\n\n" - -#ifdef HAVE_LIBCURL - " -W watchdog_url,start,cycle,timeout\n" - " Specifies an optional URL to watch while waiting for the process\n" - " to terminate. If this is specified, autorestart will start the process,\n" - " wait start seconds, and then repeatedly poll the indicated URL\n" - " every cycle seconds. If a HTTP failure code is detected,\n" - " or no response is received within timeout seconds, then the\n" - " child is terminated and restarted. The start, cycle, and timeout\n" - " parameters are all required.\n\n" -#endif /* HAVE_LIBCURL */ - - " -U username\n" - " Change to the indicated user upon startup. The logfile is still\n" - " created as the initial user.\n\n" - - " -G groupname\n" - " Change to the indicated group upon startup.\n\n" - - " -D dirname\n" - " Change to the indicated working directory upon startup. The logfile\n" - " is still created relative to the initial startup directory.\n\n" - - " -h\n" - " Output this help information.\n\n", - spam_respawn_count, spam_respawn_time, spam_restart_delay_time, respawn_delay_time); -} - -void -parse_int_triplet(char *param, int *a, int *b, int *c) { - char *comma; - char *comma2; - - comma = strchr(param, ','); - if (comma == NULL) { - fprintf(stderr, "Comma required: %s\n", param); - exit(1); - } - - comma2 = strchr(comma+1, ','); - if (comma2 == NULL) { - fprintf(stderr, "Second comma required: %s\n", param); - exit(1); - } - - *comma = '\0'; - *comma2 = '\0'; - - *a = atoi(param); - *b = atoi(comma + 1); - *c = atoi(comma2 + 1); -} - -void -parse_watchdog(char *param) { - char *comma; - char *comma2; - char *comma3; - -#ifndef HAVE_LIBCURL - fprintf(stderr, "-W requires autorestart to have been compiled with libcurl support.\n"); - exit(1); -#endif /* HAVE_LIBCURL */ - - comma = strrchr(param, ','); - if (comma == NULL) { - fprintf(stderr, "Comma required: %s\n", param); - exit(1); - } - *comma = '\0'; - - comma2 = strrchr(param, ','); - if (comma2 == NULL) { - *comma = ','; - fprintf(stderr, "Second comma required: %s\n", param); - exit(1); - } - *comma2 = '\0'; - - comma3 = strrchr(param, ','); - if (comma3 == NULL) { - *comma = ','; - *comma2 = ','; - fprintf(stderr, "Third comma required: %s\n", param); - exit(1); - } - *comma3 = '\0'; - - watchdog_url = param; - watchdog_start_sec = atoi(comma3 + 1); - watchdog_cycle_sec = atoi(comma2 + 1); - watchdog_timeout_sec = atoi(comma + 1); -} - - -int -main(int argc, char *argv[]) { - extern char *optarg; - extern int optind; - /* The initial '+' instructs GNU getopt not to reorder switches. */ - static const char *optflags = "+l:p:fntr:s:c:d:W:U:G:D:h"; - int flag; - - flag = getopt(argc, argv, optflags); - while (flag != EOF) { - switch (flag) { - case 'l': - logfile_name = optarg; - break; - - case 'p': - pidfile_name = optarg; - break; - - case 'f': - dont_fork = 1; - break; - - case 'n': - stop_always = 1; - break; - - case 't': - stop_on_terminate = 1; - break; - - case 'r': - parse_int_triplet(optarg, &spam_respawn_count, &spam_respawn_time, &spam_restart_delay_time); - break; - - case 's': - respawn_script = optarg; - break; - - case 'c': - respawn_count_time = atoi(optarg); - break; - - case 'd': - respawn_delay_time = atoi(optarg); - break; - - case 'W': - parse_watchdog(optarg); - break; - - case 'U': - startup_username = optarg; - break; - - case 'G': - startup_groupname = optarg; - break; - - case 'D': - startup_chdir = optarg; - break; - - case 'h': - help(); - return 1; - - case '?': - case '+': - usage(); - return 1; - - default: - fprintf(stderr, "Unhandled switch: -%c\n", flag); - return 1; - } - flag = getopt(argc, argv, optflags); - } - - argc -= (optind - 1); - argv += (optind - 1); - - if (argc < 2) { - fprintf(stderr, "No program to execute given.\n"); - usage(); - return 1; - } - - params = &argv[1]; - - if (logfile_name != NULL) { - logfile_fd = open(logfile_name, O_WRONLY | O_CREAT | O_TRUNC, 0666); - if (logfile_fd < 0) { - fprintf(stderr, "Cannot write to logfile %s: %s\n", - logfile_name, strerror(errno)); - return 1; - } - fprintf(stderr, "Generating output to %s.\n", logfile_name); - } - - if (startup_chdir != NULL) { - if (chdir(startup_chdir) != 0) { - perror(startup_chdir); - return 1; - } - } - - if (startup_groupname != NULL) { - struct group *grp; - grp = getgrnam(startup_groupname); - if (grp == NULL) { - perror(startup_groupname); - return 1; - } - - if (setgid(grp->gr_gid) != 0) { - perror(startup_groupname); - return 1; - } - } - - if (startup_username != NULL) { - struct passwd *pwd; - pwd = getpwnam(startup_username); - if (pwd == NULL) { - perror(startup_username); - return 1; - } - - if (setuid(pwd->pw_uid) != 0) { - perror(startup_username); - return 1; - } - } - - if (dont_fork) { - do_autorestart(); - } else { - double_fork(); - } - - return 0; -} - diff --git a/direct/src/dcparser/dcPacker.cxx b/direct/src/dcparser/dcPacker.cxx index 9be83fda34..c0e711ecc6 100755 --- a/direct/src/dcparser/dcPacker.cxx +++ b/direct/src/dcparser/dcPacker.cxx @@ -20,6 +20,10 @@ #include "dcSwitchParameter.h" #include "dcClass.h" +#ifdef HAVE_PYTHON +#include "py_panda.h" +#endif + DCPacker::StackElement *DCPacker::StackElement::_deleted_chain = NULL; int DCPacker::StackElement::_num_ever_allocated = 0; diff --git a/direct/src/dcparser/dcPacker.h b/direct/src/dcparser/dcPacker.h index 0c7cfb58ab..bbbcb3e2d3 100755 --- a/direct/src/dcparser/dcPacker.h +++ b/direct/src/dcparser/dcPacker.h @@ -220,7 +220,7 @@ private: const DCPackerCatalog *_catalog; const DCPackerCatalog::LiveCatalog *_live_catalog; - class StackElement { + class EXPCL_DIRECT StackElement { public: // As an optimization, we implement operator new and delete here // to minimize allocation overhead during push() and pop(). diff --git a/direct/src/directnotify/Notifier.py b/direct/src/directnotify/Notifier.py index eb91d5244e..2d59c5bf70 100644 --- a/direct/src/directnotify/Notifier.py +++ b/direct/src/directnotify/Notifier.py @@ -4,7 +4,7 @@ for the programmer/user """ from LoggerGlobal import defaultLogger from direct.showbase import PythonUtil -from panda3d.core import ConfigVariableBool +from panda3d.core import ConfigVariableBool, NotifyCategory, StreamWriter, Notify import time import types import sys @@ -18,9 +18,8 @@ class Notifier: # with the C++ notify system. streamWriter = None if ConfigVariableBool('notify-integrate', True): - from panda3d.core import StreamWriter, Notify streamWriter = StreamWriter(Notify.out(), False) - + showTime = ConfigVariableBool('notify-timestamp', False) def __init__(self, name, logger=None): @@ -44,9 +43,6 @@ class Notifier: self.__warning = 1 self.__debug = 0 self.__logging = 0 - - - def setServerDelta(self, delta, timezone): """ @@ -62,7 +58,6 @@ class Notifier: # The following call is necessary to make the output from C++ # notify messages show the same timestamp as those generated # from Python-level notify messages. - from pandac.PandaModules import NotifyCategory NotifyCategory.setServerDelta(self.serverDelta) self.info("Notify clock adjusted by %s (and timezone adjusted by %s hours) to synchronize with server." % (PythonUtil.formatElapsedSeconds(delta), (time.timezone - timezone) / 3600)) @@ -92,7 +87,7 @@ class Notifier: # Severity funcs def setSeverity(self, severity): - from pandac.PandaModules import NSDebug, NSInfo, NSWarning, NSError + from panda3d.core import NSDebug, NSInfo, NSWarning, NSError if severity >= NSError: self.setWarning(0) self.setInfo(0) @@ -111,7 +106,7 @@ class Notifier: self.setDebug(1) def getSeverity(self): - from pandac.PandaModules import NSDebug, NSInfo, NSWarning, NSError + from panda3d.core import NSDebug, NSInfo, NSWarning, NSError if self.getDebug(): return NSDebug elif self.getInfo(): diff --git a/direct/src/directscripts/Doxyfile.python b/direct/src/directscripts/Doxyfile.python index 32ba23481d..81b68dc6b2 100644 --- a/direct/src/directscripts/Doxyfile.python +++ b/direct/src/directscripts/Doxyfile.python @@ -643,8 +643,7 @@ RECURSIVE = YES # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. -EXCLUDE = built/direct/test \ - built/direct/plugin \ +EXCLUDE = built/direct/plugin \ built/direct/plugin_npapi \ built/direct/plugin_activex \ built/direct/plugin_installer \ diff --git a/direct/src/directscripts/profilepaths-osx.command b/direct/src/directscripts/profilepaths-osx.command old mode 100644 new mode 100755 diff --git a/direct/src/distributed/cConnectionRepository.cxx b/direct/src/distributed/cConnectionRepository.cxx index 75bde7d1d0..1216d85758 100644 --- a/direct/src/distributed/cConnectionRepository.cxx +++ b/direct/src/distributed/cConnectionRepository.cxx @@ -26,11 +26,7 @@ #include "pStatTimer.h" #ifdef HAVE_PYTHON -#ifndef CPPPARSER -#include "py_panda.h" -IMPORT_THIS struct Dtool_PyTypedObject Dtool_DatagramIterator; -IMPORT_THIS struct Dtool_PyTypedObject Dtool_DCClass; -#endif +#include "py_panda.h" #endif const string CConnectionRepository::_overflow_event_name = "CRDatagramOverflow"; @@ -42,14 +38,13 @@ PStatCollector CConnectionRepository::_update_pcollector("App:Show code:readerPo //////////////////////////////////////////////////////////////////// // Function: CConnectionRepository::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// CConnectionRepository:: CConnectionRepository(bool has_owner_view, bool threaded_net) : _lock("CConnectionRepository::_lock"), #ifdef HAVE_PYTHON _python_repository(NULL), - _python_ai_datagramiterator(NULL), #endif #ifdef HAVE_OPENSSL _http_conn(NULL), @@ -82,19 +77,12 @@ CConnectionRepository(bool has_owner_view, bool threaded_net) : } #endif _tcp_header_size = tcp_header_size; - -#ifdef HAVE_PYTHON - PyObject * PyDitterator = DTool_CreatePyInstance(&_di,Dtool_DatagramIterator,false,false); - if(PyDitterator != NULL) - _python_ai_datagramiterator = Py_BuildValue("(O)",PyDitterator); -#endif - } //////////////////////////////////////////////////////////////////// // Function: CConnectionRepository::Destructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// CConnectionRepository:: ~CConnectionRepository() { @@ -182,7 +170,7 @@ try_connect_net(const URLSpec &url) { disconnect(); - _net_conn = + _net_conn = _qcm.open_TCP_client_connection(url.get_server(), url.get_port(), game_server_timeout_ms); @@ -315,7 +303,7 @@ check_datagram() { _msg_channels.push_back(schan); } _msg_sender = _di.get_uint64(); - + #ifdef HAVE_PYTHON // For now, we need to stuff this field onto the Python // structure, to support legacy code that expects to find it @@ -361,7 +349,7 @@ check_datagram() { } break; #endif // HAVE_PYTHON - + default: // Some unknown message; let the caller deal with it. return true; @@ -372,9 +360,6 @@ check_datagram() { return false; } - - - //////////////////////////////////////////////////////////////////// // Function: CConnectionRepository::is_connected // Access: Published @@ -745,7 +730,7 @@ handle_update_field() { PStatTimer timer(_update_pcollector); unsigned int do_id = _di.get_uint32(); - if (_python_repository != (PyObject *)NULL) + if (_python_repository != (PyObject *)NULL) { PyObject *doId2do = PyObject_GetAttrString(_python_repository, "doId2do"); @@ -794,9 +779,9 @@ handle_update_field() { // method might get into trouble if it tried to delete the // object from the doId2do map. Py_INCREF(distobj); - dclass->receive_update(distobj, _di); + dclass->receive_update(distobj, _di); Py_DECREF(distobj); - + if (PyErr_Occurred()) { #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) PyGILState_Release(gstate); @@ -810,7 +795,7 @@ handle_update_field() { #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) PyGILState_Release(gstate); #endif - #endif // HAVE_PYTHON + #endif // HAVE_PYTHON return true; } @@ -880,9 +865,9 @@ handle_update_field_owner() { // make a copy of the datagram iterator so that we can use the main // iterator for the non-owner update DatagramIterator _odi(_di); - dclass->receive_update(distobjOV, _odi); + dclass->receive_update(distobjOV, _odi); Py_DECREF(distobjOV); - + if (PyErr_Occurred()) { #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) PyGILState_Release(gstate); @@ -919,9 +904,9 @@ handle_update_field_owner() { // method might get into trouble if it tried to delete the // object from the doId2do map. Py_INCREF(distobj); - dclass->receive_update(distobj, _di); + dclass->receive_update(distobj, _di); Py_DECREF(distobj); - + if (PyErr_Occurred()) { #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) PyGILState_Release(gstate); @@ -935,7 +920,7 @@ handle_update_field_owner() { #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) PyGILState_Release(gstate); #endif -#endif // HAVE_PYTHON +#endif // HAVE_PYTHON return true; } @@ -948,17 +933,17 @@ handle_update_field_owner() { // output stream. //////////////////////////////////////////////////////////////////// void CConnectionRepository:: -describe_message(ostream &out, const string &prefix, +describe_message(ostream &out, const string &prefix, const Datagram &dg) const { DCPacker packer; - + packer.set_unpack_data(dg.get_message()); CHANNEL_TYPE do_id; int msg_type; bool is_update = false; string full_prefix = "CR::" + prefix; - if (!_client_datagram) + if (!_client_datagram) { unsigned char mcnt = packer.raw_unpack_uint8(); for( ;mcnt > 0; mcnt--) @@ -967,7 +952,7 @@ describe_message(ostream &out, const string &prefix, packer.RAW_UNPACK_CHANNEL(); // msg_sender msg_type = packer.raw_unpack_uint16(); is_update = (msg_type == STATESERVER_OBJECT_SET_FIELD); - + } else { msg_type = packer.raw_unpack_uint16(); is_update = (msg_type == CLIENT_OBJECT_SET_FIELD); @@ -1045,12 +1030,12 @@ describe_message(ostream &out, const string &prefix, Py_DECREF(dclass_this); } } - #endif // HAVE_PYTHON + #endif // HAVE_PYTHON int field_id = packer.raw_unpack_uint16(); if (dclass == (DCClass *)NULL) { - out << full_prefix << "update for unknown object " << do_id + out << full_prefix << "update for unknown object " << do_id << ", field " << field_id << "\n"; } else { @@ -1059,7 +1044,7 @@ describe_message(ostream &out, const string &prefix, DCField *field = dclass->get_field_by_index(field_id); if (field == (DCField *)NULL) { out << "unknown field " << field_id << "\n"; - + } else { out << field->get_name(); packer.begin_unpack(field); @@ -1070,148 +1055,3 @@ describe_message(ostream &out, const string &prefix, } } } - - - - -#ifdef HAVE_PYTHON -#ifdef WANT_NATIVE_NET - -bool CConnectionRepository::network_based_reader_and_yielder(PyObject *PycallBackFunction,ClockObject &clock, float returnBy) -{ - ReMutexHolder holder(_lock); - while(is_connected()) - { - check_datagram_ai(PycallBackFunction); - if(is_connected()) - _bdc.Flush(); - float currentTime = clock.get_real_time(); - float dif_time = returnBy - currentTime; - if(dif_time <= 0.001) // to avoi over runs.. - break; - if(is_connected()) - _bdc.WaitForNetworkReadEvent(dif_time); - } - return false; -} - -bool CConnectionRepository::check_datagram_ai(PyObject *PycallBackFunction) -{ - ReMutexHolder holder(_lock); - // these could be static .. not - PyObject *doId2do = NULL; - float startTime =0; - float endTime = 0; - // this seems weird...here - _bdc.Flush(); - while (_bdc.GetMessage(_dg)) - { - if (get_verbose()) - describe_message(nout, "RECV", _dg); - - if (_time_warning > 0) - startTime = ClockObject::get_global_clock()->get_real_time(); - - // Start breaking apart the datagram. - _di.assign(_dg); - unsigned char wc_cnt = _di.get_uint8(); - _msg_channels.clear(); - for(unsigned char lp1 = 0; lp1 < wc_cnt; lp1++) - _msg_channels.push_back(_di.get_uint64()); - - _msg_sender = _di.get_uint64(); - _msg_type = _di.get_uint16(); - - if( _msg_type == STATESERVER_OBJECT_SET_FIELD) - { - if(doId2do == NULL) - { - // this is my attemp to take it out of the inner loop RHH - doId2do =PyObject_GetAttrString(_python_repository, "doId2do"); - nassertr(doId2do != NULL, false); - } - - if (!handle_update_field_ai(doId2do)) - { - Py_XDECREF(doId2do); - if (_time_warning > 0) { - endTime = ClockObject::get_global_clock()->get_real_time(); - if ( _time_warning < (endTime - startTime)) { - nout << "msg " << _msg_type <<" from " << _msg_sender << " took "<< (endTime-startTime) << "secs to process\n"; - _dg.dump_hex(nout,2); - } - } - return false; - } - } - else - { - PyObject * result = PyEval_CallObject(PycallBackFunction, _python_ai_datagramiterator); - if (PyErr_Occurred()) - { - Py_XDECREF(doId2do); - if (_time_warning > 0) { - endTime = ClockObject::get_global_clock()->get_real_time(); - if ( _time_warning < (endTime - startTime)) { - nout << "msg " << _msg_type <<" from " << _msg_sender << " took "<< (endTime-startTime) << "secs to process\n"; - _dg.dump_hex(nout,2); - } - } - return true; - } - } - - if (_time_warning > 0) { - endTime = ClockObject::get_global_clock()->get_real_time(); - if ( _time_warning < (endTime - startTime)) { - nout << "msg " << _msg_type <<" from " << _msg_sender << " took "<< (endTime-startTime) << "secs to process\n"; - _dg.dump_hex(nout,2); - } - } - - } - - - Py_XDECREF(doId2do); - return false; -} - -#endif // #ifdef WANT_NATIVE_NET -#endif // #ifdef HAVE_PYTHON - - -#ifdef HAVE_PYTHON -#ifdef WANT_NATIVE_NET - - -bool CConnectionRepository::handle_update_field_ai(PyObject *doId2do) -{ - PStatTimer timer(_update_pcollector); - unsigned int do_id = _di.get_uint32(); - - PyObject *doId = PyLong_FromUnsignedLong(do_id); - PyObject *distobj = PyDict_GetItem(doId2do, doId); - Py_DECREF(doId); - - if (distobj != NULL) - { - PyObject *dclass_obj = PyObject_GetAttrString(distobj, "dclass"); - nassertr(dclass_obj != NULL, false); - - DCClass *dclass = NULL; - DTOOL_Call_ExtractThisPointerForType(dclass_obj, &Dtool_DCClass, (void **) &dclass); - if(dclass == NULL) - return false; - - Py_INCREF(distobj); - dclass->receive_update(distobj, _di); - Py_DECREF(distobj); - - if (PyErr_Occurred()) - return false; - } - return true; -} - -#endif // #ifdef WANT_NATIVE_NET -#endif // #ifdef HAVE_PYTHON diff --git a/direct/src/distributed/cConnectionRepository.h b/direct/src/distributed/cConnectionRepository.h index d7adac4714..06f581764c 100644 --- a/direct/src/distributed/cConnectionRepository.h +++ b/direct/src/distributed/cConnectionRepository.h @@ -100,7 +100,7 @@ PUBLISHED: #endif #ifdef HAVE_NET BLOCKING bool try_connect_net(const URLSpec &url); - + INLINE QueuedConnectionManager &get_qcm(); INLINE ConnectionWriter &get_cw(); INLINE QueuedConnectionReader &get_qcr(); @@ -117,13 +117,7 @@ PUBLISHED: #endif BLOCKING bool check_datagram(); -#ifdef HAVE_PYTHON -#ifdef WANT_NATIVE_NET - BLOCKING bool check_datagram_ai(PyObject *PycallBackFunction); - BLOCKING bool network_based_reader_and_yielder(PyObject *PycallBackFunction,ClockObject &clock, float returnBy); -#endif -#endif - + BLOCKING INLINE void get_datagram(Datagram &dg); BLOCKING INLINE void get_datagram_iterator(DatagramIterator &di); BLOCKING INLINE CHANNEL_TYPE get_msg_channel(int offset = 0) const; @@ -167,18 +161,11 @@ PUBLISHED: INLINE float get_time_warning() const; private: -#ifdef HAVE_PYTHON -#ifdef WANT_NATIVE_NET - bool handle_update_field_ai(PyObject *doId2do); -#endif -#endif - - bool do_check_datagram(); bool handle_update_field(); bool handle_update_field_owner(); - void describe_message(ostream &out, const string &prefix, + void describe_message(ostream &out, const string &prefix, const Datagram &dg) const; private: @@ -186,7 +173,6 @@ private: #ifdef HAVE_PYTHON PyObject *_python_repository; - PyObject *_python_ai_datagramiterator; #endif #ifdef HAVE_OPENSSL diff --git a/direct/src/ffi/DoGenPyCode.py b/direct/src/ffi/DoGenPyCode.py index 62b15585a1..5bb7cb56e7 100644 --- a/direct/src/ffi/DoGenPyCode.py +++ b/direct/src/ffi/DoGenPyCode.py @@ -143,7 +143,7 @@ def doGetopts(): doSqueeze = False elif (flag == '-s'): deleteSourceAfterSqueeze = False - + else: FFIConstants.notify.error('illegal option: ' + flag) @@ -168,7 +168,7 @@ def doGetopts(): if codeLib not in newLibs: newLibs.append(codeLib) codeLibs = newLibs - + def doErrorCheck(): global outputCodeDir @@ -278,9 +278,9 @@ def generateNativeWrappers(): # in the runtime (plugin) environment, where all libraries are # not necessarily downloaded. if sys.version_info >= (3, 0): - pandaModules.write('try:\n from .%s import *\nexcept ImportError as err:\n if "DLL loader cannot find" not in str(err):\n raise\n' % (metaModuleName)) + pandaModules.write('try:\n from .%s import *\nexcept ImportError as err:\n if "DLL loader cannot find" not in str(err):\n raise\n' % (metaModuleName)) else: - pandaModules.write('try:\n from %s import *\nexcept ImportError, err:\n if "DLL loader cannot find" not in str(err):\n raise\n' % (metaModuleName)) + pandaModules.write('try:\n from %s import *\nexcept ImportError, err:\n if "DLL loader cannot find" not in str(err):\n raise\n' % (metaModuleName)) # Not sure if this message is helpful or annoying. #pandaModules.write(' print("Failed to import %s")\n' % (moduleName)) @@ -306,7 +306,7 @@ def generateNativeWrappers(): extension = open(extensionFilename, 'r') moduleModules.write(extension.read()) moduleModules.write('\n') - + def run(): global outputCodeDir diff --git a/direct/src/filter/CommonFilters.py b/direct/src/filter/CommonFilters.py index ee3de9ac8d..a561487e16 100644 --- a/direct/src/filter/CommonFilters.py +++ b/direct/src/filter/CommonFilters.py @@ -167,7 +167,7 @@ class CommonFilters: auxbits |= AuxBitplaneAttrib.ABOGlow if ("VolumetricLighting" in configuration): - needtex[configuration["VolumetricLighting"].source] = True + needtex.add(configuration["VolumetricLighting"].source) for tex in needtex: self.textures[tex] = Texture("scene-" + tex) @@ -199,7 +199,7 @@ class CommonFilters: self.ssao[0].setShaderInput("depth", self.textures["depth"]) self.ssao[0].setShaderInput("normal", self.textures["aux"]) self.ssao[0].setShaderInput("random", loader.loadTexture("maps/random.rgb")) - self.ssao[0].setShader(Shader.make(SSAO_BODY % configuration["AmbientOcclusion"].numsamples)) + self.ssao[0].setShader(Shader.make(SSAO_BODY % configuration["AmbientOcclusion"].numsamples, Shader.SL_Cg)) self.ssao[1].setShaderInput("src", ssao0) self.ssao[1].setShader(self.loadShader("filter-blurx.sha")) self.ssao[2].setShaderInput("src", ssao1) @@ -339,7 +339,7 @@ class CommonFilters: text += " o_color = float4(1, 1, 1, 1) - o_color;\n" text += "}\n" - self.finalQuad.setShader(Shader.make(text)) + self.finalQuad.setShader(Shader.make(text, Shader.SL_Cg)) for tex in self.textures: self.finalQuad.setShaderInput("tx"+tex, self.textures[tex]) diff --git a/direct/src/heapq/Sources.pp b/direct/src/heapq/Sources.pp deleted file mode 100755 index e072ecf367..0000000000 --- a/direct/src/heapq/Sources.pp +++ /dev/null @@ -1,29 +0,0 @@ -// DIR_TYPE "metalib" indicates we are building a shared library that -// consists mostly of references to other shared libraries. Under -// Windows, this directly produces a DLL (as opposed to the regular -// src libraries, which don't produce anything but a pile of OBJ files -// under Windows). - -#define DIR_TYPE metalib - -// This directory strictly contains a Python utility; therefore, only -// build it if we actually have Python. -#define BUILD_DIRECTORY $[HAVE_PYTHON] - - -#define OTHER_LIBS \ - pandaexpress:m \ - p3dconfig:c p3dtoolconfig:m \ - p3dtoolutil:c p3dtoolbase:c p3prc:c p3dtool:m - -#begin metalib_target - #define TARGET p3heapq - - // Tell ppremake to treat this file as if it had been generated via - // interrogate. On OSX, this will move it into the .so, instead of - // the .dylib, so that it can be imported into Python. - #define PYTHON_MODULE_ONLY 1 - - #define SOURCES heapq.cxx -#end metalib_target - diff --git a/direct/src/heapq/heapq.cxx b/direct/src/heapq/heapq.cxx deleted file mode 100755 index dcfe34f4bd..0000000000 --- a/direct/src/heapq/heapq.cxx +++ /dev/null @@ -1,240 +0,0 @@ - -/* Note: This module can probably go away when we upgrade to Python 2.4. - Python 2.3 has a heapq implementation, but it is in Python. This is - reported to be about 20x faster. In 2.4 they reimplemented heapq in C so - it should be comparable to this. At this time though, Python 2.4 is - still in alpha. - - Note: This code has been bastardized to only work on Tasks temporarily. - -*/ - -#include - -/* Prototypes */ -static PyObject * heappush(PyObject *self, PyObject *args); -static PyObject * heappop(PyObject *self, PyObject *args); -static PyObject * heapreplace(PyObject *self, PyObject *args); -static PyObject * heapify(PyObject *self, PyObject *args); -static int _siftdown(PyObject *list, int startpos, int pos); -static int _siftup(PyObject *list, int pos); - -#ifdef _WIN32 -extern "C" __declspec(dllexport) void initlibheapq(void); -extern "C" __declspec(dllexport) void initlibp3heapq(void); -#else -extern "C" void initlibheapq(); -extern "C" void initlibp3heapq(); -#endif - -static PyObject * -heappush(PyObject *self, PyObject *args) { - int len; - PyObject *list = NULL; - PyObject *node = NULL; - - if (!PyArg_ParseTuple(args,"O!O",&PyList_Type,&list,&node)) - return NULL; - - len = PyList_Size(list); - if (PyList_Append(list,node)) - return NULL; - - if (_siftdown(list,0,len)) - return NULL; - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -heappop(PyObject *self, PyObject *args) { - PyObject *list = NULL; - PyObject *node = NULL; - PyObject *returnNode = NULL; - int len; - - if (!PyArg_ParseTuple(args,"O!",&PyList_Type,&list)) - return NULL; - - len = PyList_Size(list); - if (len == 0) { - /* Special-case most common failure cause */ - PyErr_SetString(PyExc_IndexError, "pop from empty list"); - return NULL; - } - - node = PySequence_GetItem(list,-1); - PySequence_DelItem(list,-1); - - len -= 1; - if (len > 0) { - returnNode = PySequence_GetItem(list,0); - PyList_SetItem(list,0,node); - if (_siftup(list,0)) - return NULL; - } else { - returnNode = node; - } - - return returnNode; -} - -static PyObject * -heapreplace(PyObject *self, PyObject *args) { - PyObject *list = NULL; - PyObject *node = NULL; - PyObject *returnNode = NULL; - int len; - - if (!PyArg_ParseTuple(args,"O!O",&PyList_Type,&list,&node)) - return NULL; - - len = PyList_Size(list); - if (len == 0) { - /* Special-case most common failure cause */ - PyErr_SetString(PyExc_IndexError, "replace on an empty list"); - return NULL; - } - - returnNode = PySequence_GetItem(list,0); - PySequence_SetItem(list,0,node); - if (_siftup(list,0)) - return NULL; - - return returnNode; -} - -static PyObject * -heapify(PyObject *self, PyObject *args) { - int n, i; - PyObject *list; - - if (!PyArg_ParseTuple(args,"O!",&PyList_Type,&list)) - return NULL; - n = (PyList_Size(list)/2)-1; - - for (i=n;i>=0;i--) { - if (_siftup(list,i)) - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -static int -_siftdown(PyObject *list, int startpos, int pos) { - PyObject *newitem, *parent; - int parentpos; - - newitem = PySequence_GetItem(list,pos); - - PyObject *newitem_wakeTime_obj = PyObject_GetAttrString(newitem, "wakeTime"); - double newitem_wakeTime = 0.0; - if (newitem_wakeTime_obj != NULL) { - newitem_wakeTime = PyFloat_AS_DOUBLE(newitem_wakeTime_obj); - Py_DECREF(newitem_wakeTime_obj); - } - - while (pos > startpos) { - parentpos = (pos - 1) >> 1; - parent = PyList_GetItem(list,parentpos); - - /* - cmp = PyObject_RichCompareBool(parent,newitem,Py_LE); - if (cmp > 0) - break; - else if (cmp < 0) - return -1; - */ - - PyObject *parent_wakeTime_obj = PyObject_GetAttrString(parent, "wakeTime"); - double parent_wakeTime = 0.0; - if (parent_wakeTime_obj != NULL) { - parent_wakeTime = PyFloat_AS_DOUBLE(parent_wakeTime_obj); - Py_DECREF(parent_wakeTime_obj); - } - - if (parent_wakeTime <= newitem_wakeTime) { - break; - } - - Py_INCREF(parent); - PyList_SetItem(list,pos,parent); - pos = parentpos; - } - PyList_SetItem(list,pos,newitem); - return 0; -} - -static int -_siftup(PyObject *list, int pos) { - PyObject *newitem, *right, *child; - int endpos, rightpos, childpos; - int startpos = pos; - - endpos = PyList_Size(list); - newitem = PySequence_GetItem(list,pos); - - childpos = (2*pos)+1; - while (childpos < endpos) { - rightpos = childpos + 1; - child = PySequence_Fast_GET_ITEM(list,childpos); - - PyObject *child_wakeTime_obj = PyObject_GetAttrString(child, "wakeTime"); - double child_wakeTime = 0.0; - if (child_wakeTime_obj != NULL) { - child_wakeTime = PyFloat_AS_DOUBLE(child_wakeTime_obj); - Py_DECREF(child_wakeTime_obj); - } - - - if (rightpos < endpos) { - right = PySequence_Fast_GET_ITEM(list,rightpos); - - PyObject *right_wakeTime_obj = PyObject_GetAttrString(right, "wakeTime"); - double right_wakeTime = 0.0; - if (right_wakeTime_obj != NULL) { - right_wakeTime = PyFloat_AS_DOUBLE(right_wakeTime_obj); - Py_DECREF(right_wakeTime_obj); - } - - /* - cmp = PyObject_RichCompareBool(right,child,Py_LE); - if (cmp > 0) - childpos = rightpos; - else if (cmp < 0) - return -1; - */ - - if (right_wakeTime <= child_wakeTime) { - childpos = rightpos; - } - } - child = PySequence_GetItem(list,childpos); - PyList_SetItem(list,pos,child); - pos = childpos; - childpos = (2*pos)+1; - } - PyList_SetItem(list,pos,newitem); - - return _siftdown(list,startpos,pos); -} - -static PyMethodDef heapqcMethods[] = { - {"heappush",heappush,METH_VARARGS}, - {"heappop",heappop,METH_VARARGS}, - {"heapreplace",heapreplace,METH_VARARGS}, - {"heapify",heapify,METH_VARARGS}, - {NULL, NULL} /* Sentinel */ -}; - -void initlibheapq(void) { - (void) Py_InitModule("libheapq", heapqcMethods); -}; - -void initlibp3heapq(void) { - (void) Py_InitModule("libp3heapq", heapqcMethods); -}; - diff --git a/direct/src/showbase/HTMLTree.py b/direct/src/http/HTMLTree.py similarity index 90% rename from direct/src/showbase/HTMLTree.py rename to direct/src/http/HTMLTree.py index 9defe47dff..f96b5c9d05 100755 --- a/direct/src/showbase/HTMLTree.py +++ b/direct/src/http/HTMLTree.py @@ -1,4 +1,4 @@ -from direct.showbase import ElementTree as ET +import xml.etree.ElementTree as ET class HTMLTree(ET.ElementTree): def __init__(self, title): diff --git a/direct/src/http/LandingPage.py b/direct/src/http/LandingPage.py index 927994d326..212e3a6e20 100755 --- a/direct/src/http/LandingPage.py +++ b/direct/src/http/LandingPage.py @@ -3,7 +3,7 @@ from direct.directnotify.DirectNotifyGlobal import directNotify from pandac.PandaModules import VirtualFileSystem from pandac.PandaModules import Filename from pandac.PandaModules import DSearchPath -from direct.showbase import ElementTree as ET +import xml.etree.ElementTree as ET import LandingPageHTML from StringIO import StringIO diff --git a/direct/src/http/LandingPageHTML.py b/direct/src/http/LandingPageHTML.py index b40eac6324..bc04caf80e 100755 --- a/direct/src/http/LandingPageHTML.py +++ b/direct/src/http/LandingPageHTML.py @@ -1,6 +1,6 @@ # -- Text content for the landing page. You should change these for yours! -- -from direct.showbase import ElementTree as ET +import xml.etree.ElementTree as ET title = "Landing Page" defaultTitle = title diff --git a/direct/src/http/WebRequest.py b/direct/src/http/WebRequest.py index 95b058ef5e..dc40be7e28 100755 --- a/direct/src/http/WebRequest.py +++ b/direct/src/http/WebRequest.py @@ -4,7 +4,7 @@ from direct.directnotify.DirectNotifyGlobal import directNotify from direct.task.TaskManagerGlobal import taskMgr from direct.task import Task from LandingPage import LandingPage -from direct.showbase import ElementTree as ET +import xml.etree.ElementTree as ET notify = directNotify.newCategory('WebRequestDispatcher') diff --git a/direct/src/p3d/AppRunner.py b/direct/src/p3d/AppRunner.py index 47c1a20d65..b6b86a2c2e 100644 --- a/direct/src/p3d/AppRunner.py +++ b/direct/src/p3d/AppRunner.py @@ -25,16 +25,13 @@ if 'VFSImporter' in sys.modules: direct.showbase.VFSImporter = VFSImporter sys.modules['direct.showbase.VFSImporter'] = VFSImporter else: - # Otherwise, we can import the VFSImporter normally. We have to - # import PandaModules first, to get the funny renaming with - # pandaexpress. - import direct - from pandac import PandaModules + # Otherwise, we can import the VFSImporter normally. from direct.showbase import VFSImporter from direct.showbase.DirectObject import DirectObject -from pandac.PandaModules import VirtualFileSystem, Filename, Multifile, loadPrcFileData, unloadPrcFile, getModelPath, Thread, WindowProperties, ExecutionEnvironment, PandaSystem, Notify, StreamWriter, ConfigVariableString, ConfigPageManager, initAppForGui -from pandac import PandaModules +from panda3d.core import VirtualFileSystem, Filename, Multifile, loadPrcFileData, unloadPrcFile, getModelPath, Thread, WindowProperties, ExecutionEnvironment, PandaSystem, Notify, StreamWriter, ConfigVariableString, ConfigPageManager +from panda3d.direct import init_app_for_gui +from panda3d import core from direct.stdpy import file, glob from direct.task.TaskManagerGlobal import taskMgr from direct.showbase.MessengerGlobal import messenger @@ -83,7 +80,7 @@ class AppRunner(DirectObject): # Also from p3d_plugin.h P3D_CONTENTS_DEFAULT_MAX_AGE = 5 - + def __init__(self): DirectObject.__init__(self) @@ -119,8 +116,8 @@ class AppRunner(DirectObject): self.windowPrc = None self.http = None - if hasattr(PandaModules, 'HTTPClient'): - self.http = PandaModules.HTTPClient.getGlobalPtr() + if hasattr(core, 'HTTPClient'): + self.http = core.HTTPClient.getGlobalPtr() self.Undefined = Undefined self.ConcreteStruct = ConcreteStruct @@ -213,7 +210,7 @@ class AppRunner(DirectObject): # this instance, e.g. the WindowProperties necessary to # re-embed a window in the browser frame. self.windowProperties = None - + # Store our pointer so DirectStart-based apps can find us. if AppRunnerGlobal.appRunner is None: AppRunnerGlobal.appRunner = self @@ -263,7 +260,7 @@ class AppRunner(DirectObject): value = bool(value) return value - + def installPackage(self, packageName, version = None, hostUrl = None): @@ -353,7 +350,7 @@ class AppRunner(DirectObject): # No shenanigans, just return the requested host. return host - + def getHost(self, hostUrl, hostDir = None): """ Returns a new HostInfo object corresponding to the indicated host URL. If we have already seen this URL @@ -419,7 +416,7 @@ class AppRunner(DirectObject): # the host directory too. del self.hosts[hostUrl] self.__deleteHostFiles(host) - + return packages def __deleteHostFiles(self, host): @@ -431,7 +428,7 @@ class AppRunner(DirectObject): self.rmtree(host.hostDir) self.sendRequest('forget_package', host.hostUrl, '', '') - + def freshenFile(self, host, fileSpec, localPathname): """ Ensures that the localPathname is the most current version @@ -449,18 +446,18 @@ class AppRunner(DirectObject): doc = None if self.superMirrorUrl: # Use the "super mirror" first. - url = PandaModules.URLSpec(self.superMirrorUrl + fileSpec.filename) + url = core.URLSpec(self.superMirrorUrl + fileSpec.filename) self.notify.info("Freshening %s" % (url)) doc = self.http.getDocument(url) - + if not doc or not doc.isValid(): # Failing the super mirror, contact the actual host. - url = PandaModules.URLSpec(host.hostUrlPrefix + fileSpec.filename) + url = core.URLSpec(host.hostUrlPrefix + fileSpec.filename) self.notify.info("Freshening %s" % (url)) doc = self.http.getDocument(url) if not doc.isValid(): return False - + file = Filename.temporary('', 'p3d_') if not doc.downloadToFile(file): # Failed to download. @@ -522,12 +519,11 @@ class AppRunner(DirectObject): """ Reads the config.xml file that may be present in the root directory. """ - if not hasattr(PandaModules, 'TiXmlDocument'): + if not hasattr(core, 'TiXmlDocument'): return - from pandac.PandaModules import TiXmlDocument filename = Filename(self.rootDir, self.ConfigBasename) - doc = TiXmlDocument(filename.toOsSpecific()) + doc = core.TiXmlDocument(filename.toOsSpecific()) if not doc.LoadFile(): return @@ -544,7 +540,7 @@ class AppRunner(DirectObject): called automatically; an application may call this after adjusting some parameters (such as self.maxDiskUsage). """ - from pandac.PandaModules import TiXmlDocument, TiXmlDeclaration, TiXmlElement + from panda3d.core import TiXmlDocument, TiXmlDeclaration, TiXmlElement filename = Filename(self.rootDir, self.ConfigBasename) doc = TiXmlDocument(filename.toOsSpecific()) @@ -561,7 +557,7 @@ class AppRunner(DirectObject): tfile = Filename.temporary(self.rootDir.cStr(), '.xml') if doc.SaveFile(tfile.toOsSpecific()): tfile.renameTo(filename) - + def checkDiskUsage(self): """ Checks the total disk space used by all packages, and @@ -574,11 +570,11 @@ class AppRunner(DirectObject): totalSize += packageData.totalSize self.notify.info("Total Panda3D disk space used: %s MB" % ( (totalSize + 524288) / 1048576)) - + if self.verifyContents == self.P3DVCNever: # We're not allowed to delete anything anyway. return - + self.notify.info("Configured max usage is: %s MB" % ( (self.maxDiskUsage + 524288) / 1048576)) if totalSize <= self.maxDiskUsage: @@ -592,7 +588,7 @@ class AppRunner(DirectObject): if packageData.package and packageData.package.installed: # Don't uninstall any packages we're currently using. continue - + usedPackages.append((packageData.lastUse, packageData)) # Sort the packages into oldest-first order. @@ -609,13 +605,13 @@ class AppRunner(DirectObject): packages.append(packageData.package) else: # If it's an unknown package, just delete it directly. - print "Deleting unknown package %s" % (packageData.pathname) + print("Deleting unknown package %s" % (packageData.pathname)) self.rmtree(packageData.pathname) packages = self.deletePackages(packages) if packages: - print "Unable to delete %s packages" % (len(packages)) - + print("Unable to delete %s packages" % (len(packages))) + return def stop(self): @@ -663,10 +659,10 @@ class AppRunner(DirectObject): for child in filename.scanDirectory(): self.rmtree(Filename(filename, child)) if not filename.rmdir(): - print "could not remove directory %s" % (filename) + print("could not remove directory %s" % (filename)) else: if not filename.unlink(): - print "could not delete %s" % (filename) + print("could not delete %s" % (filename)) def setSessionId(self, sessionId): """ This message should come in at startup. """ @@ -747,10 +743,23 @@ class AppRunner(DirectObject): # will properly get ignored by ShowBase. self.initialAppImport = True - __import__(moduleName) - main = sys.modules[moduleName] - if hasattr(main, 'main') and hasattr(main.main, '__call__'): - main.main(self) + # Python won't let us import a module named __main__. So, + # we have to do that manually, via the VFSImporter. + if moduleName == '__main__': + dirName = Filename(self.multifileRoot).toOsSpecific() + importer = VFSImporter.VFSImporter(dirName) + loader = importer.find_module('__main__') + if loader is None: + raise ImportError('No module named __main__') + + mainModule = loader.load_module('__main__') + else: + __import__(moduleName) + mainModule = sys.modules[moduleName] + + # Check if it has a main() function. If so, call it. + if hasattr(mainModule, 'main') and hasattr(mainModule.main, '__call__'): + mainModule.main(self) # Now clear this flag. self.initialAppImport = False @@ -814,7 +823,7 @@ class AppRunner(DirectObject): # Now that we have rootDir, we can read the config file. self.readConfigXml() - + def addPackageInfo(self, name, platform, version, hostUrl, hostDir = None, recurse = False): @@ -858,7 +867,7 @@ class AppRunner(DirectObject): # Maybe the contents.xml file isn't current. Re-fetch it. if host.redownloadContentsFile(self.http): return self.addPackageInfo(name, platform, version, hostUrl, hostDir = hostDir, recurse = True) - + message = "Couldn't find %s %s on %s" % (name, version, hostUrl) raise OSError, message @@ -866,18 +875,18 @@ class AppRunner(DirectObject): if not package.downloadDescFile(self.http): message = "Couldn't get desc file for %s" % (name) raise OSError, message - + if not package.downloadPackage(self.http): message = "Couldn't download %s" % (name) raise OSError, message - + if not package.installPackage(self): message = "Couldn't install %s" % (name) raise OSError, message if package.guiApp: self.guiApp = True - initAppForGui() + init_app_for_gui() def setP3DFilename(self, p3dFilename, tokens, argv, instanceId, interactiveConsole, p3dOffset = 0, p3dUrl = None): @@ -885,7 +894,7 @@ class AppRunner(DirectObject): contains the application itself, along with the web tokens and/or command-line arguments. Once this method has been called, the application is effectively started. """ - + # One day we will have support for multiple instances within a # Python session. Against that day, we save the instance ID # for this instance. @@ -937,9 +946,9 @@ class AppRunner(DirectObject): self.allowPythonDev = False i = mf.findSubfile('p3d_info.xml') - if i >= 0 and hasattr(PandaModules, 'readXmlStream'): + if i >= 0 and hasattr(core, 'readXmlStream'): stream = mf.openReadSubfile(i) - self.p3dInfo = PandaModules.readXmlStream(stream) + self.p3dInfo = core.readXmlStream(stream) mf.closeReadSubfile(stream) if self.p3dInfo: self.p3dPackage = self.p3dInfo.FirstChildElement('package') @@ -975,7 +984,7 @@ class AppRunner(DirectObject): ConfigVariableString('frame-rate-meter-text-pattern').setValue('allow_python_dev %0.1f fps') if self.guiApp: - initAppForGui() + init_app_for_gui() self.initPackedAppEnvironment() @@ -992,7 +1001,7 @@ class AppRunner(DirectObject): # provided if available. It is only for documentation # purposes; the actual p3d file has already been # downloaded to p3dFilename. - self.p3dUrl = PandaModules.URLSpec(p3dUrl) + self.p3dUrl = core.URLSpec(p3dUrl) # Send this call to the main thread; don't call it directly. messenger.send('AppRunner_startIfReady', taskChain = 'default') @@ -1015,14 +1024,14 @@ class AppRunner(DirectObject): newUrl = xalthost.Attribute('url') self.altHostMap[origUrl] = newUrl break - + xalthost = xalthost.NextSiblingElement('alt_host') - + def loadMultifilePrcFiles(self, mf, root): """ Loads any prc files in the root of the indicated Multifile, which is presumed to have been mounted already under root. """ - + # We have to load these prc files explicitly, since the # ConfigPageManager can't directly look inside the vfs. Use # the Multifile interface to find the prc files, rather than @@ -1046,12 +1055,12 @@ class AppRunner(DirectObject): cp = loadPrcFileData(pathname, data) # Set it to sort value 20, behind the implicit pages. cp.setSort(20) - - + + def __clearWindowProperties(self): """ Clears the windowPrc file that was created in a previous call to setupWindow(), if any. """ - + if self.windowPrc: unloadPrcFile(self.windowPrc) self.windowPrc = None @@ -1127,12 +1136,12 @@ class AppRunner(DirectObject): function that can be used to deliver requests upstream, to the core API, and thereby to the browser. """ self.requestFunc = func - + def sendRequest(self, request, *args): """ Delivers a request to the browser via self.requestFunc. This low-level function is not intended to be called directly by user code. """ - + assert self.requestFunc return self.requestFunc(self.instanceId, request, args) @@ -1176,7 +1185,7 @@ class AppRunner(DirectObject): # Evaluate it now. return self.scriptRequest('eval', self.dom, value = expression, needsResponse = needsResponse) - + def scriptRequest(self, operation, object, propertyName = '', value = None, needsResponse = True): """ Issues a new script request to the browser. This queries @@ -1184,7 +1193,7 @@ class AppRunner(DirectObject): low-level method that user code should not call directly; instead, just operate on the Python wrapper objects that shadow the DOM objects, beginning with appRunner.dom. - + operation may be one of [ 'get_property', 'set_property', 'call', 'evaluate' ]. @@ -1233,7 +1242,7 @@ def dummyAppRunner(tokens = [], argv = None): first-look sanity check. """ if AppRunnerGlobal.appRunner: - print "Already have AppRunner, not creating a new one." + print("Already have AppRunner, not creating a new one.") return AppRunnerGlobal.appRunner appRunner = AppRunner() @@ -1243,7 +1252,7 @@ def dummyAppRunner(tokens = [], argv = None): platform = PandaSystem.getPlatform() version = PandaSystem.getPackageVersionString() hostUrl = PandaSystem.getPackageHostUrl() - + if platform.startswith('win'): rootDir = Filename(Filename.getUserAppdataDirectory(), 'Panda3D') elif platform.startswith('osx'): @@ -1256,7 +1265,7 @@ def dummyAppRunner(tokens = [], argv = None): # Of course we will have the panda3d application loaded. appRunner.addPackageInfo('panda3d', platform, version, hostUrl) - + appRunner.tokens = tokens appRunner.tokenDict = dict(tokens) if argv is None: @@ -1274,6 +1283,6 @@ def dummyAppRunner(tokens = [], argv = None): vfs.mount(cwd, appRunner.multifileRoot, vfs.MFReadOnly) appRunner.initPackedAppEnvironment() - + return appRunner diff --git a/direct/src/p3d/DeploymentTools.py b/direct/src/p3d/DeploymentTools.py index ef046a5490..b0e348f245 100644 --- a/direct/src/p3d/DeploymentTools.py +++ b/direct/src/p3d/DeploymentTools.py @@ -8,9 +8,9 @@ import os, sys, subprocess, tarfile, shutil, time, zipfile, glob, socket, getpas from cStringIO import StringIO from direct.directnotify.DirectNotifyGlobal import * from direct.showbase.AppRunnerGlobal import appRunner -from pandac.PandaModules import PandaSystem, HTTPClient, Filename, VirtualFileSystem, Multifile -from pandac.PandaModules import TiXmlDocument, TiXmlDeclaration, TiXmlElement, readXmlStream -from pandac.PandaModules import PNMImage, PNMFileTypeRegistry +from panda3d.core import PandaSystem, HTTPClient, Filename, VirtualFileSystem, Multifile +from panda3d.core import TiXmlDocument, TiXmlDeclaration, TiXmlElement, readXmlStream +from panda3d.core import PNMImage, PNMFileTypeRegistry from direct.stdpy.file import * from direct.p3d.HostInfo import HostInfo # This is important for some reason @@ -296,7 +296,7 @@ class Icon: def __init__(self): self.images = {} - + def addImage(self, image): """ Adds an image to the icon. Returns False on failure, True on success. Only one image per size can be loaded, and the image size must be square. """ @@ -1097,7 +1097,7 @@ class Installer: # Tell Vista that we require admin rights print >>nsi, 'RequestExecutionLevel admin' - print >>nsi + print >>nsi if self.offerRun: print >>nsi, 'Function launch' print >>nsi, ' ExecShell "open" "$INSTDIR\\%s.exe"' % self.shortname @@ -1112,7 +1112,7 @@ class Installer: print >>nsi, ' CreateShortcut "$DESKTOP\\%s.lnk" "$INSTDIR\\%s.exe" "" "$INSTDIR\\%s.ico"' % (self.fullname, self.shortname, self.shortname) print >>nsi, 'FunctionEnd' print >>nsi - + print >>nsi, '!include "MUI2.nsh"' print >>nsi, '!define MUI_ABORTWARNING' if self.offerRun: @@ -1213,7 +1213,7 @@ class Installer: if icofile is not None: icofile.unlink() - + return output def os_walk(self, top): diff --git a/direct/src/p3d/FileSpec.py b/direct/src/p3d/FileSpec.py index 78dff88fe8..822bfccb5f 100644 --- a/direct/src/p3d/FileSpec.py +++ b/direct/src/p3d/FileSpec.py @@ -1,6 +1,6 @@ import os import time -from pandac.PandaModules import Filename, HashVal, VirtualFileSystem +from panda3d.core import Filename, HashVal, VirtualFileSystem class FileSpec: """ This class represents a disk file whose hash and size @@ -18,13 +18,13 @@ class FileSpec: def fromFile(self, packageDir, filename, pathname = None, st = None): """ Reads the file information from the indicated file. If st is supplied, it is the result of os.stat on the filename. """ - + vfs = VirtualFileSystem.getGlobalPtr() filename = Filename(filename) if pathname is None: pathname = Filename(packageDir, filename) - + self.filename = filename.cStr() self.basename = filename.getBasename() @@ -41,17 +41,17 @@ class FileSpec: hv = HashVal() hv.hashFile(pathname) self.hash = hv.asHex() - + def loadXml(self, xelement): """ Reads the file information from the indicated XML element. """ - + self.filename = xelement.Attribute('filename') self.basename = None if self.filename: self.basename = Filename(self.filename).getBasename() - + size = xelement.Attribute('size') try: self.size = int(size) @@ -87,7 +87,7 @@ class FileSpec: xelement.SetAttribute('size', str(self.size)) if self.hash: xelement.SetAttribute('hash', self.hash) - + def quickVerify(self, packageDir = None, pathname = None, notify = None, correctSelf = False): """ Performs a quick test to ensure the file has not been @@ -157,8 +157,8 @@ class FileSpec: self.__updateTimestamp(pathname, st) return True - - + + def fullVerify(self, packageDir = None, pathname = None, notify = None): """ Performs a more thorough test to ensure the file has not been modified. This test is less vulnerable to malicious @@ -235,7 +235,7 @@ class FileSpec: """ Corrects the internal hash to match the one on disk. """ if not self.actualFile: self.checkHash(packageDir, pathname, st) - + if notify: notify.info("Correcting hash %s to %s" % ( self.filename, self.actualFile.hash)) diff --git a/direct/src/p3d/HostInfo.py b/direct/src/p3d/HostInfo.py index d72da61585..ab033f3383 100644 --- a/direct/src/p3d/HostInfo.py +++ b/direct/src/p3d/HostInfo.py @@ -1,7 +1,6 @@ -from pandac.PandaModules import HashVal, Filename, PandaSystem, DocumentSpec, Ramfile -from pandac.PandaModules import HTTPChannel -from pandac import PandaModules -from libpandaexpress import ConfigVariableInt +from panda3d.core import HashVal, Filename, PandaSystem, DocumentSpec, Ramfile +from panda3d.core import HTTPChannel, ConfigVariableInt +from panda3d import core from direct.p3d.PackageInfo import PackageInfo from direct.p3d.FileSpec import FileSpec from direct.directnotify.DirectNotifyGlobal import directNotify @@ -49,7 +48,7 @@ class HostInfo: if hostDir and not isinstance(hostDir, Filename): hostDir = Filename.fromOsSpecific(hostDir) - + self.hostDir = hostDir self.asMirror = asMirror self.perPlatform = perPlatform @@ -175,7 +174,7 @@ class HostInfo: statusString = channel.getStatusString() self.notify.warning("Could not contact download server at %s" % (url,)) self.notify.warning("Status code = %s %s" % (statusCode, statusString)) - + if not rf: self.notify.warning("Unable to download %s" % (url,)) try: @@ -206,7 +205,7 @@ class HostInfo: self.notify.warning("%s" % (str(e),)) pass return False - + tempFilename = Filename.temporary('', 'p3d_', '.xml') if rf: f = open(tempFilename.toOsSpecific(), 'wb') @@ -278,7 +277,7 @@ class HostInfo: now = int(time.time()) return now < self.contentsExpiration and self.hasContentsFile - + def readContentsFile(self, tempFilename = None, freshDownload = False): """ Reads the contents.xml file for this particular host, once it has been downloaded into the indicated temporary file. @@ -290,7 +289,7 @@ class HostInfo: there already. If tempFilename is not specified, the standard filename is read if it is known. """ - if not hasattr(PandaModules, 'TiXmlDocument'): + if not hasattr(core, 'TiXmlDocument'): return False if not tempFilename: @@ -304,7 +303,7 @@ class HostInfo: tempFilename = Filename(hostDir, 'contents.xml') - doc = PandaModules.TiXmlDocument(tempFilename.toOsSpecific()) + doc = core.TiXmlDocument(tempFilename.toOsSpecific()) if not doc.LoadFile(): return False @@ -337,12 +336,12 @@ class HostInfo: xcontents.RemoveChild(xorig) xorig = xcontents.FirstChildElement('orig') - xorig = PandaModules.TiXmlElement('orig') + xorig = core.TiXmlElement('orig') self.contentsSpec.storeXml(xorig) xorig.SetAttribute('expiration', str(self.contentsExpiration)) xcontents.InsertEndChild(xorig) - + else: # Read the download hash and expiration time from the XML. expiration = None @@ -385,7 +384,7 @@ class HostInfo: perPlatform = int(xpackage.Attribute('per_platform') or '') except ValueError: perPlatform = False - + package = self.__makePackage(name, platform, version, solo, perPlatform) package.descFile = FileSpec() package.descFile.loadXml(xpackage) @@ -418,7 +417,7 @@ class HostInfo: """ Looks for the or entry in the contents.xml that corresponds to the URL that we actually downloaded from. """ - + xhost = xcontents.FirstChildElement('host') while xhost: url = xhost.Attribute('url') @@ -433,7 +432,7 @@ class HostInfo: self.readHostXml(xalthost) return xalthost = xalthost.NextSiblingElement('alt_host') - + xhost = xhost.NextSiblingElement('host') def __findHostXmlForHostDir(self, xcontents): @@ -442,7 +441,7 @@ class HostInfo: contents.xml from. This is used when reading a contents.xml file found on disk, as opposed to downloading it from a site. """ - + xhost = xcontents.FirstChildElement('host') while xhost: url = xhost.Attribute('url') @@ -463,7 +462,7 @@ class HostInfo: self.readHostXml(xalthost) return xalthost = xalthost.NextSiblingElement('alt_host') - + xhost = xhost.NextSiblingElement('host') def readHostXml(self, xhost): @@ -487,7 +486,7 @@ class HostInfo: self.downloadUrlPrefix += '/' else: self.downloadUrlPrefix = self.hostUrlPrefix - + xmirror = xhost.FirstChildElement('mirror') while xmirror: url = xmirror.Attribute('url') @@ -611,7 +610,7 @@ class HostInfo: the list of packages that were NOT found. """ packages = packages[:] - + for key, platforms in self.packages.items(): for platform, package in platforms.items(): if package in packages: diff --git a/direct/src/p3d/InstalledHostData.py b/direct/src/p3d/InstalledHostData.py index 470c300da3..e8c9e5d5d2 100644 --- a/direct/src/p3d/InstalledHostData.py +++ b/direct/src/p3d/InstalledHostData.py @@ -1,11 +1,11 @@ -from pandac.PandaModules import URLSpec +from panda3d.core import URLSpec class InstalledHostData: """ A list of instances of this class is returned by AppRunner.scanInstalledPackages(). Each of these corresponds to a particular host that has provided packages that have been installed on the local client. """ - + def __init__(self, host, dirnode): self.host = host self.pathname = dirnode.pathname diff --git a/direct/src/p3d/PackageInfo.py b/direct/src/p3d/PackageInfo.py index 7dcd35c62e..7f2d382cd2 100644 --- a/direct/src/p3d/PackageInfo.py +++ b/direct/src/p3d/PackageInfo.py @@ -1,6 +1,5 @@ -from pandac.PandaModules import Filename, URLSpec, DocumentSpec, Ramfile, Multifile, Decompressor, EUOk, EUSuccess, VirtualFileSystem, Thread, getModelPath, ExecutionEnvironment, PStatCollector, TiXmlDocument, TiXmlDeclaration, TiXmlElement -from pandac import PandaModules -from libpandaexpress import ConfigVariableInt +from panda3d.core import Filename, URLSpec, DocumentSpec, Ramfile, Multifile, Decompressor, EUOk, EUSuccess, VirtualFileSystem, Thread, getModelPath, ExecutionEnvironment, PStatCollector, TiXmlDocument, TiXmlDeclaration, TiXmlElement +import panda3d.core as core from direct.p3d.FileSpec import FileSpec from direct.p3d.ScanDirectoryNode import ScanDirectoryNode from direct.showbase import VFSImporter @@ -55,7 +54,7 @@ class PackageInfo: tokens. This function defines a new generator that yields each of those tokens, but wraps each call into the nested generator within a pair of start/stop collector calls. """ - + self.pStatCol.start() for token in self.__funcPtr(self): self.pStatCol.stop() @@ -76,7 +75,7 @@ class PackageInfo: if self.bytesNeeded == 0: return 1 return min(float(self.bytesDone) / float(self.bytesNeeded), 1) - + def __init__(self, host, packageName, packageVersion, platform = None, solo = False, asMirror = False, perPlatform = False): self.host = host @@ -94,7 +93,7 @@ class PackageInfo: # This will be filled in when the host's contents.xml file is # read. self.packageDir = None - + # These will be filled in by HostInfo when the package is read # from contents.xml. self.descFile = None @@ -110,11 +109,11 @@ class PackageInfo: self.extracts = [] self.requires = [] self.installPlans = None - + # This is updated during downloadPackage(). It is in the # range 0..1. self.downloadProgress = 0 - + # This is set true when the package file has been fully # downloaded and unpacked. self.hasPackage = False @@ -133,12 +132,12 @@ class PackageInfo: This may not be known until the host's contents.xml file has been downloaded, which informs us of the host's own install directory. """ - + if not self.packageDir: if not self.host.hasContentsFile: if not self.host.readContentsFile(): self.host.downloadContentsFile(self.http) - + # Derive the packageDir from the hostDir. self.packageDir = Filename(self.host.hostDir, self.packageName) if self.packageVersion: @@ -159,7 +158,7 @@ class PackageInfo: # plugin--and we therefore shouldn't include the # platform in the directory hierarchy. includePlatform = False - + if includePlatform and self.platform: self.packageDir = Filename(self.packageDir, self.platform) @@ -176,7 +175,7 @@ class PackageInfo: # Return the size of plan A, assuming it will work. plan = self.installPlans[0] size = sum([step.getEffort() for step in plan]) - + return size def getPrevDownloadedEffort(self): @@ -209,13 +208,13 @@ class PackageInfo: name += ' rev %s' % (self.patchVersion) return name - + def setupFilenames(self): """ This is called by the HostInfo when the package is read from contents.xml, to set up the internal filenames and such that rely on some of the information from contents.xml. """ - + dirname, basename = self.descFile.filename.rsplit('/', 1) self.descFileDirname = dirname self.descFileBasename = basename @@ -264,7 +263,7 @@ class PackageInfo: Thread.considerYield() return (token == self.stepComplete) - + def downloadDescFileGenerator(self, http): """ A generator function that implements downloadDescFile() one piece at a time. It yields one of stepComplete, @@ -343,9 +342,9 @@ class PackageInfo: filename = Filename(self.getPackageDir(), self.descFileBasename) - if not hasattr(PandaModules, 'TiXmlDocument'): + if not hasattr(core, 'TiXmlDocument'): return False - doc = PandaModules.TiXmlDocument(filename.toOsSpecific()) + doc = core.TiXmlDocument(filename.toOsSpecific()) if not doc.LoadFile(): return False @@ -432,7 +431,7 @@ class PackageInfo: pc.start() self.hasPackage = False - + if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: # We're not allowed to download anything. self.installPlans = [] @@ -447,12 +446,12 @@ class PackageInfo: # archive. downloadSize = self.compressedArchive.size func = lambda step, fileSpec = self.compressedArchive: self.__downloadFile(step, fileSpec, allowPartial = True) - + step = self.InstallStep(func, downloadSize, self.downloadFactor, 'download') installPlan = [step] self.installPlans = [installPlan] pc.stop() - return + return # The normal download process. Determine what we will need to # download, and build a plan (or two) to download it all. @@ -520,9 +519,9 @@ class PackageInfo: # plan B as the only plan. self.installPlans = [planB] - # In case of unexpected failures on the internet, we will retry + # In case of unexpected failures on the internet, we will retry # the full download instead of just giving up. - for retry in range(ConfigVariableInt('package-full-dl-retries', 1)): + for retry in range(core.ConfigVariableInt('package-full-dl-retries', 1)): self.installPlans.append(planB[:]) pc.stop() @@ -530,7 +529,7 @@ class PackageInfo: def __scanDirectoryRecursively(self, dirname): """ Generates a list of Filename objects: all of the files (not directories) within and below the indicated dirname. """ - + contents = [] for dirpath, dirnames, filenames in os.walk(dirname.toOsSpecific()): dirpath = Filename.fromOsSpecific(dirpath) @@ -560,7 +559,7 @@ class PackageInfo: # Get a list of all of the files in the directory, so we can # remove files that don't belong. - contents = self.__scanDirectoryRecursively(self.getPackageDir()) + contents = self.__scanDirectoryRecursively(self.getPackageDir()) self.__removeFileFromList(contents, self.descFileBasename) self.__removeFileFromList(contents, self.compressedArchive.filename) self.__removeFileFromList(contents, self.UsageBasename) @@ -582,7 +581,7 @@ class PackageInfo: if self.asMirror: return self.compressedArchive.quickVerify(self.getPackageDir(), notify = self.notify) - + allExtractsOk = True if not self.uncompressedArchive.quickVerify(self.getPackageDir(), notify = self.notify): self.notify.debug("File is incorrect: %s" % (self.uncompressedArchive.filename)) @@ -593,7 +592,7 @@ class PackageInfo: # shouldn't be a compressed archive file here. pathname = Filename(self.getPackageDir(), self.compressedArchive.filename) pathname.unlink() - + for file in self.extracts: if not file.quickVerify(self.getPackageDir(), notify = self.notify): self.notify.debug("File is incorrect: %s" % (file.filename)) @@ -614,7 +613,7 @@ class PackageInfo: size = self.totalPlanCompleted + self.currentStepEffort * step.getProgress() self.downloadProgress = min(float(size) / float(self.totalPlanSize), 1) - + def downloadPackage(self, http): """ Downloads the package file, synchronously, then uncompresses and unpacks it. Returns true on success, false @@ -630,7 +629,7 @@ class PackageInfo: Thread.considerYield() return (token == self.stepComplete) - + def downloadPackageGenerator(self, http): """ A generator function that implements downloadPackage() one piece at a time. It yields one of stepComplete, stepFailed, @@ -655,7 +654,7 @@ class PackageInfo: yield token else: break - + while token == self.restartDownload: # Try again. for token in self.downloadDescFileGenerator(http): @@ -675,7 +674,7 @@ class PackageInfo: assert token == self.stepComplete yield self.stepComplete; return - + def __followInstallPlans(self): """ Performs all of the steps in self.installPlans. Yields @@ -701,16 +700,16 @@ class PackageInfo: yield token else: break - + if token == self.restartDownload: yield token if token == self.stepFailed: planFailed = True break assert token == self.stepComplete - + self.totalPlanCompleted += self.currentStepEffort - + if not planFailed: # Successfully downloaded! yield self.stepComplete; return @@ -754,7 +753,7 @@ class PackageInfo: def __downloadFile(self, step, fileSpec, urlbase = None, filename = None, allowPartial = False): """ Downloads the indicated file from the host into - packageDir. Yields one of stepComplete, stepFailed, + packageDir. Yields one of stepComplete, stepFailed, restartDownload, or stepContinue. """ if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: @@ -806,7 +805,7 @@ class PackageInfo: url += '?' + str(int(time.time())) request = DocumentSpec(url) request.setCacheControl(DocumentSpec.CCNoCache) - + self.notify.info("%s downloading %s" % (self.packageName, url)) if not filename: @@ -839,7 +838,7 @@ class PackageInfo: targetPathname.makeDir() targetPathname.unlink() channel.beginGetDocument(request) - + channel.downloadToFile(targetPathname) while channel.run(): if step: @@ -849,7 +848,7 @@ class PackageInfo: # it's the wrong file. self.notify.warning("Got more data than expected for download %s" % (url)) break - + self.__updateStepProgress(step) if taskMgr.destroyed: @@ -857,9 +856,9 @@ class PackageInfo: # be shutting down. Get out of here. self.notify.warning("Task Manager destroyed, aborting %s" % (url)) yield self.stepFailed; return - + yield self.stepContinue - + if step: step.bytesDone = channel.getBytesDownloaded() + channel.getFirstByteDelivered() self.__updateStepProgress(step) @@ -897,7 +896,7 @@ class PackageInfo: def __applyPatch(self, step, patchfile): """ Applies the indicated patching in-place to the current uncompressed archive. The patchfile is removed after the - operation. Yields one of stepComplete, stepFailed, + operation. Yields one of stepComplete, stepFailed, restartDownload, or stepContinue. """ self.updated = True @@ -907,7 +906,7 @@ class PackageInfo: result = Filename.temporary('', 'patch_') self.notify.info("Patching %s with %s" % (origPathname, patchPathname)) - p = PandaModules.Patchfile() # The C++ class + p = core.Patchfile() # The C++ class ret = p.initiate(patchPathname, origPathname, result) if ret == EUSuccess: @@ -925,7 +924,7 @@ class PackageInfo: ret = p.run() del p patchPathname.unlink() - + if ret < 0: self.notify.warning("Patching of %s failed." % (origPathname)) result.unlink() @@ -934,12 +933,12 @@ class PackageInfo: if not result.renameTo(origPathname): self.notify.warning("Couldn't rename %s to %s" % (result, origPathname)) yield self.stepFailed; return - + yield self.stepComplete; return def __uncompressArchive(self, step): """ Turns the compressed archive into the uncompressed - archive. Yields one of stepComplete, stepFailed, + archive. Yields one of stepComplete, stepFailed, restartDownload, or stepContinue. """ if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: @@ -970,7 +969,7 @@ class PackageInfo: if result != EUSuccess: yield self.stepFailed; return - + step.bytesDone = totalBytes self.__updateStepProgress(step) @@ -985,10 +984,10 @@ class PackageInfo: # Now we can safely remove the compressed archive. sourcePathname.unlink() yield self.stepComplete; return - + def __unpackArchive(self, step): """ Unpacks any files in the archive that want to be unpacked - to disk. Yields one of stepComplete, stepFailed, + to disk. Yields one of stepComplete, stepFailed, restartDownload, or stepContinue. """ if not self.extracts: @@ -1008,7 +1007,7 @@ class PackageInfo: if not mf.openRead(mfPathname): self.notify.warning("Couldn't open %s" % (mfPathname)) yield self.stepFailed; return - + allExtractsOk = True step.bytesDone = 0 for file in self.extracts: @@ -1025,7 +1024,7 @@ class PackageInfo: self.notify.warning("Couldn't extract: %s" % (file.filename)) allExtractsOk = False continue - + if not file.quickVerify(self.getPackageDir(), notify = self.notify): self.notify.warning("After extracting, still incorrect: %s" % (file.filename)) allExtractsOk = False @@ -1157,7 +1156,7 @@ class PackageInfo: """ Marks the package as having been used. This is normally called automatically by installPackage(). """ - if not hasattr(PandaModules, 'TiXmlDocument'): + if not hasattr(core, 'TiXmlDocument'): return if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: @@ -1174,14 +1173,14 @@ class PackageInfo: if not doc.LoadFile(): decl = TiXmlDeclaration("1.0", "utf-8", "") doc.InsertEndChild(decl) - + xusage = doc.FirstChildElement('usage') if not xusage: doc.InsertEndChild(TiXmlElement('usage')) xusage = doc.FirstChildElement('usage') now = int(time.time()) - + count = xusage.Attribute('count_app') try: count = int(count or '') @@ -1214,22 +1213,22 @@ class PackageInfo: tfile = Filename.temporary(self.getPackageDir().cStr(), '.xml') if doc.SaveFile(tfile.toOsSpecific()): tfile.renameTo(filename) - + def getUsage(self): """ Returns the xusage element that is read from the usage.xml file, or None if there is no usage.xml file. """ - if not hasattr(PandaModules, 'TiXmlDocument'): + if not hasattr(core, 'TiXmlDocument'): return None filename = Filename(self.getPackageDir(), self.UsageBasename) doc = TiXmlDocument(filename.toOsSpecific()) if not doc.LoadFile(): return None - + xusage = doc.FirstChildElement('usage') if not xusage: return None return copy.copy(xusage) - + diff --git a/direct/src/p3d/PackageInstaller.py b/direct/src/p3d/PackageInstaller.py index 2c97d3c7e6..3f920b8bd3 100644 --- a/direct/src/p3d/PackageInstaller.py +++ b/direct/src/p3d/PackageInstaller.py @@ -3,7 +3,7 @@ from direct.stdpy.threading import Lock, RLock from direct.showbase.MessengerGlobal import messenger from direct.task.TaskManagerGlobal import taskMgr from direct.p3d.PackageInfo import PackageInfo -from pandac.PandaModules import TPLow, PStatCollector +from panda3d.core import TPLow, PStatCollector from direct.directnotify.DirectNotifyGlobal import directNotify class PackageInstaller(DirectObject): @@ -33,7 +33,7 @@ class PackageInstaller(DirectObject): S_ready = 1 # donePackages() has been called S_started = 2 # download has started S_done = 3 # download is over - + class PendingPackage: """ This class describes a package added to the installer for download. """ @@ -121,12 +121,12 @@ class PackageInstaller(DirectObject): self.prevDownloadedEffort = self.package.getPrevDownloadedEffort() return True - + def getDescFile(self, http): """ Synchronously downloads the desc files required for the package. """ - + if not self.host.downloadContentsFile(http): return False @@ -156,10 +156,10 @@ class PackageInstaller(DirectObject): PackageInstaller.nextUniqueId += 1 finally: self.globalLock.release() - + self.appRunner = appRunner self.taskChain = taskChain - + # If we're to be running on an asynchronous task chain, and # the task chain hasn't yet been set up already, create the # default parameters now. @@ -180,7 +180,7 @@ class PackageInstaller(DirectObject): # A list of packages that are waiting for their desc files. self.needsDescFile = [] self.descFileTask = None - + # A list of packages that are waiting to be downloaded and # installed. self.needsDownload = [] @@ -198,7 +198,7 @@ class PackageInstaller(DirectObject): # This task is spawned on the default task chain, to update # the status during the download. self.progressTask = None - + self.accept('PackageInstaller-%s-allHaveDesc' % self.uniqueId, self.__allHaveDesc) self.accept('PackageInstaller-%s-packageStarted' % self.uniqueId, @@ -231,7 +231,7 @@ class PackageInstaller(DirectObject): self.progressTask = None self.ignoreAll() - + def addPackage(self, packageName, version = None, hostUrl = None): """ Adds the named package to the list of packages to be downloaded. Call donePackages() to finish the list. """ @@ -256,7 +256,7 @@ class PackageInstaller(DirectObject): if pp in self.packages: # Already added. return - + self.packages.append(pp) # We always add the package to needsDescFile, even if we @@ -323,7 +323,7 @@ class PackageInstaller(DirectObject): (beginning) to 1 (complete). """ self.notify.debug("packageProgress: %s %s" % (package.packageName, progress)) - + def downloadProgress(self, overallProgress): """ This callback is made repeatedly between downloadStarted() and downloadFinished() to update the current progress through @@ -384,7 +384,7 @@ class PackageInstaller(DirectObject): """ This method is called internally when all of the pending packages have their desc info. """ working = True - + self.packageLock.acquire() try: if self.state == self.S_ready: @@ -489,7 +489,7 @@ class PackageInstaller(DirectObject): it extracts one package from self.needsDescFile and downloads its desc file. On success, it adds the package to self.needsDownload. """ - + self.packageLock.acquire() try: # If we've finished all of the packages that need desc @@ -515,7 +515,7 @@ class PackageInstaller(DirectObject): # This package is now ready to be downloaded. We always add # it to needsDownload, even if it's already downloaded, to # guarantee ordering of packages. - + self.packageLock.acquire() try: # Also add any packages required by this one. @@ -527,7 +527,7 @@ class PackageInstaller(DirectObject): self.packageLock.release() return task.cont - + def __downloadPackageTask(self, task): """ This task runs on the aysynchronous task chain; each pass, @@ -543,7 +543,7 @@ class PackageInstaller(DirectObject): self.packageLock.release() yield task.done; return - assert self.state == self.S_started + assert self.state == self.S_started pp = self.needsDownload[0] del self.needsDownload[0] except: @@ -578,7 +578,7 @@ class PackageInstaller(DirectObject): # Continue the loop without yielding, so we pick up the # next package within this same frame. - + def __donePackage(self, pp, success): """ Marks the indicated package as done, either successfully or otherwise. """ @@ -630,9 +630,9 @@ class PackageInstaller(DirectObject): else: progress = float(currentDownloadSize) / float(downloadEffort) self.downloadProgress(progress) - + finally: self.callbackLock.release() return task.cont - + diff --git a/direct/src/p3d/PackageMerger.py b/direct/src/p3d/PackageMerger.py index 12eff00233..e5b90705e3 100644 --- a/direct/src/p3d/PackageMerger.py +++ b/direct/src/p3d/PackageMerger.py @@ -1,7 +1,7 @@ from direct.p3d.FileSpec import FileSpec from direct.p3d.SeqValue import SeqValue from direct.directnotify.DirectNotifyGlobal import * -from pandac.PandaModules import * +from panda3d.core import * import copy import shutil import os @@ -18,11 +18,11 @@ class PackageMerger: always the most current version of the file. """ notify = directNotify.newCategory("PackageMerger") - + class PackageEntry: """ This corresponds to a entry in the contents.xml file. """ - + def __init__(self, xpackage, sourceDir): self.sourceDir = sourceDir self.loadXml(xpackage) @@ -48,7 +48,7 @@ class PackageMerger: self.descFile.loadXml(xpackage) self.validatePackageContents() - + self.descFile.quickVerify(packageDir = self.sourceDir, notify = PackageMerger.notify, correctSelf = True) self.packageSeq = SeqValue() @@ -84,7 +84,7 @@ class PackageMerger: ximport = TiXmlElement('import') self.importDescFile.storeXml(ximport) xpackage.InsertEndChild(ximport) - + return xpackage def validatePackageContents(self): @@ -170,7 +170,7 @@ class PackageMerger: xhost = xcontents.FirstChildElement('host') if xhost: self.xhost = xhost.Clone() - + xpackage = xcontents.FirstChildElement('package') while xpackage: pe = self.PackageEntry(xpackage, sourceDir) @@ -183,7 +183,7 @@ class PackageMerger: if not other or pe.isNewer(other): # Store this package in the resulting output. self.contents[pe.getKey()] = pe - + xpackage = xpackage.NextSiblingElement('package') self.contentsDoc = doc @@ -247,7 +247,7 @@ class PackageMerger: else: # Both the source file and target file are # directories. - + # We have to clean out the target directory first. # Instead of using shutil.rmtree(), remove the files in # this directory one at a time, so we don't inadvertently @@ -282,10 +282,10 @@ class PackageMerger: the current pool. If packageNames is not None, it is a list of package names that we wish to include from the source; packages not named in this list will be unchanged. """ - + if not self.__readContentsFile(sourceDir, packageNames): message = "Couldn't read %s" % (sourceDir) - raise PackageMergerError, message + raise PackageMergerError, message def close(self): """ Finalizes the results of all of the previous calls to @@ -302,4 +302,4 @@ class PackageMerger: self.contentsSeq += 1 self.__writeContentsFile() - + diff --git a/direct/src/p3d/Packager.py b/direct/src/p3d/Packager.py index deb55f3a5e..18cce7d7d9 100644 --- a/direct/src/p3d/Packager.py +++ b/direct/src/p3d/Packager.py @@ -15,6 +15,7 @@ import types import getpass import platform import struct +import subprocess from direct.p3d.FileSpec import FileSpec from direct.p3d.SeqValue import SeqValue from direct.showbase import Loader @@ -58,7 +59,7 @@ class Packager: self.required = required if not self.newName: - self.newName = self.filename.cStr() + self.newName = str(self.filename) ext = Filename(self.newName).getExtension() if ext == 'pz': @@ -66,7 +67,7 @@ class Packager: # within the Multifile without it. filename = Filename(self.newName) filename.setExtension('') - self.newName = filename.cStr() + self.newName = str(filename) ext = Filename(self.newName).getExtension() if self.compress is None: self.compress = True @@ -80,8 +81,8 @@ class Packager: if self.executable and self.dependencyDir is None: # By default, install executable dependencies in the - # same directory with the executable itself. - self.dependencyDir = Filename(self.newName).getDirname() + # root directory, which is the one that's added to PATH. + self.dependencyDir = '' if self.extract is None: self.extract = self.executable or (ext in packager.extractExtensions) @@ -93,13 +94,13 @@ class Packager: if self.executable: # Look up the filename along the system PATH, if necessary. - if not self.filename.resolveFilename(packager.executablePath): + if not packager.resolveLibrary(self.filename): # If it wasn't found, try looking it up under its # basename only. Sometimes a Mac user will copy # the library file out of a framework and put that # along the PATH, instead of the framework itself. basename = Filename(self.filename.getBasename()) - if basename.resolveFilename(packager.executablePath): + if packager.resolveLibrary(basename): self.filename = basename if ext in packager.textExtensions and not self.executable: @@ -156,7 +157,7 @@ class Packager: if not self.localOnly: filename = Filename(filename) filename.makeCanonical() - self.glob = GlobPattern(filename.cStr()) + self.glob = GlobPattern(str(filename)) if self.packager.platform.startswith('win'): self.glob.setCaseSensitive(False) @@ -167,7 +168,7 @@ class Packager: if self.localOnly: return self.glob.matches(filename.getBasename()) else: - return self.glob.matches(filename.cStr()) + return self.glob.matches(str(filename)) class PackageEntry: """ This corresponds to a entry in the contents.xml @@ -586,9 +587,9 @@ class Packager: # (i.e. missing) modules. continue - if newName == '__main__': - # Ignore this special case. - continue + #if newName == '__main__': + # # Ignore this special case. + # continue self.moduleNames[newName] = mdef @@ -937,7 +938,7 @@ class Packager: # means we should include the manifest # file itself in the package. newName = Filename(file.dependencyDir, mfile.getBasename()) - self.addFile(mfile, newName = newName.cStr(), + self.addFile(mfile, newName = str(newName), explicit = False, executable = True) if afilenames is None and out != 31: @@ -957,7 +958,7 @@ class Packager: filename.makeTrueCase() newName = Filename(file.dependencyDir, filename.getBasename()) - self.addFile(filename, newName = newName.cStr(), + self.addFile(filename, newName = str(newName), explicit = False, executable = True) def __parseDependenciesWindows(self, tempFile): @@ -1172,7 +1173,7 @@ class Packager: # It's a fully-specified filename; look # for it under the system root first. if self.packager.systemRoot: - f2 = Filename(self.packager.systemRoot + filename.cStr()) + f2 = Filename(self.packager.systemRoot, filename) if f2.exists(): filename = f2 @@ -1181,7 +1182,7 @@ class Packager: continue newName = Filename(file.dependencyDir, filename.getBasename()) - self.addFile(filename, newName = newName.cStr(), + self.addFile(filename, newName = str(newName), explicit = False, executable = True) def __parseDependenciesOSX(self, tempFile): @@ -1346,6 +1347,7 @@ class Packager: # If that failed, perhaps ldd will help us. if filenames is None: + self.notify.warning("Reading ELF library %s failed, using ldd instead" % (file.filename)) tempFile = Filename.temporary('', 'p3d_', '.txt') command = 'ldd "%s" >"%s"' % ( file.filename.toOsSpecific(), @@ -1379,7 +1381,7 @@ class Packager: filename.setBinary() newName = Filename(file.dependencyDir, filename.getBasename()) - self.addFile(filename, newName = newName.cStr(), + self.addFile(filename, newName = str(newName), explicit = False, executable = True) def __parseDependenciesPosix(self, tempFile): @@ -1470,7 +1472,7 @@ class Packager: # compatible with older versions of the core API that # didn't understand the SF_text flag. filename.setBinary() - + doc.SaveFile(filename.toOsSpecific()) # It's important not to compress this file: the core API @@ -1772,8 +1774,6 @@ class Packager: return xspec - - def addPyFile(self, file): """ Adds the indicated python file, identified by filename instead of by module name, to the package. """ @@ -1793,6 +1793,18 @@ class Packager: # deal with it again. return + # Make sure that it is actually in a package. + parentName = moduleName + while '.' in parentName: + parentName = parentName.rsplit('.', 1)[0] + if parentName not in self.freezer.modules: + message = 'Cannot add Python file %s; not in package' % (file.newName) + if file.required or file.explicit: + raise StandardError, message + else: + self.notify.warning(message) + return + self.freezer.addModule(moduleName, filename = file.filename) def addEggFile(self, file): @@ -1803,7 +1815,7 @@ class Packager: bamName = Filename(file.newName) bamName.setExtension('bam') - self.addNode(np.node(), file.filename, bamName.cStr()) + self.addNode(np.node(), file.filename, str(bamName)) def addBamFile(self, file): # Load the bam file so we can massage its textures. @@ -2207,6 +2219,9 @@ class Packager: cvar = ConfigVariableSearchPath('pdef-path') self.installSearch = list(map(Filename, cvar.getDirectories())) + # This is where we cache the location of libraries. + self.libraryCache = {} + # The system PATH, for searching dll's and exe's. self.executablePath = DSearchPath() @@ -2219,22 +2234,36 @@ class Packager: # Now add the actual system search path. if self.platform.startswith('win'): self.addWindowsSearchPath(self.executablePath, "PATH") - elif self.platform.startswith('osx'): - 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') - self.executablePath.appendDirectory('/usr/local/lib') - else: - self.addPosixSearchPath(self.executablePath, "LD_LIBRARY_PATH") - self.addPosixSearchPath(self.executablePath, "PATH") - self.executablePath.appendDirectory('/lib') - self.executablePath.appendDirectory('/usr/lib') - self.executablePath.appendDirectory('/usr/local/lib') - import platform - if platform.uname()[1]=="pcbsd": + else: + if self.platform.startswith('osx'): + self.addPosixSearchPath(self.executablePath, "DYLD_LIBRARY_PATH") + + self.addPosixSearchPath(self.executablePath, "LD_LIBRARY_PATH") + self.addPosixSearchPath(self.executablePath, "PATH") + + if self.platform.startswith('linux'): + # It used to be okay to just add some common paths on Linux. + # But nowadays, each distribution has their own convention for + # where they put their libraries. Instead, we query the ldconfig + # cache, which contains the location of all libraries. + + if not self.loadLdconfigCache(): + # Ugh, failure. All that remains is to guess. This should + # work for the most common Debian configurations. + multiarchDir = "/lib/%s-linux-gnu" % (os.uname()[4]) + if os.path.isdir(multiarchDir): + self.executablePath.appendDirectory(multiarchDir) + if os.path.isdir("/usr/" + multiarchDir): + self.executablePath.appendDirectory("/usr/" + multiarchDir) + + else: + # FreeBSD, or some other system that still makes sense. + self.executablePath.appendDirectory('/lib') + self.executablePath.appendDirectory('/usr/lib') + self.executablePath.appendDirectory('/usr/local/lib') + + if os.uname()[1] == "pcbsd": self.executablePath.appendDirectory('/usr/PCBSD/local/lib') # Set this flag true to automatically add allow_python_dev to @@ -2388,6 +2417,7 @@ class Packager: GlobPattern('libpthread.so*'), GlobPattern('libthr.so*'), GlobPattern('ld-linux.so*'), + GlobPattern('ld-linux-*.so*'), ] # A Loader for loading models. @@ -2405,6 +2435,60 @@ class Packager: # file. self.contents = {} + def loadLdconfigCache(self): + """ On GNU/Linux, runs ldconfig -p to find out where all the + libraries on the system are located. Assumes that the platform + has already been set. """ + + if not os.path.isfile('/sbin/ldconfig'): + return False + + handle = subprocess.Popen(['/sbin/ldconfig', '-p'], stdout=subprocess.PIPE) + out, err = handle.communicate() + + if handle.returncode != 0: + self.notify.warning("/sbin/ldconfig -p returned code %d" %(handle.returncode)) + return False + + for line in out.splitlines(): + if '=>' not in line: + continue + + prefix, location = line.rsplit('=>', 1) + prefix = prefix.strip() + location = location.strip() + + if not location or not prefix or ' ' not in prefix: + self.notify.warning("Ignoring malformed ldconfig -p line: " + line) + continue + + lib, opts = prefix.split(' ', 1) + if ('x86-64' in opts) != self.platform.endswith('_amd64'): + # This entry isn't meant for our architecture. I think + # x86-64 is the only platform where ldconfig supplies + # this extra arch string. + continue + + self.libraryCache[lib] = Filename.fromOsSpecific(location) + + return True + + def resolveLibrary(self, filename): + """ Resolves the given shared library filename along the executable path, + or by cross-referencing it with the library cache. """ + + path = str(filename) + + if path in self.libraryCache: + filename.setFullpath(self.libraryCache[path].getFullpath()) + return True + + if filename.resolveFilename(self.executablePath): + self.libraryCache[path] = Filename(filename) + return True + + return False + def setPlatform(self, platform = None): """ Sets the platform that this Packager will compute for. On OSX, this can be used to specify the particular architecture @@ -3143,9 +3227,17 @@ class Packager: for moduleName in args: self.currentPackage.freezer.excludeModule(moduleName) + def do_main(self, filename): + """ Includes the indicated file as __main__ module of the application. + Also updates mainModule to point to this module. """ + + self.addModule(['__main__'], '__main__', filename, required = True) + self.currentPackage.mainModule = ('__main__', '__main__') + def do_mainModule(self, moduleName, newName = None, filename = None): """ Names the indicated module as the "main" module of the - application or exe. """ + application or exe. In most cases, you will want to use main() + instead. """ if not self.currentPackage: raise OutsideOfPackageError @@ -3162,7 +3254,7 @@ class Packager: newFilename = Filename('/'.join(moduleName.split('.'))) newFilename.setExtension(filename.getExtension()) self.currentPackage.addFile( - filename, newName = newFilename.cStr(), + filename, newName = str(newFilename), explicit = True, extract = True, required = True) self.currentPackage.mainModule = (moduleName, newName) @@ -3194,7 +3286,9 @@ class Packager: # Multifile, so this file can't itself be in the Multifile. # This requires a bit of care, because we only want to freeze - # VFSImporter.py, and not any other part of direct. + # VFSImporter.py, and not any other part of direct. We do + # also want panda3d/__init__.py, though, since it would + # otherwise be part of the multifile. self.do_excludeModule('direct') # Import the actual VFSImporter module to get its filename on @@ -3205,7 +3299,7 @@ class Packager: self.do_module('VFSImporter', filename = filename) self.do_freeze('_vfsimporter', compileToExe = False) - self.do_file('libpandaexpress.dll'); + self.do_file('panda3d/core.pyd'); # Now that we're done freezing, explicitly add 'direct' to # counteract the previous explicit excludeModule(). @@ -3438,13 +3532,13 @@ class Packager: # build. dllFilename = Filename(filename) dllFilename.setExtension('so') - dllFilename = Filename.dsoFilename(dllFilename.cStr()) + dllFilename = Filename.dsoFilename(str(dllFilename)) if dllFilename != filename: thisFiles = glob.glob(filename.toOsSpecific()) if not thisFiles: # We have to resolve this filename to # determine if it's a _d or not. - if dllFilename.resolveFilename(self.executablePath): + if self.resolveLibrary(dllFilename): thisFiles = [dllFilename.toOsSpecific()] else: thisFiles = [filename.toOsSpecific()] @@ -3455,7 +3549,7 @@ class Packager: prefix = '' if newDir is not None: - prefix = Filename(newDir).cStr() + prefix = str(Filename(newDir)) if prefix and prefix[-1] != '/': prefix += '/' @@ -3527,13 +3621,22 @@ class Packager: sys.path.append(dirname.toOsSpecific()) self.__recurseDir(dirname, newDir, unprocessed = unprocessed) - def __recurseDir(self, filename, newName, unprocessed = None): + def __recurseDir(self, filename, newName, unprocessed = None, packageTree = None): dirList = vfs.scanDirectory(filename) if dirList: # It's a directory name. Recurse. prefix = newName if prefix and prefix[-1] != '/': prefix += '/' + + # First check if this is a Python package tree. If so, add it + # implicitly as a module. + for subfile in dirList: + filename = subfile.getFilename() + if filename.getBasename() == '__init__.py': + moduleName = newName.replace("/", ".") + self.addModule([moduleName], filename=filename) + for subfile in dirList: filename = subfile.getFilename() self.__recurseDir(filename, prefix + filename.getBasename(), @@ -3550,7 +3653,7 @@ class Packager: # Strip off an implicit .pz extension. newFilename = Filename(filename) newFilename.setExtension('') - newFilename = Filename(newFilename.cStr()) + newFilename = Filename(str(newFilename)) ext = newFilename.getExtension() if ext in self.knownExtensions: diff --git a/direct/src/p3d/PatchMaker.py b/direct/src/p3d/PatchMaker.py index ba7bd3b222..e11306b82f 100644 --- a/direct/src/p3d/PatchMaker.py +++ b/direct/src/p3d/PatchMaker.py @@ -1,6 +1,6 @@ from direct.p3d.FileSpec import FileSpec from direct.p3d.SeqValue import SeqValue -from pandac.PandaModules import * +from panda3d.core import * import copy class PatchMaker: @@ -14,7 +14,7 @@ class PatchMaker: the package's "version" string; it also corresponds to the particular patch version, which increments independently of the "version". """ - + def __init__(self, packageName, platform, version, hostUrl, file): self.packageName = packageName self.platform = platform @@ -84,7 +84,7 @@ class PatchMaker: apply in sequence, and the packageVersion object associated with each patch. Returns (None, None, None) if there is no way to recreate this archive file. """ - + if self.tempFile: return (self.tempFile, self, []) @@ -101,7 +101,7 @@ class PatchMaker: # version of some package. package = self.packageCurrent return (Filename(package.packageDir, package.compressedFilename), self, []) - + if self.packageBase: # This PackageVersion instance represents the base # (oldest) version of some package. @@ -144,7 +144,7 @@ class PatchMaker: # Failure trying to decompress the file. return None startFile = startPv.tempFile - + if not plan: # If plan is a zero-length list, we're already # here--return startFile. If plan is None, there's no @@ -162,7 +162,7 @@ class PatchMaker: if not result: # Failure trying to re-create the file. return None - + pv.tempFile = result prevFile = result @@ -194,10 +194,10 @@ class PatchMaker: return patch.toPv return None - + class Patchfile: """ A single patchfile for a package. """ - + def __init__(self, package): self.package = package self.packageName = package.packageName @@ -233,7 +233,7 @@ class PatchMaker: def fromFile(self, packageDir, patchFilename, sourceFile, targetFile): """ Creates the data structures from an existing patchfile on disk. """ - + self.file = FileSpec() self.file.fromFile(packageDir, patchFilename) self.sourceFile = sourceFile @@ -241,7 +241,7 @@ class PatchMaker: def loadXml(self, xpatch): """ Reads the data structures from an xml file. """ - + self.packageName = xpatch.Attribute('name') or self.packageName self.platform = xpatch.Attribute('platform') or self.platform self.version = xpatch.Attribute('version') or self.version @@ -287,7 +287,7 @@ class PatchMaker: class Package: """ This is a particular package. This contains all of the information needed to reconstruct the package's desc file. """ - + def __init__(self, packageDesc, patchMaker, xpackage = None): self.packageDir = Filename(patchMaker.installDir, packageDesc.getDirname()) self.packageDesc = packageDesc @@ -312,19 +312,19 @@ class PatchMaker: def getCurrentKey(self): """ Returns the key to locate the current version of this package. """ - + return (self.packageName, self.platform, self.version, self.hostUrl, self.currentFile) def getBaseKey(self): """ Returns the key to locate the "base" or oldest version of this package. """ - + return (self.packageName, self.platform, self.version, self.hostUrl, self.baseFile) def getTopKey(self): """ Returns the key to locate the "top" or newest version of this package. """ - + return (self.packageName, self.platform, self.version, self.hostUrl, self.topFile) def getGenericKey(self, fileSpec): @@ -345,7 +345,7 @@ class PatchMaker: if not self.doc.LoadFile(): print "Couldn't read %s" % (packageDescFullpath) return False - + xpackage = self.doc.FirstChildElement('package') if not xpackage: return False @@ -358,7 +358,7 @@ class PatchMaker: # other hosts, which means we'll need to fill in a value # here for those hosts. self.hostUrl = None - + self.currentFile = None self.baseFile = None self.topFile = None @@ -388,7 +388,7 @@ class PatchMaker: else: # There's a new version this pass. Update it. self.anyChanges = True - + else: # If there isn't a top_version yet, we have to make # one, by duplicating the currentFile. @@ -516,7 +516,7 @@ class PatchMaker: xarchive = TiXmlElement('top_version') self.currentFile.storeXml(xarchive) xpackage.InsertEndChild(xarchive) - + for patchfile in self.patches: xpatch = patchfile.makeXml(self) xpackage.InsertEndChild(xpatch) @@ -571,7 +571,7 @@ class PatchMaker: patches for all packages; otherwise, it should be a list of package name strings, limiting the set of packages that are processed. """ - + if not self.readContentsFile(): return False self.buildPatchChains() @@ -587,7 +587,7 @@ class PatchMaker: def cleanup(self): """ Should be called on exit to remove temporary files and such created during processing. """ - + for pv in self.packageVersions.values(): pv.cleanup() @@ -596,11 +596,11 @@ class PatchMaker: constructs a patch chain from the version represented by fileSpec to the current version of this package, if possible. Returns the patch chain if successful, or None otherwise. """ - + package = self.readPackageDescFile(descFilename) if not package: return None - + self.buildPatchChains() fromPv = self.getPackageVersion(package.getGenericKey(fileSpec)) toPv = package.currentPv @@ -619,7 +619,7 @@ class PatchMaker: package = self.Package(Filename(descFilename), self) if not package.readDescFile(doProcessing = False): return None - + self.packages.append(package) return package @@ -640,7 +640,7 @@ class PatchMaker: contentsSeq.loadXml(xcontents) contentsSeq += 1 contentsSeq.storeXml(xcontents) - + xpackage = xcontents.FirstChildElement('package') while xpackage: solo = xpackage.Attribute('solo') @@ -651,7 +651,7 @@ class PatchMaker: package = self.Package(filename, self, xpackage) package.readDescFile(doProcessing = True) self.packages.append(package) - + xpackage = xpackage.NextSiblingElement('package') self.contentsDoc = doc @@ -685,7 +685,7 @@ class PatchMaker: pv = self.PackageVersion(*key) self.packageVersions[k] = pv return pv - + def buildPatchChains(self): """ Builds up the chains of PackageVersions and the patchfiles that connect them. """ @@ -696,7 +696,7 @@ class PatchMaker: if not package.baseFile: # This package doesn't have any versions yet. continue - + currentPv = self.getPackageVersion(package.getCurrentKey()) package.currentPv = currentPv currentPv.packageCurrent = package @@ -710,7 +710,7 @@ class PatchMaker: topPv = self.getPackageVersion(package.getTopKey()) package.topPv = topPv topPv.packageTop = package - + for patchfile in package.patches: self.recordPatchfile(patchfile) @@ -757,7 +757,7 @@ class PatchMaker: # What's the current version on the top of the tree? topPv = package.topPv currentPv = package.currentPv - + if topPv != currentPv: # They're different, so build a new patch. filename = Filename(package.currentFile.filename + '.%s.patch' % (package.patchVersion)) @@ -786,7 +786,7 @@ class PatchMaker: v1.file, v2.file) package.patches.append(patchfile) package.anyChanges = True - + self.recordPatchfile(patchfile) return True diff --git a/direct/src/p3d/ScanDirectoryNode.py b/direct/src/p3d/ScanDirectoryNode.py index b3618880ae..1569ed642f 100644 --- a/direct/src/p3d/ScanDirectoryNode.py +++ b/direct/src/p3d/ScanDirectoryNode.py @@ -1,9 +1,9 @@ -from pandac.PandaModules import VirtualFileSystem, VirtualFileMountSystem, Filename, TiXmlDocument +from panda3d.core import VirtualFileSystem, VirtualFileMountSystem, Filename, TiXmlDocument vfs = VirtualFileSystem.getGlobalPtr() class ScanDirectoryNode: """ This class is used to scan a list of files on disk. """ - + def __init__(self, pathname, ignoreUsageXml = False): self.pathname = pathname self.filenames = [] @@ -38,7 +38,7 @@ class ScanDirectoryNode: if not isinstance(vfile.getMount(), VirtualFileMountSystem): # Not a real file; ignore it. continue - + if vfile.isDirectory(): # A nested directory. subdir = ScanDirectoryNode(vfile.getFilename(), ignoreUsageXml = ignoreUsageXml) @@ -49,7 +49,7 @@ class ScanDirectoryNode: # A nested file. self.filenames.append(vfile.getFilename()) self.fileSize += vfile.getFileSize() - + else: # Some other wacky file thing. self.filenames.append(vfile.getFilename()) @@ -78,7 +78,7 @@ class ScanDirectoryNode: self.nested.remove(subdir) self.nestedSize -= subdir.getTotalSize() return subdir - + result = subdir.extractSubdir(pathname) if result: self.nestedSize -= result.getTotalSize() @@ -89,5 +89,5 @@ class ScanDirectoryNode: return result return None - + diff --git a/direct/src/p3d/coreapi.pdef b/direct/src/p3d/coreapi.pdef index c3a2086401..bf066e5d51 100644 --- a/direct/src/p3d/coreapi.pdef +++ b/direct/src/p3d/coreapi.pdef @@ -1,4 +1,4 @@ -from pandac.PandaModules import getModelPath, Filename, ConfigVariableFilename, DSearchPath, ExecutionEnvironment, PandaSystem +from panda3d.core import getModelPath, Filename, ConfigVariableFilename, DSearchPath, ExecutionEnvironment, PandaSystem # This file defines a number of standard "packages" that correspond to # a Panda3D distribution. These packages are built by passing this @@ -57,7 +57,7 @@ class images(package): basename = '%s.jpg' % (name) filename = Filename(basename) found = filename.resolveFilename(search) - + if found: # Add the image file to the package file(filename, newName = basename, extract = True) @@ -91,7 +91,7 @@ class certlist(package): # ".pem" or ".crt" extension, and they should be added with the # extract = True flag so they will be extracted to disk. pass - + class p3dcert(package): # This special application, used to pop up a dialog to prompt the @@ -102,7 +102,7 @@ class p3dcert(package): # On Mac, we package up a P3DCert.app bundle. This includes # specifications in the plist file to avoid creating a dock # icon and stuff. - + # Find p3dcert.plist in the direct source tree. import direct plist = Filename(direct.__path__[0], 'plugin/p3dcert.plist') diff --git a/direct/src/p3d/packp3d.py b/direct/src/p3d/packp3d.py index 6331995448..7dbe3a30b9 100755 --- a/direct/src/p3d/packp3d.py +++ b/direct/src/p3d/packp3d.py @@ -93,8 +93,8 @@ import os import getopt import glob import direct -from direct.p3d import Packager -from pandac.PandaModules import * +from direct.p3d import Packager +from panda3d.core import * # Temp hack for debugging. #from direct.p3d.AppRunner import dummyAppRunner; dummyAppRunner() @@ -113,7 +113,7 @@ def makePackedApp(args): configFlags = [] requires = [] allowPythonDev = False - + for option, value in opts: if option == '-o': appFilename = Filename.fromOsSpecific(value) @@ -183,11 +183,7 @@ def makePackedApp(args): main = os.path.split(main[0])[1] main = Filename.fromOsSpecific(main) - mainModule = Filename(main) - mainModule.setExtension('') - mainModule = mainModule.cStr().replace('/', '.') - packager.installDir = appDir packager.allowPythonDev = allowPythonDev @@ -206,7 +202,7 @@ def makePackedApp(args): # panda3d. if 'panda3d' not in [t[0] for t in requires]: packager.do_require('panda3d') - + for name, version, host in requires: packager.do_require(name, version = version, host = host) @@ -214,10 +210,10 @@ def makePackedApp(args): packager.do_config(**dict(configFlags)) packager.do_dir(root) - packager.do_mainModule(mainModule) + packager.do_main(main) packager.endPackage() packager.close() - + except Packager.PackagerError: # Just print the error message and exit gracefully. inst = sys.exc_info()[1] diff --git a/direct/src/p3d/panda3d.pdef b/direct/src/p3d/panda3d.pdef index 6c93c4485d..4f3df21c97 100755 --- a/direct/src/p3d/panda3d.pdef +++ b/direct/src/p3d/panda3d.pdef @@ -1,4 +1,4 @@ -from pandac.PandaModules import Filename, PandaSystem, getModelPath +from panda3d.core import Filename, PandaSystem, getModelPath # This file defines a number of standard "packages" that correspond to # a Panda3D distribution. These packages are built by passing this @@ -54,7 +54,11 @@ class panda3d(package): 'direct.showutil.*', 'direct.stdpy.*', 'direct.task.*') - module('panda3d') + + module('panda3d.core', + 'panda3d.direct', + 'panda3d.fx', + 'panda3d.physics') # Include various standard Python encodings. The rest is in morepy. module('encodings', 'encodings.aliases', 'encodings.undefined,' @@ -65,9 +69,19 @@ class panda3d(package): import direct file(Filename(direct.__path__[0], 'filter/*.sha'), newDir = 'direct/filter') + # pandac.PandaModules pulls in other Panda3D libs automatically. # Exclude these Panda3D libs; they are big and many applications don't # use them. We define them as separate, optional packages, below, # except for skel - this is useless in a shipped game anyways. + excludeModule('panda3d.egg') + excludeModule('panda3d.ode') + excludeModule('panda3d.bullet') + excludeModule('panda3d.vision') + excludeModule('panda3d.skel') + excludeModule('panda3d.physx') + excludeModule('panda3d.ai') + excludeModule('panda3d.vrpn') + excludeModule('libpandaegg') excludeModule('libpandaode') excludeModule('libpandabullet') @@ -89,6 +103,8 @@ class panda3d(package): excludeModule('MySQLdb', '_mysql') + excludeModule('xml', 'xml.parsers.expat', 'xml.sax') + # Most of the core Panda3D DLL's will be included implicitly due to # being referenced by the above Python code. Here we name a few more # that are also needed, but aren't referenced by any code. Again, @@ -96,7 +112,7 @@ class panda3d(package): # platform-specific extension for an executable. file('libpandagl.dll', 'libp3tinydisplay.dll') if platform.startswith('win'): - file('libpandadx8.dll', 'libpandadx9.dll') + file('libpandadx9.dll') # A basic config file is needed to lay some some fundamental runtime # variables. @@ -104,7 +120,6 @@ class panda3d(package): auxDisplays = """ aux-display pandagl aux-display pandadx9 -aux-display pandadx8 aux-display p3tinydisplay """ else: @@ -270,6 +285,7 @@ class egg(package): config(display_name = "Panda3D egg loader") require('panda3d') + module('panda3d.egg', required = True) file('libpandaegg.dll', required = True) file('libp3ptloader.dll', required = True) @@ -287,6 +303,7 @@ class ode(package): config(display_name = "Panda3D Open Dynamics Engine integration") require('panda3d') + module('panda3d.ode', required = True) file('libpandaode.dll', required = True) class bullet(package): @@ -297,6 +314,7 @@ class bullet(package): config(display_name = "Panda3D Bullet integration") require('panda3d') + module('panda3d.bullet', required = True) file('libpandabullet.dll', required = True) class physx(package): @@ -307,6 +325,7 @@ class physx(package): config(display_name = "Panda3D PhysX integration") require('panda3d') + module('panda3d.physx', required = True) file('libpandaphysx.dll', required = True) file('physxcudart_20.dll') file('PhysXDevice.dll') @@ -320,6 +339,7 @@ class ai(package): config(display_name = "Panda3D AI modules") require('panda3d') + module('panda3d.ai', required = True) file('libpandaai.dll', required = True) class vision(package): @@ -331,6 +351,7 @@ class vision(package): config(display_name = "Panda3D vision modules") require('panda3d') + module('panda3d.vision', required = True) file('libp3vision.dll', required = True) class rocket(package): @@ -341,6 +362,7 @@ class rocket(package): config(display_name = "Panda3D libRocket support") require('panda3d') + module('panda3d.rocket', required = True) module('_rocketcore', '_rocketcontrols') file('libp3rocket.dll', required = True) @@ -351,6 +373,7 @@ class vrpn(package): config(display_name = "Panda3D VRPN support") require('panda3d') + module('panda3d.vrpn', required = True) file('libp3vrpn.dll', required = True) diff --git a/direct/src/p3d/pdeploy.py b/direct/src/p3d/pdeploy.py index e13bd55d66..9ba14e43be 100644 --- a/direct/src/p3d/pdeploy.py +++ b/direct/src/p3d/pdeploy.py @@ -102,7 +102,7 @@ Options: is licensed under. Only relevant when generating a graphical installer. - -O + -O Specify this option when generating a graphical installer to omit the default checkboxes for "run this program" and "install a desktop shortcut" on completion. @@ -147,7 +147,7 @@ import sys import os import getopt from direct.p3d.DeploymentTools import Standalone, Installer, Icon -from pandac.PandaModules import Filename, PandaSystem +from panda3d.core import Filename, PandaSystem def usage(code, msg = ''): if not msg: diff --git a/direct/src/p3d/pmerge.py b/direct/src/p3d/pmerge.py index 835cfcc5f3..2b290eb044 100755 --- a/direct/src/p3d/pmerge.py +++ b/direct/src/p3d/pmerge.py @@ -47,7 +47,7 @@ import getopt import os from direct.p3d import PackageMerger -from pandac.PandaModules import * +from panda3d.core import * def usage(code, msg = ''): print >> sys.stderr, usageText % {'prog' : os.path.split(sys.argv[0])[1]} @@ -66,7 +66,7 @@ for opt, arg in opts: installDir = Filename.fromOsSpecific(arg) elif opt == '-p': packageNames += arg.split(',') - + elif opt == '-h': usage(0) else: @@ -92,7 +92,7 @@ try: for dir in inputDirs: pm.merge(dir, packageNames = packageNames) pm.close() - + except PackageMerger.PackageMergerError: # Just print the error message and exit gracefully. inst = sys.exc_info()[1] diff --git a/direct/src/p3d/ppackage.py b/direct/src/p3d/ppackage.py index fa2c74c846..3897c7c52c 100755 --- a/direct/src/p3d/ppackage.py +++ b/direct/src/p3d/ppackage.py @@ -132,7 +132,7 @@ import getopt import os from direct.p3d import Packager -from pandac.PandaModules import * +from panda3d.core import * def usage(code, msg = ''): print >> sys.stderr, usageText % { diff --git a/direct/src/p3d/ppatcher.py b/direct/src/p3d/ppatcher.py index 3f2ef16b67..440e22cb61 100755 --- a/direct/src/p3d/ppatcher.py +++ b/direct/src/p3d/ppatcher.py @@ -60,7 +60,7 @@ import getopt import os from direct.p3d.PatchMaker import PatchMaker -from pandac.PandaModules import * +from panda3d.core import * def usage(code, msg = ''): print >> sys.stderr, usageText % {'prog' : os.path.split(sys.argv[0])[1]} @@ -76,7 +76,7 @@ installDir = None for opt, arg in opts: if opt == '-i': installDir = Filename.fromOsSpecific(arg) - + elif opt == '-h': usage(0) else: diff --git a/direct/src/p3d/runp3d.py b/direct/src/p3d/runp3d.py index a7807de332..e561e73a0f 100644 --- a/direct/src/p3d/runp3d.py +++ b/direct/src/p3d/runp3d.py @@ -28,7 +28,7 @@ import sys import getopt from AppRunner import AppRunner, ArgumentError from direct.task.TaskManagerGlobal import taskMgr -from pandac.PandaModules import Filename +from panda3d.core import Filename def parseSysArgs(): """ Handles sys.argv, if there are any local arguments, and diff --git a/direct/src/p3d/thirdparty.pdef b/direct/src/p3d/thirdparty.pdef index 6148f27d58..b657aac95b 100644 --- a/direct/src/p3d/thirdparty.pdef +++ b/direct/src/p3d/thirdparty.pdef @@ -13,7 +13,7 @@ # Also see panda3d.pdef. -from pandac.PandaModules import Filename +from panda3d.core import Filename import sys class wx(package): @@ -95,7 +95,7 @@ class twisted(package): 'twisted.runner', 'twisted.scripts', 'twisted.spread', 'twisted.tap', 'twisted.trial', 'twisted.vfs', 'twisted.web', 'twisted.web2', 'twisted.words') - + module('twisted.*', 'twisted.*.*') class pil(package): diff --git a/direct/src/particles/ForceGroup.py b/direct/src/particles/ForceGroup.py index c0b21e4c61..8c04052232 100644 --- a/direct/src/particles/ForceGroup.py +++ b/direct/src/particles/ForceGroup.py @@ -12,7 +12,7 @@ class ForceGroup(DirectObject): def __init__(self, name=None): if (name == None): - self.name = 'ForceGroup-%d' % ForceGroup.id + self.name = 'ForceGroup-%d' % ForceGroup.id ForceGroup.id += 1 else: self.name = name @@ -65,7 +65,7 @@ class ForceGroup(DirectObject): def getNodePath(self): return self.nodePath - # Utility functions + # Utility functions def __getitem__(self, index): numForces = self.node.getNumForces() if ((index < 0) or (index >= numForces)): diff --git a/direct/src/particles/ParticleManagerGlobal.py b/direct/src/particles/ParticleManagerGlobal.py index d68070afed..b4380be412 100644 --- a/direct/src/particles/ParticleManagerGlobal.py +++ b/direct/src/particles/ParticleManagerGlobal.py @@ -1,6 +1,6 @@ """ Contains the global particle system manager """ -from pandac.PandaModules import ParticleSystemManager +from panda3d.physics import ParticleSystemManager particleMgr = ParticleSystemManager() diff --git a/direct/src/particles/Particles.py b/direct/src/particles/Particles.py index cdf0550d05..826b004b80 100644 --- a/direct/src/particles/Particles.py +++ b/direct/src/particles/Particles.py @@ -1,27 +1,27 @@ from pandac.PandaModules import * -from pandac.PandaModules import ParticleSystem -from pandac.PandaModules import BaseParticleFactory -from pandac.PandaModules import PointParticleFactory -from pandac.PandaModules import ZSpinParticleFactory -#from pandac.PandaModules import OrientedParticleFactory -from pandac.PandaModules import BaseParticleRenderer -from pandac.PandaModules import PointParticleRenderer -from pandac.PandaModules import LineParticleRenderer -from pandac.PandaModules import GeomParticleRenderer -from pandac.PandaModules import SparkleParticleRenderer -#from pandac.PandaModules import SpriteParticleRenderer -from pandac.PandaModules import BaseParticleEmitter -from pandac.PandaModules import ArcEmitter -from pandac.PandaModules import BoxEmitter -from pandac.PandaModules import DiscEmitter -from pandac.PandaModules import LineEmitter -from pandac.PandaModules import PointEmitter -from pandac.PandaModules import RectangleEmitter -from pandac.PandaModules import RingEmitter -from pandac.PandaModules import SphereSurfaceEmitter -from pandac.PandaModules import SphereVolumeEmitter -from pandac.PandaModules import TangentRingEmitter +from panda3d.physics import ParticleSystem +from panda3d.physics import BaseParticleFactory +from panda3d.physics import PointParticleFactory +from panda3d.physics import ZSpinParticleFactory +#from panda3d.physics import OrientedParticleFactory +from panda3d.physics import BaseParticleRenderer +from panda3d.physics import PointParticleRenderer +from panda3d.physics import LineParticleRenderer +from panda3d.physics import GeomParticleRenderer +from panda3d.physics import SparkleParticleRenderer +#from panda3d.physics import SpriteParticleRenderer +from panda3d.physics import BaseParticleEmitter +from panda3d.physics import ArcEmitter +from panda3d.physics import BoxEmitter +from panda3d.physics import DiscEmitter +from panda3d.physics import LineEmitter +from panda3d.physics import PointEmitter +from panda3d.physics import RectangleEmitter +from panda3d.physics import RingEmitter +from panda3d.physics import SphereSurfaceEmitter +from panda3d.physics import SphereVolumeEmitter +from panda3d.physics import TangentRingEmitter import SpriteParticleRendererExt @@ -464,7 +464,7 @@ class Particles(ParticleSystem): t_b = seg.getTimeBegin() t_e = seg.getTimeEnd() mod = seg.isModulated() - fun = seg.getFunction() + fun = seg.getFunction() typ = type(fun).__name__ if typ == 'ColorInterpolationFunctionConstant': c_a = fun.getColorA() @@ -560,7 +560,7 @@ class Particles(ParticleSystem): file.write('# Tangent Ring parameters\n') file.write(targ + '.emitter.setRadius(%.4f)\n' % self.emitter.getRadius()) file.write(targ + '.emitter.setRadiusSpread(%.4f)\n' % self.emitter.getRadiusSpread()) - + def getPoolSizeRanges(self): litterRange = [max(1,self.getLitterSize()-self.getLitterSpread()), self.getLitterSize(), @@ -573,9 +573,9 @@ class Particles(ParticleSystem): print 'Litter Ranges: ',litterRange print 'LifeSpan Ranges: ',lifespanRange print 'BirthRate Ranges: ',birthRateRange - + return dict(zip(('min','median','max'),[l*s/b for l,s,b in zip(litterRange,lifespanRange,birthRateRange)])) - + def accelerate(self,time,stepCount = 1,stepTime=0.0): if time > 0.0: @@ -585,14 +585,13 @@ class Particles(ParticleSystem): else: stepCount = int(float(time)/stepTime) remainder = time-stepCount*stepTime - + for step in range(stepCount): base.particleMgr.doParticles(stepTime,self,False) base.physicsMgr.doPhysics(stepTime,self) - + if(remainder): base.particleMgr.doParticles(remainder,self,False) base.physicsMgr.doPhysics(remainder,self) - + self.render() - diff --git a/direct/src/particles/SpriteParticleRendererExt.py b/direct/src/particles/SpriteParticleRendererExt.py index 6f8cbe5820..5a929b2dbc 100644 --- a/direct/src/particles/SpriteParticleRendererExt.py +++ b/direct/src/particles/SpriteParticleRendererExt.py @@ -1,4 +1,4 @@ -from pandac.PandaModules import SpriteParticleRenderer +from panda3d.physics import SpriteParticleRenderer class SpriteParticleRendererExt(SpriteParticleRenderer): @@ -126,4 +126,3 @@ class SpriteParticleRendererExt(SpriteParticleRenderer): m.removeNode() return True - diff --git a/direct/src/plugin/p3dPythonRun.cxx b/direct/src/plugin/p3dPythonRun.cxx index d6b2e9df1d..92002298b3 100755 --- a/direct/src/plugin/p3dPythonRun.cxx +++ b/direct/src/plugin/p3dPythonRun.cxx @@ -34,11 +34,11 @@ TypeHandle P3DPythonRun::P3DWindowHandle::_type_handle; //////////////////////////////////////////////////////////////////// // Function: P3DPythonRun::Constructor // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// P3DPythonRun:: P3DPythonRun(const char *program_name, const char *archive_file, - FHandle input_handle, FHandle output_handle, + FHandle input_handle, FHandle output_handle, const char *log_pathname, bool interactive_console) { P3DWindowHandle::init_type(); init_xml(); @@ -115,7 +115,7 @@ P3DPythonRun(const char *program_name, const char *archive_file, //////////////////////////////////////////////////////////////////// // Function: P3DPythonRun::Destructor // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// P3DPythonRun:: ~P3DPythonRun() { @@ -150,72 +150,32 @@ run_python() { PyRun_SimpleString("import sys; sys.dll_suffix = '_d'"); #endif - // We'll need libpandaexpress to be imported before we can load - // _vfsimporter. So, find it and load it. - Filename libpandaexpress; + Filename dir = _archive_file.get_dirname(); -#ifdef _WIN32 - // Of course it's already resident, so use that version. - wstring basename = Filename::dso_filename("libpandaexpress.so").to_os_specific_w(); - HMODULE h = GetModuleHandleW(basename.c_str()); - - if (h == NULL) { - nout << "Can't find libpandaexpress in memory.\n"; - } else { - static const int buffer_size = 4096; - wchar_t buffer[buffer_size]; - GetModuleFileNameW(h, buffer, buffer_size); - libpandaexpress = Filename::from_os_specific_w(buffer); - } -#endif // _WIN32 - - if (libpandaexpress.empty()) { - // Go look for it on disk. - libpandaexpress = Filename(_archive_file.get_dirname(), - Filename::dso_filename("libpandaexpress.so")); -#if defined(__APPLE__) && PY_VERSION_HEX < 0x02050000 - // On OSX, for Python versions 2.4 and before, we have to load the - // .so file, not the .dylib file. - libpandaexpress.set_type(Filename::T_general); -#endif - } - - if (!libpandaexpress.exists()) { - nout << "Can't find " << libpandaexpress << "\n"; - return false; - } - - // We need the "imp" built-in module for that. - PyObject *imp_module = PyImport_ImportModule("imp"); - if (imp_module == NULL) { - nout << "Failed to import module imp\n"; + // We'll need to synthesize a 'panda3d' module before loading + // VFSImporter. We could simply freeze it, but Python has a bug + // setting __path__ of frozen modules properly. + PyObject *panda3d_module = PyImport_AddModule("panda3d"); + if (panda3d_module == NULL) { + nout << "Failed to create panda3d module:\n"; PyErr_Print(); return false; } - // And here's where we run into a brick wall attempting to make the - // whole plugin system Unicode-safe for Windows. It turns out that - // this Python call, imp.load_dynamic(), will not accept a Unicode - // pathname. So if the DLL in question is in a location that - // contains non-ASCII characters, it can't be loaded. - string os_specific = libpandaexpress.to_os_specific(); - PyObject *result = PyObject_CallMethod - (imp_module, (char *)"load_dynamic", (char *)"ss", - "libpandaexpress", os_specific.c_str()); - if (result == NULL) { - nout << "Failed to import libpandaexpress as a module\n"; - PyErr_Print(); - return false; - } - Py_DECREF(result); - Py_DECREF(imp_module); + // Set the __path__ such that it can find panda3d/core.pyd, etc. + Filename panda3d_dir(dir, "panda3d"); + string dir_str = panda3d_dir.to_os_specific(); + PyObject *panda3d_dict = PyModule_GetDict(panda3d_module); + PyObject *panda3d_path = Py_BuildValue("[s#]", dir_str.data(), dir_str.length()); + PyDict_SetItemString(panda3d_dict, "__path__", panda3d_path); + Py_DECREF(panda3d_path); // Now we can load _vfsimporter.pyd. Since this is a magic frozen // pyd, importing it automatically makes all of its frozen contents // available to import as well. PyObject *vfsimporter = PyImport_ImportModule("_vfsimporter"); if (vfsimporter == NULL) { - nout << "Failed to import _vfsimporter\n"; + nout << "Failed to import _vfsimporter:\n"; PyErr_Print(); return false; } @@ -224,15 +184,15 @@ run_python() { // And now we can import the VFSImporter module that was so defined. PyObject *vfsimporter_module = PyImport_ImportModule("VFSImporter"); if (vfsimporter_module == NULL) { - nout << "Failed to import VFSImporter\n"; + nout << "Failed to import VFSImporter:\n"; PyErr_Print(); return false; } // And register the VFSImporter. - result = PyObject_CallMethod(vfsimporter_module, (char *)"register", (char *)""); + PyObject *result = PyObject_CallMethod(vfsimporter_module, (char *)"register", (char *)""); if (result == NULL) { - nout << "Failed to call VFSImporter.register()\n"; + nout << "Failed to call VFSImporter.register():\n"; PyErr_Print(); return false; } @@ -248,7 +208,6 @@ run_python() { nout << "Could not read " << _archive_file << "\n"; return false; } - Filename dir = _archive_file.get_dirname(); VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); if (!vfs->mount(mf, dir, VirtualFileSystem::MF_read_only)) { nout << "Could not mount " << _archive_file << "\n"; @@ -346,7 +305,7 @@ run_python() { } Py_DECREF(result); Py_DECREF(request_func); - + // Now add check_comm() as a task. It can be a threaded task, but // this does mean that application programmers will have to be alert @@ -545,7 +504,7 @@ handle_command(TiXmlDocument *doc) { assert(!needs_response); int instance_id; TiXmlElement *xwparams = xcommand->FirstChildElement("wparams"); - if (xwparams != (TiXmlElement *)NULL && + if (xwparams != (TiXmlElement *)NULL && xcommand->QueryIntAttribute("instance_id", &instance_id) == TIXML_SUCCESS) { setup_window(instance_id, xwparams); } @@ -591,7 +550,7 @@ handle_command(TiXmlDocument *doc) { _sent_objects.erase(si); } } - + } else { nout << "Unhandled command " << cmd << "\n"; if (needs_response) { @@ -678,7 +637,7 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response, if (method_name == NULL) { // No method name; call the object directly. result = PyObject_CallObject(obj, params); - + // Several special-case "method" names. } else if (strcmp(method_name, "__bool__") == 0) { result = PyBool_FromLong(PyObject_IsTrue(obj)); @@ -713,7 +672,7 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response, PyErr_Clear(); } } - + // If the object supports the mapping protocol, store it // in the object's dictionary. if (!success && PyMapping_Check(obj)) { @@ -761,7 +720,7 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response, PyErr_Clear(); } } - + if (success) { result = Py_True; } else { @@ -1066,8 +1025,8 @@ py_request_func(PyObject *args) { PyObject *value; int needs_response; int unique_id; - if (!PyArg_ParseTuple(extra_args, "sOsOii", - &operation, &object, &property_name, &value, + if (!PyArg_ParseTuple(extra_args, "sOsOii", + &operation, &object, &property_name, &value, &needs_response, &unique_id)) { return NULL; } @@ -1256,7 +1215,7 @@ set_instance_info(P3DCInstance *inst, TiXmlElement *xinstance) { xinstance->Attribute("respect_per_platform", &respect_per_platform); PyObject *result = PyObject_CallMethod - (_runner, (char *)"setInstanceInfo", (char *)"sssiOi", root_dir, + (_runner, (char *)"setInstanceInfo", (char *)"sssiOi", root_dir, log_directory, super_mirror, verify_contents, main, respect_per_platform); Py_DECREF(main); @@ -1347,7 +1306,7 @@ set_p3d_filename(P3DCInstance *inst, TiXmlElement *xfparams) { value = value_c; } - PyObject *tuple = Py_BuildValue("(ss)", keyword.c_str(), + PyObject *tuple = Py_BuildValue("(ss)", keyword.c_str(), value.c_str()); PyList_Append(token_list, tuple); Py_DECREF(tuple); @@ -1419,7 +1378,7 @@ setup_window(P3DCInstance *inst, TiXmlElement *xwparams) { } int win_x, win_y, win_width, win_height; - + xwparams->Attribute("win_x", &win_x); xwparams->Attribute("win_y", &win_y); xwparams->Attribute("win_width", &win_width); @@ -1531,7 +1490,7 @@ terminate_session() { Py_DECREF(result); } } - + _session_terminated = true; } } @@ -1772,7 +1731,7 @@ xml_to_pyobj(TiXmlElement *xvalue) { int object_id; if (xvalue->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) { // Construct a new BrowserObject wrapper around this object. - return PyObject_CallFunction(_browser_object_class, (char *)"Oi", + return PyObject_CallFunction(_browser_object_class, (char *)"Oi", _runner, object_id); } @@ -1852,7 +1811,7 @@ rt_thread_run() { } // Successfully read an XML document. - + // Check for one special case: the "exit" command means we shut // down the read thread along with everything else. TiXmlElement *xcommand = doc->FirstChildElement("command"); @@ -1875,7 +1834,7 @@ rt_thread_run() { //////////////////////////////////////////////////////////////////// // Function: P3DPythonRun::P3DWindowHandle::Constructor // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// P3DPythonRun::P3DWindowHandle:: P3DWindowHandle(P3DPythonRun *p3dpython, P3DCInstance *inst, diff --git a/direct/src/plugin/p3dX11SplashWindow.cxx b/direct/src/plugin/p3dX11SplashWindow.cxx index 18bc7d537d..aaaa4c8e0a 100755 --- a/direct/src/plugin/p3dX11SplashWindow.cxx +++ b/direct/src/plugin/p3dX11SplashWindow.cxx @@ -28,10 +28,10 @@ //////////////////////////////////////////////////////////////////// // Function: P3DX11SplashWindow::Constructor // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// P3DX11SplashWindow:: -P3DX11SplashWindow(P3DInstance *inst, bool make_visible) : +P3DX11SplashWindow(P3DInstance *inst, bool make_visible) : P3DSplashWindow(inst, make_visible) { // Init for parent process @@ -61,7 +61,7 @@ P3DX11SplashWindow(P3DInstance *inst, bool make_visible) : //////////////////////////////////////////////////////////////////// // Function: P3DX11SplashWindow::Destructor // Access: Public, Virtual -// Description: +// Description: //////////////////////////////////////////////////////////////////// P3DX11SplashWindow:: ~P3DX11SplashWindow() { @@ -312,13 +312,13 @@ stop_subprocess() { _pipe_write.close(); static const int max_wait_ms = 2000; - + // Wait for a certain amount of time for the process to stop by // itself. struct timeval start; gettimeofday(&start, NULL); int start_ms = start.tv_sec * 1000 + start.tv_usec / 1000; - + int status; pid_t result = waitpid(_subprocess_pid, &status, WNOHANG); while (result != _subprocess_pid) { @@ -326,20 +326,20 @@ stop_subprocess() { perror("waitpid"); break; } - + struct timeval now; gettimeofday(&now, NULL); int now_ms = now.tv_sec * 1000 + now.tv_usec / 1000; int elapsed = now_ms - start_ms; - + if (elapsed > max_wait_ms) { // Tired of waiting. Kill the process. - nout << "Force-killing splash window process, pid " << _subprocess_pid + nout << "Force-killing splash window process, pid " << _subprocess_pid << "\n"; kill(_subprocess_pid, SIGKILL); start_ms = now_ms; } - + // Yield the timeslice and wait some more. struct timeval tv; tv.tv_sec = 0; @@ -353,7 +353,7 @@ stop_subprocess() { nout << " exited normally, status = " << WEXITSTATUS(status) << "\n"; } else if (WIFSIGNALED(status)) { - nout << " signalled by " << WTERMSIG(status) << ", core = " + nout << " signalled by " << WTERMSIG(status) << ", core = " << WCOREDUMP(status) << "\n"; } else if (WIFSTOPPED(status)) { nout << " stopped by " << WSTOPSIG(status) << "\n"; @@ -396,7 +396,7 @@ check_stopped() { nout << " exited normally, status = " << WEXITSTATUS(status) << "\n"; } else if (WIFSIGNALED(status)) { - nout << " signalled by " << WTERMSIG(status) << ", core = " + nout << " signalled by " << WTERMSIG(status) << ", core = " << WCOREDUMP(status) << "\n"; } else if (WIFSTOPPED(status)) { nout << " stopped by " << WSTOPSIG(status) << "\n"; @@ -522,14 +522,14 @@ subprocess_run() { _win_height = event.xconfigure.height; set_button_range(_button_ready_image); - + // If the window changes size, we need to recompute the // composed image. _needs_new_composite = true; } needs_redraw = true; break; - + case MotionNotify: set_mouse_data(event.xmotion.x, event.xmotion.y, _mouse_down); break; @@ -537,7 +537,7 @@ subprocess_run() { case ButtonPress: set_mouse_data(_mouse_x, _mouse_y, true); break; - + case ButtonRelease: set_mouse_data(_mouse_x, _mouse_y, false); break; @@ -563,7 +563,7 @@ subprocess_run() { needs_redraw = true; prev_label = _install_label; } - + if (_progress_known != prev_progress_known) { needs_update_progress = true; needs_redraw_progress = true; @@ -592,7 +592,7 @@ subprocess_run() { needs_redraw = true; } } - + if (needs_redraw) { redraw(); XFlush(_display); @@ -619,23 +619,23 @@ subprocess_run() { text_width + 4, text_height + 4, false); XDrawString(_display, _window, _graphics_context, text_x, text_y, _install_label.c_str(), _install_label.size()); - + needs_draw_label = false; } - + if (needs_redraw_progress) { - XClearArea(_display, _window, + XClearArea(_display, _window, bar_x, bar_y, bar_width, bar_height, false); - XDrawRectangle(_display, _window, _graphics_context, + XDrawRectangle(_display, _window, _graphics_context, bar_x, bar_y, bar_width, bar_height); needs_update_progress = true; needs_redraw_progress = false; } - + if (needs_update_progress) { if (_progress_known) { int progress_width = (int)((bar_width - 2) * _install_progress + 0.5); - XFillRectangle(_display, _window, _bar_context, + XFillRectangle(_display, _window, _bar_context, bar_x + 1, bar_y + 1, progress_width + 1, bar_height - 1); } else { @@ -649,7 +649,7 @@ subprocess_run() { progress = block_travel * 2 - progress; } - XFillRectangle(_display, _window, _bar_context, + XFillRectangle(_display, _window, _bar_context, bar_x + 1 + progress, bar_y + 1, block_width + 1, bar_height - 1); } @@ -665,7 +665,7 @@ subprocess_run() { fd_set fds; FD_ZERO(&fds); FD_SET(read_fd, &fds); - + // Sleep a bit to yield the timeslice if there's nothing new. struct timeval tv; tv.tv_sec = 0; @@ -729,27 +729,30 @@ receive_command() { } else if (strcmp(cmd, "set_image_filename") == 0) { const string *image_filename = xcommand->Attribute(string("image_filename")); int image_placement; - if (image_filename != NULL && + if (image_filename != NULL && xcommand->QueryIntAttribute("image_placement", &image_placement) == TIXML_SUCCESS) { - + X11ImageData *image = NULL; switch ((ImagePlacement)image_placement) { case IP_background: image = &_background_image; break; - + case IP_button_ready: image = &_button_ready_image; set_button_range(_button_ready_image); break; - + case IP_button_rollover: image = &_button_rollover_image; break; - + case IP_button_click: image = &_button_click_image; break; + + case IP_none: + break; } if (image != NULL) { if (image->_filename != *image_filename) { @@ -804,7 +807,7 @@ redraw() { // If we have an image, draw it. int xo = (_win_width - _composite_width) / 2; int yo = (_win_height - _composite_height) / 2; - XPutImage(_display, _window, _graphics_context, _composite_image, 0, 0, + XPutImage(_display, _window, _graphics_context, _composite_image, 0, 0, xo, yo, _composite_width, _composite_height); // Then clear the rectangles around it carefully (rather than just @@ -840,12 +843,12 @@ make_window() { } X11_Window parent = 0; - + // Hum, if we use the display provided by the browser, // it causes a crash in some browsers when you make an Xlib // call with the plugin window minimized. // So I kept XOpenDisplay until we have a better workaround. - + //_display = (X11_Display*) _wparams.get_parent_window()._xdisplay; //_own_display = false; //if (_display == 0) { @@ -871,7 +874,7 @@ make_window() { // Create a toplevel window. parent = XRootWindow(_display, _screen); } - + assert(parent != None); int depth = DefaultDepth(_display, _screen); @@ -955,7 +958,7 @@ setup_gc() { XFontStruct* fs = XLoadQueryFont(_display, "6x13"); XGCValues gcval; - gcval.font = fs->fid; + gcval.font = fs->fid; gcval.function = GXcopy; gcval.plane_mask = AllPlanes; gcval.foreground = BlackPixel(_display, _screen); @@ -966,8 +969,8 @@ setup_gc() { if (_bg_pixel != -1) { gcval.background = _bg_pixel; } - _graphics_context = XCreateGC(_display, _window, - GCFont | GCFunction | GCPlaneMask | GCForeground | GCBackground, &gcval); + _graphics_context = XCreateGC(_display, _window, + GCFont | GCFunction | GCPlaneMask | GCForeground | GCBackground, &gcval); // Also create a gc for filling in the interior of the progress bar // in a pleasant blue color (or whatever color the user requested). @@ -983,7 +986,7 @@ setup_gc() { gcval.foreground = bar.pixel; } - _bar_context = XCreateGC(_display, _window, + _bar_context = XCreateGC(_display, _window, GCFont | GCFunction | GCPlaneMask | GCForeground | GCBackground, &gcval); } @@ -998,7 +1001,7 @@ close_window() { XDestroyImage(_composite_image); _composite_image = NULL; } - + if (_bar_context != None) { if (_bar_context != _graphics_context) { XFreeGC(_display, _bar_context); @@ -1009,22 +1012,22 @@ close_window() { Colormap colormap = DefaultColormap(_display, _screen); XFreeColors(_display, colormap, &_bar_pixel, 1, 0); } - + if (_fg_pixel != -1) { Colormap colormap = DefaultColormap(_display, _screen); XFreeColors(_display, colormap, &_fg_pixel, 1, 0); } - + if (_bg_pixel != -1) { Colormap colormap = DefaultColormap(_display, _screen); XFreeColors(_display, colormap, &_bg_pixel, 1, 0); } - + if (_graphics_context != None) { XFreeGC(_display, _graphics_context); _graphics_context = None; } - + if (_window != None) { XDestroyWindow(_display, _window); _window = None; @@ -1150,7 +1153,7 @@ compose_image() { } // Now load the image. - _composite_image = XCreateImage(_display, CopyFromParent, DefaultDepth(_display, _screen), + _composite_image = XCreateImage(_display, CopyFromParent, DefaultDepth(_display, _screen), ZPixmap, 0, (char *)new_data, image1_width, image1_height, 32, 0); _composite_width = image1_width; _composite_height = image1_height; diff --git a/direct/src/pyinst/Builder.py b/direct/src/pyinst/Builder.py deleted file mode 100644 index b43f18172b..0000000000 --- a/direct/src/pyinst/Builder.py +++ /dev/null @@ -1,504 +0,0 @@ -import string -import pprint -import sys -import os -import ConfigParser -import pprint -import shutil -import tempfile -import ltoc -import tocfilter -import resource -import archive -import archivebuilder -import carchive - -logfile = None -autopath = [] -built = {} -copyFile = None - -class Target: - def __init__(self, cfg, sectnm, cnvrts): - self.children = [] - self._dependencies = ltoc.lTOC() # the stuff an outer package will need to use me - self.cfg = cfg - self.__name__ = 'joe' - for optnm in cfg.options(sectnm): - cnvrt = cnvrts.get(optnm, 'getstringlist') - if cnvrt: - f = getattr(self, cnvrt, None) - if f: - self.__dict__[optnm] = f(cfg.get(sectnm, optnm)) - if not hasattr(self, 'name'): - self.name = self.__name__ - print "Initializing", self.__name__ - self.pathprefix = autopath + self.pathprefix - self.pathprefix.append(os.path.join(pyinsthome, 'support')) - for z in self.zlib: - if z in self.cfg.sections(): - self.children.append(z) - else: - raise ValueError, "%s - zlib '%s' does not refer to a sections" \ - % (self.name, z) - for i in range(len(self.misc)): - x = self.misc[i] - if x in self.cfg.sections(): - if self.cfg.get(x, "type") == 'PYZ': - self.zlib.append(x) - self.misc[i] = None - self.children.append(x) - self.misc = filter(None, self.misc) - self.edit() - self.toc = ltoc.lTOC() - for thingie in self.excludes: - try: - fltr = tocfilter.makefilter(thingie, self.pathprefix) - except ValueError: - print "Warning: '%s' not found - no filter created" % thingie - else: - self.toc.addFilter(fltr) - if self.exstdlib: - self.toc.addFilter(tocfilter.StdLibFilter()) - if self.extypes: - self.toc.addFilter(tocfilter.ExtFilter(self.extypes)) - if self.expatterns: - self.toc.addFilter(tocfilter.PatternFilter(self.expatterns)) - - ##------utilities------## - def dump(self): - logfile.write("---- %s: %s -----\n" % (self.__class__.__name__, self.name)) - pprint.pprint(self.__dict__, logfile) - def getstringlist(self, opt): - tmp = string.split(opt, ',') - return filter(None, map(string.strip, tmp)) - def getstring(self, opt): - return opt - def getbool(self, opt): - if opt in ('0','f','F','n','N'): - return 0 - return 1 - ##-----framework-----## - def build(self): - print "Gathering components of %s" % self.name - self.gather() - logfile.write("Final Table of Contents for %s:\n" % self.name) - pprint.pprint(self.toc.toList(), logfile) - print "Creating %s" % self.name - self.assemble() - ##-----overrideables-----## - def edit(self): - pass - def gather(self): - pass - def assemble(self): - pass - -class PYZTarget(Target): - def __init__(self, cfg, sectnm, cnvrts): - Target.__init__(self, cfg, sectnm, cnvrts) - # to use a PYZTarget, you'll need imputil and archive - archivebuilder.GetCompiled([os.path.join(pyinsthome, 'imputil.py')]) - print "pyinsthome:", pyinsthome - imputil = resource.makeresource('imputil.py', [pyinsthome]) - self._dependencies.append(imputil) - archivebuilder.GetCompiled([os.path.join(pyinsthome, 'archive_rt.py')]) - archmodule = resource.makeresource('archive_rt.py', [pyinsthome]) - self._dependencies.merge(archmodule.dependencies()) - self._dependencies.append(archmodule) - self.toc.addFilter(archmodule) - self.toc.addFilter(imputil) - for mod in archmodule.modules: - self.toc.addFilter(mod) - def edit(self): - if self.extypes: - print "PYZ target %s ignoring extypes = %s" % (self.__name__, self.extypes) - - def gather(self): - for script in self.dependencies: - rsrc = resource.makeresource(script, self.pathprefix) - if not isinstance(rsrc, resource.scriptresource): - print "Bug alert - Made %s from %s!" % (rsrc, script) - self.toc.merge(rsrc.modules) - logfile.write("lTOC after expanding 'depends':\n") - pprint.pprint(self.toc.toList(), logfile) - for thingie in self.includes + self.directories + self.packages: - rsrc = resource.makeresource(thingie, self.pathprefix) -## if not isinstance(rsrc, resource.pythonresource): -## print "PYZ target %s ignoring include %s" % (self.name, thingie) -## else: - self.toc.merge(rsrc.contents()) - logfile.write("lTOC after includes, dir, pkgs:\n") - pprint.pprint(self.toc.toList(), logfile) - self.toc.addFilter(tocfilter.ExtFilter(['.py', '.pyc', '.pyo'], 1)) - logfile.write("Applying the following filters:\n") - pprint.pprint(self.toc.filters, logfile) - self.toc.filter() - - def assemble(self): - contents = self.toc.toList() - if contents: - lib = archive.ZlibArchive() - lib.build(self.name, archivebuilder.GetCompiled(self.toc.toList())) - -class CollectTarget(Target): - def __init__(self, cfg, sectnm, cnvrts): - Target.__init__(self, cfg, sectnm, cnvrts) - - _rsrcdict = {'COLLECT': resource.dirresource, 'PYZ': resource.zlibresource, 'CARCHIVE': resource.archiveresource} - - def gather(self): - if self.support: - # the bare minimum - self.toc.merge([resource.makeresource('python20.dll')]) - self.toc.merge([resource.makeresource('exceptions.pyc').asBinary()]) - # zlib, bindepends, misc, trees, destdir - for i in range(len(self.zlib)): - # z refers to the section name - z = self.zlib[i] - nm = self.cfg.get(z, 'name') - try: - self.toc.merge([resource.makeresource(nm, ['.'])]) - except ValueError: - # zlibs aren't written if they turn out to be empty - self.zlib[i] = None - self.zlib = filter(None, self.zlib) - if self.zlib: - target = built.get(self.zlib[0], None) - if target: - self.toc.merge(target._dependencies) - for script in self.bindepends: - rsrc = resource.makeresource(script, self.pathprefix) - self.toc.merge(rsrc.binaries) - logfile.write('ltoc after bindepends:\n') - pprint.pprint(self.toc.toList(), logfile) - for thingie in self.misc: - if thingie in self.cfg.sections(): - name = self.cfg.get(thingie, "name") - typ = self.cfg.get(thingie, "type") - klass = self._rsrcdict.get(typ, resource.dataresource) - rsrc = apply(klass, (name, name)) - #now make sure we have the stuff the resource requires - target = built.get(thingie, None) - if target: - self.toc.merge(target._dependencies) - else: - rsrc = resource.makeresource(thingie, self.pathprefix) - self.toc.merge(rsrc.contents()) - logfile.write('ltoc after misc:\n') - pprint.pprint(self.toc.toList(), logfile) - for script in self.script: - if string.find(script, '.') == -1: - script = script + '.py' - rsrc = resource.makeresource(script, self.pathprefix) - if rsrc.typ == 'm': - rsrc.typ = 's' - self.toc.merge([rsrc]) - logfile.write('ltoc after scripts:\n') - pprint.pprint(self.toc.toList(), logfile) - for tree in self.trees: - try: - rsrc = resource.treeresource('.', tree) - except ValueError: - print "tree %s not found" % tree - else: - self.toc.merge(rsrc.contents()) - logfile.write('ltoc after trees:\n') - pprint.pprint(self.toc.toList(), logfile) - self.toc.addFilter(tocfilter.TypeFilter(['d'])) - logfile.write("Applying the following filters:\n") - pprint.pprint(self.toc.filters, logfile) - self.toc.filter() - #don't dupe stuff in a zlib that's part of this target - if self.zlib: - ztoc = ltoc.lTOC() - for zlibnm in self.zlib: - target = built.get(zlibnm, None) - if target: - ztoc.merge(target.toc) - for i in range(len(self.toc)-1, -1, -1): - rsrc = self.toc[i] - if isinstance(rsrc, resource.moduleresource) and rsrc in ztoc: - del self.toc[i] - - def assemble(self): - if os.path.exists(self.name): - if os.path.isdir(self.name): - for fnm in os.listdir(self.name): - try: - os.remove(os.path.join(self.name, fnm)) - except: - print "Could not delete file %s" % os.path.join(self.name, fnm) - else: - os.makedirs(self.name) - mysite = [] - for nm, path, typ in self.toc.toList(): - shutil.copy2(path, self.name) - if typ == 'z': - mysite.append('imputil.FuncImporter(archive.ZlibArchive("%s", 0).get_code).install()' % nm) - if mysite: - mysite.insert(0, 'import archive, imputil') - open(os.path.join(self.name, 'site.py'),'w').write(string.join(mysite, '\n')) - - -class ArchiveTarget(CollectTarget): - usefullname = 1 - def __init__(self, cfg, sectnm, cnvrts): - CollectTarget.__init__(self, cfg, sectnm, cnvrts) - archivebuilder.GetCompiled([os.path.join(pyinsthome, 'carchive_rt.py')]) - carchmodule = resource.makeresource('carchive_rt.py', [pyinsthome]) - self._dependencies.merge(carchmodule.dependencies()) - self._dependencies.append(carchmodule) - - def edit(self): - if self.destdir: - print "Warning 'destdir = %s' ignored for %s" % (self.destdir, self.name) - - def gather(self): - CollectTarget.gather(self) - - _cdict = {'s':2,'m':1,'b':1,'x':1,'a':0,'z':0, 'p':1} - - def assemble(self, pkgnm=None): - if pkgnm is None: - pkgnm = self.name - arch = carchive.CArchive() - toc = [] - pytoc = [] - for nm, path, typ in self.toc.toList(): - compress = self._cdict[typ] - if typ == 'b' or (self.usefullname and typ in 'ms'): - nm = os.path.basename(path) - if typ == 'm': - pytoc.append((nm, path, compress, typ)) - else: - toc.append((nm, path, compress, typ)) - toc = toc + archivebuilder.GetCompiled(pytoc) - arch.build(pkgnm, toc) - return arch - -class FullExeTarget(ArchiveTarget): - usefullname = 0 - def __init__(self, cfg, sectnm, cnvrts): - ArchiveTarget.__init__(self, cfg, sectnm, cnvrts) - - def gather(self): - for script in self.script: - #print "FullExeTarget.gather: script is", repr(script) - rsrc = resource.makeresource(script, self.pathprefix) - rsrc = resource.scriptresource(rsrc.name, rsrc.path) - #print " resource is", repr(rsrc) - self.toc.merge(rsrc.binaries) - ArchiveTarget.gather(self) - if not self.zlib: - self.toc.merge(rsrc.modules) - self._dependencies = ltoc.lTOC() - - _cdict = {'s':2,'m':0,'b':1,'x':0,'a':0,'z':0} - _edict = { (1, 1):'Runw_d.exe', (1, 0):'Runw.exe', (0, 1):'Run_d.exe', (0, 0):'Run.exe'} - - def assemble(self): - pkgname = tempfile.mktemp() - arch = ArchiveTarget.assemble(self, pkgname) - exe = self._edict[(self.userunw, self.debug)] - exe = os.path.normpath(os.path.join(pyinsthome, 'support', exe)) -## copyFile([exe, pkgname], self.name) -## os.remove(pkgname) - # Thomas Heller's icon code - # my version - if self.icon: - myexe = tempfile.mktemp() - copyFile (exe, myexe) - try: - from icon import CopyIcons - CopyIcons(myexe, self.icon) - except ImportError: - print "win32api is required for updating icons" - print "You should have win32api.pyd and PyWinTypes20.dll" - print "in the installation directory." - print "Please copy them to Python's DLLS subdirectory" - print "(or install Mark Hammond's Win32 extensions)." -## iconfile = None -## for name in self.cfg.sections(): -## if self.cfg.get (name, "type") == "STANDALONE": -## try: -## iconfile = self.cfg.get (name, "iconfile") -## except: -## pass -## if iconfile: -## from icon import CopyIcons -## CopyIcons (myexe, iconfile) - copyFile ([myexe, pkgname], self.name) - os.remove(myexe) - else: - copyFile([exe, pkgname], self.name) - #os.remove(pkgname) - -class ExeTarget(FullExeTarget): - def __init__(self, cfg, sectnm, cnvrts): - FullExeTarget.__init__(self, cfg, sectnm, cnvrts) - - def edit(self): - if not self.script: - raise ValueError, "EXE target %s requires 'script=