2 # Copyright 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
11 from telemetry
.core
import command_line
12 from telemetry
.page
import cloud_storage
16 'public': cloud_storage
.PUBLIC_BUCKET
,
17 'partner': cloud_storage
.PARTNER_BUCKET
,
18 'google-only': cloud_storage
.INTERNAL_BUCKET
,
20 BUCKETS
= {bucket
: easy_bucket_name
for easy_bucket_name
, bucket
21 in BUCKET_ALIASES
.iteritems()}
25 root
, ext
= os
.path
.splitext(path
)
31 hash_path
= path
+ '.sha1'
32 return file_path
, hash_path
35 def _FindFilesInCloudStorage(files
):
36 """Returns a dict of all files and which buckets they're in."""
37 # Preprocessing: get the contents of all buckets.
39 for bucket
in BUCKETS
:
41 bucket_contents
[bucket
] = cloud_storage
.List(bucket
)
42 except (cloud_storage
.PermissionError
, cloud_storage
.CredentialsError
):
45 # Check if each file is in the bucket contents.
48 file_path
, hash_path
= _GetPaths(path
)
50 if file_path
in file_buckets
:
51 # Ignore duplicates, if both data and sha1 file were in the file list.
53 if not os
.path
.exists(hash_path
):
54 # Probably got some non-Cloud Storage files in the file list. Ignore.
57 file_hash
= cloud_storage
.ReadHash(hash_path
)
58 file_buckets
[file_path
] = []
59 for bucket
in BUCKETS
:
60 if bucket
in bucket_contents
and file_hash
in bucket_contents
[bucket
]:
61 file_buckets
[file_path
].append(bucket
)
66 class Ls(command_line
.Command
):
67 """List which bucket each file is in."""
70 def AddCommandLineArgs(cls
, parser
):
71 parser
.add_argument('-r', '--recursive', action
='store_true')
72 parser
.add_argument('paths', nargs
='+')
75 def ProcessCommandLineArgs(cls
, parser
, args
):
76 for path
in args
.paths
:
77 if not os
.path
.exists(path
):
78 parser
.error('Path not found: %s' % path
)
81 def GetFilesInPaths(paths
, recursive
):
82 """If path is a dir, yields all files in path, otherwise just yields path.
84 If recursive is true, walks subdirectories recursively."""
86 if not os
.path
.isdir(path
):
91 for root
, _
, filenames
in os
.walk(path
):
92 for filename
in filenames
:
93 yield os
.path
.join(root
, filename
)
95 for filename
in os
.listdir(path
):
96 yield os
.path
.join(path
, filename
)
98 files
= _FindFilesInCloudStorage(GetFilesInPaths(args
.paths
, args
.recursive
))
101 print 'No files in Cloud Storage.'
104 for file_path
, buckets
in sorted(files
.iteritems()):
106 buckets
= [BUCKETS
[bucket
] for bucket
in buckets
]
107 print '%-11s %s' % (','.join(buckets
), file_path
)
109 print '%-11s %s' % ('not found', file_path
)
112 class Mv(command_line
.Command
):
113 """Move files to the given bucket."""
116 def AddCommandLineArgs(cls
, parser
):
117 parser
.add_argument('files', nargs
='+')
118 parser
.add_argument('bucket', choices
=BUCKET_ALIASES
)
121 def ProcessCommandLineArgs(cls
, parser
, args
):
122 args
.bucket
= BUCKET_ALIASES
[args
.bucket
]
125 files
= _FindFilesInCloudStorage(args
.files
)
127 for file_path
, buckets
in sorted(files
.iteritems()):
129 raise IOError('%s not found in Cloud Storage.' % file_path
)
131 for file_path
, buckets
in sorted(files
.iteritems()):
132 if args
.bucket
in buckets
:
133 buckets
.remove(args
.bucket
)
135 logging
.info('Skipping %s, no action needed.' % file_path
)
138 # Move to the target bucket.
139 file_hash
= cloud_storage
.ReadHash(file_path
+ '.sha1')
140 cloud_storage
.Move(buckets
.pop(), args
.bucket
, file_hash
)
142 # Delete all additional copies.
143 for bucket
in buckets
:
144 cloud_storage
.Delete(bucket
, file_hash
)
147 class Rm(command_line
.Command
):
148 """Remove files from Cloud Storage."""
151 def AddCommandLineArgs(cls
, parser
):
152 parser
.add_argument('files', nargs
='+')
155 files
= _FindFilesInCloudStorage(args
.files
)
156 for file_path
, buckets
in sorted(files
.iteritems()):
157 file_hash
= cloud_storage
.ReadHash(file_path
+ '.sha1')
158 for bucket
in buckets
:
159 cloud_storage
.Delete(bucket
, file_hash
)
162 class Upload(command_line
.Command
):
163 """Upload files to Cloud Storage."""
166 def AddCommandLineArgs(cls
, parser
):
167 parser
.add_argument('files', nargs
='+')
168 parser
.add_argument('bucket', choices
=BUCKET_ALIASES
)
171 def ProcessCommandLineArgs(cls
, parser
, args
):
172 args
.bucket
= BUCKET_ALIASES
[args
.bucket
]
174 for path
in args
.files
:
175 if not os
.path
.exists(path
):
176 parser
.error('File not found: %s' % path
)
179 for file_path
in args
.files
:
180 file_hash
= cloud_storage
.CalculateHash(file_path
)
182 # Create or update the hash file.
183 hash_path
= file_path
+ '.sha1'
184 with
open(hash_path
, 'wb') as f
:
188 # Add the data to Cloud Storage.
189 cloud_storage
.Insert(args
.bucket
, file_hash
, file_path
)
191 # Add the hash file to the branch, for convenience. :)
192 subprocess
.call(['git', 'add', hash_path
])
195 COMMANDS
= (Ls
, Mv
, Rm
, Upload
)
199 logging
.getLogger().setLevel(logging
.INFO
)
201 parser
= argparse
.ArgumentParser()
202 subparsers
= parser
.add_subparsers()
204 for command
in COMMANDS
:
205 subparser
= subparsers
.add_parser(
206 command
.Name(), help=command
.Description())
207 subparser
.set_defaults(command
=command
)
208 command
.AddCommandLineArgs(subparser
)
210 args
= parser
.parse_args()
211 args
.command
.ProcessCommandLineArgs(parser
, args
)
212 args
.command().Run(args
)
215 if __name__
== '__main__':