200 lines
5.8 KiB
Python
Executable file
200 lines
5.8 KiB
Python
Executable file
#!/usr/bin/env python
|
|
# Copyright 2014 The Chromium Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
import argparse
|
|
import logging
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
from telemetry.core import util
|
|
from telemetry.internal.util import command_line
|
|
|
|
sys.path.insert(1, os.path.abspath(os.path.join(
|
|
util.GetCatapultDir(), 'common', 'py_utils')))
|
|
from py_utils import cloud_storage
|
|
|
|
|
|
BUCKETS = {bucket: easy_bucket_name for easy_bucket_name, bucket
|
|
in cloud_storage.BUCKET_ALIASES.iteritems()}
|
|
|
|
|
|
def _GetPaths(path):
|
|
root, ext = os.path.splitext(path)
|
|
if ext == '.sha1':
|
|
file_path = root
|
|
hash_path = path
|
|
else:
|
|
file_path = path
|
|
hash_path = path + '.sha1'
|
|
return file_path, hash_path
|
|
|
|
|
|
def _FindFilesInCloudStorage(files):
|
|
"""Returns a dict of all files and which buckets they're in."""
|
|
# Preprocessing: get the contents of all buckets.
|
|
bucket_contents = {}
|
|
for bucket in BUCKETS:
|
|
try:
|
|
bucket_contents[bucket] = cloud_storage.List(bucket)
|
|
except (cloud_storage.PermissionError, cloud_storage.CredentialsError):
|
|
pass
|
|
|
|
# Check if each file is in the bucket contents.
|
|
file_buckets = {}
|
|
for path in files:
|
|
file_path, hash_path = _GetPaths(path)
|
|
|
|
if file_path in file_buckets:
|
|
# Ignore duplicates, if both data and sha1 file were in the file list.
|
|
continue
|
|
if not os.path.exists(hash_path):
|
|
# Probably got some non-Cloud Storage files in the file list. Ignore.
|
|
continue
|
|
|
|
file_hash = cloud_storage.ReadHash(hash_path)
|
|
file_buckets[file_path] = []
|
|
for bucket in BUCKETS:
|
|
if bucket in bucket_contents and file_hash in bucket_contents[bucket]:
|
|
file_buckets[file_path].append(bucket)
|
|
|
|
return file_buckets
|
|
|
|
|
|
class Ls(command_line.Command):
|
|
"""List which bucket each file is in."""
|
|
|
|
@classmethod
|
|
def AddCommandLineArgs(cls, parser):
|
|
parser.add_argument('-r', '--recursive', action='store_true')
|
|
parser.add_argument('paths', nargs='+')
|
|
|
|
@classmethod
|
|
def ProcessCommandLineArgs(cls, parser, args):
|
|
for path in args.paths:
|
|
if not os.path.exists(path):
|
|
parser.error('Path not found: %s' % path)
|
|
|
|
def Run(self, args):
|
|
def GetFilesInPaths(paths, recursive):
|
|
"""If path is a dir, yields all files in path, otherwise just yields path.
|
|
If recursive is true, walks subdirectories recursively."""
|
|
for path in paths:
|
|
if not os.path.isdir(path):
|
|
yield path
|
|
continue
|
|
|
|
if recursive:
|
|
for root, _, filenames in os.walk(path):
|
|
for filename in filenames:
|
|
yield os.path.join(root, filename)
|
|
else:
|
|
for filename in os.listdir(path):
|
|
yield os.path.join(path, filename)
|
|
|
|
files = _FindFilesInCloudStorage(GetFilesInPaths(args.paths, args.recursive))
|
|
|
|
if not files:
|
|
print 'No files in Cloud Storage.'
|
|
return
|
|
|
|
for file_path, buckets in sorted(files.iteritems()):
|
|
if buckets:
|
|
buckets = [BUCKETS[bucket] for bucket in buckets]
|
|
print '%-11s %s' % (','.join(buckets), file_path)
|
|
else:
|
|
print '%-11s %s' % ('not found', file_path)
|
|
|
|
|
|
class Mv(command_line.Command):
|
|
"""Move files to the given bucket."""
|
|
|
|
@classmethod
|
|
def AddCommandLineArgs(cls, parser):
|
|
parser.add_argument('files', nargs='+')
|
|
parser.add_argument('bucket', choices=cloud_storage.BUCKET_ALIASES)
|
|
|
|
@classmethod
|
|
def ProcessCommandLineArgs(cls, parser, args):
|
|
args.bucket = cloud_storage.BUCKET_ALIASES[args.bucket]
|
|
|
|
def Run(self, args):
|
|
files = _FindFilesInCloudStorage(args.files)
|
|
|
|
for file_path, buckets in sorted(files.iteritems()):
|
|
if not buckets:
|
|
raise IOError('%s not found in Cloud Storage.' % file_path)
|
|
|
|
for file_path, buckets in sorted(files.iteritems()):
|
|
if args.bucket in buckets:
|
|
buckets.remove(args.bucket)
|
|
if not buckets:
|
|
logging.info('Skipping %s, no action needed.' % file_path)
|
|
continue
|
|
|
|
# Move to the target bucket.
|
|
file_hash = cloud_storage.ReadHash(file_path + '.sha1')
|
|
cloud_storage.Move(buckets.pop(), args.bucket, file_hash)
|
|
|
|
# Delete all additional copies.
|
|
for bucket in buckets:
|
|
cloud_storage.Delete(bucket, file_hash)
|
|
|
|
|
|
class Rm(command_line.Command):
|
|
"""Remove files from Cloud Storage."""
|
|
|
|
@classmethod
|
|
def AddCommandLineArgs(cls, parser):
|
|
parser.add_argument('files', nargs='+')
|
|
|
|
def Run(self, args):
|
|
files = _FindFilesInCloudStorage(args.files)
|
|
for file_path, buckets in sorted(files.iteritems()):
|
|
file_hash = cloud_storage.ReadHash(file_path + '.sha1')
|
|
for bucket in buckets:
|
|
cloud_storage.Delete(bucket, file_hash)
|
|
|
|
|
|
class Upload(command_line.Command):
|
|
"""Upload files to Cloud Storage."""
|
|
|
|
@classmethod
|
|
def AddCommandLineArgs(cls, parser):
|
|
parser.add_argument('files', nargs='+')
|
|
parser.add_argument('bucket', choices=cloud_storage.BUCKET_ALIASES)
|
|
|
|
@classmethod
|
|
def ProcessCommandLineArgs(cls, parser, args):
|
|
args.bucket = cloud_storage.BUCKET_ALIASES[args.bucket]
|
|
|
|
for path in args.files:
|
|
if not os.path.exists(path):
|
|
parser.error('File not found: %s' % path)
|
|
|
|
def Run(self, args):
|
|
for file_path in args.files:
|
|
file_hash = cloud_storage.CalculateHash(file_path)
|
|
|
|
# Create or update the hash file.
|
|
hash_path = file_path + '.sha1'
|
|
with open(hash_path, 'wb') as f:
|
|
f.write(file_hash)
|
|
f.flush()
|
|
|
|
# Add the data to Cloud Storage.
|
|
cloud_storage.Insert(args.bucket, file_hash, file_path)
|
|
|
|
# Add the hash file to the branch, for convenience. :)
|
|
subprocess.call(['git', 'add', hash_path])
|
|
|
|
|
|
class CloudStorageCommand(command_line.SubcommandCommand):
|
|
commands = (Ls, Mv, Rm, Upload)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
logging.getLogger().setLevel(logging.INFO)
|
|
sys.exit(CloudStorageCommand.main())
|