blob: ccab0dbc4c284e88c985f30eaf597fb443e2ecca [file] [log] [blame]
# Copyright 2021 The Chromium 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 PB.recipes.infra.windows_image_builder import windows_image_builder as wib
from . import helper
GIT_URL = '{}/+/{}/{}'
class GITManager:
"""
GITManager is used to download required artifacts from git and generate
a pinned config for the downloaded artifacts. It uses gitiles to pin the
sources to refs, but downloads them using git. This is done as image
processor should be able to pin the sources without having to download
them, as depending on the result of the pinning. We might not need to
download them.
"""
def __init__(self, module, cache):
""" __init__ copies few module objects and cache dir path into class vars
Args:
* module: module object with all dependencies
* cache: path to cache file dir. Files from git will be saved here
"""
self.m = module
self._cache = cache
# cache stored as dict with url as key and pinned src as value
self._pinning_cache = {}
# cache stored as dict with url as key and downloaded src as value
self._downloads_cache = {}
# set of existing git urls.
# Note: There is a remote possibility that file might be removed/deleted in
# git after we record it's existence. This should still be okay as we are
# checking for existence after pinning. If the file is deleted, it should
# be part of a new commit.
self._existence = set()
def pin_package(self, git_src):
""" pin_package replaces a volatile ref to deterministic ref in given
git_src
Args:
* git_src: proto GITSrc object representing a volatol
"""
url = self.get_gitiles_url(git_src)
if url in self._pinning_cache:
return self._pinning_cache[url]
else:
commits, _ = self.m.gitiles.log(git_src.repo,
git_src.ref + '/' + git_src.src)
if len(commits) == 0:
raise Exception("No commits were found")
# pin the file to the latest available commit
git_src.ref = commits[0]['commit']
self._pinning_cache[url] = git_src
# as we know this file exists
self._existence.add(url)
return git_src
def download_package(self, git_src):
""" download_package downloads the given package to the downloads dir
Args:
* git_src: proto GITSrc object representing the artifact to be downloaded
"""
with self.m.step.nest(
'Download {}'.format(self.get_gitiles_url(git_src)), status='last'):
local_path = self.get_local_src(git_src)
if not local_path in self._downloads_cache:
download_path = self._cache / git_src.ref
self.m.git.checkout(
step_suffix=git_src.src,
url=git_src.repo,
dir_path=download_path,
ref=git_src.ref,
file_name=git_src.src)
self._downloads_cache[local_path] = git_src
return local_path
def get_gitiles_url(self, git_src):
""" get_gitiles_url returns string representing an url for the given source
Args:
* git_src: sources.GITSrc object representing an object
"""
return GIT_URL.format(git_src.repo, git_src.ref, git_src.src)
def get_local_src(self, git_src):
""" get_local_src returns the location of the downloaded package in
disk
Args:
* git_src: sources.GITSrc object
"""
# src is usually given as a unix path. Ensure this works on windows too
src = git_src.src.split('/')
# ref can be given as an unix path too.
ref = git_src.ref.split('/')
# Add all the path names together
ref.extend(src)
return self._cache.joinpath(*ref)
# TODO(anushruth): Cover this test path
def exists(self, git_src): #pragma: no cover
""" exists returns true if the package exists on gitiles.
Args:
*git_src: sources.GITSrc object representing a file in git
Reurns True if the file exists False otherwise.
"""
url = self.get_gitiles_url(git_src)
if url in self._existence:
return True
try:
commits, _ = self.m.gitiles.log(git_src.repo,
git_src.ref + '/' + git_src.src)
if commits:
self._existence.add(url)
return True
except Exception:
return False
return False