blob: c4a804df42956da773d24e43c2e0a0bb08597654 [file] [log] [blame]
# Copyright 2015 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Manage Project SDK installation, NOT REALATED to 'cros_sdk'."""
from __future__ import print_function
import os
import tempfile
from chromite.cbuildbot import constants
from chromite.cbuildbot import repository
from chromite.cli import command
from chromite.lib import bootstrap_lib
from chromite.lib import commandline
from chromite.lib import cros_build_lib
from chromite.lib import cros_logging as logging
from chromite.lib import git
from chromite.lib import gs
from chromite.lib import osutils
from chromite.lib import project_sdk
from chromite.lib import workspace_lib
_BRILLO_SDK_NO_UPDATE = 'BRILLO_SDK_NO_UPDATE'
# To fake the repo command into accepting a simple manifest, we
# have to put that manifest into a git repository. This is the
# name of that repo.
_BRILLO_SDK_LOCAL_MANIFEST_REPO = '.local_manifest_repo'
def _ResolveLatest(gs_ctx):
"""Find the 'latest' SDK release."""
return gs_ctx.Cat(constants.BRILLO_LATEST_RELEASE_URL).strip()
def _UpdateWorkspaceSdk(gs_ctx, bootstrap_path, workspace_path, version):
"""Install specified SDK, and associate the workspace with it.
Args:
gs_ctx: GS Context to use.
bootstrap_path: Directory to the bootstrap.
workspace_path: Directory that holds the workspace.
version: Project SDK version to sync.
"""
if project_sdk.FindRepoRoot(bootstrap_path):
cros_build_lib.Die('brillo sdk must run from a git clone. brbug.com/580')
sdk_path = bootstrap_lib.ComputeSdkPath(bootstrap_path, version)
# If this version already exists, no need to reinstall it.
if not os.path.exists(sdk_path) or version == 'tot':
_UpdateSdk(gs_ctx, sdk_path, version)
# Store the new version in the workspace.
workspace_lib.SetActiveSdkVersion(workspace_path, version)
def _UpdateSdk(gs_ctx, sdk_dir, version):
"""Install the specified SDK at the specified location.
Args:
gs_ctx: GS Context to use.
sdk_dir: Directory in which to create a repo.
version: Project SDK version to sync.
"""
# Create the SDK dir, if it doesn't already exist.
osutils.SafeMakedirs(sdk_dir)
logging.notice('Fetching files. This could take a few minutes...')
# TOT is a special case, handle it first.
if version.lower() == 'tot':
# Init new repo.
repo = repository.RepoRepository(
constants.MANIFEST_URL, sdk_dir, groups='project_sdk')
# Sync it.
repo.Sync()
return
with tempfile.NamedTemporaryFile() as manifest:
# Fetch manifest into temp file.
manifest_url = os.path.join(constants.BRILLO_RELEASE_MANIFESTS_URL,
'%s.xml' % version)
gs_ctx.Copy(manifest_url, manifest.name)
manifest_git_dir = os.path.join(sdk_dir, _BRILLO_SDK_LOCAL_MANIFEST_REPO)
# Convert manifest into a git repository for the repo command.
repository.PrepManifestForRepo(manifest_git_dir, manifest.name)
# Fetch the SDK.
repo = repository.RepoRepository(manifest_git_dir, sdk_dir, depth=1)
repo.Sync()
# TODO(dgarrett): Embed this step into the manifest itself.
# Write out the SDK Version.
sdk_version_file = project_sdk.VersionFile(sdk_dir)
osutils.WriteFile(sdk_version_file, version)
def _HandleUpdate(bootstrap_path, workspace_path, sdk_dir, version):
"""Handle an update request for a variety of conditions.
Args:
bootstrap_path: Path to bootstrap location (or None).
workspace_path: Path to workspace location (or None).
sdk_dir: Directory in which to create a repo (or None).
version: Project SDK version to sync.
"""
# We fetch versioned manifests from GS.
gs_ctx = gs.GSContext()
# Resolve 'latest' into a concrete version.
if version.lower() == 'latest':
version = _ResolveLatest(gs_ctx)
if sdk_dir:
# Install the SDK to an explicit location.
_UpdateSdk(gs_ctx, sdk_dir, version)
elif workspace_path:
# If we are in a workspace, update the SDK for that workspace.
_UpdateWorkspaceSdk(gs_ctx, bootstrap_path, workspace_path, version)
def _FindVersion(workspace_path, sdk_dir):
"""Find SDK version of an existing specific sdk_dir.
Args:
workspace_path: Path to workspace location (or None).
sdk_dir: Directory in which to create a repo (or None).
"""
if sdk_dir:
# This will find a version, if it's an official release manifest checkout.
version = project_sdk.FindVersion(sdk_dir)
if version is None:
# If it's not official, use a heuristic to see if it's an SDK at all.
sdk_root = project_sdk.FindRepoRoot(sdk_dir)
expected = ('chromite', 'src')
if (sdk_root and
all([os.path.exists(os.path.join(sdk_root, d)) for d in expected])):
version = 'Unofficial SDK'
return version
if workspace_path:
return workspace_lib.GetActiveSdkVersion(workspace_path)
return None
def _SelfUpdate(bootstrap_path):
"""Update the bootstrap repository."""
# If our bootstrap is part of a repository, we shouldn't update.
if project_sdk.FindRepoRoot(bootstrap_path):
return
# If the 'skip update' variable is set, we shouldn't update.
if os.environ.get(_BRILLO_SDK_NO_UPDATE):
return
# Perform the git pull to update our bootstrap.
logging.info('Updating SDK bootstrap...')
git.RunGit(bootstrap_path, ['pull'])
# Prevent updating again, after we restart.
logging.debug('Re-exec...')
os.environ[_BRILLO_SDK_NO_UPDATE] = "1"
commandline.ReExec()
@command.CommandDecorator('sdk')
class SdkCommand(command.CliCommand):
"""Manage Project SDK installations."""
@classmethod
def AddParser(cls, parser):
super(cls, SdkCommand).AddParser(parser)
# Expanduser is used to get ~ expanaded for "--sdk-dir=~/foo".
parser.add_argument(
'--sdk-dir', type='path',
help='Force install to specific directory.')
parser.add_argument(
'--update', help='Update the SDK to version 1.2.3, tot, latest')
def Run(self):
"""Run brillo sdk."""
self.options.Freeze()
# Must run outside the chroot.
cros_build_lib.AssertOutsideChroot()
workspace_path = workspace_lib.WorkspacePath()
sdk_dir = self.options.sdk_dir
if not sdk_dir and not workspace_path:
cros_build_lib.Die('You must be in a workspace, or specifiy --sdk-dir.')
# Perform the update.
if self.options.update:
bootstrap_path = bootstrap_lib.FindBootstrapPath()
logging.info('Update bootstrap...')
_SelfUpdate(bootstrap_path)
logging.notice('Updating SDK...')
_HandleUpdate(
bootstrap_path, workspace_path, sdk_dir, self.options.update)
# Find the version (possibly post-update). We re-detect as a
# temp hack for discovering what version 'latest' resolved as.
version = _FindVersion(workspace_path, sdk_dir)
if version is None:
cros_build_lib.Die('No valid SDK found.')
logging.notice('Version: %s', version)