blob: 1af7e332b17ad2a79786f73c7481fc4a9048a290 [file] [log] [blame]
# Copyright 2017 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from recipe_engine import recipe_api
import os
class IsolatedApi(recipe_api.RecipeApi):
"""APIs for interacting with isolates."""
def __init__(self, isolate_server, *args, **kwargs):
super(IsolatedApi, self).__init__(*args, **kwargs)
self._isolate_server = isolate_server
self._isolated_client = None
def __call__(self, *args, **kwargs):
"""Return an isolate command step."""
assert self._isolated_client
name = kwargs.pop('name', 'isolate ' + args[0])
return self.m.step(name, [self._isolated_client] + list(args), **kwargs)
def ensure_isolated(self, version=None):
"""Ensures that isolate client is installed."""
if self._isolated_client:
return self._isolated_client
with self.m.step.nest('ensure_isolated'):
with self.m.context(infra_steps=True):
pkgs = self.m.cipd.EnsureFile()
pkgs.add_package('infra/tools/luci/isolated/${platform}', version or 'release')
cipd_dir = self.m.path['start_dir'].join('cipd', 'isolated')
self.m.cipd.ensure(cipd_dir, pkgs)
self._isolated_client = cipd_dir.join('isolated')
return self._isolated_client
@property
def isolated_client(self):
return self._isolated_client
@property
def isolate_server(self):
"""URL of Isolate server to use, default is a production one."""
return self._isolate_server
@isolate_server.setter
def isolate_server(self, value):
"""Changes URL of Isolate server to use."""
self._isolate_server = value
def isolated(self):
"""Returns an Isolated object that can be used to archive a set of files
and directories."""
return Isolated(self)
class Isolated(object):
"""Used to gather a list of files and directories to an isolated."""
def __init__(self, module):
self._module = module
self._files = {}
self._dirs = {}
def add_file(self, path, wd=None):
"""Stages a single file to be added to the isolated.
The isolated client implements a tar-like scatter-gather mechanism for
archiving files. |path| refers to an absolute path to the file, while
|cwd| is some subset of |path| which will become the path used by the
isolated client.
For example, /usr/local/data/foo can be added to the isolated as
data/foo by specifying wd=/usr/local.
Args:
path: absolute path to a file.
cwd: absolute path to the working directory for the file.
"""
assert path
wd = wd or self._module.m.context.cwd
assert wd.is_parent_of(path)
self._files.setdefault(str(wd), []).append(str(path))
def add_dir(self, path, wd=None):
"""Stages a single directory to be added to the isolated.
The isolated client implements a tar-like scatter-gather mechanism for
archiving directories. |path| refers to an absolute path to the directory,
while |cwd| is some subset of |path| which will become the path used by the
isolated client.
For example, /usr/local/data/foo can be added to the isolated as
data/foo by specifying wd=/usr/local.
Args:
path: absolute path to a directory.
cwd: absolute path to the working directory for the directory.
"""
assert path
wd = wd or self._module.m.context.cwd
assert wd.is_parent_of(path)
self._dirs.setdefault(str(wd), []).append(str(path))
def archive(self, step_name):
"""Step to archive all staged files and directories."""
assert self._module._isolated_client
cmd = [
self._module._isolated_client,
'archive',
'-isolate-server', self._module.isolate_server,
'-namespace', 'default-gzip',
'-dump-hash', self._module.m.raw_io.output_text(),
]
for wd, files in self._files.iteritems():
for f in files:
cmd.extend(['-files', wd + ':' + os.path.relpath(f, wd)])
for wd, dirs in self._dirs.iteritems():
for d in dirs:
cmd.extend(['-dirs', wd + ':' + os.path.relpath(d, wd)])
return self._module.m.step(
'archive',
cmd,
step_test_data=lambda: self._module.test_api.archive(),
).raw_io.output_text