14311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch# Copyright (c) 2013 The Chromium Authors. All rights reserved.
2a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
3a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)# found in the LICENSE file.
4a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)import os
5a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)import re
6a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)import sys
7a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
8a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
9a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)def _SyncFilesToCloud(input_api, output_api):
10a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  """Searches for .sha1 files and uploads them to Cloud Storage.
11a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
12a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  It validates all the hashes and skips upload if not necessary.
13a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  """
14a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  # Because this script will be called from a magic PRESUBMIT demon,
15a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  # avoid angering it; don't pollute its sys.path.
16a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  old_sys_path = sys.path
17a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  try:
18a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    sys.path = [os.path.join(os.pardir, os.pardir, 'telemetry')] + sys.path
19a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    from telemetry.page import cloud_storage
20a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  finally:
21a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    sys.path = old_sys_path
22a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
234311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  hashes_in_cloud_storage = cloud_storage.List(cloud_storage.DEFAULT_BUCKET)
24a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
25a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  results = []
26a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  for hash_path in input_api.AbsoluteLocalPaths():
27a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    file_path, extension = os.path.splitext(hash_path)
28a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if extension != '.sha1':
29a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      continue
30a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
31a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    with open(hash_path, 'rb') as f:
32a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      file_hash = f.read(1024).rstrip()
33a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if file_hash in hashes_in_cloud_storage:
34a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      results.append(output_api.PresubmitNotifyResult(
35a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          'File already in Cloud Storage, skipping upload: %s' % hash_path))
36a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      continue
37a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
38a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if not re.match('^([A-Za-z0-9]{40})$', file_hash):
39a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      results.append(output_api.PresubmitError(
40a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          'Hash file does not contain a valid SHA-1 hash: %s' % hash_path))
41a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      continue
42a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if not os.path.exists(file_path):
43a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      results.append(output_api.PresubmitError(
44a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          'Hash file exists, but file not found: %s' % hash_path))
45a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      continue
46a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if cloud_storage.GetHash(file_path) != file_hash:
47a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      results.append(output_api.PresubmitError(
48a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          'Hash file does not match file\'s actual hash: %s' % hash_path))
49a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      continue
50a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
51a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    try:
524311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch      cloud_storage.Insert(cloud_storage.DEFAULT_BUCKET, file_hash, file_path)
53a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    except cloud_storage.CloudStorageError:
54a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      results.append(output_api.PresubmitError(
55a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          'Unable to upload to Cloud Storage: %s' % hash_path))
56a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
57a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return results
58a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
59a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
60a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)def CheckChangeOnCommit(input_api, output_api):
61a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  results = []
62a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  results += _SyncFilesToCloud(input_api, output_api)
63a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return results
64