58 |
58 |
|
59 |
59 |
kloger = getLogger('kamaki')
|
60 |
60 |
|
61 |
|
pithos_cmds = CommandTree('store', 'Pithos+ storage commands')
|
|
61 |
pithos_cmds = CommandTree('file', 'Pithos+ storage commands')
|
62 |
62 |
_commands = [pithos_cmds]
|
63 |
63 |
|
64 |
64 |
|
... | ... | |
161 |
161 |
|
162 |
162 |
@errors.generic.all
|
163 |
163 |
def _run(self):
|
164 |
|
self.token = self.config.get('store', 'token')\
|
|
164 |
self.token = self.config.get('file', 'token')\
|
165 |
165 |
or self.config.get('global', 'token')
|
166 |
|
self.base_url = self.config.get('store', 'url')\
|
|
166 |
self.base_url = self.config.get('file', 'url')\
|
167 |
167 |
or self.config.get('global', 'url')
|
168 |
168 |
self._set_account()
|
169 |
|
self.container = self.config.get('store', 'container')\
|
|
169 |
self.container = self.config.get('file', 'container')\
|
170 |
170 |
or self.config.get('global', 'container')
|
171 |
171 |
self.client = PithosClient(
|
172 |
172 |
base_url=self.base_url,
|
... | ... | |
185 |
185 |
|
186 |
186 |
"""Backwards compatibility"""
|
187 |
187 |
self.account = self.account\
|
188 |
|
or self.config.get('store', 'account')\
|
|
188 |
or self.config.get('file', 'account')\
|
189 |
189 |
or self.config.get('global', 'account')
|
190 |
190 |
|
191 |
191 |
|
192 |
|
class _store_account_command(_pithos_init):
|
|
192 |
class _file_account_command(_pithos_init):
|
193 |
193 |
"""Base class for account level storage commands"""
|
194 |
194 |
|
195 |
195 |
def __init__(self, arguments={}):
|
196 |
|
super(_store_account_command, self).__init__(arguments)
|
|
196 |
super(_file_account_command, self).__init__(arguments)
|
197 |
197 |
self['account'] = ValueArgument(
|
198 |
198 |
'Set user account (not permanent)',
|
199 |
199 |
('-A', '--account'))
|
200 |
200 |
|
201 |
201 |
def _run(self):
|
202 |
|
super(_store_account_command, self)._run()
|
|
202 |
super(_file_account_command, self)._run()
|
203 |
203 |
if self['account']:
|
204 |
204 |
self.client.account = self['account']
|
205 |
205 |
|
... | ... | |
208 |
208 |
self._run()
|
209 |
209 |
|
210 |
210 |
|
211 |
|
class _store_container_command(_store_account_command):
|
|
211 |
class _file_container_command(_file_account_command):
|
212 |
212 |
"""Base class for container level storage commands"""
|
213 |
213 |
|
214 |
214 |
container = None
|
215 |
215 |
path = None
|
216 |
216 |
|
217 |
217 |
def __init__(self, arguments={}):
|
218 |
|
super(_store_container_command, self).__init__(arguments)
|
|
218 |
super(_file_container_command, self).__init__(arguments)
|
219 |
219 |
self['container'] = ValueArgument(
|
220 |
220 |
'Set container to work with (temporary)',
|
221 |
221 |
('-C', '--container'))
|
... | ... | |
277 |
277 |
|
278 |
278 |
@errors.generic.all
|
279 |
279 |
def _run(self, container_with_path=None, path_is_optional=True):
|
280 |
|
super(_store_container_command, self)._run()
|
|
280 |
super(_file_container_command, self)._run()
|
281 |
281 |
if self['container']:
|
282 |
282 |
self.client.container = self['container']
|
283 |
283 |
if container_with_path:
|
... | ... | |
298 |
298 |
|
299 |
299 |
|
300 |
300 |
@command(pithos_cmds)
|
301 |
|
class store_list(_store_container_command):
|
|
301 |
class file_list(_file_container_command):
|
302 |
302 |
"""List containers, object trees or objects in a directory
|
303 |
303 |
Use with:
|
304 |
304 |
1 no parameters : containers in current account
|
... | ... | |
427 |
427 |
|
428 |
428 |
|
429 |
429 |
@command(pithos_cmds)
|
430 |
|
class store_mkdir(_store_container_command):
|
|
430 |
class file_mkdir(_file_container_command):
|
431 |
431 |
"""Create a directory"""
|
432 |
432 |
|
433 |
433 |
__doc__ += '\n. '.join([
|
... | ... | |
451 |
451 |
|
452 |
452 |
|
453 |
453 |
@command(pithos_cmds)
|
454 |
|
class store_touch(_store_container_command):
|
|
454 |
class file_touch(_file_container_command):
|
455 |
455 |
"""Create an empty object (file)
|
456 |
456 |
If object exists, this command will reset it to 0 length
|
457 |
457 |
"""
|
... | ... | |
470 |
470 |
self.client.create_object(self.path, self['content_type'])
|
471 |
471 |
|
472 |
472 |
def main(self, container___path):
|
473 |
|
super(store_touch, self)._run(
|
|
473 |
super(file_touch, self)._run(
|
474 |
474 |
container___path,
|
475 |
475 |
path_is_optional=False)
|
476 |
476 |
self._run()
|
477 |
477 |
|
478 |
478 |
|
479 |
479 |
@command(pithos_cmds)
|
480 |
|
class store_create(_store_container_command):
|
|
480 |
class file_create(_file_container_command):
|
481 |
481 |
"""Create a container"""
|
482 |
482 |
|
483 |
483 |
arguments = dict(
|
... | ... | |
508 |
508 |
self._run()
|
509 |
509 |
|
510 |
510 |
|
511 |
|
class _source_destination_command(_store_container_command):
|
|
511 |
class _source_destination_command(_file_container_command):
|
512 |
512 |
|
513 |
513 |
arguments = dict(
|
514 |
514 |
destination_account=ValueArgument('', ('a', '--dst-account')),
|
... | ... | |
614 |
614 |
'Cannot merge multiple paths to path %s' % dst_path,
|
615 |
615 |
details=[
|
616 |
616 |
'Try to use / or a directory as destination',
|
617 |
|
'or create the destination dir (/store mkdir)',
|
|
617 |
'or create the destination dir (/file mkdir)',
|
618 |
618 |
'or use a single object as source'])
|
619 |
619 |
elif trgerr.status not in (204,):
|
620 |
620 |
raise
|
... | ... | |
626 |
626 |
'Cannot merge multiple paths to path' % dst_path,
|
627 |
627 |
details=[
|
628 |
628 |
'Try to use / or a directory as destination',
|
629 |
|
'or create the destination dir (/store mkdir)',
|
|
629 |
'or create the destination dir (/file mkdir)',
|
630 |
630 |
'or use a single object as source'])
|
631 |
631 |
|
632 |
632 |
if src_N:
|
... | ... | |
652 |
652 |
|
653 |
653 |
|
654 |
654 |
@command(pithos_cmds)
|
655 |
|
class store_copy(_source_destination_command):
|
|
655 |
class file_copy(_source_destination_command):
|
656 |
656 |
"""Copy objects from container to (another) container
|
657 |
657 |
Semantics:
|
658 |
658 |
copy cont:path dir
|
... | ... | |
733 |
733 |
self,
|
734 |
734 |
source_container___path,
|
735 |
735 |
destination_container___path=None):
|
736 |
|
super(store_copy, self)._run(
|
|
736 |
super(file_copy, self)._run(
|
737 |
737 |
source_container___path,
|
738 |
738 |
path_is_optional=False)
|
739 |
739 |
(dst_cont, dst_path) = self._dest_container_path(
|
... | ... | |
743 |
743 |
|
744 |
744 |
|
745 |
745 |
@command(pithos_cmds)
|
746 |
|
class store_move(_source_destination_command):
|
|
746 |
class file_move(_source_destination_command):
|
747 |
747 |
"""Move/rename objects from container to (another) container
|
748 |
748 |
Semantics:
|
749 |
749 |
move cont:path dir
|
... | ... | |
835 |
835 |
|
836 |
836 |
|
837 |
837 |
@command(pithos_cmds)
|
838 |
|
class store_append(_store_container_command):
|
|
838 |
class file_append(_file_container_command):
|
839 |
839 |
"""Append local file to (existing) remote object
|
840 |
840 |
The remote object should exist.
|
841 |
841 |
If the remote object is a directory, it is transformed into a file.
|
... | ... | |
872 |
872 |
|
873 |
873 |
|
874 |
874 |
@command(pithos_cmds)
|
875 |
|
class store_truncate(_store_container_command):
|
|
875 |
class file_truncate(_file_container_command):
|
876 |
876 |
"""Truncate remote file up to a size (default is 0)"""
|
877 |
877 |
|
878 |
878 |
@errors.generic.all
|
... | ... | |
889 |
889 |
|
890 |
890 |
|
891 |
891 |
@command(pithos_cmds)
|
892 |
|
class store_overwrite(_store_container_command):
|
|
892 |
class file_overwrite(_file_container_command):
|
893 |
893 |
"""Overwrite part (from start to end) of a remote file
|
894 |
894 |
overwrite local-path container 10 20
|
895 |
895 |
. will overwrite bytes from 10 to 20 of a remote file with the same name
|
... | ... | |
944 |
944 |
|
945 |
945 |
|
946 |
946 |
@command(pithos_cmds)
|
947 |
|
class store_manifest(_store_container_command):
|
|
947 |
class file_manifest(_file_container_command):
|
948 |
948 |
"""Create a remote file of uploaded parts by manifestation
|
949 |
949 |
Remains functional for compatibility with OOS Storage. Users are advised
|
950 |
950 |
to use the upload command instead.
|
... | ... | |
997 |
997 |
|
998 |
998 |
|
999 |
999 |
@command(pithos_cmds)
|
1000 |
|
class store_upload(_store_container_command):
|
|
1000 |
class file_upload(_file_container_command):
|
1001 |
1001 |
"""Upload a file"""
|
1002 |
1002 |
|
1003 |
1003 |
arguments = dict(
|
... | ... | |
1099 |
1099 |
|
1100 |
1100 |
|
1101 |
1101 |
@command(pithos_cmds)
|
1102 |
|
class store_cat(_store_container_command):
|
|
1102 |
class file_cat(_file_container_command):
|
1103 |
1103 |
"""Print remote file contents to console"""
|
1104 |
1104 |
|
1105 |
1105 |
arguments = dict(
|
... | ... | |
1142 |
1142 |
|
1143 |
1143 |
|
1144 |
1144 |
@command(pithos_cmds)
|
1145 |
|
class store_download(_store_container_command):
|
|
1145 |
class file_download(_file_container_command):
|
1146 |
1146 |
"""Download remote object as local file
|
1147 |
1147 |
If local destination is a directory:
|
1148 |
1148 |
* download <container>:<path> <local dir> -R
|
... | ... | |
1152 |
1152 |
will download only one file, exactly matching <path>
|
1153 |
1153 |
ATTENTION: to download cont:dir1/dir2/file there must exist objects
|
1154 |
1154 |
cont:dir1 and cont:dir1/dir2 of type application/directory
|
1155 |
|
To create directory objects, use /store mkdir
|
|
1155 |
To create directory objects, use /file mkdir
|
1156 |
1156 |
"""
|
1157 |
1157 |
|
1158 |
1158 |
arguments = dict(
|
... | ... | |
1196 |
1196 |
for newdir in rname.strip('/').split('/')[:-1]:
|
1197 |
1197 |
tmppath = '/'.join([tmppath, newdir])
|
1198 |
1198 |
dirlist.update({tmppath.strip('/'): True})
|
1199 |
|
remotes.append((rname, store_download._is_dir(remote)))
|
|
1199 |
remotes.append((rname, file_download._is_dir(remote)))
|
1200 |
1200 |
dir_remotes = [r[0] for r in remotes if r[1]]
|
1201 |
1201 |
if not set(dirlist).issubset(dir_remotes):
|
1202 |
1202 |
badguys = [bg.strip('/') for bg in set(
|
... | ... | |
1208 |
1208 |
r = self.client.get_object_info(
|
1209 |
1209 |
self.path,
|
1210 |
1210 |
version=self['object_version'])
|
1211 |
|
if store_download._is_dir(r):
|
|
1211 |
if file_download._is_dir(r):
|
1212 |
1212 |
raiseCLIError(
|
1213 |
1213 |
'Illegal download: Remote object %s is a directory' % (
|
1214 |
1214 |
self.path),
|
... | ... | |
1230 |
1230 |
self.container),
|
1231 |
1231 |
details=[
|
1232 |
1232 |
'To list the contents of %s, try:' % self.container,
|
1233 |
|
' /store list %s' % self.container])
|
|
1233 |
' /file list %s' % self.container])
|
1234 |
1234 |
raiseCLIError(
|
1235 |
1235 |
'Illegal download of container %s' % self.container,
|
1236 |
1236 |
details=[
|
1237 |
1237 |
'To download a whole container, try:',
|
1238 |
|
' /store download --recursive <container>'])
|
|
1238 |
' /file download --recursive <container>'])
|
1239 |
1239 |
|
1240 |
1240 |
lprefix = path.abspath(local_path or path.curdir)
|
1241 |
1241 |
if path.isdir(lprefix):
|
... | ... | |
1342 |
1342 |
|
1343 |
1343 |
|
1344 |
1344 |
@command(pithos_cmds)
|
1345 |
|
class store_hashmap(_store_container_command):
|
|
1345 |
class file_hashmap(_file_container_command):
|
1346 |
1346 |
"""Get the hash-map of an object"""
|
1347 |
1347 |
|
1348 |
1348 |
arguments = dict(
|
... | ... | |
1383 |
1383 |
|
1384 |
1384 |
|
1385 |
1385 |
@command(pithos_cmds)
|
1386 |
|
class store_delete(_store_container_command):
|
|
1386 |
class file_delete(_file_container_command):
|
1387 |
1387 |
"""Delete a container [or an object]
|
1388 |
1388 |
How to delete a non-empty container:
|
1389 |
|
- empty the container: /store delete -R <container>
|
1390 |
|
- delete it: /store delete <container>
|
|
1389 |
- empty the container: /file delete -R <container>
|
|
1390 |
- delete it: /file delete <container>
|
1391 |
1391 |
.
|
1392 |
1392 |
Semantics of directory deletion:
|
1393 |
|
.a preserve the contents: /store delete <container>:<directory>
|
|
1393 |
.a preserve the contents: /file delete <container>:<directory>
|
1394 |
1394 |
. objects of the form dir/filename can exist with a dir object
|
1395 |
|
.b delete contents: /store delete -R <container>:<directory>
|
|
1395 |
.b delete contents: /file delete -R <container>:<directory>
|
1396 |
1396 |
. all dir/* objects are affected, even if dir does not exist
|
1397 |
1397 |
.
|
1398 |
1398 |
To restore a deleted object OBJ in a container CONT:
|
1399 |
|
- get object versions: /store versions CONT:OBJ
|
|
1399 |
- get object versions: /file versions CONT:OBJ
|
1400 |
1400 |
. and choose the version to be restored
|
1401 |
|
- restore the object: /store copy --source-version=<version> CONT:OBJ OBJ
|
|
1401 |
- restore the object: /file copy --source-version=<version> CONT:OBJ OBJ
|
1402 |
1402 |
"""
|
1403 |
1403 |
|
1404 |
1404 |
arguments = dict(
|
... | ... | |
1448 |
1448 |
|
1449 |
1449 |
|
1450 |
1450 |
@command(pithos_cmds)
|
1451 |
|
class store_purge(_store_container_command):
|
|
1451 |
class file_purge(_file_container_command):
|
1452 |
1452 |
"""Delete a container and release related data blocks
|
1453 |
1453 |
Non-empty containers can not purged.
|
1454 |
1454 |
To purge a container with content:
|
1455 |
|
. /store delete -R <container>
|
|
1455 |
. /file delete -R <container>
|
1456 |
1456 |
. objects are deleted, but data blocks remain on server
|
1457 |
|
. /store purge <container>
|
|
1457 |
. /file purge <container>
|
1458 |
1458 |
. container and data blocks are released and deleted
|
1459 |
1459 |
"""
|
1460 |
1460 |
|
... | ... | |
1481 |
1481 |
|
1482 |
1482 |
|
1483 |
1483 |
@command(pithos_cmds)
|
1484 |
|
class store_publish(_store_container_command):
|
|
1484 |
class file_publish(_file_container_command):
|
1485 |
1485 |
"""Publish the object and print the public url"""
|
1486 |
1486 |
|
1487 |
1487 |
@errors.generic.all
|
... | ... | |
1500 |
1500 |
|
1501 |
1501 |
|
1502 |
1502 |
@command(pithos_cmds)
|
1503 |
|
class store_unpublish(_store_container_command):
|
|
1503 |
class file_unpublish(_file_container_command):
|
1504 |
1504 |
"""Unpublish an object"""
|
1505 |
1505 |
|
1506 |
1506 |
@errors.generic.all
|
... | ... | |
1518 |
1518 |
|
1519 |
1519 |
|
1520 |
1520 |
@command(pithos_cmds)
|
1521 |
|
class store_permissions(_store_container_command):
|
|
1521 |
class file_permissions(_file_container_command):
|
1522 |
1522 |
"""Get read and write permissions of an object
|
1523 |
1523 |
Permissions are lists of users and user groups. There is read and write
|
1524 |
1524 |
permissions. Users and groups with write permission have also read
|
... | ... | |
1541 |
1541 |
|
1542 |
1542 |
|
1543 |
1543 |
@command(pithos_cmds)
|
1544 |
|
class store_setpermissions(_store_container_command):
|
|
1544 |
class file_setpermissions(_file_container_command):
|
1545 |
1545 |
"""Set permissions for an object
|
1546 |
1546 |
New permissions overwrite existing permissions.
|
1547 |
1547 |
Permission format:
|
1548 |
1548 |
- read=<username>[,usergroup[,...]]
|
1549 |
1549 |
- write=<username>[,usegroup[,...]]
|
1550 |
1550 |
E.g. to give read permissions for file F to users A and B and write for C:
|
1551 |
|
. /store setpermissions F read=A,B write=C
|
|
1551 |
. /file setpermissions F read=A,B write=C
|
1552 |
1552 |
"""
|
1553 |
1553 |
|
1554 |
1554 |
@errors.generic.all
|
... | ... | |
1585 |
1585 |
|
1586 |
1586 |
|
1587 |
1587 |
@command(pithos_cmds)
|
1588 |
|
class store_delpermissions(_store_container_command):
|
|
1588 |
class file_delpermissions(_file_container_command):
|
1589 |
1589 |
"""Delete all permissions set on object
|
1590 |
|
To modify permissions, use /store setpermssions
|
|
1590 |
To modify permissions, use /file setpermssions
|
1591 |
1591 |
"""
|
1592 |
1592 |
|
1593 |
1593 |
@errors.generic.all
|
... | ... | |
1605 |
1605 |
|
1606 |
1606 |
|
1607 |
1607 |
@command(pithos_cmds)
|
1608 |
|
class store_info(_store_container_command):
|
|
1608 |
class file_info(_file_container_command):
|
1609 |
1609 |
"""Get detailed information for user account, containers or objects
|
1610 |
|
to get account info: /store info
|
1611 |
|
to get container info: /store info <container>
|
1612 |
|
to get object info: /store info <container>:<path>
|
|
1610 |
to get account info: /file info
|
|
1611 |
to get container info: /file info <container>
|
|
1612 |
to get object info: /file info <container>:<path>
|
1613 |
1613 |
"""
|
1614 |
1614 |
|
1615 |
1615 |
arguments = dict(
|
... | ... | |
1639 |
1639 |
|
1640 |
1640 |
|
1641 |
1641 |
@command(pithos_cmds)
|
1642 |
|
class store_meta(_store_container_command):
|
|
1642 |
class file_meta(_file_container_command):
|
1643 |
1643 |
"""Get metadata for account, containers or objects"""
|
1644 |
1644 |
|
1645 |
1645 |
arguments = dict(
|
... | ... | |
1695 |
1695 |
|
1696 |
1696 |
|
1697 |
1697 |
@command(pithos_cmds)
|
1698 |
|
class store_setmeta(_store_container_command):
|
|
1698 |
class file_setmeta(_file_container_command):
|
1699 |
1699 |
"""Set a piece of metadata for account, container or object
|
1700 |
1700 |
Metadata are formed as key:value pairs
|
1701 |
1701 |
"""
|
... | ... | |
1718 |
1718 |
|
1719 |
1719 |
|
1720 |
1720 |
@command(pithos_cmds)
|
1721 |
|
class store_delmeta(_store_container_command):
|
|
1721 |
class file_delmeta(_file_container_command):
|
1722 |
1722 |
"""Delete metadata with given key from account, container or object
|
1723 |
1723 |
Metadata are formed as key:value objects
|
1724 |
|
- to get metadata of current account: /store meta
|
1725 |
|
- to get metadata of a container: /store meta <container>
|
1726 |
|
- to get metadata of an object: /store meta <container>:<path>
|
|
1724 |
- to get metadata of current account: /file meta
|
|
1725 |
- to get metadata of a container: /file meta <container>
|
|
1726 |
- to get metadata of an object: /file meta <container>:<path>
|
1727 |
1727 |
"""
|
1728 |
1728 |
|
1729 |
1729 |
@errors.generic.all
|
... | ... | |
1744 |
1744 |
|
1745 |
1745 |
|
1746 |
1746 |
@command(pithos_cmds)
|
1747 |
|
class store_quota(_store_account_command):
|
|
1747 |
class file_quota(_file_account_command):
|
1748 |
1748 |
"""Get quota for account or container"""
|
1749 |
1749 |
|
1750 |
1750 |
arguments = dict(
|
... | ... | |
1771 |
1771 |
|
1772 |
1772 |
|
1773 |
1773 |
@command(pithos_cmds)
|
1774 |
|
class store_setquota(_store_account_command):
|
|
1774 |
class file_setquota(_file_account_command):
|
1775 |
1775 |
"""Set new quota for account or container
|
1776 |
1776 |
By default, quota is set in bytes
|
1777 |
1777 |
Users may specify a different unit, e.g:
|
1778 |
|
/store setquota 2.3GB mycontainer
|
|
1778 |
/file setquota 2.3GB mycontainer
|
1779 |
1779 |
Accepted units: B, KiB (1024 B), KB (1000 B), MiB, MB, GiB, GB, TiB, TB
|
1780 |
1780 |
"""
|
1781 |
1781 |
|
... | ... | |
1821 |
1821 |
|
1822 |
1822 |
|
1823 |
1823 |
@command(pithos_cmds)
|
1824 |
|
class store_versioning(_store_account_command):
|
|
1824 |
class file_versioning(_file_account_command):
|
1825 |
1825 |
"""Get versioning for account or container"""
|
1826 |
1826 |
|
1827 |
1827 |
@errors.generic.all
|
... | ... | |
1841 |
1841 |
|
1842 |
1842 |
|
1843 |
1843 |
@command(pithos_cmds)
|
1844 |
|
class store_setversioning(_store_account_command):
|
|
1844 |
class file_setversioning(_file_account_command):
|
1845 |
1845 |
"""Set versioning mode (auto, none) for account or container"""
|
1846 |
1846 |
|
1847 |
1847 |
def _check_versioning(self, versioning):
|
... | ... | |
1866 |
1866 |
|
1867 |
1867 |
|
1868 |
1868 |
@command(pithos_cmds)
|
1869 |
|
class store_group(_store_account_command):
|
|
1869 |
class file_group(_file_account_command):
|
1870 |
1870 |
"""Get groups and group members"""
|
1871 |
1871 |
|
1872 |
1872 |
@errors.generic.all
|
... | ... | |
1881 |
1881 |
|
1882 |
1882 |
|
1883 |
1883 |
@command(pithos_cmds)
|
1884 |
|
class store_setgroup(_store_account_command):
|
|
1884 |
class file_setgroup(_file_account_command):
|
1885 |
1885 |
"""Set a user group"""
|
1886 |
1886 |
|
1887 |
1887 |
@errors.generic.all
|
... | ... | |
1898 |
1898 |
|
1899 |
1899 |
|
1900 |
1900 |
@command(pithos_cmds)
|
1901 |
|
class store_delgroup(_store_account_command):
|
|
1901 |
class file_delgroup(_file_account_command):
|
1902 |
1902 |
"""Delete a user group"""
|
1903 |
1903 |
|
1904 |
1904 |
@errors.generic.all
|
... | ... | |
1912 |
1912 |
|
1913 |
1913 |
|
1914 |
1914 |
@command(pithos_cmds)
|
1915 |
|
class store_sharers(_store_account_command):
|
|
1915 |
class file_sharers(_file_account_command):
|
1916 |
1916 |
"""List the accounts that share objects with current user"""
|
1917 |
1917 |
|
1918 |
1918 |
arguments = dict(
|
... | ... | |
1935 |
1935 |
|
1936 |
1936 |
|
1937 |
1937 |
@command(pithos_cmds)
|
1938 |
|
class store_versions(_store_container_command):
|
|
1938 |
class file_versions(_file_container_command):
|
1939 |
1939 |
"""Get the list of object versions
|
1940 |
1940 |
Deleted objects may still have versions that can be used to restore it and
|
1941 |
1941 |
get information about its previous state.
|
1942 |
1942 |
The version number can be used in a number of other commands, like info,
|
1943 |
1943 |
copy, move, meta. See these commands for more information, e.g.
|
1944 |
|
/store info -h
|
|
1944 |
/file info -h
|
1945 |
1945 |
"""
|
1946 |
1946 |
|
1947 |
1947 |
@errors.generic.all
|
... | ... | |
1955 |
1955 |
localtime(float(vitem[1])))) for vitem in versions])
|
1956 |
1956 |
|
1957 |
1957 |
def main(self, container___path):
|
1958 |
|
super(store_versions, self)._run(
|
|
1958 |
super(file_versions, self)._run(
|
1959 |
1959 |
container___path,
|
1960 |
1960 |
path_is_optional=False)
|
1961 |
1961 |
self._run()
|