root / kamaki / cli / commands / pithos.py @ 74b7c6dc
History | View | Annotate | Download (43.3 kB)
1 | e3f01d64 | Stavros Sachtouris | # Copyright 2011-2013 GRNET S.A. All rights reserved.
|
---|---|---|---|
2 | 7493ccb6 | Stavros Sachtouris | #
|
3 | 7493ccb6 | Stavros Sachtouris | # Redistribution and use in source and binary forms, with or
|
4 | 7493ccb6 | Stavros Sachtouris | # without modification, are permitted provided that the following
|
5 | 7493ccb6 | Stavros Sachtouris | # conditions are met:
|
6 | 7493ccb6 | Stavros Sachtouris | #
|
7 | 7493ccb6 | Stavros Sachtouris | # 1. Redistributions of source code must retain the above
|
8 | 7493ccb6 | Stavros Sachtouris | # copyright notice, this list of conditions and the following
|
9 | 7493ccb6 | Stavros Sachtouris | # disclaimer.
|
10 | 7493ccb6 | Stavros Sachtouris | #
|
11 | 7493ccb6 | Stavros Sachtouris | # 2. Redistributions in binary form must reproduce the above
|
12 | 7493ccb6 | Stavros Sachtouris | # copyright notice, this list of conditions and the following
|
13 | 7493ccb6 | Stavros Sachtouris | # disclaimer in the documentation and/or other materials
|
14 | 7493ccb6 | Stavros Sachtouris | # provided with the distribution.
|
15 | 7493ccb6 | Stavros Sachtouris | #
|
16 | 7493ccb6 | Stavros Sachtouris | # THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
|
17 | 7493ccb6 | Stavros Sachtouris | # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18 | 7493ccb6 | Stavros Sachtouris | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
19 | 7493ccb6 | Stavros Sachtouris | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
|
20 | 7493ccb6 | Stavros Sachtouris | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
21 | 7493ccb6 | Stavros Sachtouris | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
22 | 7493ccb6 | Stavros Sachtouris | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
23 | 7493ccb6 | Stavros Sachtouris | # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
24 | 7493ccb6 | Stavros Sachtouris | # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
25 | 7493ccb6 | Stavros Sachtouris | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
26 | 7493ccb6 | Stavros Sachtouris | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
27 | 7493ccb6 | Stavros Sachtouris | # POSSIBILITY OF SUCH DAMAGE.
|
28 | 7493ccb6 | Stavros Sachtouris | #
|
29 | 7493ccb6 | Stavros Sachtouris | # The views and conclusions contained in the software and
|
30 | 7493ccb6 | Stavros Sachtouris | # documentation are those of the authors and should not be
|
31 | 7493ccb6 | Stavros Sachtouris | # interpreted as representing official policies, either expressed
|
32 | 7493ccb6 | Stavros Sachtouris | # or implied, of GRNET S.A.command
|
33 | 7493ccb6 | Stavros Sachtouris | |
34 | fa9c0c38 | Stavros Sachtouris | from io import StringIO |
35 | 76f58e2e | Stavros Sachtouris | from pydoc import pager |
36 | edc1182f | Stavros Sachtouris | from os import path, walk, makedirs |
37 | 1395c40e | Stavros Sachtouris | |
38 | effa4b8f | Stavros Sachtouris | from kamaki.clients.pithos import PithosClient, ClientError |
39 | effa4b8f | Stavros Sachtouris | |
40 | 234954d1 | Stavros Sachtouris | from kamaki.cli import command |
41 | d486baec | Stavros Sachtouris | from kamaki.cli.command_tree import CommandTree |
42 | 6d190dd1 | Stavros Sachtouris | from kamaki.cli.commands import ( |
43 | cec2dfcd | Stavros Sachtouris | _command_init, errors, addLogSettings, DontRaiseKeyError, _optional_json, |
44 | cec2dfcd | Stavros Sachtouris | _name_filter, _optional_output_cmd) |
45 | 74b7c6dc | Stavros Sachtouris | from kamaki.cli.errors import ( |
46 | 74b7c6dc | Stavros Sachtouris | CLIBaseUrlError, CLIError, CLIInvalidArgument, raiseCLIError) |
47 | cec2dfcd | Stavros Sachtouris | from kamaki.cli.argument import ( |
48 | edc1182f | Stavros Sachtouris | FlagArgument, IntArgument, ValueArgument, DateArgument, |
49 | edc1182f | Stavros Sachtouris | ProgressBarArgument, RepeatableArgument) |
50 | edc1182f | Stavros Sachtouris | from kamaki.cli.utils import ( |
51 | edc1182f | Stavros Sachtouris | format_size, bold, get_path_size, guess_mime_type) |
52 | 201baa17 | Stavros Sachtouris | |
53 | cec2dfcd | Stavros Sachtouris | file_cmds = CommandTree('file', 'Pithos+/Storage object level API commands') |
54 | cec2dfcd | Stavros Sachtouris | container_cmds = CommandTree( |
55 | cec2dfcd | Stavros Sachtouris | 'container', 'Pithos+/Storage container level API commands') |
56 | cec2dfcd | Stavros Sachtouris | sharers_commands = CommandTree('sharers', 'Pithos+/Storage sharers') |
57 | cec2dfcd | Stavros Sachtouris | _commands = [file_cmds, container_cmds, sharers_commands] |
58 | 234954d1 | Stavros Sachtouris | |
59 | e3d4d442 | Stavros Sachtouris | |
60 | 5eae854d | Stavros Sachtouris | class _pithos_init(_command_init): |
61 | cec2dfcd | Stavros Sachtouris | """Initilize a pithos+ client
|
62 | cec2dfcd | Stavros Sachtouris | There is always a default account (current user uuid)
|
63 | cec2dfcd | Stavros Sachtouris | There is always a default container (pithos)
|
64 | cec2dfcd | Stavros Sachtouris | """
|
65 | ece4ae4b | Stavros Sachtouris | |
66 | b4f69041 | Stavros Sachtouris | @DontRaiseKeyError
|
67 | b4f69041 | Stavros Sachtouris | def _custom_container(self): |
68 | 144b3551 | Stavros Sachtouris | return self.config.get_cloud(self.cloud, 'pithos_container') |
69 | b4f69041 | Stavros Sachtouris | |
70 | b4f69041 | Stavros Sachtouris | @DontRaiseKeyError
|
71 | b4f69041 | Stavros Sachtouris | def _custom_uuid(self): |
72 | 144b3551 | Stavros Sachtouris | return self.config.get_cloud(self.cloud, 'pithos_uuid') |
73 | b4f69041 | Stavros Sachtouris | |
74 | b4f69041 | Stavros Sachtouris | def _set_account(self): |
75 | b4f69041 | Stavros Sachtouris | self.account = self._custom_uuid() |
76 | b4f69041 | Stavros Sachtouris | if self.account: |
77 | b4f69041 | Stavros Sachtouris | return
|
78 | cec2dfcd | Stavros Sachtouris | astakos = getattr(self, 'auth_base', None) |
79 | cec2dfcd | Stavros Sachtouris | if astakos:
|
80 | cec2dfcd | Stavros Sachtouris | self.account = astakos.user_term('id', self.token) |
81 | b4f69041 | Stavros Sachtouris | else:
|
82 | cec2dfcd | Stavros Sachtouris | raise CLIBaseUrlError(service='astakos') |
83 | b4f69041 | Stavros Sachtouris | |
84 | 1395c40e | Stavros Sachtouris | @errors.generic.all
|
85 | b4f69041 | Stavros Sachtouris | @addLogSettings
|
86 | 1395c40e | Stavros Sachtouris | def _run(self): |
87 | cec2dfcd | Stavros Sachtouris | cloud = getattr(self, 'cloud', None) |
88 | cec2dfcd | Stavros Sachtouris | if cloud:
|
89 | b4f69041 | Stavros Sachtouris | self.base_url = self._custom_url('pithos') |
90 | b4f69041 | Stavros Sachtouris | else:
|
91 | b4f69041 | Stavros Sachtouris | self.cloud = 'default' |
92 | b4f69041 | Stavros Sachtouris | self.token = self._custom_token('pithos') |
93 | cec2dfcd | Stavros Sachtouris | self.container = self._custom_container() or 'pithos' |
94 | 8cec3671 | Stavros Sachtouris | |
95 | cec2dfcd | Stavros Sachtouris | astakos = getattr(self, 'auth_base', None) |
96 | cec2dfcd | Stavros Sachtouris | if astakos:
|
97 | cec2dfcd | Stavros Sachtouris | self.token = self.token or astakos.token |
98 | b4f69041 | Stavros Sachtouris | if not self.base_url: |
99 | cec2dfcd | Stavros Sachtouris | pithos_endpoints = astakos.get_service_endpoints( |
100 | b4f69041 | Stavros Sachtouris | self._custom_type('pithos') or 'object-store', |
101 | b4f69041 | Stavros Sachtouris | self._custom_version('pithos') or '') |
102 | b4f69041 | Stavros Sachtouris | self.base_url = pithos_endpoints['publicURL'] |
103 | cec2dfcd | Stavros Sachtouris | else:
|
104 | cec2dfcd | Stavros Sachtouris | raise CLIBaseUrlError(service='astakos') |
105 | 8cec3671 | Stavros Sachtouris | |
106 | 1f5debf7 | Stavros Sachtouris | self._set_account()
|
107 | de73876b | Stavros Sachtouris | self.client = PithosClient(
|
108 | cec2dfcd | Stavros Sachtouris | self.base_url, self.token, self.account, self.container) |
109 | 7493ccb6 | Stavros Sachtouris | |
110 | 1395c40e | Stavros Sachtouris | def main(self): |
111 | 1395c40e | Stavros Sachtouris | self._run()
|
112 | 1395c40e | Stavros Sachtouris | |
113 | 234954d1 | Stavros Sachtouris | |
114 | cec2dfcd | Stavros Sachtouris | class _pithos_account(_pithos_init): |
115 | cec2dfcd | Stavros Sachtouris | """Setup account"""
|
116 | 7493ccb6 | Stavros Sachtouris | |
117 | effa4b8f | Stavros Sachtouris | def __init__(self, arguments={}, auth_base=None, cloud=None): |
118 | effa4b8f | Stavros Sachtouris | super(_pithos_account, self).__init__(arguments, auth_base, cloud) |
119 | 439826ec | Stavros Sachtouris | self['account'] = ValueArgument( |
120 | cec2dfcd | Stavros Sachtouris | 'Use (a different) user uuid', ('-A', '--account')) |
121 | 1395c40e | Stavros Sachtouris | |
122 | cec2dfcd | Stavros Sachtouris | def _run(self): |
123 | cec2dfcd | Stavros Sachtouris | super(_pithos_account, self)._run() |
124 | cec2dfcd | Stavros Sachtouris | self.client.account = self['account'] or getattr( |
125 | cec2dfcd | Stavros Sachtouris | self, 'account', getattr(self.client, 'account', None)) |
126 | 234954d1 | Stavros Sachtouris | |
127 | 7493ccb6 | Stavros Sachtouris | |
128 | cec2dfcd | Stavros Sachtouris | class _pithos_container(_pithos_account): |
129 | cec2dfcd | Stavros Sachtouris | """Setup container"""
|
130 | 2d7ce81e | Stavros Sachtouris | |
131 | effa4b8f | Stavros Sachtouris | def __init__(self, arguments={}, auth_base=None, cloud=None): |
132 | effa4b8f | Stavros Sachtouris | super(_pithos_container, self).__init__(arguments, auth_base, cloud) |
133 | 439826ec | Stavros Sachtouris | self['container'] = ValueArgument( |
134 | cec2dfcd | Stavros Sachtouris | 'Use this container (default: pithos)', ('-C', '--container')) |
135 | 7493ccb6 | Stavros Sachtouris | |
136 | effa4b8f | Stavros Sachtouris | @staticmethod
|
137 | effa4b8f | Stavros Sachtouris | def _is_dir(remote_dict): |
138 | effa4b8f | Stavros Sachtouris | return 'application/directory' == remote_dict.get( |
139 | effa4b8f | Stavros Sachtouris | 'content_type', remote_dict.get('content-type', '')) |
140 | effa4b8f | Stavros Sachtouris | |
141 | effa4b8f | Stavros Sachtouris | @staticmethod
|
142 | effa4b8f | Stavros Sachtouris | def _resolve_pithos_url(url): |
143 | cec2dfcd | Stavros Sachtouris | """Match urls of one of the following formats:
|
144 | cec2dfcd | Stavros Sachtouris | pithos://ACCOUNT/CONTAINER/OBJECT_PATH
|
145 | cec2dfcd | Stavros Sachtouris | /CONTAINER/OBJECT_PATH
|
146 | effa4b8f | Stavros Sachtouris | return account, container, path
|
147 | 1395c40e | Stavros Sachtouris | """
|
148 | edc1182f | Stavros Sachtouris | account, container, obj_path, prefix = '', '', url, 'pithos://' |
149 | cec2dfcd | Stavros Sachtouris | if url.startswith(prefix):
|
150 | effa4b8f | Stavros Sachtouris | account, sep, url = url[len(prefix):].partition('/') |
151 | cec2dfcd | Stavros Sachtouris | url = '/%s' % url
|
152 | cec2dfcd | Stavros Sachtouris | if url.startswith('/'): |
153 | edc1182f | Stavros Sachtouris | container, sep, obj_path = url[1:].partition('/') |
154 | edc1182f | Stavros Sachtouris | return account, container, obj_path
|
155 | 447c9568 | Stavros Sachtouris | |
156 | cec2dfcd | Stavros Sachtouris | def _run(self, url=None): |
157 | effa4b8f | Stavros Sachtouris | acc, con, self.path = self._resolve_pithos_url(url or '') |
158 | effa4b8f | Stavros Sachtouris | self.account = acc or getattr(self, 'account', '') |
159 | cec2dfcd | Stavros Sachtouris | super(_pithos_container, self)._run() |
160 | effa4b8f | Stavros Sachtouris | self.container = con or self['container'] or getattr( |
161 | cec2dfcd | Stavros Sachtouris | self, 'container', None) or getattr(self.client, 'container', '') |
162 | effa4b8f | Stavros Sachtouris | self.client.container = self.container |
163 | 447c9568 | Stavros Sachtouris | |
164 | 1395c40e | Stavros Sachtouris | |
165 | cec2dfcd | Stavros Sachtouris | @command(file_cmds)
|
166 | cec2dfcd | Stavros Sachtouris | class file_list(_pithos_container, _optional_json, _name_filter): |
167 | cec2dfcd | Stavros Sachtouris | """List all objects in a container or a directory object"""
|
168 | 7493ccb6 | Stavros Sachtouris | |
169 | 47ae7577 | Stavros Sachtouris | arguments = dict(
|
170 | f40f0cb7 | Stavros Sachtouris | detail=FlagArgument('detailed output', ('-l', '--list')), |
171 | f40f0cb7 | Stavros Sachtouris | limit=IntArgument('limit number of listed items', ('-n', '--number')), |
172 | f40f0cb7 | Stavros Sachtouris | marker=ValueArgument('output greater that marker', '--marker'), |
173 | 47ae7577 | Stavros Sachtouris | delimiter=ValueArgument('show output up to delimiter', '--delimiter'), |
174 | 47ae7577 | Stavros Sachtouris | meta=ValueArgument( |
175 | 201baa17 | Stavros Sachtouris | 'show output with specified meta keys', '--meta', |
176 | 47ae7577 | Stavros Sachtouris | default=[]), |
177 | 47ae7577 | Stavros Sachtouris | if_modified_since=ValueArgument( |
178 | 201baa17 | Stavros Sachtouris | 'show output modified since then', '--if-modified-since'), |
179 | 47ae7577 | Stavros Sachtouris | if_unmodified_since=ValueArgument( |
180 | 201baa17 | Stavros Sachtouris | 'show output not modified since then', '--if-unmodified-since'), |
181 | 47ae7577 | Stavros Sachtouris | until=DateArgument('show metadata until then', '--until'), |
182 | 47ae7577 | Stavros Sachtouris | format=ValueArgument( |
183 | 201baa17 | Stavros Sachtouris | 'format to parse until data (default: d/m/Y H:M:S )', '--format'), |
184 | 47ae7577 | Stavros Sachtouris | shared=FlagArgument('show only shared', '--shared'), |
185 | fa9c0c38 | Stavros Sachtouris | more=FlagArgument('read long results', '--more'), |
186 | 8694bdad | Stavros Sachtouris | enum=FlagArgument('Enumerate results', '--enumerate'), |
187 | 8694bdad | Stavros Sachtouris | recursive=FlagArgument( |
188 | 8694bdad | Stavros Sachtouris | 'Recursively list containers and their contents',
|
189 | 8694bdad | Stavros Sachtouris | ('-R', '--recursive')) |
190 | 47ae7577 | Stavros Sachtouris | ) |
191 | c41a86b2 | Stavros Sachtouris | |
192 | 1757c616 | Stavros Sachtouris | def print_objects(self, object_list): |
193 | 234954d1 | Stavros Sachtouris | for index, obj in enumerate(object_list): |
194 | 7493ccb6 | Stavros Sachtouris | pretty_obj = obj.copy() |
195 | 7493ccb6 | Stavros Sachtouris | index += 1
|
196 | 234954d1 | Stavros Sachtouris | empty_space = ' ' * (len(str(len(object_list))) - len(str(index))) |
197 | a339a3ee | Stavros Sachtouris | if 'subdir' in obj: |
198 | a339a3ee | Stavros Sachtouris | continue
|
199 | edc1182f | Stavros Sachtouris | if self._is_dir(obj): |
200 | edc1182f | Stavros Sachtouris | size = 'D'
|
201 | 7493ccb6 | Stavros Sachtouris | else:
|
202 | edc1182f | Stavros Sachtouris | size = format_size(obj['bytes'])
|
203 | 234954d1 | Stavros Sachtouris | pretty_obj['bytes'] = '%s (%s)' % (obj['bytes'], size) |
204 | fa9c0c38 | Stavros Sachtouris | oname = obj['name'] if self['more'] else bold(obj['name']) |
205 | cec2dfcd | Stavros Sachtouris | prfx = ('%s%s. ' % (empty_space, index)) if self['enum'] else '' |
206 | 47ae7577 | Stavros Sachtouris | if self['detail']: |
207 | ff1c0296 | Stavros Sachtouris | self.writeln('%s%s' % (prfx, oname)) |
208 | 76f58e2e | Stavros Sachtouris | self.print_dict(pretty_obj, exclude=('name')) |
209 | ff1c0296 | Stavros Sachtouris | self.writeln()
|
210 | 7493ccb6 | Stavros Sachtouris | else:
|
211 | ff1c0296 | Stavros Sachtouris | oname = '%s%9s %s' % (prfx, size, oname)
|
212 | edc1182f | Stavros Sachtouris | oname += '/' if self._is_dir(obj) else u'' |
213 | ff1c0296 | Stavros Sachtouris | self.writeln(oname)
|
214 | 7493ccb6 | Stavros Sachtouris | |
215 | 1395c40e | Stavros Sachtouris | @errors.generic.all
|
216 | 1395c40e | Stavros Sachtouris | @errors.pithos.connection
|
217 | 1395c40e | Stavros Sachtouris | @errors.pithos.container
|
218 | cec2dfcd | Stavros Sachtouris | @errors.pithos.object_path
|
219 | 1395c40e | Stavros Sachtouris | def _run(self): |
220 | cec2dfcd | Stavros Sachtouris | r = self.client.container_get(
|
221 | cec2dfcd | Stavros Sachtouris | limit=False if self['more'] else self['limit'], |
222 | cec2dfcd | Stavros Sachtouris | marker=self['marker'], |
223 | cec2dfcd | Stavros Sachtouris | prefix=self['name_pref'] or '/', |
224 | cec2dfcd | Stavros Sachtouris | delimiter=self['delimiter'], |
225 | cec2dfcd | Stavros Sachtouris | path=self.path or '', |
226 | cec2dfcd | Stavros Sachtouris | if_modified_since=self['if_modified_since'], |
227 | cec2dfcd | Stavros Sachtouris | if_unmodified_since=self['if_unmodified_since'], |
228 | cec2dfcd | Stavros Sachtouris | until=self['until'], |
229 | cec2dfcd | Stavros Sachtouris | meta=self['meta'], |
230 | cec2dfcd | Stavros Sachtouris | show_only_shared=self['shared']) |
231 | cec2dfcd | Stavros Sachtouris | files = self._filter_by_name(r.json)
|
232 | 1757c616 | Stavros Sachtouris | if self['more']: |
233 | 1757c616 | Stavros Sachtouris | outbu, self._out = self._out, StringIO() |
234 | 1757c616 | Stavros Sachtouris | try:
|
235 | f76c6bbc | Stavros Sachtouris | if self['json_output'] or self['output_format']: |
236 | 1757c616 | Stavros Sachtouris | self._print(files)
|
237 | 1757c616 | Stavros Sachtouris | else:
|
238 | cec2dfcd | Stavros Sachtouris | self.print_objects(files)
|
239 | 1757c616 | Stavros Sachtouris | finally:
|
240 | 1757c616 | Stavros Sachtouris | if self['more']: |
241 | 1757c616 | Stavros Sachtouris | pager(self._out.getvalue())
|
242 | 1757c616 | Stavros Sachtouris | self._out = outbu
|
243 | 1395c40e | Stavros Sachtouris | |
244 | cec2dfcd | Stavros Sachtouris | def main(self, path_or_url='/'): |
245 | cec2dfcd | Stavros Sachtouris | super(self.__class__, self)._run(path_or_url) |
246 | 1395c40e | Stavros Sachtouris | self._run()
|
247 | 7493ccb6 | Stavros Sachtouris | |
248 | 234954d1 | Stavros Sachtouris | |
249 | cec2dfcd | Stavros Sachtouris | @command(file_cmds)
|
250 | cec2dfcd | Stavros Sachtouris | class file_create(_pithos_container, _optional_output_cmd): |
251 | effa4b8f | Stavros Sachtouris | """Create an empty file"""
|
252 | 1e29b9f6 | Stavros Sachtouris | |
253 | 1e29b9f6 | Stavros Sachtouris | arguments = dict(
|
254 | 1e29b9f6 | Stavros Sachtouris | content_type=ValueArgument( |
255 | 1e29b9f6 | Stavros Sachtouris | 'Set content type (default: application/octet-stream)',
|
256 | 1e29b9f6 | Stavros Sachtouris | '--content-type',
|
257 | 915b99b5 | Stavros Sachtouris | default='application/octet-stream')
|
258 | 1e29b9f6 | Stavros Sachtouris | ) |
259 | 1e29b9f6 | Stavros Sachtouris | |
260 | effa4b8f | Stavros Sachtouris | @errors.generic.all
|
261 | effa4b8f | Stavros Sachtouris | @errors.pithos.connection
|
262 | effa4b8f | Stavros Sachtouris | @errors.pithos.container
|
263 | 1395c40e | Stavros Sachtouris | def _run(self): |
264 | 915b99b5 | Stavros Sachtouris | self._optional_output(
|
265 | 915b99b5 | Stavros Sachtouris | self.client.create_object(self.path, self['content_type'])) |
266 | 1395c40e | Stavros Sachtouris | |
267 | cec2dfcd | Stavros Sachtouris | def main(self, path_or_url): |
268 | cec2dfcd | Stavros Sachtouris | super(self.__class__, self)._run(path_or_url) |
269 | b4cf92b8 | Stavros Sachtouris | self._run()
|
270 | effa4b8f | Stavros Sachtouris | |
271 | effa4b8f | Stavros Sachtouris | |
272 | effa4b8f | Stavros Sachtouris | @command(file_cmds)
|
273 | effa4b8f | Stavros Sachtouris | class file_mkdir(_pithos_container, _optional_output_cmd): |
274 | effa4b8f | Stavros Sachtouris | """Create a directory: /file create --content-type='applcation/directory'
|
275 | effa4b8f | Stavros Sachtouris | """
|
276 | effa4b8f | Stavros Sachtouris | |
277 | effa4b8f | Stavros Sachtouris | @errors.generic.all
|
278 | effa4b8f | Stavros Sachtouris | @errors.pithos.connection
|
279 | effa4b8f | Stavros Sachtouris | @errors.pithos.container
|
280 | effa4b8f | Stavros Sachtouris | def _run(self): |
281 | effa4b8f | Stavros Sachtouris | self._optional_output(self.client.create_directory(self.path)) |
282 | effa4b8f | Stavros Sachtouris | |
283 | 74b7c6dc | Stavros Sachtouris | def main(self, path_or_url): |
284 | 74b7c6dc | Stavros Sachtouris | super(self.__class__, self)._run(path_or_url) |
285 | effa4b8f | Stavros Sachtouris | self._run()
|
286 | effa4b8f | Stavros Sachtouris | |
287 | effa4b8f | Stavros Sachtouris | |
288 | effa4b8f | Stavros Sachtouris | class _source_destination(_pithos_container, _optional_output_cmd): |
289 | effa4b8f | Stavros Sachtouris | |
290 | de932277 | Stavros Sachtouris | sd_arguments = dict(
|
291 | effa4b8f | Stavros Sachtouris | destination_user_uuid=ValueArgument( |
292 | effa4b8f | Stavros Sachtouris | 'default: current user uuid', '--to-account'), |
293 | effa4b8f | Stavros Sachtouris | destination_container=ValueArgument( |
294 | effa4b8f | Stavros Sachtouris | 'default: pithos', '--to-container'), |
295 | effa4b8f | Stavros Sachtouris | source_prefix=FlagArgument( |
296 | effa4b8f | Stavros Sachtouris | 'Transfer all files that are prefixed with SOURCE PATH If the '
|
297 | effa4b8f | Stavros Sachtouris | 'destination path is specified, replace SOURCE_PATH with '
|
298 | effa4b8f | Stavros Sachtouris | 'DESTINATION_PATH',
|
299 | de932277 | Stavros Sachtouris | ('-r', '--recursive')), |
300 | effa4b8f | Stavros Sachtouris | force=FlagArgument( |
301 | effa4b8f | Stavros Sachtouris | 'Overwrite destination objects, if needed', ('-f', '--force')) |
302 | effa4b8f | Stavros Sachtouris | ) |
303 | effa4b8f | Stavros Sachtouris | |
304 | effa4b8f | Stavros Sachtouris | def __init__(self, arguments={}, auth_base=None, cloud=None): |
305 | effa4b8f | Stavros Sachtouris | self.arguments.update(arguments)
|
306 | de932277 | Stavros Sachtouris | self.arguments.update(self.sd_arguments) |
307 | de932277 | Stavros Sachtouris | super(_source_destination, self).__init__( |
308 | de932277 | Stavros Sachtouris | self.arguments, auth_base, cloud)
|
309 | de932277 | Stavros Sachtouris | |
310 | de932277 | Stavros Sachtouris | def _report_transfer(self, src, dst, transfer_name): |
311 | de932277 | Stavros Sachtouris | if not dst: |
312 | de932277 | Stavros Sachtouris | if transfer_name in ('move', ): |
313 | de932277 | Stavros Sachtouris | self.error(' delete source directory %s' % src) |
314 | de932277 | Stavros Sachtouris | return
|
315 | de932277 | Stavros Sachtouris | dst_prf = '' if self.account == self.dst_client.account else ( |
316 | de932277 | Stavros Sachtouris | 'pithos://%s' % self.dst_client.account) |
317 | de932277 | Stavros Sachtouris | if src:
|
318 | de932277 | Stavros Sachtouris | src_prf = '' if self.account == self.dst_client.account else ( |
319 | de932277 | Stavros Sachtouris | 'pithos://%s' % self.account) |
320 | de932277 | Stavros Sachtouris | self.error(' %s %s/%s/%s\n --> %s/%s/%s' % ( |
321 | de932277 | Stavros Sachtouris | transfer_name, |
322 | de932277 | Stavros Sachtouris | src_prf, self.container, src,
|
323 | de932277 | Stavros Sachtouris | dst_prf, self.dst_client.container, dst))
|
324 | de932277 | Stavros Sachtouris | else:
|
325 | de932277 | Stavros Sachtouris | self.error(' mkdir %s/%s/%s' % ( |
326 | de932277 | Stavros Sachtouris | dst_prf, self.dst_client.container, dst))
|
327 | effa4b8f | Stavros Sachtouris | |
328 | effa4b8f | Stavros Sachtouris | @errors.generic.all
|
329 | effa4b8f | Stavros Sachtouris | @errors.pithos.account
|
330 | effa4b8f | Stavros Sachtouris | def _src_dst(self, version=None): |
331 | effa4b8f | Stavros Sachtouris | """Preconditions:
|
332 | effa4b8f | Stavros Sachtouris | self.account, self.container, self.path
|
333 | effa4b8f | Stavros Sachtouris | self.dst_acc, self.dst_con, self.dst_path
|
334 | effa4b8f | Stavros Sachtouris | They should all be configured properly
|
335 | effa4b8f | Stavros Sachtouris | :returns: [(src_path, dst_path), ...], if src_path is None, create
|
336 | effa4b8f | Stavros Sachtouris | destination directory
|
337 | effa4b8f | Stavros Sachtouris | """
|
338 | effa4b8f | Stavros Sachtouris | src_objects, dst_objects, pairs = dict(), dict(), [] |
339 | effa4b8f | Stavros Sachtouris | try:
|
340 | effa4b8f | Stavros Sachtouris | for obj in self.dst_client.list_objects( |
341 | effa4b8f | Stavros Sachtouris | prefix=self.dst_path or self.path or '/'): |
342 | effa4b8f | Stavros Sachtouris | dst_objects[obj['name']] = obj
|
343 | effa4b8f | Stavros Sachtouris | except ClientError as ce: |
344 | effa4b8f | Stavros Sachtouris | if ce.status in (404, ): |
345 | effa4b8f | Stavros Sachtouris | raise CLIError(
|
346 | effa4b8f | Stavros Sachtouris | 'Destination container pithos://%s/%s not found' % (
|
347 | effa4b8f | Stavros Sachtouris | self.dst_client.account, self.dst_client.container)) |
348 | de932277 | Stavros Sachtouris | raise ce
|
349 | effa4b8f | Stavros Sachtouris | if self['source_prefix']: |
350 | effa4b8f | Stavros Sachtouris | # Copy and replace prefixes
|
351 | effa4b8f | Stavros Sachtouris | for src_obj in self.client.list_objects(prefix=self.path or '/'): |
352 | effa4b8f | Stavros Sachtouris | src_objects[src_obj['name']] = src_obj
|
353 | effa4b8f | Stavros Sachtouris | for src_path, src_obj in src_objects.items(): |
354 | effa4b8f | Stavros Sachtouris | dst_path = '%s%s' % (
|
355 | effa4b8f | Stavros Sachtouris | self.dst_path or self.path, src_path[len(self.path):]) |
356 | effa4b8f | Stavros Sachtouris | dst_obj = dst_objects.get(dst_path, None)
|
357 | effa4b8f | Stavros Sachtouris | if self['force'] or not dst_obj: |
358 | effa4b8f | Stavros Sachtouris | # Just do it
|
359 | de932277 | Stavros Sachtouris | pairs.append(( |
360 | de932277 | Stavros Sachtouris | None if self._is_dir(src_obj) else src_path, dst_path)) |
361 | de932277 | Stavros Sachtouris | if self._is_dir(src_obj): |
362 | de932277 | Stavros Sachtouris | pairs.append((self.path or dst_path, None)) |
363 | effa4b8f | Stavros Sachtouris | elif not (self._is_dir(dst_obj) and self._is_dir(src_obj)): |
364 | effa4b8f | Stavros Sachtouris | raise CLIError(
|
365 | effa4b8f | Stavros Sachtouris | 'Destination object exists', importance=2, details=[ |
366 | effa4b8f | Stavros Sachtouris | 'Failed while transfering:',
|
367 | effa4b8f | Stavros Sachtouris | ' pithos://%s/%s/%s' % (
|
368 | effa4b8f | Stavros Sachtouris | self.account,
|
369 | effa4b8f | Stavros Sachtouris | self.container,
|
370 | effa4b8f | Stavros Sachtouris | src_path), |
371 | effa4b8f | Stavros Sachtouris | '--> pithos://%s/%s/%s' % (
|
372 | effa4b8f | Stavros Sachtouris | self.dst_client.account,
|
373 | effa4b8f | Stavros Sachtouris | self.dst_client.container,
|
374 | effa4b8f | Stavros Sachtouris | dst_path), |
375 | effa4b8f | Stavros Sachtouris | 'Use %s to transfer overwrite' % ('/'.join( |
376 | effa4b8f | Stavros Sachtouris | self.arguments['force'].parsed_name))]) |
377 | effa4b8f | Stavros Sachtouris | else:
|
378 | de932277 | Stavros Sachtouris | # One object transfer
|
379 | de932277 | Stavros Sachtouris | try:
|
380 | de932277 | Stavros Sachtouris | src_obj = self.client.get_object_info(self.path) |
381 | de932277 | Stavros Sachtouris | except ClientError as ce: |
382 | de932277 | Stavros Sachtouris | if ce.status in (204, ): |
383 | de932277 | Stavros Sachtouris | raise CLIError(
|
384 | de932277 | Stavros Sachtouris | 'Missing specific path container %s' % self.container, |
385 | de932277 | Stavros Sachtouris | importance=2, details=[
|
386 | de932277 | Stavros Sachtouris | 'To transfer container contents %s' % (
|
387 | de932277 | Stavros Sachtouris | '/'.join(self.arguments[ |
388 | de932277 | Stavros Sachtouris | 'source_prefix'].parsed_name))])
|
389 | de932277 | Stavros Sachtouris | raise
|
390 | effa4b8f | Stavros Sachtouris | dst_path = self.dst_path or self.path |
391 | 74b7c6dc | Stavros Sachtouris | dst_obj = dst_objects.get(dst_path or self.path, None) |
392 | effa4b8f | Stavros Sachtouris | if self['force'] or not dst_obj: |
393 | effa4b8f | Stavros Sachtouris | pairs.append( |
394 | de932277 | Stavros Sachtouris | (None if self._is_dir(src_obj) else self.path, dst_path)) |
395 | de932277 | Stavros Sachtouris | if self._is_dir(src_obj): |
396 | de932277 | Stavros Sachtouris | pairs.append((self.path or dst_path, None)) |
397 | effa4b8f | Stavros Sachtouris | elif self._is_dir(src_obj): |
398 | effa4b8f | Stavros Sachtouris | raise CLIError(
|
399 | effa4b8f | Stavros Sachtouris | 'Cannot transfer an application/directory object',
|
400 | effa4b8f | Stavros Sachtouris | importance=2, details=[
|
401 | effa4b8f | Stavros Sachtouris | 'The object pithos://%s/%s/%s is a directory' % (
|
402 | effa4b8f | Stavros Sachtouris | self.account,
|
403 | effa4b8f | Stavros Sachtouris | self.container,
|
404 | de932277 | Stavros Sachtouris | self.path),
|
405 | effa4b8f | Stavros Sachtouris | 'To recursively copy a directory, use',
|
406 | effa4b8f | Stavros Sachtouris | ' %s' % ('/'.join( |
407 | effa4b8f | Stavros Sachtouris | self.arguments['source_prefix'].parsed_name)), |
408 | effa4b8f | Stavros Sachtouris | 'To create a file, use',
|
409 | effa4b8f | Stavros Sachtouris | ' /file create (general purpose)',
|
410 | effa4b8f | Stavros Sachtouris | ' /file mkdir (a directory object)'])
|
411 | effa4b8f | Stavros Sachtouris | else:
|
412 | effa4b8f | Stavros Sachtouris | raise CLIError(
|
413 | effa4b8f | Stavros Sachtouris | 'Destination object exists',
|
414 | effa4b8f | Stavros Sachtouris | importance=2, details=[
|
415 | effa4b8f | Stavros Sachtouris | 'Failed while transfering:',
|
416 | effa4b8f | Stavros Sachtouris | ' pithos://%s/%s/%s' % (
|
417 | effa4b8f | Stavros Sachtouris | self.account,
|
418 | effa4b8f | Stavros Sachtouris | self.container,
|
419 | de932277 | Stavros Sachtouris | self.path),
|
420 | effa4b8f | Stavros Sachtouris | '--> pithos://%s/%s/%s' % (
|
421 | effa4b8f | Stavros Sachtouris | self.dst_client.account,
|
422 | effa4b8f | Stavros Sachtouris | self.dst_client.container,
|
423 | effa4b8f | Stavros Sachtouris | dst_path), |
424 | effa4b8f | Stavros Sachtouris | 'Use %s to transfer overwrite' % ('/'.join( |
425 | effa4b8f | Stavros Sachtouris | self.arguments['force'].parsed_name))]) |
426 | effa4b8f | Stavros Sachtouris | return pairs
|
427 | effa4b8f | Stavros Sachtouris | |
428 | effa4b8f | Stavros Sachtouris | def _run(self, source_path_or_url, destination_path_or_url=''): |
429 | effa4b8f | Stavros Sachtouris | super(_source_destination, self)._run(source_path_or_url) |
430 | effa4b8f | Stavros Sachtouris | dst_acc, dst_con, dst_path = self._resolve_pithos_url(
|
431 | effa4b8f | Stavros Sachtouris | destination_path_or_url) |
432 | effa4b8f | Stavros Sachtouris | self.dst_client = PithosClient(
|
433 | effa4b8f | Stavros Sachtouris | base_url=self.client.base_url, token=self.client.token, |
434 | effa4b8f | Stavros Sachtouris | container=self[
|
435 | effa4b8f | Stavros Sachtouris | 'destination_container'] or dst_con or self.client.container, |
436 | effa4b8f | Stavros Sachtouris | account=self[
|
437 | effa4b8f | Stavros Sachtouris | 'destination_user_uuid'] or dst_acc or self.client.account) |
438 | effa4b8f | Stavros Sachtouris | self.dst_path = dst_path or self.path |
439 | effa4b8f | Stavros Sachtouris | |
440 | effa4b8f | Stavros Sachtouris | |
441 | effa4b8f | Stavros Sachtouris | @command(file_cmds)
|
442 | effa4b8f | Stavros Sachtouris | class file_copy(_source_destination): |
443 | effa4b8f | Stavros Sachtouris | """Copy objects, even between different accounts or containers"""
|
444 | effa4b8f | Stavros Sachtouris | |
445 | effa4b8f | Stavros Sachtouris | arguments = dict(
|
446 | effa4b8f | Stavros Sachtouris | public=ValueArgument('publish new object', '--public'), |
447 | effa4b8f | Stavros Sachtouris | content_type=ValueArgument( |
448 | effa4b8f | Stavros Sachtouris | 'change object\'s content type', '--content-type'), |
449 | effa4b8f | Stavros Sachtouris | source_version=ValueArgument( |
450 | effa4b8f | Stavros Sachtouris | 'copy specific version', ('-S', '--source-version')) |
451 | effa4b8f | Stavros Sachtouris | ) |
452 | effa4b8f | Stavros Sachtouris | |
453 | effa4b8f | Stavros Sachtouris | @errors.generic.all
|
454 | effa4b8f | Stavros Sachtouris | @errors.pithos.connection
|
455 | effa4b8f | Stavros Sachtouris | @errors.pithos.container
|
456 | effa4b8f | Stavros Sachtouris | @errors.pithos.account
|
457 | effa4b8f | Stavros Sachtouris | def _run(self): |
458 | effa4b8f | Stavros Sachtouris | for src, dst in self._src_dst(self['source_version']): |
459 | de932277 | Stavros Sachtouris | self._report_transfer(src, dst, 'copy') |
460 | de932277 | Stavros Sachtouris | if src and dst: |
461 | effa4b8f | Stavros Sachtouris | self.dst_client.copy_object(
|
462 | effa4b8f | Stavros Sachtouris | src_container=self.client.container,
|
463 | effa4b8f | Stavros Sachtouris | src_object=src, |
464 | effa4b8f | Stavros Sachtouris | dst_container=self.dst_client.container,
|
465 | effa4b8f | Stavros Sachtouris | dst_object=dst, |
466 | effa4b8f | Stavros Sachtouris | source_account=self.account,
|
467 | effa4b8f | Stavros Sachtouris | source_version=self['source_version'], |
468 | effa4b8f | Stavros Sachtouris | public=self['public'], |
469 | effa4b8f | Stavros Sachtouris | content_type=self['content_type']) |
470 | de932277 | Stavros Sachtouris | elif dst:
|
471 | de932277 | Stavros Sachtouris | self.dst_client.create_directory(dst)
|
472 | effa4b8f | Stavros Sachtouris | |
473 | effa4b8f | Stavros Sachtouris | def main(self, source_path_or_url, destination_path_or_url=None): |
474 | effa4b8f | Stavros Sachtouris | super(file_copy, self)._run( |
475 | effa4b8f | Stavros Sachtouris | source_path_or_url, destination_path_or_url or '') |
476 | effa4b8f | Stavros Sachtouris | self._run()
|
477 | effa4b8f | Stavros Sachtouris | |
478 | effa4b8f | Stavros Sachtouris | |
479 | effa4b8f | Stavros Sachtouris | @command(file_cmds)
|
480 | effa4b8f | Stavros Sachtouris | class file_move(_source_destination): |
481 | effa4b8f | Stavros Sachtouris | """Move objects, even between different accounts or containers"""
|
482 | effa4b8f | Stavros Sachtouris | |
483 | effa4b8f | Stavros Sachtouris | arguments = dict(
|
484 | effa4b8f | Stavros Sachtouris | public=ValueArgument('publish new object', '--public'), |
485 | effa4b8f | Stavros Sachtouris | content_type=ValueArgument( |
486 | effa4b8f | Stavros Sachtouris | 'change object\'s content type', '--content-type') |
487 | effa4b8f | Stavros Sachtouris | ) |
488 | effa4b8f | Stavros Sachtouris | |
489 | effa4b8f | Stavros Sachtouris | @errors.generic.all
|
490 | effa4b8f | Stavros Sachtouris | @errors.pithos.connection
|
491 | effa4b8f | Stavros Sachtouris | @errors.pithos.container
|
492 | effa4b8f | Stavros Sachtouris | @errors.pithos.account
|
493 | effa4b8f | Stavros Sachtouris | def _run(self): |
494 | effa4b8f | Stavros Sachtouris | for src, dst in self._src_dst(): |
495 | de932277 | Stavros Sachtouris | self._report_transfer(src, dst, 'move') |
496 | de932277 | Stavros Sachtouris | if src and dst: |
497 | effa4b8f | Stavros Sachtouris | self.dst_client.move_object(
|
498 | effa4b8f | Stavros Sachtouris | src_container=self.client.container,
|
499 | effa4b8f | Stavros Sachtouris | src_object=src, |
500 | effa4b8f | Stavros Sachtouris | dst_container=self.dst_client.container,
|
501 | effa4b8f | Stavros Sachtouris | dst_object=dst, |
502 | effa4b8f | Stavros Sachtouris | source_account=self.account,
|
503 | effa4b8f | Stavros Sachtouris | public=self['public'], |
504 | effa4b8f | Stavros Sachtouris | content_type=self['content_type']) |
505 | de932277 | Stavros Sachtouris | elif dst:
|
506 | de932277 | Stavros Sachtouris | self.dst_client.create_directory(dst)
|
507 | effa4b8f | Stavros Sachtouris | else:
|
508 | de932277 | Stavros Sachtouris | self.client.del_object(src)
|
509 | effa4b8f | Stavros Sachtouris | |
510 | effa4b8f | Stavros Sachtouris | def main(self, source_path_or_url, destination_path_or_url=None): |
511 | effa4b8f | Stavros Sachtouris | super(file_move, self)._run( |
512 | effa4b8f | Stavros Sachtouris | source_path_or_url, destination_path_or_url or '') |
513 | effa4b8f | Stavros Sachtouris | self._run()
|
514 | edc1182f | Stavros Sachtouris | |
515 | edc1182f | Stavros Sachtouris | |
516 | edc1182f | Stavros Sachtouris | @command(file_cmds)
|
517 | edc1182f | Stavros Sachtouris | class file_append(_pithos_container, _optional_output_cmd): |
518 | edc1182f | Stavros Sachtouris | """Append local file to (existing) remote object
|
519 | edc1182f | Stavros Sachtouris | The remote object should exist.
|
520 | edc1182f | Stavros Sachtouris | If the remote object is a directory, it is transformed into a file.
|
521 | edc1182f | Stavros Sachtouris | In the later case, objects under the directory remain intact.
|
522 | edc1182f | Stavros Sachtouris | """
|
523 | edc1182f | Stavros Sachtouris | |
524 | edc1182f | Stavros Sachtouris | arguments = dict(
|
525 | edc1182f | Stavros Sachtouris | progress_bar=ProgressBarArgument( |
526 | edc1182f | Stavros Sachtouris | 'do not show progress bar', ('-N', '--no-progress-bar'), |
527 | edc1182f | Stavros Sachtouris | default=False),
|
528 | edc1182f | Stavros Sachtouris | max_threads=IntArgument('default: 1', '--threads'), |
529 | edc1182f | Stavros Sachtouris | ) |
530 | edc1182f | Stavros Sachtouris | |
531 | edc1182f | Stavros Sachtouris | @errors.generic.all
|
532 | edc1182f | Stavros Sachtouris | @errors.pithos.connection
|
533 | edc1182f | Stavros Sachtouris | @errors.pithos.container
|
534 | edc1182f | Stavros Sachtouris | @errors.pithos.object_path
|
535 | edc1182f | Stavros Sachtouris | def _run(self, local_path): |
536 | edc1182f | Stavros Sachtouris | if self['max_threads'] > 0: |
537 | edc1182f | Stavros Sachtouris | self.client.MAX_THREADS = int(self['max_threads']) |
538 | edc1182f | Stavros Sachtouris | (progress_bar, upload_cb) = self._safe_progress_bar('Appending') |
539 | edc1182f | Stavros Sachtouris | try:
|
540 | edc1182f | Stavros Sachtouris | with open(local_path, 'rb') as f: |
541 | edc1182f | Stavros Sachtouris | self._optional_output(
|
542 | edc1182f | Stavros Sachtouris | self.client.append_object(self.path, f, upload_cb)) |
543 | edc1182f | Stavros Sachtouris | finally:
|
544 | edc1182f | Stavros Sachtouris | self._safe_progress_bar_finish(progress_bar)
|
545 | edc1182f | Stavros Sachtouris | |
546 | edc1182f | Stavros Sachtouris | def main(self, local_path, remote_path_or_url): |
547 | edc1182f | Stavros Sachtouris | super(self.__class__, self)._run(remote_path_or_url) |
548 | edc1182f | Stavros Sachtouris | self._run(local_path)
|
549 | edc1182f | Stavros Sachtouris | |
550 | edc1182f | Stavros Sachtouris | |
551 | edc1182f | Stavros Sachtouris | @command(file_cmds)
|
552 | edc1182f | Stavros Sachtouris | class file_truncate(_pithos_container, _optional_output_cmd): |
553 | edc1182f | Stavros Sachtouris | """Truncate remote file up to size"""
|
554 | edc1182f | Stavros Sachtouris | |
555 | edc1182f | Stavros Sachtouris | arguments = dict(
|
556 | edc1182f | Stavros Sachtouris | size_in_bytes=IntArgument('Length of file after truncation', '--size') |
557 | edc1182f | Stavros Sachtouris | ) |
558 | edc1182f | Stavros Sachtouris | required = ('size_in_bytes', )
|
559 | edc1182f | Stavros Sachtouris | |
560 | edc1182f | Stavros Sachtouris | @errors.generic.all
|
561 | edc1182f | Stavros Sachtouris | @errors.pithos.connection
|
562 | edc1182f | Stavros Sachtouris | @errors.pithos.container
|
563 | edc1182f | Stavros Sachtouris | @errors.pithos.object_path
|
564 | edc1182f | Stavros Sachtouris | @errors.pithos.object_size
|
565 | edc1182f | Stavros Sachtouris | def _run(self, size): |
566 | edc1182f | Stavros Sachtouris | self._optional_output(self.client.truncate_object(self.path, size)) |
567 | edc1182f | Stavros Sachtouris | |
568 | edc1182f | Stavros Sachtouris | def main(self, path_or_url): |
569 | edc1182f | Stavros Sachtouris | super(self.__class__, self)._run(path_or_url) |
570 | edc1182f | Stavros Sachtouris | self._run(size=self['size_in_bytes']) |
571 | edc1182f | Stavros Sachtouris | |
572 | edc1182f | Stavros Sachtouris | |
573 | edc1182f | Stavros Sachtouris | @command(file_cmds)
|
574 | edc1182f | Stavros Sachtouris | class file_overwrite(_pithos_container, _optional_output_cmd): |
575 | edc1182f | Stavros Sachtouris | """Overwrite part of a remote file"""
|
576 | edc1182f | Stavros Sachtouris | |
577 | edc1182f | Stavros Sachtouris | arguments = dict(
|
578 | edc1182f | Stavros Sachtouris | progress_bar=ProgressBarArgument( |
579 | edc1182f | Stavros Sachtouris | 'do not show progress bar', ('-N', '--no-progress-bar'), |
580 | edc1182f | Stavros Sachtouris | default=False),
|
581 | edc1182f | Stavros Sachtouris | start_position=IntArgument('File position in bytes', '--from'), |
582 | edc1182f | Stavros Sachtouris | end_position=IntArgument('File position in bytes', '--to') |
583 | edc1182f | Stavros Sachtouris | ) |
584 | edc1182f | Stavros Sachtouris | required = ('start_position', 'end_position') |
585 | edc1182f | Stavros Sachtouris | |
586 | edc1182f | Stavros Sachtouris | @errors.generic.all
|
587 | edc1182f | Stavros Sachtouris | @errors.pithos.connection
|
588 | edc1182f | Stavros Sachtouris | @errors.pithos.container
|
589 | edc1182f | Stavros Sachtouris | @errors.pithos.object_path
|
590 | edc1182f | Stavros Sachtouris | @errors.pithos.object_size
|
591 | edc1182f | Stavros Sachtouris | def _run(self, local_path, start, end): |
592 | edc1182f | Stavros Sachtouris | start, end = int(start), int(end) |
593 | edc1182f | Stavros Sachtouris | (progress_bar, upload_cb) = self._safe_progress_bar(
|
594 | edc1182f | Stavros Sachtouris | 'Overwrite %s bytes' % (end - start))
|
595 | edc1182f | Stavros Sachtouris | try:
|
596 | edc1182f | Stavros Sachtouris | with open(path.abspath(local_path), 'rb') as f: |
597 | edc1182f | Stavros Sachtouris | self._optional_output(self.client.overwrite_object( |
598 | edc1182f | Stavros Sachtouris | obj=self.path,
|
599 | edc1182f | Stavros Sachtouris | start=start, |
600 | edc1182f | Stavros Sachtouris | end=end, |
601 | edc1182f | Stavros Sachtouris | source_file=f, |
602 | edc1182f | Stavros Sachtouris | upload_cb=upload_cb)) |
603 | edc1182f | Stavros Sachtouris | finally:
|
604 | edc1182f | Stavros Sachtouris | self._safe_progress_bar_finish(progress_bar)
|
605 | edc1182f | Stavros Sachtouris | |
606 | edc1182f | Stavros Sachtouris | def main(self, local_path, path_or_url): |
607 | edc1182f | Stavros Sachtouris | super(self.__class__, self)._run(path_or_url) |
608 | edc1182f | Stavros Sachtouris | self.path = self.path or path.basename(local_path) |
609 | edc1182f | Stavros Sachtouris | self._run(
|
610 | edc1182f | Stavros Sachtouris | local_path=local_path, |
611 | edc1182f | Stavros Sachtouris | start=self['start_position'], |
612 | edc1182f | Stavros Sachtouris | end=self['end_position']) |
613 | edc1182f | Stavros Sachtouris | |
614 | edc1182f | Stavros Sachtouris | |
615 | edc1182f | Stavros Sachtouris | @command(file_cmds)
|
616 | edc1182f | Stavros Sachtouris | class file_upload(_pithos_container, _optional_output_cmd): |
617 | edc1182f | Stavros Sachtouris | """Upload a file"""
|
618 | edc1182f | Stavros Sachtouris | |
619 | edc1182f | Stavros Sachtouris | arguments = dict(
|
620 | edc1182f | Stavros Sachtouris | max_threads=IntArgument('default: 5', '--threads'), |
621 | edc1182f | Stavros Sachtouris | content_encoding=ValueArgument( |
622 | edc1182f | Stavros Sachtouris | 'set MIME content type', '--content-encoding'), |
623 | edc1182f | Stavros Sachtouris | content_disposition=ValueArgument( |
624 | edc1182f | Stavros Sachtouris | 'specify objects presentation style', '--content-disposition'), |
625 | edc1182f | Stavros Sachtouris | content_type=ValueArgument('specify content type', '--content-type'), |
626 | edc1182f | Stavros Sachtouris | uuid_for_read_permission=RepeatableArgument( |
627 | edc1182f | Stavros Sachtouris | 'Give read access to a user of group (can be repeated)',
|
628 | edc1182f | Stavros Sachtouris | '--read-permission'),
|
629 | edc1182f | Stavros Sachtouris | uuid_for_write_permission=RepeatableArgument( |
630 | edc1182f | Stavros Sachtouris | 'Give write access to a user of group (can be repeated)',
|
631 | edc1182f | Stavros Sachtouris | '--write-permission'),
|
632 | edc1182f | Stavros Sachtouris | public=FlagArgument('make object publicly accessible', '--public'), |
633 | edc1182f | Stavros Sachtouris | overwrite=FlagArgument('Force (over)write', ('-f', '--force')), |
634 | edc1182f | Stavros Sachtouris | recursive=FlagArgument( |
635 | edc1182f | Stavros Sachtouris | 'Recursively upload directory *contents* + subdirectories',
|
636 | edc1182f | Stavros Sachtouris | ('-r', '--recursive')), |
637 | edc1182f | Stavros Sachtouris | unchunked=FlagArgument( |
638 | edc1182f | Stavros Sachtouris | 'Upload file as one block (not recommended)', '--unchunked'), |
639 | edc1182f | Stavros Sachtouris | md5_checksum=ValueArgument( |
640 | edc1182f | Stavros Sachtouris | 'Confirm upload with a custom checksum (MD5)', '--etag'), |
641 | edc1182f | Stavros Sachtouris | use_hashes=FlagArgument( |
642 | edc1182f | Stavros Sachtouris | 'Source file contains hashmap not data', '--source-is-hashmap'), |
643 | edc1182f | Stavros Sachtouris | ) |
644 | edc1182f | Stavros Sachtouris | |
645 | edc1182f | Stavros Sachtouris | def _sharing(self): |
646 | edc1182f | Stavros Sachtouris | sharing = dict()
|
647 | edc1182f | Stavros Sachtouris | readlist = self['uuid_for_read_permission'] |
648 | edc1182f | Stavros Sachtouris | if readlist:
|
649 | edc1182f | Stavros Sachtouris | sharing['read'] = self['uuid_for_read_permission'] |
650 | edc1182f | Stavros Sachtouris | writelist = self['uuid_for_write_permission'] |
651 | edc1182f | Stavros Sachtouris | if writelist:
|
652 | edc1182f | Stavros Sachtouris | sharing['write'] = self['uuid_for_write_permission'] |
653 | edc1182f | Stavros Sachtouris | return sharing or None |
654 | edc1182f | Stavros Sachtouris | |
655 | edc1182f | Stavros Sachtouris | def _check_container_limit(self, path): |
656 | edc1182f | Stavros Sachtouris | cl_dict = self.client.get_container_limit()
|
657 | edc1182f | Stavros Sachtouris | container_limit = int(cl_dict['x-container-policy-quota']) |
658 | edc1182f | Stavros Sachtouris | r = self.client.container_get()
|
659 | edc1182f | Stavros Sachtouris | used_bytes = sum(int(o['bytes']) for o in r.json) |
660 | edc1182f | Stavros Sachtouris | path_size = get_path_size(path) |
661 | edc1182f | Stavros Sachtouris | if container_limit and path_size > (container_limit - used_bytes): |
662 | edc1182f | Stavros Sachtouris | raise CLIError(
|
663 | edc1182f | Stavros Sachtouris | 'Container %s (limit(%s) - used(%s)) < (size(%s) of %s)' % (
|
664 | edc1182f | Stavros Sachtouris | self.client.container,
|
665 | edc1182f | Stavros Sachtouris | format_size(container_limit), |
666 | edc1182f | Stavros Sachtouris | format_size(used_bytes), |
667 | edc1182f | Stavros Sachtouris | format_size(path_size), |
668 | edc1182f | Stavros Sachtouris | path), |
669 | edc1182f | Stavros Sachtouris | details=[ |
670 | edc1182f | Stavros Sachtouris | 'Check accound limit: /file quota',
|
671 | edc1182f | Stavros Sachtouris | 'Check container limit:',
|
672 | edc1182f | Stavros Sachtouris | '\t/file containerlimit get %s' % self.client.container, |
673 | edc1182f | Stavros Sachtouris | 'Increase container limit:',
|
674 | edc1182f | Stavros Sachtouris | '\t/file containerlimit set <new limit> %s' % (
|
675 | edc1182f | Stavros Sachtouris | self.client.container)])
|
676 | edc1182f | Stavros Sachtouris | |
677 | edc1182f | Stavros Sachtouris | def _src_dst(self, local_path, remote_path, objlist=None): |
678 | edc1182f | Stavros Sachtouris | lpath = path.abspath(local_path) |
679 | edc1182f | Stavros Sachtouris | short_path = path.basename(path.abspath(local_path)) |
680 | edc1182f | Stavros Sachtouris | rpath = remote_path or short_path
|
681 | edc1182f | Stavros Sachtouris | if path.isdir(lpath):
|
682 | edc1182f | Stavros Sachtouris | if not self['recursive']: |
683 | edc1182f | Stavros Sachtouris | raise CLIError('%s is a directory' % lpath, details=[ |
684 | edc1182f | Stavros Sachtouris | 'Use %s to upload directories & contents' % '/'.join( |
685 | edc1182f | Stavros Sachtouris | self.arguments['recursive'].parsed_name)]) |
686 | edc1182f | Stavros Sachtouris | robj = self.client.container_get(path=rpath)
|
687 | edc1182f | Stavros Sachtouris | if not self['overwrite']: |
688 | edc1182f | Stavros Sachtouris | if robj.json:
|
689 | edc1182f | Stavros Sachtouris | raise CLIError(
|
690 | edc1182f | Stavros Sachtouris | 'Objects/files prefixed as %s already exist' % rpath,
|
691 | edc1182f | Stavros Sachtouris | details=['Existing objects:'] + ['\t%s:\t%s' % ( |
692 | edc1182f | Stavros Sachtouris | o['name'],
|
693 | edc1182f | Stavros Sachtouris | o['content_type'][12:]) for o in robj.json] + [ |
694 | edc1182f | Stavros Sachtouris | 'Use -f to add, overwrite or resume'])
|
695 | edc1182f | Stavros Sachtouris | else:
|
696 | edc1182f | Stavros Sachtouris | try:
|
697 | edc1182f | Stavros Sachtouris | topobj = self.client.get_object_info(rpath)
|
698 | edc1182f | Stavros Sachtouris | if not self._is_dir(topobj): |
699 | edc1182f | Stavros Sachtouris | raise CLIError(
|
700 | edc1182f | Stavros Sachtouris | 'Object /%s/%s exists but not a directory' % (
|
701 | edc1182f | Stavros Sachtouris | self.container, rpath),
|
702 | edc1182f | Stavros Sachtouris | details=['Use -f to overwrite'])
|
703 | edc1182f | Stavros Sachtouris | except ClientError as ce: |
704 | edc1182f | Stavros Sachtouris | if ce.status not in (404, ): |
705 | edc1182f | Stavros Sachtouris | raise
|
706 | edc1182f | Stavros Sachtouris | self._check_container_limit(lpath)
|
707 | edc1182f | Stavros Sachtouris | prev = ''
|
708 | edc1182f | Stavros Sachtouris | for top, subdirs, files in walk(lpath): |
709 | edc1182f | Stavros Sachtouris | if top != prev:
|
710 | edc1182f | Stavros Sachtouris | prev = top |
711 | edc1182f | Stavros Sachtouris | try:
|
712 | edc1182f | Stavros Sachtouris | rel_path = rpath + top.split(lpath)[1]
|
713 | edc1182f | Stavros Sachtouris | except IndexError: |
714 | edc1182f | Stavros Sachtouris | rel_path = rpath |
715 | edc1182f | Stavros Sachtouris | self.error('mkdir %s:%s' % ( |
716 | edc1182f | Stavros Sachtouris | self.client.container, rel_path))
|
717 | edc1182f | Stavros Sachtouris | self.client.create_directory(rel_path)
|
718 | edc1182f | Stavros Sachtouris | for f in files: |
719 | edc1182f | Stavros Sachtouris | fpath = path.join(top, f) |
720 | edc1182f | Stavros Sachtouris | if path.isfile(fpath):
|
721 | edc1182f | Stavros Sachtouris | rel_path = rel_path.replace(path.sep, '/')
|
722 | edc1182f | Stavros Sachtouris | pathfix = f.replace(path.sep, '/')
|
723 | edc1182f | Stavros Sachtouris | yield open(fpath, 'rb'), '%s/%s' % (rel_path, pathfix) |
724 | edc1182f | Stavros Sachtouris | else:
|
725 | edc1182f | Stavros Sachtouris | self.error('%s is not a regular file' % fpath) |
726 | edc1182f | Stavros Sachtouris | else:
|
727 | edc1182f | Stavros Sachtouris | if not path.isfile(lpath): |
728 | edc1182f | Stavros Sachtouris | raise CLIError(('%s is not a regular file' % lpath) if ( |
729 | edc1182f | Stavros Sachtouris | path.exists(lpath)) else '%s does not exist' % lpath) |
730 | edc1182f | Stavros Sachtouris | try:
|
731 | edc1182f | Stavros Sachtouris | robj = self.client.get_object_info(rpath)
|
732 | edc1182f | Stavros Sachtouris | if remote_path and self._is_dir(robj): |
733 | edc1182f | Stavros Sachtouris | rpath += '/%s' % (short_path.replace(path.sep, '/')) |
734 | edc1182f | Stavros Sachtouris | self.client.get_object_info(rpath)
|
735 | edc1182f | Stavros Sachtouris | if not self['overwrite']: |
736 | edc1182f | Stavros Sachtouris | raise CLIError(
|
737 | edc1182f | Stavros Sachtouris | 'Object /%s/%s already exists' % (
|
738 | edc1182f | Stavros Sachtouris | self.container, rpath),
|
739 | edc1182f | Stavros Sachtouris | details=['use -f to overwrite / resume'])
|
740 | edc1182f | Stavros Sachtouris | except ClientError as ce: |
741 | edc1182f | Stavros Sachtouris | if ce.status not in (404, ): |
742 | edc1182f | Stavros Sachtouris | raise
|
743 | edc1182f | Stavros Sachtouris | self._check_container_limit(lpath)
|
744 | edc1182f | Stavros Sachtouris | yield open(lpath, 'rb'), rpath |
745 | edc1182f | Stavros Sachtouris | |
746 | edc1182f | Stavros Sachtouris | def _run(self, local_path, remote_path): |
747 | edc1182f | Stavros Sachtouris | if self['max_threads'] > 0: |
748 | edc1182f | Stavros Sachtouris | self.client.MAX_THREADS = int(self['max_threads']) |
749 | edc1182f | Stavros Sachtouris | params = dict(
|
750 | edc1182f | Stavros Sachtouris | content_encoding=self['content_encoding'], |
751 | edc1182f | Stavros Sachtouris | content_type=self['content_type'], |
752 | edc1182f | Stavros Sachtouris | content_disposition=self['content_disposition'], |
753 | edc1182f | Stavros Sachtouris | sharing=self._sharing(),
|
754 | edc1182f | Stavros Sachtouris | public=self['public']) |
755 | edc1182f | Stavros Sachtouris | uploaded, container_info_cache = list, dict() |
756 | edc1182f | Stavros Sachtouris | rpref = 'pithos://%s' if self['account'] else '' |
757 | edc1182f | Stavros Sachtouris | for f, rpath in self._src_dst(local_path, remote_path): |
758 | edc1182f | Stavros Sachtouris | self.error('%s --> %s/%s/%s' % ( |
759 | edc1182f | Stavros Sachtouris | f.name, rpref, self.client.container, rpath))
|
760 | edc1182f | Stavros Sachtouris | if not (self['content_type'] and self['content_encoding']): |
761 | edc1182f | Stavros Sachtouris | ctype, cenc = guess_mime_type(f.name) |
762 | edc1182f | Stavros Sachtouris | params['content_type'] = self['content_type'] or ctype |
763 | edc1182f | Stavros Sachtouris | params['content_encoding'] = self['content_encoding'] or cenc |
764 | edc1182f | Stavros Sachtouris | if self['unchunked']: |
765 | edc1182f | Stavros Sachtouris | r = self.client.upload_object_unchunked(
|
766 | edc1182f | Stavros Sachtouris | rpath, f, |
767 | edc1182f | Stavros Sachtouris | etag=self['md5_checksum'], withHashFile=self['use_hashes'], |
768 | edc1182f | Stavros Sachtouris | **params) |
769 | edc1182f | Stavros Sachtouris | if self['with_output'] or self['json_output']: |
770 | edc1182f | Stavros Sachtouris | r['name'] = '/%s/%s' % (self.client.container, rpath) |
771 | edc1182f | Stavros Sachtouris | uploaded.append(r) |
772 | edc1182f | Stavros Sachtouris | else:
|
773 | edc1182f | Stavros Sachtouris | try:
|
774 | edc1182f | Stavros Sachtouris | (progress_bar, upload_cb) = self._safe_progress_bar(
|
775 | edc1182f | Stavros Sachtouris | 'Uploading %s' % f.name.split(path.sep)[-1]) |
776 | edc1182f | Stavros Sachtouris | if progress_bar:
|
777 | edc1182f | Stavros Sachtouris | hash_bar = progress_bar.clone() |
778 | edc1182f | Stavros Sachtouris | hash_cb = hash_bar.get_generator( |
779 | edc1182f | Stavros Sachtouris | 'Calculating block hashes')
|
780 | edc1182f | Stavros Sachtouris | else:
|
781 | edc1182f | Stavros Sachtouris | hash_cb = None
|
782 | edc1182f | Stavros Sachtouris | r = self.client.upload_object(
|
783 | edc1182f | Stavros Sachtouris | rpath, f, |
784 | edc1182f | Stavros Sachtouris | hash_cb=hash_cb, |
785 | edc1182f | Stavros Sachtouris | upload_cb=upload_cb, |
786 | edc1182f | Stavros Sachtouris | container_info_cache=container_info_cache, |
787 | edc1182f | Stavros Sachtouris | **params) |
788 | edc1182f | Stavros Sachtouris | if self['with_output'] or self['json_output']: |
789 | edc1182f | Stavros Sachtouris | r['name'] = '/%s/%s' % (self.client.container, rpath) |
790 | edc1182f | Stavros Sachtouris | uploaded.append(r) |
791 | edc1182f | Stavros Sachtouris | except Exception: |
792 | edc1182f | Stavros Sachtouris | self._safe_progress_bar_finish(progress_bar)
|
793 | edc1182f | Stavros Sachtouris | raise
|
794 | edc1182f | Stavros Sachtouris | finally:
|
795 | edc1182f | Stavros Sachtouris | self._safe_progress_bar_finish(progress_bar)
|
796 | edc1182f | Stavros Sachtouris | self._optional_output(uploaded)
|
797 | edc1182f | Stavros Sachtouris | self.error('Upload completed') |
798 | edc1182f | Stavros Sachtouris | |
799 | edc1182f | Stavros Sachtouris | def main(self, local_path, remote_path_or_url): |
800 | edc1182f | Stavros Sachtouris | super(self.__class__, self)._run(remote_path_or_url) |
801 | edc1182f | Stavros Sachtouris | remote_path = self.path or path.basename(path.abspath(local_path)) |
802 | edc1182f | Stavros Sachtouris | self._run(local_path=local_path, remote_path=remote_path)
|
803 | edc1182f | Stavros Sachtouris | |
804 | edc1182f | Stavros Sachtouris | |
805 | edc1182f | Stavros Sachtouris | class RangeArgument(ValueArgument): |
806 | edc1182f | Stavros Sachtouris | """
|
807 | edc1182f | Stavros Sachtouris | :value type: string of the form <start>-<end> where <start> and <end> are
|
808 | edc1182f | Stavros Sachtouris | integers
|
809 | edc1182f | Stavros Sachtouris | :value returns: the input string, after type checking <start> and <end>
|
810 | edc1182f | Stavros Sachtouris | """
|
811 | edc1182f | Stavros Sachtouris | |
812 | edc1182f | Stavros Sachtouris | @property
|
813 | edc1182f | Stavros Sachtouris | def value(self): |
814 | edc1182f | Stavros Sachtouris | return getattr(self, '_value', self.default) |
815 | edc1182f | Stavros Sachtouris | |
816 | edc1182f | Stavros Sachtouris | @value.setter
|
817 | edc1182f | Stavros Sachtouris | def value(self, newvalues): |
818 | edc1182f | Stavros Sachtouris | if newvalues:
|
819 | edc1182f | Stavros Sachtouris | self._value = getattr(self, '_value', self.default) |
820 | edc1182f | Stavros Sachtouris | for newvalue in newvalues.split(','): |
821 | edc1182f | Stavros Sachtouris | self._value = ('%s,' % self._value) if self._value else '' |
822 | edc1182f | Stavros Sachtouris | start, sep, end = newvalue.partition('-')
|
823 | edc1182f | Stavros Sachtouris | if sep:
|
824 | edc1182f | Stavros Sachtouris | if start:
|
825 | edc1182f | Stavros Sachtouris | start, end = (int(start), int(end)) |
826 | edc1182f | Stavros Sachtouris | if start > end:
|
827 | edc1182f | Stavros Sachtouris | raise CLIInvalidArgument(
|
828 | edc1182f | Stavros Sachtouris | 'Invalid range %s' % newvalue, details=[
|
829 | edc1182f | Stavros Sachtouris | 'Valid range formats',
|
830 | edc1182f | Stavros Sachtouris | ' START-END', ' UP_TO', ' -FROM', |
831 | edc1182f | Stavros Sachtouris | 'where all values are integers'])
|
832 | edc1182f | Stavros Sachtouris | self._value += '%s-%s' % (start, end) |
833 | edc1182f | Stavros Sachtouris | else:
|
834 | edc1182f | Stavros Sachtouris | self._value += '-%s' % int(end) |
835 | edc1182f | Stavros Sachtouris | else:
|
836 | edc1182f | Stavros Sachtouris | self._value += '%s' % int(start) |
837 | edc1182f | Stavros Sachtouris | |
838 | edc1182f | Stavros Sachtouris | |
839 | edc1182f | Stavros Sachtouris | @command(file_cmds)
|
840 | edc1182f | Stavros Sachtouris | class file_cat(_pithos_container): |
841 | edc1182f | Stavros Sachtouris | """Fetch remote file contents"""
|
842 | edc1182f | Stavros Sachtouris | |
843 | edc1182f | Stavros Sachtouris | arguments = dict(
|
844 | edc1182f | Stavros Sachtouris | range=RangeArgument('show range of data', '--range'), |
845 | edc1182f | Stavros Sachtouris | if_match=ValueArgument('show output if ETags match', '--if-match'), |
846 | edc1182f | Stavros Sachtouris | if_none_match=ValueArgument( |
847 | edc1182f | Stavros Sachtouris | 'show output if ETags match', '--if-none-match'), |
848 | edc1182f | Stavros Sachtouris | if_modified_since=DateArgument( |
849 | edc1182f | Stavros Sachtouris | 'show output modified since then', '--if-modified-since'), |
850 | edc1182f | Stavros Sachtouris | if_unmodified_since=DateArgument( |
851 | edc1182f | Stavros Sachtouris | 'show output unmodified since then', '--if-unmodified-since'), |
852 | edc1182f | Stavros Sachtouris | object_version=ValueArgument( |
853 | edc1182f | Stavros Sachtouris | 'Get contents of the chosen version', '--object-version') |
854 | edc1182f | Stavros Sachtouris | ) |
855 | edc1182f | Stavros Sachtouris | |
856 | edc1182f | Stavros Sachtouris | @errors.generic.all
|
857 | edc1182f | Stavros Sachtouris | @errors.pithos.connection
|
858 | edc1182f | Stavros Sachtouris | @errors.pithos.container
|
859 | edc1182f | Stavros Sachtouris | @errors.pithos.object_path
|
860 | edc1182f | Stavros Sachtouris | def _run(self): |
861 | edc1182f | Stavros Sachtouris | self.client.download_object(
|
862 | edc1182f | Stavros Sachtouris | self.path, self._out, |
863 | edc1182f | Stavros Sachtouris | range_str=self['range'], |
864 | edc1182f | Stavros Sachtouris | version=self['object_version'], |
865 | edc1182f | Stavros Sachtouris | if_match=self['if_match'], |
866 | edc1182f | Stavros Sachtouris | if_none_match=self['if_none_match'], |
867 | edc1182f | Stavros Sachtouris | if_modified_since=self['if_modified_since'], |
868 | edc1182f | Stavros Sachtouris | if_unmodified_since=self['if_unmodified_since']) |
869 | edc1182f | Stavros Sachtouris | |
870 | edc1182f | Stavros Sachtouris | def main(self, path_or_url): |
871 | edc1182f | Stavros Sachtouris | super(self.__class__, self)._run(path_or_url) |
872 | edc1182f | Stavros Sachtouris | self._run()
|
873 | 74b7c6dc | Stavros Sachtouris | |
874 | 74b7c6dc | Stavros Sachtouris | |
875 | 74b7c6dc | Stavros Sachtouris | @command(file_cmds)
|
876 | 74b7c6dc | Stavros Sachtouris | class file_download(_pithos_container): |
877 | 74b7c6dc | Stavros Sachtouris | """Download a remove file or directory object to local file system"""
|
878 | 74b7c6dc | Stavros Sachtouris | |
879 | 74b7c6dc | Stavros Sachtouris | arguments = dict(
|
880 | 74b7c6dc | Stavros Sachtouris | resume=FlagArgument( |
881 | 74b7c6dc | Stavros Sachtouris | 'Resume/Overwrite (attempt resume, else overwrite)',
|
882 | 74b7c6dc | Stavros Sachtouris | ('-f', '--resume')), |
883 | 74b7c6dc | Stavros Sachtouris | range=RangeArgument('Download only that range of data', '--range'), |
884 | 74b7c6dc | Stavros Sachtouris | matching_etag=ValueArgument('download iff ETag match', '--if-match'), |
885 | 74b7c6dc | Stavros Sachtouris | non_matching_etag=ValueArgument( |
886 | 74b7c6dc | Stavros Sachtouris | 'download iff ETags DO NOT match', '--if-none-match'), |
887 | 74b7c6dc | Stavros Sachtouris | modified_since_date=DateArgument( |
888 | 74b7c6dc | Stavros Sachtouris | 'download iff remote file is modified since then',
|
889 | 74b7c6dc | Stavros Sachtouris | '--if-modified-since'),
|
890 | 74b7c6dc | Stavros Sachtouris | unmodified_since_date=DateArgument( |
891 | 74b7c6dc | Stavros Sachtouris | 'show output iff remote file is unmodified since then',
|
892 | 74b7c6dc | Stavros Sachtouris | '--if-unmodified-since'),
|
893 | 74b7c6dc | Stavros Sachtouris | object_version=ValueArgument( |
894 | 74b7c6dc | Stavros Sachtouris | 'download a file of a specific version',
|
895 | 74b7c6dc | Stavros Sachtouris | ('-O', '--object-version')), |
896 | 74b7c6dc | Stavros Sachtouris | max_threads=IntArgument('default: 5', '--threads'), |
897 | 74b7c6dc | Stavros Sachtouris | progress_bar=ProgressBarArgument( |
898 | 74b7c6dc | Stavros Sachtouris | 'do not show progress bar', ('-N', '--no-progress-bar'), |
899 | 74b7c6dc | Stavros Sachtouris | default=False),
|
900 | 74b7c6dc | Stavros Sachtouris | recursive=FlagArgument( |
901 | 74b7c6dc | Stavros Sachtouris | 'Download a remote directory object and its contents',
|
902 | 74b7c6dc | Stavros Sachtouris | ('-r', '--recursive')) |
903 | 74b7c6dc | Stavros Sachtouris | ) |
904 | 74b7c6dc | Stavros Sachtouris | |
905 | 74b7c6dc | Stavros Sachtouris | def _src_dst(self, local_path): |
906 | 74b7c6dc | Stavros Sachtouris | """Create a list of (src, dst) where src is a remote location and dst
|
907 | 74b7c6dc | Stavros Sachtouris | is an open file descriptor. Directories are denoted as (None, dirpath)
|
908 | 74b7c6dc | Stavros Sachtouris | and they are pretended to other objects in a very strict order (shorter
|
909 | 74b7c6dc | Stavros Sachtouris | to longer path)."""
|
910 | 74b7c6dc | Stavros Sachtouris | ret = [] |
911 | 74b7c6dc | Stavros Sachtouris | try:
|
912 | 74b7c6dc | Stavros Sachtouris | obj = self.client.get_object_info(
|
913 | 74b7c6dc | Stavros Sachtouris | self.path, version=self['object_version']) |
914 | 74b7c6dc | Stavros Sachtouris | obj.setdefault('name', self.path.strip('/')) |
915 | 74b7c6dc | Stavros Sachtouris | except ClientError as ce: |
916 | 74b7c6dc | Stavros Sachtouris | if ce.status in (404, ): |
917 | 74b7c6dc | Stavros Sachtouris | raiseCLIError(ce, details=[ |
918 | 74b7c6dc | Stavros Sachtouris | 'To download an object, the object must exist either as a'
|
919 | 74b7c6dc | Stavros Sachtouris | ' file or as a directory.',
|
920 | 74b7c6dc | Stavros Sachtouris | 'For example, to download everything under prefix/ the '
|
921 | 74b7c6dc | Stavros Sachtouris | 'directory "prefix" must exist.',
|
922 | 74b7c6dc | Stavros Sachtouris | 'To see if an remote object is actually there:',
|
923 | 74b7c6dc | Stavros Sachtouris | ' /file info [/CONTAINER/]OBJECT',
|
924 | 74b7c6dc | Stavros Sachtouris | 'To create a directory object:',
|
925 | 74b7c6dc | Stavros Sachtouris | ' /file mkdir [/CONTAINER/]OBJECT'])
|
926 | 74b7c6dc | Stavros Sachtouris | if ce.status in (204, ): |
927 | 74b7c6dc | Stavros Sachtouris | raise CLIError(
|
928 | 74b7c6dc | Stavros Sachtouris | 'No file or directory objects to download',
|
929 | 74b7c6dc | Stavros Sachtouris | details=[ |
930 | 74b7c6dc | Stavros Sachtouris | 'To download a container (e.g., %s):' % self.container, |
931 | 74b7c6dc | Stavros Sachtouris | ' [kamaki] container download %s [LOCAL_PATH]' % (
|
932 | 74b7c6dc | Stavros Sachtouris | self.container)])
|
933 | 74b7c6dc | Stavros Sachtouris | raise
|
934 | 74b7c6dc | Stavros Sachtouris | rpath = self.path.strip('/') |
935 | 74b7c6dc | Stavros Sachtouris | local_path = local_path[-1:] if ( |
936 | 74b7c6dc | Stavros Sachtouris | local_path.endswith('/')) else local_path |
937 | 74b7c6dc | Stavros Sachtouris | |
938 | 74b7c6dc | Stavros Sachtouris | if self._is_dir(obj): |
939 | 74b7c6dc | Stavros Sachtouris | if self['recursive']: |
940 | 74b7c6dc | Stavros Sachtouris | dirs, files = [obj, ], [] |
941 | 74b7c6dc | Stavros Sachtouris | objects = self.client.container_get(
|
942 | 74b7c6dc | Stavros Sachtouris | path=self.path or '/', |
943 | 74b7c6dc | Stavros Sachtouris | if_modified_since=self['modified_since_date'], |
944 | 74b7c6dc | Stavros Sachtouris | if_unmodified_since=self['unmodified_since_date']) |
945 | 74b7c6dc | Stavros Sachtouris | for obj in objects.json: |
946 | 74b7c6dc | Stavros Sachtouris | (dirs if self._is_dir(obj) else files).append(obj) |
947 | 74b7c6dc | Stavros Sachtouris | |
948 | 74b7c6dc | Stavros Sachtouris | # Put the directories on top of the list
|
949 | 74b7c6dc | Stavros Sachtouris | for dpath in sorted(['%s%s' % ( |
950 | 74b7c6dc | Stavros Sachtouris | local_path, d['name'][len(rpath):]) for d in dirs]): |
951 | 74b7c6dc | Stavros Sachtouris | if path.exists(dpath):
|
952 | 74b7c6dc | Stavros Sachtouris | if path.isdir(dpath):
|
953 | 74b7c6dc | Stavros Sachtouris | continue
|
954 | 74b7c6dc | Stavros Sachtouris | raise CLIError(
|
955 | 74b7c6dc | Stavros Sachtouris | 'Cannot replace local file %s with a directory '
|
956 | 74b7c6dc | Stavros Sachtouris | 'of the same name' % dpath,
|
957 | 74b7c6dc | Stavros Sachtouris | details=[ |
958 | 74b7c6dc | Stavros Sachtouris | 'Either remove the file or specify a'
|
959 | 74b7c6dc | Stavros Sachtouris | 'different target location'])
|
960 | 74b7c6dc | Stavros Sachtouris | ret.append((None, dpath, None)) |
961 | 74b7c6dc | Stavros Sachtouris | |
962 | 74b7c6dc | Stavros Sachtouris | # Append the file objects
|
963 | 74b7c6dc | Stavros Sachtouris | for opath in [o['name'] for o in files]: |
964 | 74b7c6dc | Stavros Sachtouris | lpath = '%s%s' % (local_path, opath[len(rpath):]) |
965 | 74b7c6dc | Stavros Sachtouris | if self['resume']: |
966 | 74b7c6dc | Stavros Sachtouris | fxists = path.exists(lpath) |
967 | 74b7c6dc | Stavros Sachtouris | if fxists and path.isdir(lpath): |
968 | 74b7c6dc | Stavros Sachtouris | raise CLIError(
|
969 | 74b7c6dc | Stavros Sachtouris | 'Cannot change local dir %s info file' % (
|
970 | 74b7c6dc | Stavros Sachtouris | lpath), |
971 | 74b7c6dc | Stavros Sachtouris | details=[ |
972 | 74b7c6dc | Stavros Sachtouris | 'Either remove the file or specify a'
|
973 | 74b7c6dc | Stavros Sachtouris | 'different target location'])
|
974 | 74b7c6dc | Stavros Sachtouris | ret.append((opath, lpath, fxists)) |
975 | 74b7c6dc | Stavros Sachtouris | elif path.exists(lpath):
|
976 | 74b7c6dc | Stavros Sachtouris | raise CLIError(
|
977 | 74b7c6dc | Stavros Sachtouris | 'Cannot overwrite %s' % lpath,
|
978 | 74b7c6dc | Stavros Sachtouris | details=['To overwrite/resume, use %s' % '/'.join( |
979 | 74b7c6dc | Stavros Sachtouris | self.arguments['resume'].parsed_name)]) |
980 | 74b7c6dc | Stavros Sachtouris | else:
|
981 | 74b7c6dc | Stavros Sachtouris | ret.append((opath, lpath, None))
|
982 | 74b7c6dc | Stavros Sachtouris | else:
|
983 | 74b7c6dc | Stavros Sachtouris | raise CLIError(
|
984 | 74b7c6dc | Stavros Sachtouris | 'Remote object /%s/%s is a directory' % (
|
985 | 74b7c6dc | Stavros Sachtouris | self.container, local_path),
|
986 | 74b7c6dc | Stavros Sachtouris | details=['Use %s to download directories' % '/'.join( |
987 | 74b7c6dc | Stavros Sachtouris | self.arguments['recursive'].parsed_name)]) |
988 | 74b7c6dc | Stavros Sachtouris | else:
|
989 | 74b7c6dc | Stavros Sachtouris | # Remote object is just a file
|
990 | 74b7c6dc | Stavros Sachtouris | if path.exists(local_path) and not self['resume']: |
991 | 74b7c6dc | Stavros Sachtouris | raise CLIError(
|
992 | 74b7c6dc | Stavros Sachtouris | 'Cannot overwrite local file %s' % (lpath),
|
993 | 74b7c6dc | Stavros Sachtouris | details=['To overwrite/resume, use %s' % '/'.join( |
994 | 74b7c6dc | Stavros Sachtouris | self.arguments['resume'].parsed_name)]) |
995 | 74b7c6dc | Stavros Sachtouris | ret.append((rpath, local_path, self['resume'])) |
996 | 74b7c6dc | Stavros Sachtouris | for r, l, resume in ret: |
997 | 74b7c6dc | Stavros Sachtouris | if r:
|
998 | 74b7c6dc | Stavros Sachtouris | with open(l, 'rwb+' if resume else 'wb+') as f: |
999 | 74b7c6dc | Stavros Sachtouris | yield (r, f)
|
1000 | 74b7c6dc | Stavros Sachtouris | else:
|
1001 | 74b7c6dc | Stavros Sachtouris | yield (r, l)
|
1002 | 74b7c6dc | Stavros Sachtouris | |
1003 | 74b7c6dc | Stavros Sachtouris | @errors.generic.all
|
1004 | 74b7c6dc | Stavros Sachtouris | @errors.pithos.connection
|
1005 | 74b7c6dc | Stavros Sachtouris | @errors.pithos.container
|
1006 | 74b7c6dc | Stavros Sachtouris | @errors.pithos.object_path
|
1007 | 74b7c6dc | Stavros Sachtouris | @errors.pithos.local_path
|
1008 | 74b7c6dc | Stavros Sachtouris | def _run(self, local_path): |
1009 | 74b7c6dc | Stavros Sachtouris | self.client.MAX_THREADS = self['max_threads'] or 5 |
1010 | 74b7c6dc | Stavros Sachtouris | progress_bar = None
|
1011 | 74b7c6dc | Stavros Sachtouris | try:
|
1012 | 74b7c6dc | Stavros Sachtouris | for rpath, output_file in self._src_dst(local_path): |
1013 | 74b7c6dc | Stavros Sachtouris | if not rpath: |
1014 | 74b7c6dc | Stavros Sachtouris | self.error('Create local directory %s' % output_file) |
1015 | 74b7c6dc | Stavros Sachtouris | makedirs(output_file) |
1016 | 74b7c6dc | Stavros Sachtouris | continue
|
1017 | 74b7c6dc | Stavros Sachtouris | self.error('/%s/%s --> %s' % ( |
1018 | 74b7c6dc | Stavros Sachtouris | self.container, rpath, output_file.name))
|
1019 | 74b7c6dc | Stavros Sachtouris | progress_bar, download_cb = self._safe_progress_bar(
|
1020 | 74b7c6dc | Stavros Sachtouris | ' download')
|
1021 | 74b7c6dc | Stavros Sachtouris | self.client.download_object(
|
1022 | 74b7c6dc | Stavros Sachtouris | rpath, output_file, |
1023 | 74b7c6dc | Stavros Sachtouris | download_cb=download_cb, |
1024 | 74b7c6dc | Stavros Sachtouris | range_str=self['range'], |
1025 | 74b7c6dc | Stavros Sachtouris | version=self['object_version'], |
1026 | 74b7c6dc | Stavros Sachtouris | if_match=self['matching_etag'], |
1027 | 74b7c6dc | Stavros Sachtouris | resume=self['resume'], |
1028 | 74b7c6dc | Stavros Sachtouris | if_none_match=self['non_matching_etag'], |
1029 | 74b7c6dc | Stavros Sachtouris | if_modified_since=self['modified_since_date'], |
1030 | 74b7c6dc | Stavros Sachtouris | if_unmodified_since=self['unmodified_since_date']) |
1031 | 74b7c6dc | Stavros Sachtouris | except KeyboardInterrupt: |
1032 | 74b7c6dc | Stavros Sachtouris | from threading import activeCount, enumerate as activethreads |
1033 | 74b7c6dc | Stavros Sachtouris | timeout = 0.5
|
1034 | 74b7c6dc | Stavros Sachtouris | while activeCount() > 1: |
1035 | 74b7c6dc | Stavros Sachtouris | self._out.write('\nCancel %s threads: ' % (activeCount() - 1)) |
1036 | 74b7c6dc | Stavros Sachtouris | self._out.flush()
|
1037 | 74b7c6dc | Stavros Sachtouris | for thread in activethreads(): |
1038 | 74b7c6dc | Stavros Sachtouris | try:
|
1039 | 74b7c6dc | Stavros Sachtouris | thread.join(timeout) |
1040 | 74b7c6dc | Stavros Sachtouris | self._out.write('.' if thread.isAlive() else '*') |
1041 | 74b7c6dc | Stavros Sachtouris | except RuntimeError: |
1042 | 74b7c6dc | Stavros Sachtouris | continue
|
1043 | 74b7c6dc | Stavros Sachtouris | finally:
|
1044 | 74b7c6dc | Stavros Sachtouris | self._out.flush()
|
1045 | 74b7c6dc | Stavros Sachtouris | timeout += 0.1
|
1046 | 74b7c6dc | Stavros Sachtouris | self.error('\nDownload canceled by user') |
1047 | 74b7c6dc | Stavros Sachtouris | if local_path is not None: |
1048 | 74b7c6dc | Stavros Sachtouris | self.error('to resume, re-run with --resume') |
1049 | 74b7c6dc | Stavros Sachtouris | except Exception: |
1050 | 74b7c6dc | Stavros Sachtouris | self._safe_progress_bar_finish(progress_bar)
|
1051 | 74b7c6dc | Stavros Sachtouris | raise
|
1052 | 74b7c6dc | Stavros Sachtouris | finally:
|
1053 | 74b7c6dc | Stavros Sachtouris | self._safe_progress_bar_finish(progress_bar)
|
1054 | 74b7c6dc | Stavros Sachtouris | |
1055 | 74b7c6dc | Stavros Sachtouris | def main(self, remote_path_or_url, local_path=None): |
1056 | 74b7c6dc | Stavros Sachtouris | super(self.__class__, self)._run(remote_path_or_url) |
1057 | 74b7c6dc | Stavros Sachtouris | local_path = local_path or self.path or '.' |
1058 | 74b7c6dc | Stavros Sachtouris | self._run(local_path=local_path) |