| # 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 |