/usr/share/pyshared/couchdb/tools/replicate.py is in python-couchdb 0.8-0ubuntu2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | #!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2009 Maximillian Dornseif <md@hudora.de>
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution.
"""
This script replicates databases from one CouchDB server to an other.
This is mainly for backup purposes or "priming" a new server before
setting up trigger based replication. But you can also use the
'--continuous' option to set up automatic replication on newer
CouchDB versions.
Use 'python replicate.py --help' to get more detailed usage instructions.
"""
from couchdb import http, client
import optparse
import sys
import time
import urllib
import urlparse
import fnmatch
def findpath(parser, s):
'''returns (server url, path component)'''
if s == '.':
return client.DEFAULT_BASE_URL, ''
if not s.startswith('http'):
return client.DEFAULT_BASE_URL, s
bits = urlparse.urlparse(s)
res = http.Resource('%s://%s/' % (bits.scheme, bits.netloc), None)
parts = bits.path.split('/')[1:]
if parts and not parts[-1]:
parts = parts[:-1]
cut = None
for i in range(0, len(parts) + 1):
try:
data = res.get_json(parts[:i])[2]
except Exception:
data = None
if data and 'couchdb' in data:
cut = i
if cut is None:
raise parser.error("'%s' does not appear to be a CouchDB" % s)
base = res.url + (parts[:cut] and '/'.join(parts[:cut]) or '')
return base, '/'.join(parts[cut:])
def main():
usage = '%prog [options] <source> <target>'
parser = optparse.OptionParser(usage=usage)
parser.add_option('--continuous',
action='store_true',
dest='continuous',
help='trigger continuous replication in cochdb')
parser.add_option('--compact',
action='store_true',
dest='compact',
help='compact target database after replication')
options, args = parser.parse_args()
if len(args) != 2:
raise parser.error('need source and target arguments')
# set up server objects
src, tgt = args
sbase, spath = findpath(parser, src)
source = client.Server(sbase)
tbase, tpath = findpath(parser, tgt)
target = client.Server(tbase)
# check database name specs
if '*' in tpath:
raise parser.error('invalid target path: must be single db or empty')
elif '*' in spath and tpath:
raise parser.error('target path must be empty with multiple sources')
all = sorted(i for i in source if i[0] != '_') # Skip reserved names.
if not spath:
raise parser.error('source database must be specified')
databases = [(i, i) for i in all if fnmatch.fnmatchcase(i, spath)]
if not databases:
raise parser.error("no source databases match glob '%s'" % spath)
# do the actual replication
for sdb, tdb in databases:
start = time.time()
print sdb, '->', tdb,
sys.stdout.flush()
if tdb not in target:
target.create(tdb)
print "created",
sys.stdout.flush()
sdb = '%s%s' % (sbase, urllib.quote(sdb, ''))
if options.continuous:
target.replicate(sdb, tdb, continuous=options.continuous)
else:
target.replicate(sdb, tdb)
print '%.1fs' % (time.time() - start)
sys.stdout.flush()
if options.compact:
for (sdb, tdb) in databases:
print 'compact', tdb
target[tdb].compact()
if __name__ == '__main__':
main()
|