Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(378)

Side by Side Diff: infra/bots/assets/asset_utils.py

Issue 2069543002: Add asset management scripts (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Add asset_utils_test Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « infra/bots/assets/__init__.py ('k') | infra/bots/assets/asset_utils_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 #
3 # Copyright 2016 Google Inc.
4 #
5 # Use of this source code is governed by a BSD-style license that can be
6 # found in the LICENSE file.
7
8
9 """Utilities for managing assets."""
10
11
12 import argparse
13 import os
14 import shlex
15 import shutil
16 import subprocess
17 import sys
18
19 SKIA_DIR = os.path.abspath(os.path.realpath(os.path.join(
20 os.path.dirname(os.path.abspath(__file__)),
21 os.pardir, os.pardir, os.pardir)))
22 INFRA_BOTS_DIR = os.path.join(SKIA_DIR, 'infra', 'bots')
23 sys.path.insert(0, INFRA_BOTS_DIR)
24 import utils
25 import zip_utils
26
27
28 ASSETS_DIR = os.path.join(INFRA_BOTS_DIR, 'assets')
29 DEFAULT_GS_BUCKET = 'skia-buildbots'
30 GS_SUBDIR_TMPL = 'gs://%s/assets/%s'
31 GS_PATH_TMPL = '%s/%s.zip'
32 VERSION_FILENAME = 'VERSION'
33 ZIP_BLACKLIST = ['.git', '.svn', '*.pyc', '.DS_STORE']
34
35
36 class _GSWrapper(object):
37 """Wrapper object for interacting with Google Storage."""
38 def __init__(self, gsutil):
39 gsutil = os.path.abspath(gsutil) if gsutil else 'gsutil'
40 self._gsutil = [gsutil]
41 if gsutil.endswith('.py'):
42 self._gsutil = ['python', gsutil]
43
44 def copy(self, src, dst):
45 """Copy src to dst."""
46 subprocess.check_call(self._gsutil + ['cp', src, dst])
47
48 def list(self, path):
49 """List objects in the given path."""
50 try:
51 return subprocess.check_output(self._gsutil + ['ls', path]).splitlines()
52 except subprocess.CalledProcessError:
53 # If the prefix does not exist, we'll get an error, which is okay.
54 return []
55
56
57 def _prompt(prompt):
58 """Prompt for input, return result."""
59 return raw_input(prompt)
60
61
62 class Asset(object):
63 def __init__(self, name, gs_bucket=DEFAULT_GS_BUCKET, gsutil=None):
64 self._gs = _GSWrapper(gsutil)
65 self._gs_subdir = GS_SUBDIR_TMPL % (gs_bucket, name)
66 self._name = name
67 self._dir = os.path.join(ASSETS_DIR, self._name)
68
69 @property
70 def version_file(self):
71 """Return the path to the version file for this asset."""
72 return os.path.join(self._dir, VERSION_FILENAME)
73
74 def get_current_version(self):
75 """Obtain the current version of the asset."""
76 if not os.path.isfile(self.version_file):
77 return -1
78 with open(self.version_file) as f:
79 return int(f.read())
80
81 def get_available_versions(self):
82 """Return the existing version numbers for this asset."""
83 files = self._gs.list(self._gs_subdir)
84 bnames = [os.path.basename(f) for f in files]
85 suffix = '.zip'
86 versions = [int(f[:-len(suffix)]) for f in bnames if f.endswith(suffix)]
87 versions.sort()
88 return versions
89
90 def get_next_version(self):
91 """Find the next available version number for the asset."""
92 versions = self.get_available_versions()
93 if len(versions) == 0:
94 return 0
95 return versions[-1] + 1
96
97 def download_version(self, version, target_dir):
98 """Download the specified version of the asset."""
99 gs_path = GS_PATH_TMPL % (self._gs_subdir, str(version))
100 target_dir = os.path.abspath(target_dir)
101 with utils.tmp_dir():
102 zip_file = os.path.join(os.getcwd(), '%d.zip' % version)
103 self._gs.copy(gs_path, zip_file)
104 zip_utils.unzip(zip_file, target_dir)
105
106 def download_current_version(self, target_dir):
107 """Download the version of the asset specified in its version file."""
108 v = self.get_current_version()
109 self.download_version(v, target_dir)
110
111 def upload_new_version(self, target_dir, commit=False):
112 """Upload a new version and update the version file for the asset."""
113 version = self.get_next_version()
114 target_dir = os.path.abspath(target_dir)
115 with utils.tmp_dir():
116 zip_file = os.path.join(os.getcwd(), '%d.zip' % version)
117 zip_utils.zip(target_dir, zip_file, blacklist=ZIP_BLACKLIST)
118 gs_path = GS_PATH_TMPL % (self._gs_subdir, str(version))
119 self._gs.copy(zip_file, gs_path)
120
121 def _write_version():
122 with open(self.version_file, 'w') as f:
123 f.write(str(version))
124 subprocess.check_call([utils.GIT, 'add', self.version_file])
125
126 with utils.chdir(SKIA_DIR):
127 if commit:
128 with utils.git_branch():
129 _write_version()
130 subprocess.check_call([
131 utils.GIT, 'commit', '-m', 'Update %s version' % self._name])
132 subprocess.check_call([utils.GIT, 'cl', 'upload', '--bypass-hooks'])
133 else:
134 _write_version()
135
136 @classmethod
137 def add(cls, name, gs_bucket=DEFAULT_GS_BUCKET, gsutil=None):
138 """Add an asset."""
139 asset = cls(name, gs_bucket=gs_bucket, gsutil=gsutil)
140 if os.path.isdir(asset._dir):
141 raise Exception('Asset %s already exists!' % asset._name)
142
143 print 'Creating asset in %s' % asset._dir
144 os.mkdir(asset._dir)
145 def copy_script(script):
146 src = os.path.join(ASSETS_DIR, 'scripts', script)
147 dst = os.path.join(asset._dir, script)
148 print 'Creating %s' % dst
149 shutil.copy(src, dst)
150 subprocess.check_call([utils.GIT, 'add', dst])
151
152 for script in ('download.py', 'upload.py', 'common.py'):
153 copy_script(script)
154 resp = _prompt('Add script to automate creation of this asset? (y/n) ')
155 if resp == 'y':
156 copy_script('create.py')
157 copy_script('create_and_upload.py')
158 print 'You will need to add implementation to the creation script.'
159 print 'Successfully created asset %s.' % asset._name
160 return asset
161
162 def remove(self):
163 """Remove this asset."""
164 # Ensure that the asset exists.
165 if not os.path.isdir(self._dir):
166 raise Exception('Asset %s does not exist!' % self._name)
167
168 # Remove the asset.
169 subprocess.check_call([utils.GIT, 'rm', '-rf', self._dir])
170 if os.path.isdir(self._dir):
171 shutil.rmtree(self._dir)
172
173 # We *could* remove all uploaded versions of the asset in Google Storage but
174 # we choose not to be that destructive.
OLDNEW
« no previous file with comments | « infra/bots/assets/__init__.py ('k') | infra/bots/assets/asset_utils_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698