...
|
...
|
@@ -1082,39 +1082,43 @@ def cmd_sync(args):
|
1082
|
1082
|
|
1083
|
1083
|
def cmd_setacl(args):
|
1084
|
1084
|
def _update_acl(uri, seq_label = ""):
|
|
1085
|
+ something_changed = False
|
1085
|
1086
|
acl = s3.get_acl(uri)
|
1086
|
1087
|
debug(u"acl: %s - %r" % (uri, acl.grantees))
|
1087
|
1088
|
if cfg.acl_public == True:
|
1088
|
1089
|
if acl.isAnonRead():
|
1089
|
1090
|
info(u"%s: already Public, skipping %s" % (uri, seq_label))
|
1090
|
|
- if not cfg.acl_grants and not cfg.acl_revokes:
|
1091
|
|
- return
|
1092
|
1091
|
else:
|
1093
|
1092
|
acl.grantAnonRead()
|
|
1093
|
+ something_changed = True
|
1094
|
1094
|
elif cfg.acl_public == False: # we explicitely check for False, because it could be None
|
1095
|
1095
|
if not acl.isAnonRead():
|
1096
|
1096
|
info(u"%s: already Private, skipping %s" % (uri, seq_label))
|
1097
|
|
- if not cfg.acl_grants and not cfg.acl_revokes:
|
1098
|
|
- return
|
1099
|
1097
|
else:
|
1100
|
1098
|
acl.revokeAnonRead()
|
|
1099
|
+ something_changed = True
|
1101
|
1100
|
|
1102
|
1101
|
# update acl with arguments
|
1103
|
1102
|
# grant first and revoke later, because revoke has priority
|
1104
|
1103
|
if cfg.acl_grants:
|
|
1104
|
+ something_changed = True
|
1105
|
1105
|
for grant in cfg.acl_grants:
|
1106
|
1106
|
acl.grant(**grant);
|
1107
|
1107
|
|
1108
|
1108
|
if cfg.acl_revokes:
|
|
1109
|
+ something_changed = True
|
1109
|
1110
|
for revoke in cfg.acl_revokes:
|
1110
|
1111
|
acl.revoke(**revoke);
|
1111
|
1112
|
|
|
1113
|
+ if not something_changed:
|
|
1114
|
+ return
|
|
1115
|
+
|
1112
|
1116
|
retsponse = s3.set_acl(uri, acl)
|
1113
|
1117
|
if retsponse['status'] == 200:
|
1114
|
|
- if cfg.acl_public == True or cfg.acl_public == False:
|
|
1118
|
+ if cfg.acl_public in (True, False):
|
1115
|
1119
|
output(u"%s: ACL set to %s %s" % (uri, set_to_acl, seq_label))
|
1116
|
1120
|
else:
|
1117
|
|
- output(u"ACL updated")
|
|
1121
|
+ output(u"%s: ACL updated" % uri)
|
1118
|
1122
|
|
1119
|
1123
|
s3 = S3(cfg)
|
1120
|
1124
|
|
...
|
...
|
@@ -1507,9 +1511,26 @@ class OptionMimeType(Option):
|
1507
|
1507
|
return value
|
1508
|
1508
|
raise OptionValueError("option %s: invalid MIME-Type format: %r" % (opt, value))
|
1509
|
1509
|
|
1510
|
|
- TYPES = Option.TYPES + ("mimetype",)
|
|
1510
|
+class OptionS3ACL(Option):
|
|
1511
|
+ def check_s3acl(option, opt, value):
|
|
1512
|
+ permissions = ('read', 'write', 'read_acp', 'write_acp', 'full_control', 'all')
|
|
1513
|
+ try:
|
|
1514
|
+ permission, grantee = re.compile("^(\w+):(.+)$", re.IGNORECASE).match(value).groups()
|
|
1515
|
+ if not permission or not grantee:
|
|
1516
|
+ raise
|
|
1517
|
+ if permission in permissions:
|
|
1518
|
+ return { 'name' : grantee, 'permission' : permission.upper() }
|
|
1519
|
+ else:
|
|
1520
|
+ raise OptionValueError("option %s: invalid S3 ACL permission: %s (valid values: %s)" %
|
|
1521
|
+ (opt, permission, ", ".join(permissions)))
|
|
1522
|
+ except:
|
|
1523
|
+ raise OptionValueError("option %s: invalid S3 ACL format: %r" % (opt, value))
|
|
1524
|
+
|
|
1525
|
+class OptionAll(OptionMimeType, OptionS3ACL):
|
1511
|
1526
|
TYPE_CHECKER = copy(Option.TYPE_CHECKER)
|
1512
|
|
- TYPE_CHECKER["mimetype"] = check_mimetype
|
|
1527
|
+ TYPE_CHECKER["mimetype"] = OptionMimeType.check_mimetype
|
|
1528
|
+ TYPE_CHECKER["s3acl"] = OptionS3ACL.check_s3acl
|
|
1529
|
+ TYPES = Option.TYPES + ("mimetype", "s3acl")
|
1513
|
1530
|
|
1514
|
1531
|
class MyHelpFormatter(IndentedHelpFormatter):
|
1515
|
1532
|
def format_epilog(self, epilog):
|
...
|
...
|
@@ -1530,7 +1551,7 @@ def main():
|
1530
|
1530
|
commands[cmd["cmd"]] = cmd
|
1531
|
1531
|
|
1532
|
1532
|
default_verbosity = Config().verbosity
|
1533
|
|
- optparser = OptionParser(option_class=OptionMimeType, formatter=MyHelpFormatter())
|
|
1533
|
+ optparser = OptionParser(option_class=OptionAll, formatter=MyHelpFormatter())
|
1534
|
1534
|
#optparser.disable_interspersed_args()
|
1535
|
1535
|
|
1536
|
1536
|
config_file = None
|
...
|
...
|
@@ -1559,8 +1580,8 @@ def main():
|
1559
|
1559
|
optparser.add_option("-r", "--recursive", dest="recursive", action="store_true", help="Recursive upload, download or removal.")
|
1560
|
1560
|
optparser.add_option("-P", "--acl-public", dest="acl_public", action="store_true", help="Store objects with ACL allowing read for anyone.")
|
1561
|
1561
|
optparser.add_option( "--acl-private", dest="acl_public", action="store_false", help="Store objects with default ACL allowing access for you only.")
|
1562
|
|
- optparser.add_option( "--acl-grant", dest="acl_grants", action="append", metavar="PERMISSION:EMAIL or USER_CANONICAL_ID", help="Grant stated permission to a given amazon user. Permission is one of: read, write, read_acp, write_acp, full_control, all")
|
1563
|
|
- optparser.add_option( "--acl-revoke", dest="acl_revokes", action="append", metavar="PERMISSION:USER_CANONICAL_ID", help="Revoke stated permission for a given amazon user. Permission is one of: read, write, read_acp, wr ite_acp, full_control, all")
|
|
1562
|
+ optparser.add_option( "--acl-grant", dest="acl_grants", type="s3acl", action="append", metavar="PERMISSION:EMAIL or USER_CANONICAL_ID", help="Grant stated permission to a given amazon user. Permission is one of: read, write, read_acp, write_acp, full_control, all")
|
|
1563
|
+ optparser.add_option( "--acl-revoke", dest="acl_revokes", type="s3acl", action="append", metavar="PERMISSION:USER_CANONICAL_ID", help="Revoke stated permission for a given amazon user. Permission is one of: read, write, read_acp, wr ite_acp, full_control, all")
|
1564
|
1564
|
|
1565
|
1565
|
optparser.add_option( "--delete-removed", dest="delete_removed", action="store_true", help="Delete remote objects with no corresponding local file [sync]")
|
1566
|
1566
|
optparser.add_option( "--no-delete-removed", dest="delete_removed", action="store_false", help="Don't delete remote objects.")
|
...
|
...
|
@@ -1671,28 +1692,14 @@ def main():
|
1671
|
1671
|
debug(u"Updating Config.Config extra_headers[%s] -> %s" % (key.strip(), val.strip()))
|
1672
|
1672
|
cfg.extra_headers[key.strip()] = val.strip()
|
1673
|
1673
|
|
1674
|
|
-
|
1675
|
|
- permission_re = "(?P<PERMISSION>read(_acp)?|write(_acp)?|full_control|all)"
|
1676
|
|
-
|
|
1674
|
+ ## --acl-grant/--acl-revoke arguments are pre-parsed by OptionS3ACL()
|
1677
|
1675
|
if options.acl_grants:
|
1678
|
|
- r_acl_grant = re.compile("^%s:(?P<NAME>.+)$" % permission_re, re.IGNORECASE)
|
1679
|
1676
|
for grant in options.acl_grants:
|
1680
|
|
- is_data = r_acl_grant.match(grant)
|
1681
|
|
- if is_data:
|
1682
|
|
- data = is_data.groupdict()
|
1683
|
|
- cfg.acl_grants.append({'name': data['NAME'].lower(), 'permission': data["PERMISSION"].upper()})
|
1684
|
|
- else:
|
1685
|
|
- warning(u"skipped invalid --acl-grant option: [%s]" % grant)
|
|
1677
|
+ cfg.acl_grants.append(grant)
|
1686
|
1678
|
|
1687
|
1679
|
if options.acl_revokes:
|
1688
|
|
- r_acl_revoke = re.compile("^%s:(?P<NAME>.+)$" % permission_re, re.IGNORECASE)
|
1689
|
|
- for revoke in options.acl_revokes:
|
1690
|
|
- is_data = r_acl_revoke.match(revoke)
|
1691
|
|
- if is_data:
|
1692
|
|
- data = is_data.groupdict()
|
1693
|
|
- cfg.acl_revokes.append({'name': data['NAME'].lower(), 'permission': data["PERMISSION"].upper()})
|
1694
|
|
- else:
|
1695
|
|
- warning(u"skipped invalid --acl-revoke option: [%s]" % revoke)
|
|
1680
|
+ for grant in options.acl_revokes:
|
|
1681
|
+ cfg.acl_revokes.append(grant)
|
1696
|
1682
|
|
1697
|
1683
|
## Update Config with other parameters
|
1698
|
1684
|
for option in cfg.option_list():
|