github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/clients/python/camliclient.py (about) 1 #!/usr/bin/env python 2 # 3 # Camlistore uploader client for Python. 4 # 5 # Copyright 2010 Google Inc. 6 # 7 # Licensed under the Apache License, Version 2.0 (the "License"); 8 # you may not use this file except in compliance with the License. 9 # You may obtain a copy of the License at 10 # 11 # http://www.apache.org/licenses/LICENSE-2.0 12 # 13 # Unless required by applicable law or agreed to in writing, software 14 # distributed under the License is distributed on an "AS IS" BASIS, 15 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 # See the License for the specific language governing permissions and 17 # limitations under the License. 18 # 19 """Command-line example client for Camlistore.""" 20 21 __author__ = 'Brett Slatkin (bslatkin@gmail.com)' 22 23 import logging 24 import optparse 25 import os 26 import re 27 import sys 28 29 try: 30 import camli.op 31 except ImportError: 32 sys.path.insert(0, '../../lib/python') 33 import camli.op 34 35 36 def upload_files(op, path_list): 37 """Uploads a list of files. 38 39 Args: 40 op: The CamliOp to use. 41 path_list: The list of file paths to upload. 42 43 Returns: 44 Exit code. 45 """ 46 real_path_set = set([os.path.abspath(path) for path in path_list]) 47 all_blob_files = [open(path, 'rb') for path in real_path_set] 48 logging.debug('Uploading blob paths: %r', real_path_set) 49 op.put_blobs(all_blob_files) 50 return 0 51 52 53 def upload_dir(op, root_path, recursive=True, ignore_patterns=[r'^\..*']): 54 """Uploads a directory of files recursively. 55 56 Args: 57 op: The CamliOp to use. 58 root_path: The path of the directory to upload. 59 recursively: If the whole directory and its children should be uploaded. 60 ignore_patterns: Set of ignore regex expressions. 61 62 Returns: 63 Exit code. 64 """ 65 def should_ignore(dirname): 66 for pattern in ignore_patterns: 67 if re.match(pattern, dirname): 68 return True 69 return False 70 71 def error(e): 72 raise e 73 74 all_blob_paths = [] 75 for dirpath, dirnames, filenames in os.walk(root_path, onerror=error): 76 allowed_dirnames = [] 77 for name in dirnames: 78 if not should_ignore(name): 79 allowed_dirnames.append(name) 80 for i in xrange(len(dirnames)): 81 dirnames.pop(0) 82 if recursive: 83 dirnames.extend(allowed_dirnames) 84 85 all_blob_paths.extend(os.path.join(dirpath, name) for name in filenames) 86 87 logging.debug('Uploading dir=%r', root_path) 88 upload_files(op, all_blob_paths) 89 return 0 90 91 92 def download_files(op, blobref_list, target_dir): 93 """Downloads blobs to a target directory. 94 95 Args: 96 op: The CamliOp to use. 97 blobref_list: The list of blobrefs to download. 98 target_dir: The directory to save the downloaded blobrefs in. 99 100 Returns: 101 Exit code. 1 if there were any missing blobrefs. 102 """ 103 all_blobs = set(blobref_list) 104 found_blobs = set() 105 106 def start_out(blobref): 107 blob_path = os.path.join(target_dir, blobref) 108 return open(blob_path, 'wb') 109 110 def end_out(blobref, blob_file): 111 found_blobs.add(blobref) 112 blob_file.close() 113 114 op.get_blobs(blobref_list, start_out=start_out, end_out=end_out) 115 missing_blobs = all_blobs - found_blobs 116 if missing_blobs: 117 print >>sys.stderr, 'Missing blobrefs: %s' % ', '.join(missing_blobs) 118 return 1 119 else: 120 return 0 121 122 123 def main(argv): 124 usage = \ 125 """usage: %prog [options] [command] 126 127 Commands: 128 put <filepath> ... [filepathN] 129 \t\t\tupload a set of specific files 130 putdir <directory> 131 \t\t\tput all blobs present in a directory recursively 132 get <blobref> ... [blobrefN] <directory> 133 \t\t\tget and save blobs to a directory, named as their blobrefs; 134 \t\t\t(!) files already present will be overwritten""" 135 parser = optparse.OptionParser(usage=usage) 136 parser.add_option('-a', '--auth', dest='auth', 137 default='', 138 help='username:pasword for HTTP basic authentication') 139 parser.add_option('-s', '--server', dest='server', 140 default='localhost:3179', 141 help='hostname:port to connect to') 142 parser.add_option('-d', '--debug', dest='debug', 143 action='store_true', 144 help='print debug logging') 145 parser.add_option('-i', '--ignore_patterns', dest="ignore_patterns", 146 default="", 147 help='regexp patterns to ignore') 148 149 def error_and_exit(message): 150 print >>sys.stderr, message, '\n' 151 parser.print_help() 152 sys.exit(2) 153 154 opts, args = parser.parse_args(argv[1:]) 155 if not args: 156 parser.print_help() 157 sys.exit(2) 158 159 if opts.debug: 160 logging.getLogger().setLevel(logging.DEBUG) 161 162 op = camli.op.CamliOp(opts.server, auth=opts.auth, basepath="/bs") 163 command = args[0].lower() 164 165 if command == 'putdir': 166 if len(args) < 2: 167 error_and_exit('Must supply at least a directory to put') 168 return upload_dir(op, args[1], opts.ignore_patterns) 169 elif command == 'put': 170 if len(args) < 2: 171 error_and_exit('Must supply one or more file paths to upload') 172 return upload_files(op, args[1:]) 173 elif command == 'get': 174 if len(args) < 3: 175 error_and_exit('Must supply one or more blobrefs to download ' 176 'and a directory to save them to') 177 return download_files(op, args[1:-1], args[-1]) 178 else: 179 error_and_exit('Unknown command: %s' % command) 180 181 182 if __name__ == '__main__': 183 sys.exit(main(sys.argv))