blob: 1936e2bae6c933320698e03dfe9f3a095226f382 [file] [log] [blame]
Chris Sosa47a7d4e2012-03-28 11:26:55 -07001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Module containing classes that wrap artifact downloads."""
6
7import cherrypy
8import os
9import shutil
10import subprocess
11
12import gsutil_util
13
14
15# Names of artifacts we care about.
Chris Masone816e38c2012-05-02 12:22:36 -070016DEBUG_SYMBOLS = 'debug.tgz'
Chris Sosa47a7d4e2012-03-28 11:26:55 -070017STATEFUL_UPDATE = 'stateful.tgz'
18TEST_IMAGE = 'chromiumos_test_image.bin'
19ROOT_UPDATE = 'update.gz'
Yu-Ju Hongbee1ba62012-07-02 13:12:55 -070020AUTOTEST_PACKAGE = 'autotest.tar'
Chris Sosa47a7d4e2012-03-28 11:26:55 -070021TEST_SUITES_PACKAGE = 'test_suites.tar.bz2'
22
23
24class ArtifactDownloadError(Exception):
25 """Error used to signify an issue processing an artifact."""
26 pass
27
28
29class DownloadableArtifact(object):
30 """Wrapper around an artifact to download from gsutil.
31
32 The purpose of this class is to download objects from Google Storage
33 and install them to a local directory. There are two main functions, one to
34 download/prepare the artifacts in to a temporary staging area and the second
35 to stage it into its final destination.
36 """
37 def __init__(self, gs_path, tmp_staging_dir, install_path, synchronous=False):
38 """Args:
39 gs_path: Path to artifact in google storage.
40 tmp_staging_dir: Temporary working directory maintained by caller.
41 install_path: Final destination of artifact.
42 synchronous: If True, artifact must be downloaded in the foreground.
43 """
44 self._gs_path = gs_path
45 self._tmp_staging_dir = tmp_staging_dir
46 self._tmp_stage_path = os.path.join(tmp_staging_dir,
47 os.path.basename(self._gs_path))
48 self._synchronous = synchronous
49 self._install_path = install_path
50
51 if not os.path.isdir(self._tmp_staging_dir):
52 os.makedirs(self._tmp_staging_dir)
53
54 if not os.path.isdir(os.path.dirname(self._install_path)):
55 os.makedirs(os.path.dirname(self._install_path))
56
57 def Download(self):
58 """Stages the artifact from google storage to a local staging directory."""
59 gsutil_util.DownloadFromGS(self._gs_path, self._tmp_stage_path)
60
61 def Synchronous(self):
62 """Returns False if this artifact can be downloaded in the background."""
63 return self._synchronous
64
65 def Stage(self):
66 """Moves the artifact from the tmp staging directory to the final path."""
67 shutil.move(self._tmp_stage_path, self._install_path)
68
69 def __str__(self):
70 """String representation for the download."""
71 return '->'.join([self._gs_path, self._tmp_staging_dir, self._install_path])
72
73
74class AUTestPayload(DownloadableArtifact):
75 """Wrapper for AUTest delta payloads which need additional setup."""
76 def Stage(self):
77 super(AUTestPayload, self).Stage()
78
79 payload_dir = os.path.dirname(self._install_path)
80 # Setup necessary symlinks for updating.
81 os.symlink(os.path.join(os.pardir, os.pardir, TEST_IMAGE),
82 os.path.join(payload_dir, TEST_IMAGE))
83 os.symlink(os.path.join(os.pardir, os.pardir, STATEFUL_UPDATE),
84 os.path.join(payload_dir, STATEFUL_UPDATE))
85
86
87class Tarball(DownloadableArtifact):
88 """Wrapper around an artifact to download from gsutil which is a tarball."""
89
90 def _ExtractTarball(self, exclude=None):
91 """Extracts the tarball into the install_path with optional exclude path."""
92 exclude_str = '--exclude=%s' % exclude if exclude else ''
93 cmd = 'tar xf %s %s --use-compress-prog=pbzip2 --directory=%s' % (
94 self._tmp_stage_path, exclude_str, self._install_path)
95 msg = 'An error occurred when attempting to untar %s' % self._tmp_stage_path
96 try:
97 subprocess.check_call(cmd, shell=True)
98 except subprocess.CalledProcessError, e:
99 raise ArtifactDownloadError('%s %s' % (msg, e))
100
101 def Stage(self):
102 """Changes directory into the install path and untars the tarball."""
103 if not os.path.isdir(self._install_path):
104 os.makedirs(self._install_path)
105
106 self._ExtractTarball()
107
108
109class AutotestTarball(Tarball):
110 """Wrapper around the autotest tarball to download from gsutil."""
111
Yu-Ju Hongbee1ba62012-07-02 13:12:55 -0700112 def _ExtractTarball(self, exclude=None):
113 """Extracts the tarball into the install_path with optional exclude path."""
114 exclude_str = '--exclude=%s' % exclude if exclude else ''
115 cmd = 'tar xf %s %s --directory=%s' % (
116 self._tmp_stage_path, exclude_str, self._install_path)
117 msg = 'An error occurred when attempting to untar %s' % self._tmp_stage_path
118 try:
119 subprocess.check_call(cmd, shell=True)
120 except subprocess.CalledProcessError, e:
121 raise ArtifactDownloadError('%s %s' % (msg, e))
122
Chris Sosa47a7d4e2012-03-28 11:26:55 -0700123 def Stage(self):
124 """Untars the autotest tarball into the install path excluding test suites.
125 """
126 if not os.path.isdir(self._install_path):
127 os.makedirs(self._install_path)
128
129 self._ExtractTarball(exclude='autotest/test_suites')
130 autotest_dir = os.path.join(self._install_path, 'autotest')
131 autotest_pkgs_dir = os.path.join(autotest_dir, 'packages')
132 if not os.path.exists(autotest_pkgs_dir):
133 os.makedirs(autotest_pkgs_dir)
134
135 if not os.path.exists(os.path.join(autotest_pkgs_dir, 'packages.checksum')):
136 cmd = 'autotest/utils/packager.py upload --repository=%s --all' % (
137 autotest_pkgs_dir)
138 msg = 'Failed to create autotest packages!'
139 try:
140 subprocess.check_call(cmd, cwd=self._tmp_staging_dir,
141 shell=True)
142 except subprocess.CalledProcessError, e:
143 raise ArtifactDownloadError('%s %s' % (msg, e))
144 else:
145 cherrypy.log('Using pre-generated packages from autotest',
146 'DEVSERVER_UTIL')
147
148 # TODO(scottz): Remove after we have moved away from the old test_scheduler
149 # code.
150 cmd = 'cp %s/* %s' % (autotest_pkgs_dir, autotest_dir)
151 subprocess.check_call(cmd, shell=True)
Chris Masone816e38c2012-05-02 12:22:36 -0700152
153
154class DebugTarball(Tarball):
155 """Wrapper around the debug symbols tarball to download from gsutil."""
156
157 def _ExtractTarball(self):
158 """Extracts debug/breakpad from the tarball into the install_path."""
159 cmd = 'tar xzf %s --directory=%s debug/breakpad' % (
160 self._tmp_stage_path, self._install_path)
161 msg = 'An error occurred when attempting to untar %s' % self._tmp_stage_path
162 try:
163 subprocess.check_call(cmd, shell=True)
164 except subprocess.CalledProcessError, e:
165 raise ArtifactDownloadError('%s %s' % (msg, e))