| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- #!/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())
|