Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: only clone init templates when required #4817

Merged
merged 14 commits into from
Mar 7, 2023
Merged
27 changes: 21 additions & 6 deletions samcli/commands/init/init_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import re
from enum import Enum
from pathlib import Path
from subprocess import STDOUT, CalledProcessError, check_output
from typing import Dict, Optional

import requests
Expand Down Expand Up @@ -87,13 +88,16 @@ def clone_templates_repo(self):
os_name = system().lower()
cloned_folder_name = APP_TEMPLATES_REPO_NAME_WINDOWS if os_name == "windows" else APP_TEMPLATES_REPO_NAME

to_upsert = self._check_upsert_templates(shared_dir, cloned_folder_name)

try:
self._git_repo.clone(
clone_dir=shared_dir,
clone_name=cloned_folder_name,
replace_existing=True,
commit=APP_TEMPLATES_REPO_COMMIT,
)
if to_upsert:
self._git_repo.clone(
clone_dir=shared_dir,
clone_name=cloned_folder_name,
replace_existing=True,
commit=APP_TEMPLATES_REPO_COMMIT,
)
except CloneRepoUnstableStateException as ex:
raise AppTemplateUpdateException(str(ex)) from ex
except (OSError, CloneRepoException):
Expand All @@ -102,6 +106,17 @@ def clone_templates_repo(self):
if expected_previous_clone_local_path.exists():
self._git_repo.local_path = expected_previous_clone_local_path

def _check_upsert_templates(self, shared_dir, cloned_folder_name):
cache_dir = shared_dir / cloned_folder_name
git_executable = self._git_repo.get_git_executable()
command = [git_executable, "rev-parse", "--verify", "HEAD"]
try:
existing_hash = check_output(command, cwd=cache_dir, stderr=STDOUT).decode("utf-8").strip()
except CalledProcessError:
LOG.error("Unable to check existing cache hash")
return True
return not existing_hash == APP_TEMPLATES_REPO_COMMIT

def _init_options_from_manifest(self, package_type, runtime, base_image, dependency_manager):
manifest_path = self.get_manifest_path()
with open(str(manifest_path)) as fp:
Expand Down
5 changes: 4 additions & 1 deletion samcli/lib/utils/git_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ def _ensure_clone_directory_exists(clone_dir: Path) -> None:
LOG.warning("WARN: Unable to create clone directory.", exc_info=ex)
raise

def get_git_executable(self):
return self._git_executable()

@staticmethod
def _git_executable() -> str:
if platform.system().lower() == "windows":
Expand Down Expand Up @@ -172,7 +175,7 @@ def _persist_local_repo(temp_path: str, dest_dir: Path, dest_name: str, replace_

LOG.debug("Copying from %s to %s", temp_path, dest_path)
# Todo consider not removing the .git files/directories
shutil.copytree(temp_path, dest_path, ignore=shutil.ignore_patterns("*.git"))
shutil.copytree(temp_path, dest_path)
return Path(dest_path)
except (OSError, shutil.Error) as ex:
# UNSTABLE STATE
Expand Down
5 changes: 4 additions & 1 deletion tests/unit/commands/init/test_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from pathlib import Path
from re import search
from unittest import TestCase
from unittest.mock import mock_open, patch, PropertyMock
from unittest.mock import mock_open, patch, PropertyMock, Mock

from samcli.commands.init.init_templates import InitTemplates
from samcli.lib.utils.packagetype import IMAGE, ZIP
Expand All @@ -15,6 +15,7 @@ class TestTemplates(TestCase):
@patch("shutil.copytree")
def test_location_from_app_template_zip(self, subprocess_mock, git_exec_mock, cd_mock, copy_mock):
it = InitTemplates()
it._check_upsert_templates = Mock()

manifest = {
"ruby2.7": [
Expand All @@ -36,12 +37,14 @@ def test_location_from_app_template_zip(self, subprocess_mock, git_exec_mock, cd
location = it.location_from_app_template(ZIP, "ruby2.7", None, "bundler", "hello-world")
self.assertTrue(search("mock-ruby-template", location))

@patch("samcli.lib.utils.init_templates.")
@patch("samcli.lib.utils.git_repo.check_output")
@patch("samcli.lib.utils.git_repo.GitRepo._git_executable")
@patch("samcli.lib.utils.git_repo.GitRepo._ensure_clone_directory_exists")
@patch("shutil.copytree")
def test_location_from_app_template_image(self, subprocess_mock, git_exec_mock, cd_mock, copy_mock):
it = InitTemplates()
it._check_upsert_templates = Mock()

manifest = {
"ruby2.7-image": [
Expand Down