From a8b09fd4c33572a204a80c81e5755cc6d164805d Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 18 Mar 2008 17:25:13 +0000 Subject: Add Tools/scripts/patchcheck.py. Invoked from ``make check``, the script does some verification: - Runs reindent.py on all .py files. - Checks if any changes in Doc exist. - Whether Misc/ACKS was changed. - Whether Misc/NEWS was changed. The hope is that ``make check`` can become a command anybody can run to get reminders about what all the requisite steps needed to create a proper patch/checkin. --- Makefile.pre.in | 4 ++ Tools/scripts/patchcheck.py | 90 +++++++++++++++++++++++++++++++++++++++++++++ Tools/scripts/reindent.py | 2 + 3 files changed, 96 insertions(+) create mode 100644 Tools/scripts/patchcheck.py diff --git a/Makefile.pre.in b/Makefile.pre.in index 61e7282..4edc784 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1140,6 +1140,10 @@ funny: -o -name MANIFEST \ -o -print +# Perform some verification checks on any modified files. +check: + ./$(BUILDPYTHON) $(srcdir)/Tools/scripts/patchcheck.py + # Dependencies Python/thread.o: @THREADHEADERS@ diff --git a/Tools/scripts/patchcheck.py b/Tools/scripts/patchcheck.py new file mode 100644 index 0000000..cc177e7 --- /dev/null +++ b/Tools/scripts/patchcheck.py @@ -0,0 +1,90 @@ +import os.path +import subprocess +import sys + +import reindent + + +def status(message, modal=False, info=None): + """Decorator to output status info to stdout.""" + def decorated_fxn(fxn): + def call_fxn(*args, **kwargs): + sys.stdout.write(message + ' ... ') + sys.stdout.flush() + result = fxn(*args, **kwargs) + if not modal and not info: + print "done" + elif info: + print info(result) + else: + if result: + print "yes" + else: + print "NO" + return result + return call_fxn + return decorated_fxn + +@status("Getting the list of files that have been added/changed", + info=lambda x: "%s files" % len(x)) +def changed_files(): + """Run ``svn status`` and return a set of files that have been + changed/added.""" + cmd = 'svn status --quiet --non-interactive --ignore-externals' + svn_st = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) + svn_st.wait() + output = [line.strip() for line in svn_st.stdout.readlines()] + files = set() + for line in output: + if not line[0] in ('A', 'M'): + continue + line_parts = line.split() + path = line_parts[-1] + if os.path.isfile(path): + files.add(path) + return files + +@status("Fixing whitespace", info=lambda x: "%s files" % x) +def normalize_whitespace(file_paths): + """Make sure that the whitespace for .py files have been normalized.""" + reindent.makebackup = False # No need to create backups. + result = map(reindent.check, (x for x in file_paths if x.endswith('.py'))) + return sum(result) + +@status("Docs modified", modal=True) +def docs_modified(file_paths): + """Report if any files in the Docs directory.""" + for path in file_paths: + if path.startswith("Doc"): + return True + return False + +@status("Misc/ACKS updated", modal=True) +def credit_given(file_paths): + """Check if Misc/ACKS has been changed.""" + return True if 'Misc/ACKS' in file_paths else False + +@status("Misc/NEWS updated", modal=True) +def reported_news(file_paths): + """Check if Misc/NEWS has been changed.""" + return True if 'Misc/NEWS' in file_paths else False + + +def main(): + file_paths = changed_files() + # PEP 7/8 verification. + normalize_whitespace(file_paths) + # Docs updated. + docs_modified(file_paths) + # Misc/ACKS changed. + credit_given(file_paths) + # Misc/NEWS changed. + reported_news(file_paths) + + # Test suite run and passed. + print + print "Did you run the test suite?" + + +if __name__ == '__main__': + main() diff --git a/Tools/scripts/reindent.py b/Tools/scripts/reindent.py index 0805ef7..65749f0 100755 --- a/Tools/scripts/reindent.py +++ b/Tools/scripts/reindent.py @@ -130,9 +130,11 @@ def check(file): f.close() if verbose: print "wrote new", file + return True else: if verbose: print "unchanged." + return False def _rstrip(line, JUNK='\n \t'): """Return line stripped of trailing spaces, tabs, newlines. -- cgit v0.12 def struct { char locked; /* 0=unlocked, 1=locked */ /* a pair to handle an acquire of a locked lock */ pthread_cond_t lock_released; pthread_mutex_t mut; } pthread_lock; #define CHECK_STATUS(name) if (status != 0) { perror(name); error = 1; } /* * Initialization. */ #if defined(_HAVE_BSDI) static void _noop(void) { } static void PyThread__init_thread(void) { /* DO AN INIT BY STARTING THE THREAD */ static int dummy = 0; pthread_t thread1; pthread_create(&thread1, NULL, (void *) _noop, &dummy); pthread_join(thread1, NULL); } #else /* !_HAVE_BSDI */ static void PyThread__init_thread(void) { #if defined(_AIX) && defined(__GNUC__) extern void pthread_init(void); pthread_init(); #endif } #endif /* !_HAVE_BSDI */ /* * Thread support. */ long PyThread_start_new_thread(void (*func)(void *), void *arg) { pthread_t th; int status; #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) pthread_attr_t attrs; #endif #if defined(THREAD_STACK_SIZE) size_t tss; #endif dprintf(("PyThread_start_new_thread called\n")); if (!initialized) PyThread_init_thread(); #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) if (pthread_attr_init(&attrs) != 0) return -1; #endif #if defined(THREAD_STACK_SIZE) tss = (_pythread_stacksize != 0) ? _pythread_stacksize : THREAD_STACK_SIZE; if (tss != 0) { if (pthread_attr_setstacksize(&attrs, tss) != 0) { pthread_attr_destroy(&attrs); return -1; } } #endif #if defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM); #endif status = pthread_create(&th, #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) &attrs, #else (pthread_attr_t*)NULL, #endif (void* (*)(void *))func, (void *)arg ); #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) pthread_attr_destroy(&attrs); #endif if (status != 0) return -1; pthread_detach(th); #if SIZEOF_PTHREAD_T <= SIZEOF_LONG return (long) th; #else return (long) *(long *) &th; #endif } /* XXX This implementation is considered (to quote Tim Peters) "inherently hosed" because: - It does not guarantee the promise that a non-zero integer is returned. - The cast to long is inherently unsafe. - It is not clear that the 'volatile' (for AIX?) are any longer necessary. */ long PyThread_get_thread_ident(void) { volatile pthread_t threadid; if (!initialized) PyThread_init_thread(); threadid = pthread_self(); return (long) threadid; } void PyThread_exit_thread(void) { dprintf(("PyThread_exit_thread called\n")); if (!initialized) exit(0); pthread_exit(0); } #ifdef USE_SEMAPHORES /* * Lock support. */ PyThread_type_lock PyThread_allocate_lock(void) { sem_t *lock; int status, error = 0; dprintf(("PyThread_allocate_lock called\n")); if (!initialized) PyThread_init_thread(); lock = (sem_t *)PyMem_RawMalloc(sizeof(sem_t)); if (lock) { status = sem_init(lock,0,1); CHECK_STATUS("sem_init"); if (error) { PyMem_RawFree((void *)lock); lock = NULL; } } dprintf(("PyThread_allocate_lock() -> %p\n", lock)); return (PyThread_type_lock)lock; } void PyThread_free_lock(PyThread_type_lock lock) { sem_t *thelock = (sem_t *)lock; int status, error = 0; (void) error; /* silence unused-but-set-variable warning */ dprintf(("PyThread_free_lock(%p) called\n", lock)); if (!thelock) return; status = sem_destroy(thelock); CHECK_STATUS("sem_destroy"); PyMem_RawFree((void *)thelock); } /* * As of February 2002, Cygwin thread implementations mistakenly report error * codes in the return value of the sem_ calls (like the pthread_ functions). * Correct implementations return -1 and put the code in errno. This supports * either. */ static int fix_status(int status) { return (status == -1) ? errno : status; } PyLockStatus PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, int intr_flag) { PyLockStatus success; sem_t *thelock = (sem_t *)lock; int status, error = 0; struct timespec ts; (void) error; /* silence unused-but-set-variable warning */ dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) called\n", lock, microseconds, intr_flag)); if (microseconds > 0) MICROSECONDS_TO_TIMESPEC(microseconds, ts); do { if (microseconds > 0) status = fix_status(sem_timedwait(thelock, &ts)); else if (microseconds == 0) status = fix_status(sem_trywait(thelock)); else status = fix_status(sem_wait(thelock)); /* Retry if interrupted by a signal, unless the caller wants to be notified. */ } while (!intr_flag && status == EINTR); /* Don't check the status if we're stopping because of an interrupt. */ if (!(intr_flag && status == EINTR)) { if (microseconds > 0) { if (status != ETIMEDOUT) CHECK_STATUS("sem_timedwait"); } else if (microseconds == 0) { if (status != EAGAIN) CHECK_STATUS("sem_trywait"); } else { CHECK_STATUS("sem_wait"); } } if (status == 0) { success = PY_LOCK_ACQUIRED; } else if (intr_flag && status == EINTR) { success = PY_LOCK_INTR; } else { success = PY_LOCK_FAILURE; } dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) -> %d\n", lock, microseconds, intr_flag, success)); return success; } void PyThread_release_lock(PyThread_type_lock lock) { sem_t *thelock = (sem_t *)lock; int status, error = 0; (void) error; /* silence unused-but-set-variable warning */ dprintf(("PyThread_release_lock(%p) called\n", lock)); status = sem_post(thelock); CHECK_STATUS("sem_post"); } #else /* USE_SEMAPHORES */ /* * Lock support. */ PyThread_type_lock PyThread_allocate_lock(void) { pthread_lock *lock; int status, error = 0; dprintf(("PyThread_allocate_lock called\n")); if (!initialized) PyThread_init_thread(); lock = (pthread_lock *) PyMem_RawMalloc(sizeof(pthread_lock)); if (lock) { memset((void *)lock, '\0', sizeof(pthread_lock)); lock->locked = 0; status = pthread_mutex_init(&lock->mut, pthread_mutexattr_default); CHECK_STATUS("pthread_mutex_init"); /* Mark the pthread mutex underlying a Python mutex as pure happens-before. We can't simply mark the Python-level mutex as a mutex because it can be acquired and released in different threads, which will cause errors. */ _Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(&lock->mut); status = pthread_cond_init(&lock->lock_released, pthread_condattr_default); CHECK_STATUS("pthread_cond_init"); if (error) { PyMem_RawFree((void *)lock); lock = 0; } } dprintf(("PyThread_allocate_lock() -> %p\n", lock)); return (PyThread_type_lock) lock; } void PyThread_free_lock(PyThread_type_lock lock) { pthread_lock *thelock = (pthread_lock *)lock; int status, error = 0; (void) error; /* silence unused-but-set-variable warning */ dprintf(("PyThread_free_lock(%p) called\n", lock)); /* some pthread-like implementations tie the mutex to the cond * and must have the cond destroyed first. */ status = pthread_cond_destroy( &thelock->lock_released ); CHECK_STATUS("pthread_cond_destroy"); status = pthread_mutex_destroy( &thelock->mut ); CHECK_STATUS("pthread_mutex_destroy"); PyMem_RawFree((void *)thelock); } PyLockStatus PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, int intr_flag) { PyLockStatus success; pthread_lock *thelock = (pthread_lock *)lock; int status, error = 0; dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) called\n", lock, microseconds, intr_flag)); status = pthread_mutex_lock( &thelock->mut ); CHECK_STATUS("pthread_mutex_lock[1]"); if (thelock->locked == 0) { success = PY_LOCK_ACQUIRED; } else if (microseconds == 0) { success = PY_LOCK_FAILURE; } else { struct timespec ts; if (microseconds > 0) MICROSECONDS_TO_TIMESPEC(microseconds, ts); /* continue trying until we get the lock */ /* mut must be locked by me -- part of the condition * protocol */ success = PY_LOCK_FAILURE; while (success == PY_LOCK_FAILURE) { if (microseconds > 0) { status = pthread_cond_timedwait( &thelock->lock_released, &thelock->mut, &ts); if (status == ETIMEDOUT) break; CHECK_STATUS("pthread_cond_timed_wait"); } else { status = pthread_cond_wait( &thelock->lock_released, &thelock->mut); CHECK_STATUS("pthread_cond_wait"); } if (intr_flag && status == 0 && thelock->locked) { /* We were woken up, but didn't get the lock. We probably received * a signal. Return PY_LOCK_INTR to allow the caller to handle * it and retry. */ success = PY_LOCK_INTR; break; } else if (status == 0 && !thelock->locked) { success = PY_LOCK_ACQUIRED; } else { success = PY_LOCK_FAILURE; } } } if (success == PY_LOCK_ACQUIRED) thelock->locked = 1; status = pthread_mutex_unlock( &thelock->mut ); CHECK_STATUS("pthread_mutex_unlock[1]"); if (error) success = PY_LOCK_FAILURE; dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) -> %d\n", lock, microseconds, intr_flag, success)); return success; } void PyThread_release_lock(PyThread_type_lock lock) { pthread_lock *thelock = (pthread_lock *)lock; int status, error = 0; (void) error; /* silence unused-but-set-variable warning */ dprintf(("PyThread_release_lock(%p) called\n", lock)); status = pthread_mutex_lock( &thelock->mut ); CHECK_STATUS("pthread_mutex_lock[3]"); thelock->locked = 0; /* wake up someone (anyone, if any) waiting on the lock */ status = pthread_cond_signal( &thelock->lock_released ); CHECK_STATUS("pthread_cond_signal"); status = pthread_mutex_unlock( &thelock->mut ); CHECK_STATUS("pthread_mutex_unlock[3]"); } #endif /* USE_SEMAPHORES */ int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) { return PyThread_acquire_lock_timed(lock, waitflag ? -1 : 0, /*intr_flag=*/0); } /* set the thread stack size. * Return 0 if size is valid, -1 if size is invalid, * -2 if setting stack size is not supported. */ static int _pythread_pthread_set_stacksize(size_t size) { #if defined(THREAD_STACK_SIZE) pthread_attr_t attrs; size_t tss_min; int rc = 0; #endif /* set to default */ if (size == 0) { _pythread_stacksize = 0; return 0; } #if defined(THREAD_STACK_SIZE) #if defined(PTHREAD_STACK_MIN) tss_min = PTHREAD_STACK_MIN > THREAD_STACK_MIN ? PTHREAD_STACK_MIN : THREAD_STACK_MIN; #else tss_min = THREAD_STACK_MIN; #endif if (size >= tss_min) { /* validate stack size by setting thread attribute */ if (pthread_attr_init(&attrs) == 0) { rc = pthread_attr_setstacksize(&attrs, size); pthread_attr_destroy(&attrs); if (rc == 0) { _pythread_stacksize = size; return 0; } } } return -1; #else return -2; #endif } #define THREAD_SET_STACKSIZE(x) _pythread_pthread_set_stacksize(x) #define Py_HAVE_NATIVE_TLS int PyThread_create_key(void) { pthread_key_t key; int fail = pthread_key_create(&key, NULL); if (fail) return -1; if (key > INT_MAX) { /* Issue #22206: handle integer overflow */ pthread_key_delete(key); errno = ENOMEM; return -1; } return (int)key; } void PyThread_delete_key(int key) { pthread_key_delete(key); } void PyThread_delete_key_value(int key) { pthread_setspecific(key, NULL); } int PyThread_set_key_value(int key, void *value) { int fail; fail = pthread_setspecific(key, value); return fail ? -1 : 0; } void * PyThread_get_key_value(int key) { return pthread_getspecific(key); } void PyThread_ReInitTLS(void) {}