mirror of
https://github.com/python/cpython.git
synced 2025-09-27 10:50:04 +00:00
Dangerous feature added: when removing local files (i.e., only when -r
is used), do a recursive delete. Use -r with even more caution! Also changed usage message into a doc string, added a comment or two, and rearranged a long line.
This commit is contained in:
parent
85a5c52752
commit
fdc5adc594
1 changed files with 53 additions and 28 deletions
|
@ -1,12 +1,26 @@
|
||||||
#! /usr/bin/env python
|
#! /usr/bin/env python
|
||||||
|
|
||||||
# Mirror a remote ftp subtree into a local directory tree.
|
"""Mirror a remote ftp subtree into a local directory tree.
|
||||||
# Basic usage: ftpmirror [options] host remotedir localdir
|
|
||||||
#
|
usage: ftpmirror [-v] [-q] [-i] [-m] [-n] [-r] [-s pat]
|
||||||
|
[-l username [-p passwd [-a account]]]
|
||||||
|
hostname [remotedir [localdir]]
|
||||||
|
-v: verbose
|
||||||
|
-q: quiet
|
||||||
|
-i: interactive mode
|
||||||
|
-m: macintosh server (NCSA telnet 2.4) (implies -n -s '*.o')
|
||||||
|
-n: don't log in
|
||||||
|
-r: remove local files/directories no longer pertinent
|
||||||
|
-l username [-p passwd [-a account]]: login info (default anonymous ftp)
|
||||||
|
-s pat: skip files matching pattern
|
||||||
|
hostname: remote host
|
||||||
|
remotedir: remote directory (default initial)
|
||||||
|
localdir: local directory (default current)
|
||||||
|
"""
|
||||||
|
|
||||||
# XXX To do:
|
# XXX To do:
|
||||||
# - handle symbolic links
|
# - handle symbolic links
|
||||||
# - back up .mirrorinfo before overwriting
|
# - back up .mirrorinfo before overwriting
|
||||||
# - use pickles for .mirrorinfo?
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
@ -16,26 +30,11 @@ import string
|
||||||
import ftplib
|
import ftplib
|
||||||
from fnmatch import fnmatch
|
from fnmatch import fnmatch
|
||||||
|
|
||||||
usage_msg = """
|
# Print usage message and exit
|
||||||
usage: ftpmirror [-v] [-q] [-i] [-m] [-n] [-r] [-s pat]
|
|
||||||
[-l username [-p passwd [-a account]]]
|
|
||||||
hostname [remotedir [localdir]]
|
|
||||||
-v: verbose
|
|
||||||
-q: quiet
|
|
||||||
-i: interactive mode
|
|
||||||
-m: macintosh server (NCSA telnet 2.4) (implies -n -s '*.o')
|
|
||||||
-n: don't log in
|
|
||||||
-r: remove files no longer pertinent
|
|
||||||
-l username [-p passwd [-a account]]: login info (default anonymous ftp)
|
|
||||||
-s pat: skip files matching pattern
|
|
||||||
hostname: remote host
|
|
||||||
remotedir: remote directory (default initial)
|
|
||||||
localdir: local directory (default current)
|
|
||||||
"""
|
|
||||||
def usage(*args):
|
def usage(*args):
|
||||||
sys.stdout = sys.stderr
|
sys.stdout = sys.stderr
|
||||||
for msg in args: print msg
|
for msg in args: print msg
|
||||||
print usage_msg
|
print __doc__
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
verbose = 1 # 0 for -q, 2 for -v
|
verbose = 1 # 0 for -q, 2 for -v
|
||||||
|
@ -45,6 +44,7 @@ rmok = 0
|
||||||
nologin = 0
|
nologin = 0
|
||||||
skippats = ['.', '..', '.mirrorinfo']
|
skippats = ['.', '..', '.mirrorinfo']
|
||||||
|
|
||||||
|
# Main program: parse command line and start processing
|
||||||
def main():
|
def main():
|
||||||
global verbose, interactive, mac, rmok, nologin
|
global verbose, interactive, mac, rmok, nologin
|
||||||
try:
|
try:
|
||||||
|
@ -94,6 +94,7 @@ def main():
|
||||||
#
|
#
|
||||||
mirrorsubdir(f, localdir)
|
mirrorsubdir(f, localdir)
|
||||||
|
|
||||||
|
# Core logic: mirror one subdirectory (recursively)
|
||||||
def mirrorsubdir(f, localdir):
|
def mirrorsubdir(f, localdir):
|
||||||
pwd = f.pwd()
|
pwd = f.pwd()
|
||||||
if localdir and not os.path.isdir(localdir):
|
if localdir and not os.path.isdir(localdir):
|
||||||
|
@ -137,7 +138,7 @@ def mirrorsubdir(f, localdir):
|
||||||
continue
|
continue
|
||||||
if words[-2] == '->':
|
if words[-2] == '->':
|
||||||
if verbose > 1:
|
if verbose > 1:
|
||||||
print 'Skipping symbolic link %s -> %s' % \
|
print 'Skipping symbolic link %s -> %s' % \
|
||||||
(words[-3], words[-1])
|
(words[-3], words[-1])
|
||||||
continue
|
continue
|
||||||
filename = words[-1]
|
filename = words[-1]
|
||||||
|
@ -259,12 +260,8 @@ def mirrorsubdir(f, localdir):
|
||||||
print 'Local file', fullname,
|
print 'Local file', fullname,
|
||||||
print 'is no longer pertinent'
|
print 'is no longer pertinent'
|
||||||
continue
|
continue
|
||||||
if verbose: print 'Removing local file', fullname
|
if verbose: print 'Removing local file/dir', fullname
|
||||||
try:
|
remove(fullname)
|
||||||
os.unlink(fullname)
|
|
||||||
except os.error, msg:
|
|
||||||
print "Can't remove local file %s: %s" % \
|
|
||||||
(fullname, str(msg))
|
|
||||||
#
|
#
|
||||||
# Recursively mirror subdirectories
|
# Recursively mirror subdirectories
|
||||||
for subdir in subdirs:
|
for subdir in subdirs:
|
||||||
|
@ -294,6 +291,34 @@ def mirrorsubdir(f, localdir):
|
||||||
else:
|
else:
|
||||||
if verbose > 1: print 'OK.'
|
if verbose > 1: print 'OK.'
|
||||||
|
|
||||||
|
# Helper to remove a file or directory tree
|
||||||
|
def remove(fullname):
|
||||||
|
if os.path.isdir(fullname) and not os.path.islink(fullname):
|
||||||
|
try:
|
||||||
|
names = os.listdir(fullname)
|
||||||
|
except os.error:
|
||||||
|
names = []
|
||||||
|
ok = 1
|
||||||
|
for name in names:
|
||||||
|
if not remove(os.path.join(fullname, name)):
|
||||||
|
ok = 0
|
||||||
|
if not ok:
|
||||||
|
return 0
|
||||||
|
try:
|
||||||
|
os.rmdir(fullname)
|
||||||
|
except os.error, msg:
|
||||||
|
print "Can't remove local directory %s: %s" % \
|
||||||
|
(fullname, str(msg))
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
os.unlink(fullname)
|
||||||
|
except os.error, msg:
|
||||||
|
print "Can't remove local file %s: %s" % \
|
||||||
|
(fullname, str(msg))
|
||||||
|
return 0
|
||||||
|
return 1
|
||||||
|
|
||||||
# Wrapper around a file for writing to write a hash sign every block.
|
# Wrapper around a file for writing to write a hash sign every block.
|
||||||
class LoggingFile:
|
class LoggingFile:
|
||||||
def __init__(self, fp, blocksize, outfp):
|
def __init__(self, fp, blocksize, outfp):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue