Skip to content

Commit

Permalink
Merge pull request #48 from devcontainers-contrib/release-0-4-45
Browse files Browse the repository at this point in the history
Release-0-4-45
  • Loading branch information
danielbraun89 authored Aug 16, 2023
2 parents 582aabc + a76655b commit 62dbb5c
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 59 deletions.
3 changes: 2 additions & 1 deletion .devcontainer/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ npm install -g @devcontainers/cli

pip install -e .[dev]

apt-get -y install qemu binfmt-support qemu-user-static
sudo apt-get update
sudo apt-get -y install qemu binfmt-support qemu-user-static

docker run --rm --privileged multiarch/qemu-user-static:latest --reset --credential yes -p yes
12 changes: 8 additions & 4 deletions nanolayer/installers/apt/apt_installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ def install(
cls.is_debian_like()
), "apt should be used on debian-like linux distribution (debian, ubuntu, raspian etc)"

software_properties_common_installed = False
support_packages_installed: List[str] = []
installed_ppas: List[str] = []

with tempfile.TemporaryDirectory() as tempdir:
if preserve_apt_list:
Expand All @@ -47,7 +48,10 @@ def install(
Invoker.invoke(command="apt update -y")

if ppas:
software_properties_common_installed = AptGetInstaller._add_ppas(
(
installed_ppas,
support_packages_installed,
) = AptGetInstaller._add_ppas(
ppas=ppas,
update=True,
force_ppas_on_non_ubuntu=force_ppas_on_non_ubuntu,
Expand All @@ -60,8 +64,8 @@ def install(
finally:
if clean_ppas:
AptGetInstaller._clean_ppas(
ppas=ppas,
remove_software_properties_common=software_properties_common_installed,
ppas=installed_ppas,
purge_packages=support_packages_installed,
)

if clean_cache:
Expand Down
82 changes: 52 additions & 30 deletions nanolayer/installers/apt_get/apt_get_installer.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import tempfile
from typing import List, Optional
import warnings
from typing import List, Optional, Tuple

from nanolayer.utils.invoker import Invoker
from nanolayer.utils.linux_information_desk import LinuxInformationDesk


class AptGetInstaller:
PPA_SUPPORT_PACKAGES = ("software-properties-common",)
PPA_SUPPORT_PACKAGES_DEBIAN = ("python3-launchpadlib",)

class AptGetInstallerError(Exception):
pass

Expand Down Expand Up @@ -33,48 +37,64 @@ def is_debian_like(cls) -> bool:

@classmethod
def _clean_ppas(
cls, ppas: List[str], remove_software_properties_common: bool
cls, ppas: List[str], purge_packages: Optional[List[str]] = None
) -> None:
normalized_ppas = cls.normalize_ppas(ppas)

for ppa in normalized_ppas:
Invoker.invoke(command=f"add-apt-repository -y --remove {ppa}")

if remove_software_properties_common:
Invoker.invoke(
command="apt-get -y purge software-properties-common --auto-remove"
)
if purge_packages is not None:
for package in purge_packages:
Invoker.invoke(command=f"apt-get -y purge {package} --auto-remove")

@classmethod
def _add_ppas(
cls, ppas: List[str], update: bool, force_ppas_on_non_ubuntu: bool = False
) -> bool:
software_properties_common_installed = False
cls,
ppas: Optional[List[str]] = None,
update: bool = True,
force_ppas_on_non_ubuntu: bool = False,
) -> Tuple[List[str], List[str]]:
installed_ppas: List[str] = []

if not ppas:
return software_properties_common_installed
installed_ppa_support_packages: List[str] = []

if not cls.is_ubuntu() and not force_ppas_on_non_ubuntu:
raise cls.AptGetInstallerError(
"in order to install ppas on non-ubuntu distros use the force-ppas-on-non-ubuntu flag"
if ppas is None:
ppas = []

if ppas and not cls.is_ubuntu() and not force_ppas_on_non_ubuntu:
warnings.warn(
"ppas are ignored on non-ubuntu distros!\n in order to include them anyway use the --force-ppas-on-non-ubuntu flag"
)
ppas = []

if not ppas:
return [], installed_ppa_support_packages

normalized_ppas = cls.normalize_ppas(ppas)

if (
Invoker.invoke("dpkg -s software-properties-common", raise_on_failure=False)
!= 0
):
Invoker.invoke(command="apt-get install -y software-properties-common")
software_properties_common_installed = True
required_ppa_support_package = (
cls.PPA_SUPPORT_PACKAGES
if cls.is_ubuntu()
else cls.PPA_SUPPORT_PACKAGES + cls.PPA_SUPPORT_PACKAGES_DEBIAN
)

for ppa_support_package in required_ppa_support_package:
if (
Invoker.invoke(f"dpkg -s {ppa_support_package}", raise_on_failure=False)
!= 0
):
Invoker.invoke(command=f"apt-get install -y {ppa_support_package}")
installed_ppa_support_packages.append(ppa_support_package)

for ppa in normalized_ppas:
Invoker.invoke(command=f"add-apt-repository -y {ppa}")
installed_ppas.append(ppa)

if update:
Invoker.invoke(command="apt-get update -y")

return software_properties_common_installed
return installed_ppas, installed_ppa_support_packages

@classmethod
def install(
Expand All @@ -86,24 +106,26 @@ def install(
clean_cache: bool = True,
preserve_apt_list: bool = True,
) -> None:
if ppas is None:
ppas = []

assert (
cls.is_debian_like()
), "apt-get should be used on debian-like linux distribution (debian, ubuntu, raspian etc)"

software_properties_common_installed = False
support_packages_installed: List[str] = []
installed_ppas: List[str] = []

with tempfile.TemporaryDirectory() as tempdir:
if preserve_apt_list:
Invoker.invoke(command=f"cp -p -R /var/lib/apt/lists {tempdir}")

try:
Invoker.invoke(command="apt-get update -y")

if ppas:
software_properties_common_installed = cls._add_ppas(
ppas,
update=True,
force_ppas_on_non_ubuntu=force_ppas_on_non_ubuntu,
)
installed_ppas, support_packages_installed = cls._add_ppas(
ppas, update=True, force_ppas_on_non_ubuntu=force_ppas_on_non_ubuntu
)

Invoker.invoke(
command=f"apt-get install -y --no-install-recommends {' '.join(packages)}"
Expand All @@ -112,8 +134,8 @@ def install(
finally:
if ppas and clean_ppas:
cls._clean_ppas(
ppas=ppas,
remove_software_properties_common=software_properties_common_installed,
ppas=installed_ppas,
purge_packages=support_packages_installed,
)

if clean_cache:
Expand Down
17 changes: 10 additions & 7 deletions nanolayer/installers/aptitude/aptitude_installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,28 +29,31 @@ def install(
cls.is_debian_like()
), "aptitude should be used on debian-like linux distribution (debian, ubuntu, raspian etc)"

software_properties_common_installed = False
support_packages_installed: List[str] = []
installed_ppas: List[str] = []
aptitude_installed = False

with tempfile.TemporaryDirectory() as tempdir:
try:
if preserve_apt_list:
Invoker.invoke(command=f"cp -p -R /var/lib/apt/lists {tempdir}")

Invoker.invoke(command="apt-get update -y")

# ensure aptitude existance
if Invoker.invoke("dpkg -s aptitude", raise_on_failure=False) != 0:
AptGetInstaller.install(
packages=["aptitude"],
ppas=ppas,
force_ppas_on_non_ubuntu=force_ppas_on_non_ubuntu,
clean_ppas=clean_ppas,
clean_cache=clean_cache,
preserve_apt_list=preserve_apt_list,
)
aptitude_installed = True

if ppas:
software_properties_common_installed = AptGetInstaller._add_ppas(
(
installed_ppas,
support_packages_installed,
) = AptGetInstaller._add_ppas(
ppas=ppas,
update=True,
force_ppas_on_non_ubuntu=force_ppas_on_non_ubuntu,
Expand All @@ -61,8 +64,8 @@ def install(
finally:
if clean_ppas:
AptGetInstaller._clean_ppas(
ppas=ppas,
remove_software_properties_common=software_properties_common_installed,
ppas=installed_ppas,
purge_packages=support_packages_installed,
)

if clean_cache:
Expand Down
3 changes: 3 additions & 0 deletions nanolayer/utils/invoker.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ def invoke(
if clean_history:
envs["HISTFILE"] = "/dev/null"

if "DEBIAN_FRONTEND" not in envs:
envs["DEBIAN_FRONTEND"] = "noninteractive"

response = invoke.run(
command,
out_stream=sys.stdout,
Expand Down
8 changes: 4 additions & 4 deletions tests/installers/apt/test_apt_installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,23 @@
"neovim",
"ppa:neovim-ppa/stable",
"nvim --version",
"mcr.microsoft.com/devcontainers/base:debian",
1,
"mcr.microsoft.com/vscode/devcontainers/python:3.10-bullseye",
0,
"linux/amd64",
),
(
"neovim",
"",
"nvim --version",
"mcr.microsoft.com/devcontainers/base:debian",
"mcr.microsoft.com/vscode/devcontainers/python:3.10-bullseye",
0,
"linux/amd64",
),
(
"neovim",
"",
"nvim --version",
"mcr.microsoft.com/devcontainers/base:debian",
"mcr.microsoft.com/vscode/devcontainers/python:3.10-bullseye",
0,
"linux/arm64",
),
Expand Down
25 changes: 16 additions & 9 deletions tests/installers/apt_get/test_apt_get_installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,52 +5,59 @@


@pytest.mark.parametrize(
"packages,ppas,test_command,image,excpected_result,docker_platform",
"packages,additional_flags,test_command,image,excpected_result,docker_platform",
[
(
"neovim",
"ppa:neovim-ppa/stable",
"--ppas ppa:neovim-ppa/stable",
"nvim --version",
"mcr.microsoft.com/devcontainers/base:ubuntu",
0,
"linux/amd64",
),
(
"neovim",
"ppa:neovim-ppa/stable",
"--ppas ppa:neovim-ppa/stable",
"nvim --version",
"mcr.microsoft.com/devcontainers/base:debian",
"mcr.microsoft.com/vscode/devcontainers/python:3.10-bullseye", # debian based
0,
"linux/amd64",
),
(
"neovim",
"--ppas ppa:neovim-ppa/stable --force-ppas-on-non-ubuntu",
"nvim --version",
"mcr.microsoft.com/vscode/devcontainers/python:3.10-bullseye", # debian based
1,
"linux/amd64",
),
(
"neovim",
"",
"nvim --version",
"mcr.microsoft.com/devcontainers/base:debian",
"mcr.microsoft.com/vscode/devcontainers/python:3.10-bullseye",
0,
"linux/amd64",
),
(
"neovim",
"",
"nvim --version",
"mcr.microsoft.com/devcontainers/base:debian",
"mcr.microsoft.com/vscode/devcontainers/python:3.10-bullseye",
0,
"linux/arm64",
),
],
)
def test_apt_get_install(
packages: str,
ppas: str,
additional_flags: str,
test_command,
image: str,
excpected_result: int,
docker_platform: str,
) -> None:
ppas_cmd = f" --ppas {ppas} " if ppas else ""
full_test_command = f"sudo PYTHONPATH=$PYTHONPATH python3 -m nanolayer install apt-get {packages} {ppas_cmd} && {test_command}"
full_test_command = f"sudo PYTHONPATH=$PYTHONPATH python3 -m nanolayer install apt-get {packages} {additional_flags} && {test_command}"

assert excpected_result == execute_current_python_in_container(
test_command=full_test_command, image=image, docker_platform=docker_platform
Expand Down
8 changes: 4 additions & 4 deletions tests/installers/aptitude/test_aptitude_installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,23 @@
"neovim",
"ppa:neovim-ppa/stable",
"nvim --version",
"mcr.microsoft.com/devcontainers/base:debian",
1,
"mcr.microsoft.com/vscode/devcontainers/python:3.10-bullseye",
0,
"linux/amd64",
),
(
"neovim",
"",
"nvim --version",
"mcr.microsoft.com/devcontainers/base:debian",
"mcr.microsoft.com/vscode/devcontainers/python:3.10-bullseye",
0,
"linux/amd64",
),
(
"neovim",
"",
"nvim --version",
"mcr.microsoft.com/devcontainers/base:debian",
"mcr.microsoft.com/vscode/devcontainers/python:3.10-bullseye",
0,
"linux/arm64",
),
Expand Down

0 comments on commit 62dbb5c

Please sign in to comment.