├── .dockerignore ├── .github ├── FUNDING.yml └── workflows │ ├── continuous-builds.yml │ └── stable-releases.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── MANIFEST.in ├── Pipfile ├── README.md ├── appimagebuilder ├── __init__.py ├── __main__.py ├── cli │ ├── __init__.py │ └── argparse.py ├── commands │ ├── __init__.py │ ├── apt_deploy.py │ ├── command.py │ ├── create_appimage.py │ ├── deploy_record.py │ ├── file_deploy.py │ ├── pacman_deploy.py │ ├── run_script.py │ ├── run_test.py │ ├── setup_app_info.py │ ├── setup_runtime.py │ └── setup_symlinks.py ├── context.py ├── invoker.py ├── modules │ ├── __init__.py │ ├── analisys │ │ ├── __init__.py │ │ ├── app_runtime_analyser.py │ │ ├── appimage_mount.py │ │ └── inspector.py │ ├── appimage.py │ ├── deploy │ │ ├── __init__.py │ │ ├── apt │ │ │ ├── __init__.py │ │ │ ├── deploy.py │ │ │ ├── errors.py │ │ │ ├── listings.py │ │ │ ├── package.py │ │ │ └── venv.py │ │ ├── files │ │ │ ├── __init__.py │ │ │ ├── dependencies_resolver │ │ │ │ ├── __init__.py │ │ │ │ ├── base_resolver.py │ │ │ │ ├── elf_resolver.py │ │ │ │ └── resolver.py │ │ │ └── deploy_helper.py │ │ ├── pacman │ │ │ ├── __init__.py │ │ │ ├── deploy.py │ │ │ └── venv.py │ │ └── util.py │ ├── generate │ │ ├── __init__.py │ │ ├── apt_recipe_generator.py │ │ ├── bundle_info_gatherer.py │ │ ├── bundle_info_gatherer_cli.py │ │ ├── bundle_info_gatherer_ui.py │ │ ├── command_generate.py │ │ ├── desktop_entry_parser.py │ │ ├── package_managers │ │ │ ├── __init__.py │ │ │ ├── apt │ │ │ │ ├── __init__.py │ │ │ │ ├── file_package_resolver.py │ │ │ │ ├── package_filter.py │ │ │ │ └── package_repository_resolver.py │ │ │ └── pacman │ │ │ │ ├── __init__.py │ │ │ │ └── file_package_resolver.py │ │ ├── recipe_generator.py │ │ └── recipe_sections │ │ │ ├── __init__.py │ │ │ ├── apt_section_generator.py │ │ │ ├── files_section_generator.py │ │ │ ├── package_manager_recipe_section_generator.py │ │ │ ├── pacman_section_generator.py │ │ │ └── test_section_generator.py │ ├── prime │ │ ├── __init__.py │ │ ├── appimage_primer.py │ │ ├── base_primer.py │ │ └── errors.py │ ├── setup │ │ ├── __init__.py │ │ ├── apprun_2 │ │ │ ├── __init__.py │ │ │ ├── apprun2.py │ │ │ ├── executables.py │ │ │ ├── executables_patcher.py │ │ │ └── executables_scanner.py │ │ ├── apprun_3 │ │ │ ├── __init__.py │ │ │ ├── app_dir_info.py │ │ │ ├── apprun3.py │ │ │ ├── apprun3_context.py │ │ │ └── helpers │ │ │ │ ├── base_helper.py │ │ │ │ ├── gdk_pixbuf.py │ │ │ │ ├── glib.py │ │ │ │ ├── glibc_module.py │ │ │ │ ├── glibstcpp_module.py │ │ │ │ ├── gstreamer.py │ │ │ │ ├── python.py │ │ │ │ └── qt.py │ │ ├── apprun_binaries_resolver.py │ │ ├── apprun_utils.py │ │ ├── desktop_entry_generator.py │ │ ├── environment.py │ │ ├── file_matching_patterns.py │ │ ├── helpers │ │ │ ├── __init__.py │ │ │ ├── apprun_2_libc.py │ │ │ ├── base_helper.py │ │ │ ├── gdk_pixbuf.py │ │ │ ├── glib.py │ │ │ ├── gstreamer.py │ │ │ ├── gtk.py │ │ │ ├── java.py │ │ │ ├── libgl.py │ │ │ ├── mime.py │ │ │ ├── openssl.py │ │ │ ├── python.py │ │ │ └── qt.py │ │ └── icon_bundler.py │ └── test │ │ ├── __init__.py │ │ ├── dependencies_test.py │ │ ├── errors.py │ │ └── execution_test.py ├── orchestrator.py ├── recipe │ ├── __init__.py │ ├── errors.py │ ├── loader.py │ ├── roamer.py │ └── schema.py └── utils │ ├── __init__.py │ ├── appimagetool.py │ ├── command.py │ ├── dpkg_architecture.py │ ├── dpkg_query.py │ ├── elf.py │ ├── file_utils.py │ ├── finder.py │ ├── patchelf.py │ ├── shell.py │ └── symlinks.py ├── recipes ├── appimage-builder │ └── AppImageBuilder.yml ├── bash-files │ └── AppImageBuilder.yml ├── bash-pacman │ └── AppImageBuilder.yml ├── bash │ ├── AppImageBuilder.yml │ ├── bash-apprun-v3.yml │ ├── run_tests.sh │ └── tests │ │ ├── exec_script.sh │ │ ├── exec_script_with_env_at_shebang.sh │ │ └── exec_script_with_external_shell.sh ├── gimp │ └── AppImageBuilder.yml ├── gnome-calculator │ └── AppImageBuilder.yml ├── hello-world-gtk │ ├── AppImageBuilder.yml │ └── main.cpp ├── hello-world-qt5 │ ├── AppImageBuilder.yml │ ├── recipe-with-apprun-v3.yml │ └── src │ │ ├── CMakeLists.txt │ │ ├── main.cpp │ │ ├── main.qml │ │ └── qml.qrc ├── hello-world-qt6 │ ├── AppImageBuilder.yml │ └── src │ │ ├── CMakeLists.txt │ │ ├── main.cpp │ │ └── main.qml ├── kcalc-files │ └── AppImageBuilder.yml ├── kcalc-nbc │ └── AppImageBuilder.yml ├── kcalc │ └── AppImageBuilder.yml ├── parole │ └── AppImageBuilder.yml ├── pyqt5 │ ├── AppImageBuilder.yml │ ├── main.py │ └── requirements.txt ├── python │ ├── AppImageBuilder.yml │ ├── one.py │ └── two.py ├── qmlscene │ ├── AppImageBuilder.yml │ └── main.qml ├── tkinter │ ├── AppImageBuilder.yml │ ├── main.py │ └── requirements.txt ├── vlc │ └── AppImageBuilder.yml ├── wget │ └── AppImageBuilder.yml └── wine │ └── AppImageBuilder.yml ├── requirements.txt ├── resources ├── appimage-builder.svg └── application-vnd.appimage.svg ├── setup.py └── tests ├── __init__.py ├── builder ├── __init__.py └── runtime │ ├── __init__.py │ ├── test_environment.py │ ├── test_executables.py │ └── test_executables_scanner.py ├── commands ├── __init__.py └── run_script.py ├── modules ├── __init__.py ├── deploy │ ├── __init__.py │ ├── apt │ │ ├── __init__.py │ │ ├── test_deploy.py │ │ ├── test_package.py │ │ └── test_venv.py │ ├── file │ │ ├── __init__.py │ │ └── dependencies_resolver │ │ │ ├── TestElfResolver.py │ │ │ └── __init__.py │ └── pacman │ │ ├── __init__.py │ │ ├── test_deploy.py │ │ ├── test_file_package_resolver.py │ │ └── test_venv.py ├── generate │ ├── __init__.py │ ├── fake_bundle_info_gatherer.py │ ├── fake_bundle_info_gatherer_ui.py │ ├── fake_desktop_entry_parser.py │ ├── fake_file_package_resolver.py │ ├── fake_package_manager_section_generator.py │ ├── fake_package_repository_resolver.py │ ├── fake_path.py │ ├── fake_runtime_analyser.py │ ├── test_apt_section_generator.py │ ├── test_bundle_info_gatherer.py │ └── test_recipe_generator.py └── setup │ ├── __init__.py │ └── test_executables_patcher.py ├── recipe ├── __init__.py └── test_validator.py └── utils ├── __init__.py ├── test_elf.py └── test_finder.py /.dockerignore: -------------------------------------------------------------------------------- 1 | # PyCharm 2 | .idea 3 | 4 | # git 5 | .github 6 | 7 | # Example builds 8 | /examples/*/AppDir 9 | /examples/*/appimage-builder-cache 10 | 11 | # Build results 12 | *.AppImage 13 | *.AppImage.zsync 14 | 15 | # Byte-compiled / optimized / DLL files 16 | __pycache__/ 17 | *.py[cod] 18 | *$py.class 19 | 20 | # C extensions 21 | *.so 22 | 23 | # Distribution / packaging 24 | .Python 25 | build/ 26 | develop-eggs/ 27 | dist/ 28 | downloads/ 29 | eggs/ 30 | .eggs/ 31 | lib/ 32 | lib64/ 33 | parts/ 34 | sdist/ 35 | var/ 36 | wheels/ 37 | pip-wheel-metadata/ 38 | share/python-wheels/ 39 | *.egg-info/ 40 | .installed.cfg 41 | *.egg 42 | MANIFEST 43 | 44 | # PyInstaller 45 | # Usually these files are written by a python script from a template 46 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 47 | *.manifest 48 | *.spec 49 | 50 | # Installer logs 51 | pip-log.txt 52 | pip-delete-this-directory.txt 53 | 54 | # Unit test / coverage reports 55 | htmlcov/ 56 | .tox/ 57 | .nox/ 58 | .coverage 59 | .coverage.* 60 | .cache 61 | nosetests.xml 62 | coverage.xml 63 | *.cover 64 | *.py,cover 65 | .hypothesis/ 66 | .pytest_cache/ 67 | 68 | # Translations 69 | *.mo 70 | *.pot 71 | 72 | # Sphinx documentation 73 | docs/_build/ 74 | 75 | # PyBuilder 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | .python-version 87 | 88 | # pipenv 89 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 90 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 91 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 92 | # install all needed dependencies. 93 | Pipfile.lock 94 | 95 | # Environments 96 | .env 97 | .venv 98 | env/ 99 | venv/ 100 | ENV/ 101 | env.bak/ 102 | venv.bak/ 103 | 104 | # mkdocs documentation 105 | /site 106 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | open_collective: appimage-crafters # Replace with a single Open Collective username 4 | 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # PyCharm 2 | .idea 3 | 4 | # vscode 5 | .vscode/* 6 | 7 | # Example builds 8 | /recipes/*/AppDir 9 | /recipes/*/appimage-build 10 | /recipes/*/appimage-builder-cache 11 | /AppDir 12 | /appimage-build 13 | /appimage-builder-cache 14 | 15 | 16 | # Build results 17 | *.AppImage 18 | *.AppImage.zsync 19 | 20 | # Byte-compiled / optimized / DLL files 21 | __pycache__/ 22 | *.py[cod] 23 | *$py.class 24 | 25 | # C extensions 26 | *.so 27 | 28 | # Distribution / packaging 29 | .Python 30 | build/ 31 | develop-eggs/ 32 | dist/ 33 | downloads/ 34 | eggs/ 35 | .eggs/ 36 | lib/ 37 | lib64/ 38 | parts/ 39 | sdist/ 40 | var/ 41 | wheels/ 42 | pip-wheel-metadata/ 43 | share/python-wheels/ 44 | *.egg-info/ 45 | .installed.cfg 46 | *.egg 47 | MANIFEST 48 | 49 | # PyInstaller 50 | # Usually these files are written by a python script from a template 51 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 52 | *.manifest 53 | *.spec 54 | 55 | # Installer logs 56 | pip-log.txt 57 | pip-delete-this-directory.txt 58 | 59 | # Unit test / coverage reports 60 | htmlcov/ 61 | .tox/ 62 | .nox/ 63 | .coverage 64 | .coverage.* 65 | .cache 66 | nosetests.xml 67 | coverage.xml 68 | *.cover 69 | *.py,cover 70 | .hypothesis/ 71 | .pytest_cache/ 72 | 73 | # Translations 74 | *.mo 75 | *.pot 76 | 77 | # Sphinx documentation 78 | docs/_build/ 79 | 80 | # PyBuilder 81 | target/ 82 | 83 | # Jupyter Notebook 84 | .ipynb_checkpoints 85 | 86 | # IPython 87 | profile_default/ 88 | ipython_config.py 89 | 90 | # pyenv 91 | .python-version 92 | 93 | # pipenv 94 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 95 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 96 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 97 | # install all needed dependencies. 98 | Pipfile.lock 99 | 100 | # Environments 101 | .env 102 | .venv 103 | env/ 104 | venv/ 105 | ENV/ 106 | env.bak/ 107 | venv.bak/ 108 | 109 | # mkdocs documentation 110 | /site 111 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | ENV DEBIAN_FRONTEND=noninteractive 3 | 4 | RUN apt-get update && \ 5 | apt-get -yq install \ 6 | breeze-icon-theme \ 7 | desktop-file-utils \ 8 | elfutils \ 9 | fakeroot \ 10 | file \ 11 | git \ 12 | gnupg2 \ 13 | gtk-update-icon-cache \ 14 | libgdk-pixbuf2.0-dev \ 15 | libglib2.0-bin \ 16 | librsvg2-dev \ 17 | libyaml-dev \ 18 | python3 \ 19 | python3-pip \ 20 | python3-setuptools \ 21 | strace \ 22 | wget \ 23 | squashfs-tools \ 24 | zsync && \ 25 | apt-get -yq autoclean 26 | 27 | WORKDIR /tmp 28 | RUN wget https://github.com/NixOS/patchelf/releases/download/0.12/patchelf-0.12.tar.bz2; \ 29 | tar -xvf patchelf-0.12.tar.bz2; \ 30 | cd patchelf-0.12.20200827.8d3a16e; \ 31 | ./configure && make && make install; \ 32 | rm -rf patchelf-* 33 | 34 | ADD . /opt/appimage-builder 35 | RUN python3 -m pip install /opt/appimage-builder 36 | RUN rm -rf /opt/appimage-builder 37 | 38 | WORKDIR / 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 Alexis Lopez Zubieta 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 4 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 5 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 6 | persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the 9 | Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 12 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 13 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 14 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include appimagebuilder/generator/templates/*.yml.in 2 | include appimagebuilder/tester/utils/* -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | black = "*" 8 | 9 | [packages] 10 | pyyaml = "*" 11 | docker = "*" 12 | requests = "*" 13 | schema = "*" 14 | packaging = "*" 15 | questionary = "*" 16 | emrichen = "*" 17 | shutils = "*" 18 | "ruamel.yaml" = "*" 19 | roam = "*" 20 | urllib3 = "==1.26.18" 21 | lief = "==0.12.2" 22 | python-gnupg = "==0.4.9" 23 | libconf = "*" 24 | pydpkg = "*" 25 | 26 | [requires] 27 | python_version = "3.8" 28 | -------------------------------------------------------------------------------- /appimagebuilder/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright 2020 Alexis Lopez Zubieta 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a 5 | # copy of this software and associated documentation files (the "Software"), 6 | # to deal in the Software without restriction, including without limitation the 7 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | # sell copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in 12 | # all copies or substantial portions of the Software. 13 | -------------------------------------------------------------------------------- /appimagebuilder/__main__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright 2021 Alexis Lopez Zubieta 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a 5 | # copy of this software and associated documentation files (the "Software"), 6 | # to deal in the Software without restriction, including without limitation the 7 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | # sell copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in 12 | # all copies or substantial portions of the Software. 13 | import logging 14 | import subprocess 15 | from importlib.metadata import version 16 | 17 | from appimagebuilder import recipe 18 | from appimagebuilder.cli.argparse import ArgumentsParser 19 | from appimagebuilder.modules.generate.command_generate import CommandGenerate 20 | from appimagebuilder.invoker import Invoker 21 | from appimagebuilder.orchestrator import Orchestrator 22 | 23 | 24 | def __main__(): 25 | parser = ArgumentsParser() 26 | args = parser.parse() 27 | 28 | _setup_logging_config(args) 29 | 30 | if args.version: 31 | print("appimage-builder:", version("appimage-builder")) 32 | exit(0) 33 | 34 | if args.generate: 35 | generator = CommandGenerate(args.appdir) 36 | generator.generate() 37 | exit(0) 38 | 39 | recipe_loader = recipe.Loader() 40 | raw_recipe_data = recipe_loader.load(args.recipe) 41 | recipe_roamer = recipe.Roamer(raw_recipe_data) 42 | 43 | schema = recipe.Schema() 44 | schema.validate(recipe_roamer) 45 | 46 | orchestrator = Orchestrator() 47 | commands = orchestrator.process(recipe_roamer, args) 48 | 49 | invoker = Invoker() 50 | invoker.execute(commands) 51 | 52 | 53 | def _setup_logging_config(args): 54 | numeric_level = getattr(logging, args.loglevel.upper()) 55 | if not isinstance(numeric_level, int): 56 | logging.error("Invalid log level: %s" % args.loglevel) 57 | 58 | logging.basicConfig(level=numeric_level) 59 | 60 | 61 | if __name__ == "__main__": 62 | # execute only if run as the entry point into the program 63 | __main__() 64 | -------------------------------------------------------------------------------- /appimagebuilder/cli/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | -------------------------------------------------------------------------------- /appimagebuilder/commands/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | from .command import Command 14 | from .apt_deploy import AptDeployCommand 15 | from .create_appimage import CreateAppImageCommand 16 | from .deploy_record import WriteDeployRecordCommand 17 | from .file_deploy import FileDeployCommand 18 | from .pacman_deploy import PacmanDeployCommand 19 | from .run_script import RunScriptCommand 20 | from .run_test import RunTestCommand 21 | from .setup_app_info import SetupAppInfoCommand 22 | from .setup_runtime import SetupRuntimeCommand 23 | from .setup_symlinks import SetupSymlinksCommand 24 | -------------------------------------------------------------------------------- /appimagebuilder/commands/apt_deploy.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | from pathlib import Path 13 | 14 | from appimagebuilder.commands import Command 15 | from appimagebuilder.context import Context 16 | from appimagebuilder.modules.deploy.apt import Deploy, Venv 17 | 18 | 19 | class AptDeployCommand(Command): 20 | def __init__( 21 | self, 22 | context: Context, 23 | packages: [str], 24 | exclude: [str] = None, 25 | architectures: [str] = None, 26 | sources: [str] = None, 27 | keys: [str] = None, 28 | allow_unauthenticated: str = None, 29 | ): 30 | super().__init__(context, "apt deploy") 31 | self.packages = packages 32 | self._exclude = exclude 33 | self._allow_unauthenticated = allow_unauthenticated 34 | self._keys = keys 35 | self._sources = sources 36 | self._architectures = architectures 37 | 38 | def id(self): 39 | return "apt-deploy" 40 | 41 | def __call__(self, *args, **kwargs): 42 | apt_venv = self._setup_apt_venv() 43 | 44 | apt_deploy = Deploy(apt_venv) 45 | 46 | deployed_packages = apt_deploy.deploy( 47 | self.packages, self.context.app_dir, self._exclude 48 | ) 49 | 50 | self.context.record["apt"] = { 51 | "sources": apt_venv.sources, 52 | "packages": deployed_packages, 53 | } 54 | 55 | def _setup_apt_venv(self): 56 | apt_options = { 57 | "APT::Get::AllowUnauthenticated": self._allow_unauthenticated, 58 | "Acquire::AllowInsecureRepositories": self._allow_unauthenticated, 59 | } 60 | apt_venv = Venv( 61 | str(Path(self.context.build_dir) / "apt"), 62 | self._sources, 63 | self._keys, 64 | self._architectures, 65 | apt_options, 66 | ) 67 | return apt_venv 68 | -------------------------------------------------------------------------------- /appimagebuilder/commands/command.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | from appimagebuilder.context import Context 13 | 14 | 15 | class Command: 16 | """Represent a single action in the AppImage creation process""" 17 | 18 | def __init__(self, context: Context, description): 19 | self.context = context 20 | self.description = description 21 | 22 | def id(self): 23 | pass 24 | 25 | def __call__(self, *args, **kwargs): 26 | pass 27 | -------------------------------------------------------------------------------- /appimagebuilder/commands/create_appimage.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | from appimagebuilder.modules.appimage import AppImageCreator 13 | from appimagebuilder.modules.prime import AppImagePrimer 14 | from appimagebuilder.commands.command import Command 15 | from appimagebuilder.recipe.roamer import Roamer 16 | 17 | 18 | class CreateAppImageCommand(Command): 19 | def __init__(self, context, recipe: Roamer): 20 | super().__init__(context, "AppImage creation") 21 | self.primer = AppImagePrimer(context) 22 | 23 | def id(self): 24 | return "prime-bundle" 25 | 26 | def __call__(self, *args, **kwargs): 27 | self.primer.prime() 28 | -------------------------------------------------------------------------------- /appimagebuilder/commands/deploy_record.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import logging 13 | import os 14 | 15 | from ruamel.yaml import YAML 16 | 17 | from appimagebuilder.commands.command import Command 18 | 19 | 20 | class WriteDeployRecordCommand(Command): 21 | def __init__(self, context): 22 | super().__init__(context, "deploy record generation") 23 | 24 | def id(self): 25 | return "write-deploy-record" 26 | 27 | def __call__(self, *args, **kwargs): 28 | path = self.context.app_dir / ".bundle.yml" 29 | with open(path, "w") as f: 30 | logging.info( 31 | "Writing deploy record to: %s" 32 | % os.path.relpath(path, self.context.app_dir) 33 | ) 34 | yaml = YAML() 35 | yaml.dump(self.context.record, f) 36 | -------------------------------------------------------------------------------- /appimagebuilder/commands/file_deploy.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | from appimagebuilder.commands import Command 13 | from appimagebuilder.context import Context 14 | from appimagebuilder.modules.deploy import FileDeploy 15 | 16 | 17 | class FileDeployCommand(Command): 18 | def __init__(self, context: Context, paths, exclude): 19 | super().__init__(context, "file deploy") 20 | self._paths = paths 21 | self._exclude = exclude 22 | 23 | def id(self): 24 | return "file-deploy" 25 | 26 | def __call__(self, *args, **kwargs): 27 | helper = FileDeploy(str(self.context.app_dir)) 28 | if self._paths: 29 | helper.deploy(self._paths) 30 | 31 | if self._exclude: 32 | helper.clean(self._exclude) 33 | -------------------------------------------------------------------------------- /appimagebuilder/commands/pacman_deploy.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | from pathlib import Path 13 | 14 | from appimagebuilder.commands import Command 15 | from appimagebuilder.context import Context 16 | from appimagebuilder.modules.deploy.pacman.deploy import Deploy 17 | from appimagebuilder.modules.deploy.pacman.venv import Venv 18 | 19 | 20 | class PacmanDeployCommand(Command): 21 | def __init__( 22 | self, 23 | context: Context, 24 | packages: [str], 25 | exclude: [str], 26 | architecture: str, 27 | repositories: [str], 28 | options: dict, 29 | ): 30 | super().__init__(context, "pacman deploy") 31 | 32 | self._packages = packages 33 | self._exclude = exclude 34 | self._architecture = architecture 35 | self._repositories = repositories 36 | self._options = options 37 | 38 | def id(self): 39 | return "pacman-deploy" 40 | 41 | def __call__(self, *args, **kwargs): 42 | venv = Venv( 43 | root=Path(self.context.build_dir) / "pacman", 44 | repositories=self._repositories, 45 | architecture=self._architecture, 46 | user_options=self._options, 47 | ) 48 | 49 | pacman_deploy = Deploy(venv) 50 | deployed_packages = pacman_deploy.deploy( 51 | self._packages, self.context.app_dir, self._exclude 52 | ) 53 | self.context.record["pacman"] = { 54 | "packages": deployed_packages, 55 | } 56 | -------------------------------------------------------------------------------- /appimagebuilder/commands/run_test.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import logging 13 | import os 14 | 15 | from .command import Command 16 | from appimagebuilder.recipe.roamer import Roamer 17 | from appimagebuilder.modules.test import ExecutionTest, TestFailed 18 | from ..context import Context 19 | 20 | import docker 21 | from docker.errors import DockerException 22 | 23 | class RunTestCommand(Command): 24 | def __init__(self, context: Context, tests_settings: Roamer): 25 | super().__init__(context, "AppDir tests") 26 | self.app_dir = context.app_dir 27 | self.tests_settings = tests_settings 28 | 29 | def id(self): 30 | return "test" 31 | 32 | def __call__(self, *args, **kwargs): 33 | try: 34 | test_cases = self._load_tests(self.tests_settings()) 35 | except DockerException as e: 36 | logging.error("Docker error : "+str(e)) 37 | logging.error("(Is docker installed/started ?)") 38 | logging.error("Tests will be skipped") 39 | return 40 | 41 | try: 42 | for test in test_cases: 43 | test.run() 44 | except TestFailed as err: 45 | logging.error("test failed") 46 | logging.error(err) 47 | 48 | exit(1) 49 | 50 | def _load_tests(self, test_settings: {}): 51 | test_cases = [] 52 | 53 | for name, data in test_settings.items(): 54 | data_accessor = Roamer(data) 55 | env = data_accessor.env() or [] 56 | if isinstance(env, dict): 57 | env = ["%s=%s" % (k, v) for k, v in env.items()] 58 | 59 | test = ExecutionTest( 60 | appdir=self.app_dir, 61 | name=name, 62 | image=data_accessor.image(), 63 | command=data_accessor.command(), 64 | before_command=data_accessor.before_command(), 65 | env=env, 66 | ) 67 | test_cases.append(test) 68 | 69 | return test_cases 70 | -------------------------------------------------------------------------------- /appimagebuilder/commands/setup_app_info.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | from appimagebuilder.modules.setup.desktop_entry_generator import ( 13 | DesktopEntryGenerator, 14 | ) 15 | from appimagebuilder.modules.setup.icon_bundler import IconBundler 16 | from appimagebuilder.context import AppInfo, Context 17 | from appimagebuilder.commands.command import Command 18 | 19 | 20 | class SetupAppInfoCommand(Command): 21 | def __init__(self, context: Context): 22 | super().__init__(context, "desktop entry setup") 23 | 24 | def id(self): 25 | return "app-info-setup" 26 | 27 | def __call__(self, *args, **kwargs): 28 | icon_bundler = IconBundler(self.context.app_dir, self.context.app_info.icon) 29 | icon_bundler.bundle_icon() 30 | 31 | desktop_entry_generator = DesktopEntryGenerator(self.context.app_dir) 32 | desktop_entry_generator.generate( 33 | self.context.app_info, self.context.bundle_info.runtime_arch 34 | ) 35 | -------------------------------------------------------------------------------- /appimagebuilder/commands/setup_runtime.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | from appimagebuilder.context import Context 13 | from appimagebuilder.modules.setup.apprun_2.apprun2 import AppRunV2Setup 14 | from appimagebuilder.commands.command import Command 15 | from packaging import version 16 | 17 | from appimagebuilder.modules.setup.apprun_3.apprun3 import AppRunV3Setup 18 | 19 | 20 | class SetupRuntimeCommand(Command): 21 | def __init__(self, context: Context, finder): 22 | super().__init__(context, "runtime setup") 23 | self.context = context 24 | self._finder = finder 25 | 26 | def id(self): 27 | return "runtime-setup" 28 | 29 | def __call__(self, *args, **kwargs): 30 | apprun_version = self.context.recipe.AppDir.runtime.version() or "v2.0.0" 31 | apprun_version = version.parse(apprun_version) 32 | runtime_setup = None 33 | if ( 34 | version.parse("v2.0.0") <= apprun_version < version.parse("v3.0.0") 35 | ) or apprun_version == version.parse("continuous"): 36 | runtime_setup = AppRunV2Setup(self.context, self._finder) 37 | 38 | if not runtime_setup and version.parse("v3.0.0-devel") <= apprun_version < version.parse("v4.0.0"): 39 | runtime_setup = AppRunV3Setup(self.context) 40 | 41 | if not runtime_setup: 42 | raise RuntimeError("Unsupported runtime version: %s" % apprun_version) 43 | 44 | runtime_setup.setup() 45 | -------------------------------------------------------------------------------- /appimagebuilder/commands/setup_symlinks.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import os 13 | import pathlib 14 | 15 | from appimagebuilder.recipe import Roamer 16 | from appimagebuilder.utils.finder import Finder 17 | from appimagebuilder.commands.command import Command 18 | 19 | 20 | class SetupSymlinksCommand(Command): 21 | def __init__(self, context, recipe: Roamer, finder: Finder): 22 | super().__init__(context, "symlinks setup") 23 | self._finder = finder 24 | 25 | self._preserve_files = self._finder.get_preserve_files( 26 | recipe.AppDir.runtime.preserve() or [] 27 | ) 28 | 29 | def id(self): 30 | return "symlinks-setup" 31 | 32 | def __call__(self, *args, **kwargs): 33 | for link in self._finder.find("*", [Finder.is_symlink]): 34 | if Finder.list_does_not_contain_file(self._preserve_files, link): 35 | relative_root = ( 36 | self.context.app_dir 37 | if "runtime/compat" not in str(link) 38 | else self.context.app_dir / "runtime" / "compat" 39 | ) 40 | self._make_symlink_relative(link, relative_root) 41 | 42 | @staticmethod 43 | def _make_symlink_relative(path, relative_root): 44 | path = pathlib.Path(path) 45 | relative_root = pathlib.Path(relative_root) 46 | 47 | if path.is_symlink(): 48 | target = pathlib.Path(os.readlink(path)) 49 | if target.is_absolute(): 50 | # workaround issue with concatenating paths using the "/" operator 51 | new_target = str(relative_root) + str(target) 52 | new_target = os.path.relpath(new_target, path.parent) 53 | 54 | path.unlink() 55 | path.symlink_to(new_target) 56 | -------------------------------------------------------------------------------- /appimagebuilder/invoker.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import logging 13 | 14 | from appimagebuilder.commands.command import Command 15 | 16 | 17 | class Invoker: 18 | """Execute a given set of tasks""" 19 | 20 | def __init__(self): 21 | self.logger = logging.getLogger("main") 22 | 23 | def execute(self, commands: [Command] = None): 24 | if not commands: 25 | commands = [] 26 | 27 | for command in commands: 28 | self.logger.info("Running %s", command.description) 29 | command() 30 | -------------------------------------------------------------------------------- /appimagebuilder/modules/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | -------------------------------------------------------------------------------- /appimagebuilder/modules/analisys/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | -------------------------------------------------------------------------------- /appimagebuilder/modules/analisys/appimage_mount.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import os 13 | import logging 14 | import subprocess 15 | 16 | 17 | class AppImageMount: 18 | def __init__(self, appimage_path): 19 | self._appimage_path = appimage_path 20 | self.path = None 21 | self._process = None 22 | 23 | def __del__(self): 24 | if self._process: 25 | self.unmount() 26 | 27 | def __enter__(self): 28 | self.mount() 29 | return self 30 | 31 | def __exit__(self): 32 | self.unmount() 33 | return self 34 | 35 | def mount(self): 36 | if self._process: 37 | raise RuntimeError("The target is mounted already") 38 | 39 | abs_target_path = os.path.abspath(self._appimage_path) 40 | self._process = subprocess.Popen( 41 | [abs_target_path, "--appimage-mount"], stdout=subprocess.PIPE 42 | ) 43 | self.path = self._process.stdout.readline().decode("utf-8").strip() 44 | ret_code = self._process.poll() 45 | 46 | if not ret_code: 47 | logging.info("AppImage mounted at: %s" % self.path) 48 | return self.path 49 | else: 50 | raise RuntimeError( 51 | "Unable to run: %s --appimage-mount" % self._appimage_path 52 | ) 53 | 54 | def unmount(self): 55 | self._process.kill() 56 | self._process.wait() 57 | 58 | self.path = None 59 | self._process = None 60 | 61 | logging.info("AppImage unmounted") 62 | -------------------------------------------------------------------------------- /appimagebuilder/modules/deploy/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | from .files.deploy_helper import FileDeploy 14 | 15 | from .apt.deploy import Deploy as AptDeploy 16 | from .apt.venv import Venv as AptVenv 17 | 18 | from .pacman.deploy import Deploy as PacmanDeploy 19 | from .pacman.venv import Venv as PacmanVenv 20 | 21 | from .util import make_symlink_relative 22 | -------------------------------------------------------------------------------- /appimagebuilder/modules/deploy/apt/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | from .deploy import Deploy 14 | from .venv import Venv 15 | 16 | from .errors import AptDeployError, AptVenvError 17 | -------------------------------------------------------------------------------- /appimagebuilder/modules/deploy/apt/errors.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | 14 | class AptDeployError(Exception): 15 | pass 16 | 17 | 18 | class AptVenvError(Exception): 19 | pass 20 | -------------------------------------------------------------------------------- /appimagebuilder/modules/deploy/apt/listings.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | 14 | """ 15 | Manually crafted lists of packages used to determine what should be excluded by default or deployed in 16 | a different partition. 17 | """ 18 | 19 | # libc, libstdc++ its close dependencies, those packages will be deployed to AppDir/runtime/compat 20 | glibc = ["libc6", "zlib1g", "libstdc++6"] 21 | 22 | # packages that apt and dpkg assume as installed 23 | apt_core = ["dpkg", "debconf", "apt"] 24 | 25 | # system service packages are usually safe to exclude 26 | system_services = [ 27 | "adduser", 28 | "avahi-daemon", 29 | "base-files", 30 | "bind9-host", 31 | "consolekit", 32 | "coreutils", 33 | "dbus", 34 | "debconf", 35 | "debianutils", 36 | "dpkg", 37 | "fdisk", 38 | "init-system-helpers", 39 | "iso-codes", 40 | "libcap2-bin", 41 | "libinput-bin", 42 | "libpam-modules-bin", 43 | "libpam-runtime", 44 | "lsb-base", 45 | "mount", 46 | "multiarch-support", 47 | "passwd", 48 | "shared-mime-info", 49 | "systemd", 50 | "systemd-sysv", 51 | "sysvinit-utils", 52 | "ucf", 53 | "util-linux", 54 | "xdg-user-dirs", 55 | # fontconfig can be excluded most of the time 56 | "fontconfig", 57 | "fontconfig-config", 58 | ] 59 | 60 | # because of issues with the nvidia driver and to achieve better performance the graphics 61 | # stack packages are also excluded by default 62 | graphics = [ 63 | "libdrm*", 64 | "libegl-*", 65 | "libegl1*", 66 | "libegl1-*", 67 | "libgbm*", 68 | "libgl1*", 69 | "libglapi*", 70 | "libgles*", 71 | "libglvnd*", 72 | "libglx*", 73 | "mesa-*", 74 | # the following X11/Wayland libraries are tightly related to the packages above 75 | "libx11-*", 76 | "libxcb-dri2-0", 77 | "libxcb-dri3-0", 78 | "libxcb-glx0", 79 | "libxcb-present0", 80 | "libxcb-render0", 81 | "libxcb-shape0", 82 | "libxcb-shm0", 83 | "libxcb-xfixes0", 84 | "libxcb1", 85 | "x11-common", 86 | "libwayland-*", 87 | ] 88 | 89 | default_exclude_list = [] 90 | default_exclude_list.extend(apt_core) 91 | default_exclude_list.extend(system_services) 92 | default_exclude_list.extend(graphics) 93 | -------------------------------------------------------------------------------- /appimagebuilder/modules/deploy/apt/package.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import re 13 | import urllib 14 | from pathlib import Path 15 | 16 | from pydpkg import Dpkg 17 | 18 | 19 | class Package: 20 | def __init__(self, name, version, arch): 21 | # remove arch from the name 22 | colon_idx = name.find(":") 23 | if colon_idx != -1: 24 | self.name = name[:colon_idx] 25 | self.arch = name[colon_idx + 1 :] 26 | else: 27 | self.name = name 28 | 29 | self.version = version 30 | self.arch = arch 31 | 32 | def get_expected_file_name(self): 33 | file_name = "%s_%s_%s.deb" % (self.name, self.version, self.arch) 34 | 35 | # apt encodes invalid chars to comply the deb file naming convention 36 | file_name = urllib.parse.quote(file_name, safe="+*~") 37 | 38 | # Only converts the case of letters from percent-encoding, not the entire string. 39 | file_name = re.sub( 40 | r"%[0-9A-Z]{2}", lambda matchobj: matchobj.group(0).lower(), file_name 41 | ) 42 | return file_name 43 | 44 | def get_apt_install_string(self): 45 | return "%s:%s=%s" % (self.name, self.arch, self.version) 46 | 47 | @staticmethod 48 | def from_file_path(path): 49 | path = Path(path) 50 | name_parts = path.stem.split("_") 51 | 52 | return Package( 53 | urllib.parse.unquote(name_parts[0]), 54 | urllib.parse.unquote(name_parts[1]), 55 | urllib.parse.unquote(name_parts[2]), 56 | ) 57 | 58 | def __eq__(self, other: object) -> bool: 59 | """Overrides the default implementation""" 60 | if isinstance(other, Package): 61 | return ( 62 | self.name == other.name 63 | and self.version == other.version 64 | and self.arch == other.arch 65 | ) 66 | return False 67 | 68 | def __str__(self): 69 | """apt input format""" 70 | output = self.name 71 | if self.arch: 72 | output = "%s:%s" % (output, self.arch) 73 | if self.version: 74 | output = "%s=%s" % (output, self.version) 75 | return output 76 | 77 | def __gt__(self, other): 78 | if isinstance(other, Package): 79 | return Dpkg.compare_versions(self.version, other.version) > 0 80 | 81 | def __hash__(self): 82 | return self.__str__().__hash__() 83 | -------------------------------------------------------------------------------- /appimagebuilder/modules/deploy/files/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AppImageCrafters/appimage-builder/bf6123ee43715e52d2a73639f9acb1251e8af640/appimagebuilder/modules/deploy/files/__init__.py -------------------------------------------------------------------------------- /appimagebuilder/modules/deploy/files/dependencies_resolver/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | -------------------------------------------------------------------------------- /appimagebuilder/modules/deploy/files/dependencies_resolver/base_resolver.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import pathlib 13 | 14 | 15 | class BaseResolver: 16 | def resolve(self, files: [pathlib.Path]) -> [pathlib.Path]: 17 | pass 18 | -------------------------------------------------------------------------------- /appimagebuilder/modules/deploy/files/dependencies_resolver/elf_resolver.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import os 13 | import pathlib 14 | import re 15 | import shutil 16 | import subprocess 17 | 18 | from .base_resolver import BaseResolver 19 | 20 | 21 | class ElfResolver(BaseResolver): 22 | def __init__(self): 23 | self.needed_libraries_cache = {} 24 | 25 | def resolve(self, files: [pathlib.Path]) -> [pathlib.Path]: 26 | results = [] 27 | for file in files: 28 | # skip files that are shown in results as their dependencies are also included 29 | if file not in results: 30 | file_results = self.resolve_needed_recursively(file) 31 | results.extend(file_results) 32 | 33 | return results 34 | 35 | def resolve_needed_recursively(self, file: pathlib) -> [str]: 36 | # use cache to speed up lookups 37 | if file in self.needed_libraries_cache: 38 | needed_libraries = self.needed_libraries_cache[file] 39 | else: 40 | needed_libraries = self._resolved_needed_using_ldd(file) 41 | self.needed_libraries_cache[file] = needed_libraries 42 | 43 | return needed_libraries 44 | 45 | @staticmethod 46 | def _resolved_needed_using_ldd(file): 47 | ldd_bin = shutil.which("ldd") 48 | 49 | # set locale to C to avoid output variations due localizations 50 | _proc_env = os.environ.copy() 51 | _proc_env["LC_ALL"] = "C" 52 | 53 | _proc = subprocess.run( 54 | [ldd_bin, str(file)], 55 | stdout=subprocess.PIPE, 56 | stderr=subprocess.PIPE, 57 | env=_proc_env, 58 | ) 59 | 60 | # process output 61 | output = _proc.stdout.decode() 62 | needed_libraries = [] 63 | for line in output.splitlines(): 64 | # match paths in lines 65 | path_search = re.search(r"(/.*)\s?\(", line) 66 | if path_search: 67 | path = path_search.group(1) 68 | needed_libraries.append(path.strip()) 69 | 70 | return needed_libraries 71 | -------------------------------------------------------------------------------- /appimagebuilder/modules/deploy/files/dependencies_resolver/resolver.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import pathlib 13 | 14 | from .base_resolver import BaseResolver 15 | from .elf_resolver import ElfResolver 16 | 17 | 18 | class Resolver(BaseResolver): 19 | """ 20 | Collection of heuristic methods to resolve application dependencies based of file paths. 21 | """ 22 | 23 | def __init__(self): 24 | self.resolvers = [ElfResolver()] 25 | 26 | def resolve(self, files: [pathlib.Path]) -> [pathlib.Path]: 27 | results = set() 28 | for resolver in self.resolvers: 29 | partial_results = resolver.resolve(files) 30 | results.update(partial_results) 31 | 32 | return list(results) 33 | -------------------------------------------------------------------------------- /appimagebuilder/modules/deploy/pacman/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | -------------------------------------------------------------------------------- /appimagebuilder/modules/deploy/util.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import os 13 | from pathlib import Path 14 | 15 | 16 | def make_symlink_relative(path, relative_root): 17 | path = Path(path) 18 | relative_root = Path(relative_root) 19 | 20 | if path.is_symlink(): 21 | target = Path(os.readlink(path)) 22 | if target.is_absolute(): 23 | # workaround issue with concatenating paths using the "/" operator 24 | new_target = str(relative_root) + str(target) 25 | new_target = os.path.relpath(new_target, path.parent) 26 | 27 | path.unlink() 28 | path.symlink_to(new_target) 29 | -------------------------------------------------------------------------------- /appimagebuilder/modules/generate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AppImageCrafters/appimage-builder/bf6123ee43715e52d2a73639f9acb1251e8af640/appimagebuilder/modules/generate/__init__.py -------------------------------------------------------------------------------- /appimagebuilder/modules/generate/bundle_info_gatherer_cli.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import questionary 13 | 14 | from appimagebuilder.modules.generate.bundle_info_gatherer_ui import ( 15 | BundleInfoGathererUi, 16 | ) 17 | 18 | 19 | class BundleInfoGathererCLI(BundleInfoGathererUi): 20 | def ask_text(self, text, default=None): 21 | # workaround "TypeError: object of type 'NoneType' has no len()" when default is None 22 | if default: 23 | question = questionary.text( 24 | message=text, default=default, validate=_not_empty_str 25 | ) 26 | else: 27 | question = questionary.text(message=text, validate=_not_empty_str) 28 | 29 | return question.ask() 30 | 31 | def ask_select(self, text, choices, default=None): 32 | # workaround "TypeError: object of type 'NoneType' has no len()" when default is None 33 | choices = [str(choice) for choice in choices] 34 | if default: 35 | question = questionary.select( 36 | message=text, choices=choices, default=default 37 | ) 38 | else: 39 | question = questionary.select(message=text, choices=choices) 40 | 41 | return question.ask() 42 | 43 | 44 | def _not_empty_str(val): 45 | return not not val 46 | -------------------------------------------------------------------------------- /appimagebuilder/modules/generate/bundle_info_gatherer_ui.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | 14 | class BundleInfoGathererUi: 15 | def ask_text(self, text, default=None): 16 | pass 17 | 18 | def ask_select(self, text, choices, default=None): 19 | pass 20 | -------------------------------------------------------------------------------- /appimagebuilder/modules/generate/desktop_entry_parser.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | import configparser 14 | import pathlib 15 | import shlex 16 | 17 | from appimagebuilder.context import AppInfo 18 | 19 | 20 | class DesktopEntryParser: 21 | def parse(self, entry_path) -> AppInfo: 22 | entry_path = pathlib.Path(entry_path) 23 | 24 | app_info = AppInfo() 25 | 26 | parser = configparser.RawConfigParser() 27 | parser.read(entry_path) 28 | 29 | app_info.id = entry_path.stem 30 | app_info.name = parser["Desktop Entry"]["Name"] 31 | app_info.icon = parser["Desktop Entry"]["Icon"] 32 | 33 | # process exec 34 | exec_str = parser["Desktop Entry"]["Exec"].strip() 35 | 36 | # convert desktop file exec args to bash notation 37 | exec_str = exec_str.replace("%f", "$1") 38 | exec_str = exec_str.replace("%F", "$@") 39 | exec_str = exec_str.replace("%U", "$@") 40 | exec_str = exec_str.replace("%u", "$1") 41 | 42 | exec_str_parts = shlex.split(exec_str) 43 | app_info.exec = exec_str_parts[0] 44 | 45 | if len(exec_str_parts) > 1: 46 | app_info.exec_args = " ".join(exec_str_parts[1:]) 47 | else: 48 | app_info.exec_args = "" 49 | 50 | return app_info 51 | -------------------------------------------------------------------------------- /appimagebuilder/modules/generate/package_managers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AppImageCrafters/appimage-builder/bf6123ee43715e52d2a73639f9acb1251e8af640/appimagebuilder/modules/generate/package_managers/__init__.py -------------------------------------------------------------------------------- /appimagebuilder/modules/generate/package_managers/apt/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | from .file_package_resolver import FilePackageResolver 14 | from .package_repository_resolver import PackageRepositoryResolver 15 | -------------------------------------------------------------------------------- /appimagebuilder/modules/generate/package_managers/apt/file_package_resolver.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import logging 13 | import subprocess 14 | import re 15 | import os 16 | 17 | from appimagebuilder.utils import shell 18 | 19 | CLI_REQUIRE = ["dpkg-query"] 20 | 21 | 22 | class FilePackageResolver: 23 | """Resolve which deb packages provide a given file using `dpkg-query -S`""" 24 | 25 | def __init__(self): 26 | self.logger = logging.getLogger(str(self.__class__.__name__)) 27 | self._cli_tools = shell.require_executables(CLI_REQUIRE) 28 | 29 | def resolve(self, files) -> {}: 30 | stdout_data = self._run_dpkg_query_s(files) 31 | results = self._parse_dpkg_query_s_output(stdout_data) 32 | 33 | return results 34 | 35 | def _run_dpkg_query_s(self, files): 36 | command = "{dpkg-query} -S {files}" 37 | command = command.format(**self._cli_tools, files=" ".join(files)) 38 | self.logger.info(command) 39 | _proc = subprocess.run(command, stdout=subprocess.PIPE, shell=True) 40 | stdout_data = _proc.stdout.decode() 41 | return stdout_data 42 | 43 | def _extract_package_names(self, pkg_names): 44 | match = re.match(r"diversion by (.+?) (to|from)", pkg_names) 45 | if match: 46 | extracted_names = match.group(1).strip() 47 | return extracted_names 48 | else: 49 | return pkg_names.strip() 50 | 51 | def _parse_dpkg_query_s_output(self, stdout_data): 52 | results = {} 53 | for line in stdout_data.splitlines(): 54 | line_parts = line.split(sep=": ", maxsplit=1) 55 | pkg_names = self._extract_package_names(line_parts[0]) 56 | file_path = line_parts[1] 57 | for pkg_name in pkg_names.split(","): 58 | pkg_name = pkg_name.strip() 59 | results[file_path] = pkg_name 60 | return results 61 | -------------------------------------------------------------------------------- /appimagebuilder/modules/generate/package_managers/apt/package_filter.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import fnmatch 13 | 14 | from appimagebuilder.modules.deploy.apt import listings 15 | from appimagebuilder.utils.dpkg_query import DpkgQuery 16 | 17 | 18 | class PackageFilter: 19 | """ 20 | Filters a given apt packages removing: 21 | - packages that are required by other packages in the list 22 | - packages that are known to reduce the bundle portability 23 | - packages that are useless in a bundle (i.e.: system services) 24 | """ 25 | 26 | def __init__(self): 27 | self.exclusion_patterns = set().union( 28 | listings.apt_core, listings.system_services, listings.graphics 29 | ) 30 | 31 | def filter(self, packages): 32 | # discard duplicates and ease future operations 33 | packages = set(packages) 34 | 35 | packages = self.discard_simblings(packages) 36 | packages = self.discard_blacklisted(packages) 37 | 38 | return packages 39 | 40 | def discard_blacklisted(self, packages): 41 | filtered_packages = set() 42 | for pkg in packages: 43 | pkg_name = pkg.split(":")[0] 44 | if not self._is_package_blacklisted(pkg_name): 45 | filtered_packages.add(pkg) 46 | 47 | return filtered_packages 48 | 49 | def _is_package_blacklisted(self, pkg_name): 50 | for pattern in self.exclusion_patterns: 51 | if fnmatch.fnmatch(pkg_name, pattern): 52 | return True 53 | return False 54 | 55 | def discard_simblings(self, packages): 56 | dpkg_query = DpkgQuery() 57 | dependency_map = dpkg_query.depends(packages) 58 | dependencies = set() 59 | for dependencies_list in dependency_map.values(): 60 | dependencies = dependencies.union(dependencies_list) 61 | 62 | filtered_packages = set() 63 | for pkg in packages: 64 | pkg_name = pkg.split(":")[0] 65 | if pkg_name not in dependencies: 66 | filtered_packages.add(pkg) 67 | 68 | return filtered_packages 69 | -------------------------------------------------------------------------------- /appimagebuilder/modules/generate/package_managers/apt/package_repository_resolver.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import logging 13 | import pathlib 14 | 15 | 16 | class PackageRepositoryResolver: 17 | """Resolve which repository provides a given package""" 18 | 19 | def __init__(self): 20 | self.logger = logging.getLogger(str(self.__class__.__name__)) 21 | 22 | def resolve_source_lines(self, packages) -> []: 23 | source_lines = [] 24 | 25 | apt_config_path = pathlib.Path("/etc/apt") 26 | for sources_list in apt_config_path.glob("**/*.list"): 27 | with open(sources_list) as list_file: 28 | for line in list_file.readlines(): 29 | if line.startswith("deb "): 30 | source_line = line.strip() 31 | source_lines.append(source_line) 32 | 33 | return source_lines 34 | -------------------------------------------------------------------------------- /appimagebuilder/modules/generate/package_managers/pacman/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | from .file_package_resolver import FilePackageResolver 14 | -------------------------------------------------------------------------------- /appimagebuilder/modules/generate/package_managers/pacman/file_package_resolver.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import logging 13 | import os 14 | import pathlib 15 | import re 16 | import subprocess 17 | 18 | from appimagebuilder.utils import shell 19 | 20 | 21 | class FilePackageResolver: 22 | """Resolve which package provide a given file using `pacman -F`""" 23 | 24 | REQUIRED_COMMANDS = ["pacman"] 25 | 26 | def __init__(self): 27 | self.logger = logging.getLogger(str(self.__class__.__name__)) 28 | self._cli_tools = shell.require_executables(self.REQUIRED_COMMANDS) 29 | 30 | def resolve(self, files) -> {}: 31 | output = self._run_pacman_f(files) 32 | results = self._parse_pacman_f_output(output) 33 | return results 34 | 35 | def _run_pacman_f(self, files): 36 | # make sure that the files are str 37 | files = [str(file) for file in files] 38 | 39 | command = "{pacman} -Fy {files}" 40 | 41 | # ensure C locale is used to avoid locales affecting the output format 42 | env = os.environ.copy() 43 | env["LC_ALL"] = "C" 44 | 45 | command = command.format(**self._cli_tools, files=" ".join(files)) 46 | self.logger.info(command) 47 | _proc = subprocess.run(command, stdout=subprocess.PIPE, shell=True, env=env) 48 | stdout_data = _proc.stdout.decode() 49 | return stdout_data 50 | 51 | @staticmethod 52 | def _parse_pacman_f_output(output): 53 | results = {} 54 | for match in re.findall( 55 | r"(?P.*) is owned by (?P.*) (?P.*)", output 56 | ): 57 | file = pathlib.Path(match[0]) 58 | pkg_name = match[1] 59 | pkg_name = pkg_name.split("/")[-1] 60 | results[file] = pkg_name 61 | return results 62 | -------------------------------------------------------------------------------- /appimagebuilder/modules/generate/recipe_sections/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | from .apt_section_generator import AptSectionGenerator 14 | from .pacman_section_generator import PacmanSectionGenerator 15 | from .files_section_generator import FilesSectionGenerator 16 | -------------------------------------------------------------------------------- /appimagebuilder/modules/generate/recipe_sections/package_manager_recipe_section_generator.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | from appimagebuilder.context import BundleInfo 14 | 15 | 16 | class PackageManagerSectionGenerator: 17 | """Generates a recipe section for a package manager""" 18 | 19 | def id(self) -> str: 20 | """Identifies the generator""" 21 | pass 22 | 23 | def generate(self, dependencies: [str], bundle_info: BundleInfo) -> ({}, [str]): 24 | """ 25 | Generate a recipe section to deploy using the system package manager into the bundle 26 | Returns: map like recipe section and a list of non-resolved dependencies 27 | """ 28 | pass 29 | -------------------------------------------------------------------------------- /appimagebuilder/modules/generate/recipe_sections/pacman_section_generator.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | from appimagebuilder.context import BundleInfo 13 | from appimagebuilder.modules.generate.package_managers.pacman.file_package_resolver import ( 14 | FilePackageResolver, 15 | ) 16 | from appimagebuilder.modules.generate.recipe_sections.package_manager_recipe_section_generator import ( 17 | PackageManagerSectionGenerator, 18 | ) 19 | 20 | 21 | class PacmanSectionGenerator(PackageManagerSectionGenerator): 22 | def __init__(self, file_package_resolver: FilePackageResolver): 23 | self._file_package_resolver = file_package_resolver 24 | 25 | def id(self) -> str: 26 | return "pacman" 27 | 28 | def generate(self, dependencies: [str], bundle_info: BundleInfo) -> ({}, [str]): 29 | file_package_map = self._file_package_resolver.resolve(dependencies) 30 | 31 | include_list = set(file_package_map.values()) 32 | 33 | missing_files = self._find_missing_files(dependencies, file_package_map) 34 | 35 | section = { 36 | # "Architecture": "", 37 | # "repositories": {}, 38 | "include": sorted(include_list), 39 | "exclude": [], 40 | # "options": {"SigLevel": "Optional TrustAll"}, 41 | } 42 | 43 | return section, missing_files 44 | 45 | def _find_missing_files(self, dependencies, file_package_map): 46 | missing_files = set(dependencies) 47 | for k in file_package_map.keys(): 48 | if k in missing_files: 49 | missing_files.remove(k) 50 | return missing_files 51 | -------------------------------------------------------------------------------- /appimagebuilder/modules/generate/recipe_sections/test_section_generator.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | 14 | class TestSectionGenerator: 15 | def __init__(self): 16 | self.docker_images = [ 17 | "appimagecrafters/tests-env:fedora-30", 18 | "appimagecrafters/tests-env:debian-stable", 19 | "appimagecrafters/tests-env:archlinux-latest", 20 | "appimagecrafters/tests-env:centos-7", 21 | "appimagecrafters/tests-env:ubuntu-xenial", 22 | ] 23 | 24 | def generate(self): 25 | section = {} 26 | for image in self.docker_images: 27 | test_case_title = image.rsplit(":", maxsplit=1)[1] 28 | section[test_case_title] = {"image": image, "command": "./AppRun"} 29 | return section 30 | -------------------------------------------------------------------------------- /appimagebuilder/modules/prime/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | from .appimage_primer import AppImagePrimer 14 | -------------------------------------------------------------------------------- /appimagebuilder/modules/prime/base_primer.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import pathlib 13 | 14 | from appimagebuilder.context import Context 15 | 16 | 17 | class BasePrimer: 18 | def __init__(self, context: Context): 19 | self.context = context 20 | 21 | def prime(self): 22 | pass 23 | -------------------------------------------------------------------------------- /appimagebuilder/modules/prime/errors.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | 14 | class PrimerError(RuntimeError): 15 | pass 16 | -------------------------------------------------------------------------------- /appimagebuilder/modules/setup/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | -------------------------------------------------------------------------------- /appimagebuilder/modules/setup/apprun_2/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | -------------------------------------------------------------------------------- /appimagebuilder/modules/setup/apprun_2/executables.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import os 13 | from pathlib import Path 14 | 15 | 16 | class Executable: 17 | """Executable unit with its environment""" 18 | 19 | def __init__(self, path): 20 | self.path = Path(path) 21 | self.args = ["$@"] 22 | self.env = {} 23 | 24 | def __str__(self) -> str: 25 | return self.path.__str__() 26 | 27 | def __eq__(self, o: object) -> bool: 28 | return ( 29 | self.__class__ == o.__class__ 30 | and self.path == o.path 31 | and self.args == o.args 32 | ) 33 | 34 | 35 | class BinaryExecutable(Executable): 36 | """Binary executable (an elf file)""" 37 | 38 | def __init__(self, path, arch): 39 | path = os.path.realpath(path) 40 | super().__init__(path) 41 | self.arch = arch 42 | 43 | def __eq__(self, o: object) -> bool: 44 | return ( 45 | self.__class__ == o.__class__ 46 | and self.path == o.path 47 | and self.arch == o.arch 48 | ) 49 | 50 | def __str__(self) -> str: 51 | return "BinaryExecutable(%s)" % self.path.__str__() 52 | 53 | 54 | class InterpretedExecutable(Executable): 55 | """Interpreted executable of any kind""" 56 | 57 | def __init__(self, path, shebang: [str]): 58 | super().__init__(path) 59 | self.shebang = shebang 60 | self.interpreter = None 61 | 62 | def __eq__(self, o: object) -> bool: 63 | return ( 64 | self.__class__ == o.__class__ 65 | and self.path == o.path 66 | and self.shebang == o.shebang 67 | and self.interpreter == o.interpreter 68 | ) 69 | 70 | def __str__(self) -> str: 71 | return "InterpretedExecutable(%s)" % self.path 72 | -------------------------------------------------------------------------------- /appimagebuilder/modules/setup/apprun_2/executables_patcher.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import logging 13 | import pathlib 14 | import lief 15 | 16 | 17 | class ExecutablesPatcherError(RuntimeError): 18 | pass 19 | 20 | 21 | class ExecutablesPatcher: 22 | def __init__(self): 23 | self.script_interpreters_paths = {} 24 | self.binary_interpreters_paths = {} 25 | self.logger = logging.getLogger("ExecutablesPatcher") 26 | 27 | def patch_interpreted_executable(self, path: pathlib.Path): 28 | try: 29 | with open(path, "r+") as f: 30 | shebang = f.readline() 31 | patched_shebang = self.make_bin_path_in_shebang_relative(shebang) 32 | 33 | f.seek(0) 34 | f.write(patched_shebang) 35 | 36 | self._register_interpreter_used_in_shebang(path, patched_shebang) 37 | except Exception as e: 38 | self.logger.warning("Unable to patch script shebang %s: %s", path, e) 39 | 40 | def _register_interpreter_used_in_shebang(self, executable_path, shebang): 41 | interpreter_path = self.read_interpreter_path_from_shebang(shebang) 42 | self.script_interpreters_paths[executable_path] = interpreter_path 43 | 44 | @staticmethod 45 | def read_interpreter_path_from_shebang(shebang): 46 | interpreter_path = shebang[2:].strip() 47 | interpreter_path = interpreter_path.split(" ")[0] 48 | return interpreter_path 49 | 50 | @staticmethod 51 | def make_bin_path_in_shebang_relative(shebang): 52 | shebang_len = len(shebang) 53 | idx = 2 54 | while shebang_len > idx and (shebang[idx] == "/" or shebang[idx] == " "): 55 | idx = idx + 1 56 | 57 | patched = shebang[:2] + " " * (idx - 2) + shebang[idx:] 58 | 59 | return patched 60 | 61 | def patch_binary_executable(self, path: pathlib.Path): 62 | try: 63 | binary = lief.parse(path.__str__()) 64 | interpreter_path = binary.interpreter 65 | if interpreter_path: 66 | patched_interpreter_path = interpreter_path.lstrip("/") 67 | binary.interpreter = patched_interpreter_path 68 | binary.write(path.__str__()) 69 | 70 | self.binary_interpreters_paths[path] = patched_interpreter_path 71 | except Exception as e: 72 | logging.warning(f"Unable to patch binary executables: {e}") 73 | -------------------------------------------------------------------------------- /appimagebuilder/modules/setup/apprun_3/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | -------------------------------------------------------------------------------- /appimagebuilder/modules/setup/apprun_3/apprun3_context.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import pathlib 13 | 14 | from appimagebuilder.context import Context 15 | from appimagebuilder.modules.setup.apprun_3.app_dir_info import AppDir 16 | from appimagebuilder.modules.setup.apprun_binaries_resolver import AppRunBinariesResolver 17 | 18 | 19 | class AppRun3Context: 20 | build_context: Context = None 21 | binaries_resolver: AppRunBinariesResolver = None 22 | app_dir: AppDir = None 23 | 24 | modules_dir: pathlib.Path = None 25 | debug: bool = False 26 | 27 | main_arch: str = None 28 | architectures = set() 29 | runtime_env = dict() 30 | 31 | # files matching the given pattern will not be modified by setup helpers 32 | files_to_preserve = set() 33 | 34 | def __init__(self, build_context: Context): 35 | self.build_context = build_context 36 | self.modules_dir = build_context.app_dir / "opt" 37 | self.debug = build_context.recipe.AppDir.runtime.debug() or False 38 | self.path_mappings = build_context.recipe.AppDir.runtime.path_mappings() or [] 39 | 40 | # init AppRun binaries resolver 41 | apprun_version = build_context.recipe.AppDir.runtime.version() or "v3.0.0" 42 | build_context.build_dir / "AppRun" / apprun_version 43 | self.binaries_resolver = AppRunBinariesResolver(apprun_version, self.debug, build_context.build_dir) 44 | 45 | self.app_info = build_context.app_info 46 | 47 | # information gathered during the setup process 48 | self.bundle_archs = set(build_context.recipe.AppDir.runtime.architecture()) 49 | 50 | self.app_dir = AppDir(build_context.app_dir) 51 | -------------------------------------------------------------------------------- /appimagebuilder/modules/setup/apprun_3/helpers/base_helper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | from appimagebuilder.modules.setup.apprun_3.apprun3_context import AppRun3Context 13 | 14 | 15 | class AppRun3Helper: 16 | def __init__(self, context: AppRun3Context): 17 | self.context = context 18 | 19 | def run(self): 20 | pass 21 | -------------------------------------------------------------------------------- /appimagebuilder/modules/setup/apprun_3/helpers/glib.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import shutil 13 | import subprocess 14 | 15 | from .base_helper import AppRun3Helper 16 | 17 | 18 | class AppRun3GLib(AppRun3Helper): 19 | def run(self): 20 | self._configure_gio_modules() 21 | self._configure_schemas() 22 | self._configure_girepository() 23 | 24 | def _configure_gio_modules(self): 25 | gio_module = self.context.app_dir.find_one(["**/gio/modules/*"]) 26 | if gio_module: 27 | self.context.runtime_env["GIO_MODULE_DIR"] = str(gio_module.path.parent) 28 | 29 | def _configure_girepository(self): 30 | path = self.context.app_dir.find_one(["*/girepository-1.0/*"]) 31 | if path: 32 | self.context.runtime_env["GI_TYPELIB_PATH"] = str(path.path.parent) 33 | 34 | def _configure_schemas(self): 35 | schema_file = self.context.app_dir.find_one(["*/glib-2.0/schemas/*"]) 36 | if schema_file: 37 | bin_path = shutil.which("glib-compile-schemas") 38 | if not bin_path: 39 | raise RuntimeError("Missing 'glib-compile-schemas' executable") 40 | 41 | subprocess.run([bin_path, schema_file.path.parent]) 42 | self.context.runtime_env["GSETTINGS_SCHEMA_DIR"] = str(schema_file.path.parent) 43 | -------------------------------------------------------------------------------- /appimagebuilder/modules/setup/apprun_3/helpers/python.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import logging 13 | 14 | from appimagebuilder.modules.setup.apprun_3.helpers.base_helper import AppRun3Helper 15 | 16 | 17 | class AppRun3Python(AppRun3Helper): 18 | def run(self): 19 | python_bin = self.context.app_dir.find_one(["*/bin/python2*", "*/bin/python3*"]) 20 | if python_bin: 21 | logging.info("Found python binary: %s", python_bin.path) 22 | python_home = python_bin.path.parent.parent 23 | self.context.runtime_env["PYTHONHOME"] = str(python_home) 24 | logging.info("Setting PYTHONHOME to: %s", python_home) 25 | 26 | python_site_package = self.context.app_dir.find_one(["*/python*/site-packages/*/*"]) 27 | if python_site_package: 28 | python_path = python_site_package.path.parent.parent 29 | self.context.runtime_env["PYTHONPATH"] = str(python_path) 30 | logging.info("Setting PYTHONPATH to: %s", python_path) 31 | -------------------------------------------------------------------------------- /appimagebuilder/modules/setup/file_matching_patterns.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | """ 14 | Manually curated list of file matching patterns used to identify certain parts of the AppDir. 15 | 16 | Groups describe matching that are binary dependent between them and must be used together at runtime. Excluding them 17 | from the list will result in a failure. 18 | """ 19 | 20 | "glibc related binaries" 21 | glibc = [ 22 | "**/audit/*", 23 | "**/doc/gcc-10-base/*", 24 | "**/doc/libc6/*", 25 | "**/doc/libcrypt1/*", 26 | "**/doc/libgcc-s1/*", 27 | "**/doc/zlib1g/*", 28 | "**/gconv/*", 29 | "**/ld-*.so", 30 | "**/ld-linux-x86-64.so*", 31 | "**/ld-linux-x86-64.so*", 32 | "**/ld-linux-x86-64.so.2", 33 | "**/ld-linux-aarch64.so*", 34 | "**/ld-linux-armhf.so*", 35 | "**/ld-linux.so.2", 36 | "**/libBrokenLocale-*.so", 37 | "**/libBrokenLocale.so*", 38 | "**/libSegFault.so", 39 | "**/libanl-*.so", 40 | "**/libanl.so*", 41 | "**/libc-*.so", 42 | "**/libc.so*", 43 | "**/libcrypt.so*", 44 | "**/libcrypt.so*", 45 | "**/libdl-*.so", 46 | "**/libdl.so*", 47 | "**/libgcc_s.so*", 48 | "**/libm-*.so", 49 | "**/libm.so*", 50 | "**/libmemusage.so*", 51 | "**/libmvec-*.so", 52 | "**/libmvec.so*", 53 | "**/libnsl-*.so", 54 | "**/libnsl.so*", 55 | "**/libnss_compat-*.so", 56 | "**/libnss_compat.so*", 57 | "**/libnss_dns-*.so", 58 | "**/libnss_dns.so*", 59 | "**/libnss_files-*.so", 60 | "**/libnss_files.so*", 61 | "**/libnss_hesiod-*.so", 62 | "**/libnss_hesiod.so*", 63 | "**/libnss_nis-*.so", 64 | "**/libnss_nis.so*", 65 | "**/libnss_nisplus-*.so", 66 | "**/libnss_nisplus.so*", 67 | "**/libpcprofile.so", 68 | "**/libpthread-*.so", 69 | "**/libpthread.so*", 70 | "**/libresolv-*.so", 71 | "**/libresolv.so*", 72 | "**/librt-*.so", 73 | "**/librt.so*", 74 | "**/libthread_db-*.so", 75 | "**/libthread_db.so*", 76 | "**/libutil-*.so", 77 | "**/libutil.so*", 78 | "**/libz.so*", 79 | "**/libz.so*", 80 | "etc/ld.so.conf.d/*", 81 | ] 82 | 83 | "glibstdc++ related binaries" 84 | glibstdcpp = [ 85 | "**/doc/libstdc++6/*", 86 | "**/libstdc++.so*", 87 | "**/libstdc++stdc++.so*", 88 | "**/libstdcxx/*", 89 | ] 90 | 91 | "glibc and glibstc++ related binaries (used for compatibility with AppRun v2)" 92 | glibc_with_glibstdcpp = glibc + glibstdcpp 93 | -------------------------------------------------------------------------------- /appimagebuilder/modules/setup/helpers/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | from .gdk_pixbuf import GdkPixbuf 14 | from .glib import GLib 15 | from .gstreamer import GStreamer 16 | from .gtk import Gtk 17 | from .apprun_2_libc import AppRun2LibC 18 | from .java import Java 19 | from .libgl import LibGL 20 | from .openssl import OpenSSL 21 | from .python import Python 22 | from .qt import Qt 23 | from .mime import MIME 24 | -------------------------------------------------------------------------------- /appimagebuilder/modules/setup/helpers/base_helper.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | from appimagebuilder.utils.finder import Finder 14 | 15 | 16 | class BaseHelper: 17 | def __init__(self, app_dir, finder: Finder): 18 | self.app_dir = app_dir 19 | self.finder = finder 20 | 21 | self.priority = 0 22 | self.env = {} 23 | self.scripts = {} 24 | 25 | def configure(self, env, preserve_files): 26 | pass 27 | 28 | @staticmethod 29 | def _remove_prefix(text, prefix): 30 | if text.startswith(prefix): 31 | return text[len(prefix) :] 32 | return text 33 | -------------------------------------------------------------------------------- /appimagebuilder/modules/setup/helpers/glib.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import shutil 13 | import subprocess 14 | 15 | from appimagebuilder.utils.finder import Finder 16 | from .base_helper import BaseHelper 17 | from ..environment import Environment 18 | 19 | 20 | class GLib(BaseHelper): 21 | def configure(self, env: Environment, preserve_files): 22 | self._configure_gio_modules(env) 23 | self._configure_schemas(env) 24 | self._configure_girepository(env) 25 | 26 | def _configure_gio_modules(self, env): 27 | gio_modules_dir = self.finder.find_one("**/gio/modules") 28 | if gio_modules_dir: 29 | env.set("GIO_MODULE_DIR", str(gio_modules_dir)) 30 | 31 | def _configure_girepository(self, env): 32 | path = self.finder.find_one("*/girepository-1.0", [Finder.is_dir]) 33 | if path: 34 | env.set("GI_TYPELIB_PATH", path) 35 | 36 | def _configure_schemas(self, env): 37 | path = self.finder.find_one("*/glib-2.0/schemas", [Finder.is_dir]) 38 | if path: 39 | bin_path = shutil.which("glib-compile-schemas") 40 | if not bin_path: 41 | raise RuntimeError("Missing 'glib-compile-schemas' executable") 42 | 43 | subprocess.run([bin_path, path]) 44 | env.set("GSETTINGS_SCHEMA_DIR", path) 45 | -------------------------------------------------------------------------------- /appimagebuilder/modules/setup/helpers/gtk.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import os 13 | import re 14 | import subprocess 15 | 16 | from .base_helper import BaseHelper 17 | from ..environment import Environment 18 | 19 | 20 | class Gtk(BaseHelper): 21 | """ 22 | Helper for making Gtk based applications portable 23 | Reference: https://developer.gnome.org/gtk3/stable/gtk-running.html 24 | """ 25 | 26 | def configure(self, env: Environment, preserve_files): 27 | prefix = self.app_dir / "usr" 28 | env.set("GTK_EXE_PREFIX", str(prefix)) 29 | env.set("GTK_DATA_PREFIX", str(prefix)) 30 | 31 | gtk_path = [ 32 | str(path) 33 | for path in self.finder.find("lib/**/gtk-?.0", [self.finder.is_dir]) 34 | ] 35 | env.set("GTK_PATH", gtk_path) 36 | 37 | for path in self.finder.find("usr/share/icons/*", [self.finder.is_dir]): 38 | subprocess.run(["gtk-update-icon-cache", str(path)]) 39 | -------------------------------------------------------------------------------- /appimagebuilder/modules/setup/helpers/java.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import os 13 | from pathlib import Path 14 | 15 | from appimagebuilder.utils.finder import Finder 16 | from .base_helper import BaseHelper 17 | from ..environment import Environment 18 | 19 | 20 | class Java(BaseHelper): 21 | def configure(self, env: Environment, preserve_files): 22 | java_path = self.finder.find_one("java", [Finder.is_file, Finder.is_executable]) 23 | if java_path: 24 | java_home = Path(java_path).parent.parent 25 | env.set("JAVA_HOME", str(java_home)) 26 | -------------------------------------------------------------------------------- /appimagebuilder/modules/setup/helpers/libgl.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import os 13 | 14 | from appimagebuilder.utils.finder import Finder 15 | from .base_helper import BaseHelper 16 | from ..environment import Environment 17 | 18 | 19 | class LibGL(BaseHelper): 20 | def configure(self, env: Environment, preserve_files): 21 | dri_path = self.finder.find_one("*/dri/*.so", [Finder.is_file, Finder.is_elf]) 22 | if dri_path: 23 | env.set("LIBGL_DRIVERS_PATH", dri_path.parent) 24 | -------------------------------------------------------------------------------- /appimagebuilder/modules/setup/helpers/mime.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 TheBrokenRail 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import shutil 13 | import subprocess 14 | 15 | from .base_helper import BaseHelper 16 | 17 | 18 | class MIME(BaseHelper): 19 | def configure(self, env, preserve_files): 20 | path = self.finder.base_path / "usr" / "share" / "mime" 21 | if path.is_dir(): 22 | bin_path = shutil.which("update-mime-database") 23 | if not bin_path: 24 | raise RuntimeError("Missing 'update-mime-database' executable") 25 | 26 | subprocess.run([bin_path, path]) 27 | -------------------------------------------------------------------------------- /appimagebuilder/modules/setup/helpers/openssl.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import logging 13 | import os 14 | 15 | from appimagebuilder.utils.finder import Finder 16 | from .base_helper import BaseHelper 17 | from ..environment import Environment 18 | 19 | 20 | class OpenSSL(BaseHelper): 21 | def configure(self, env: Environment, preserve_files): 22 | engines_dir = self.finder.find_one("*/openssl-*/engines", [Finder.is_dir]) 23 | if engines_dir: 24 | env.set("OPENSSL_ENGINES", engines_dir) 25 | -------------------------------------------------------------------------------- /appimagebuilder/modules/setup/helpers/python.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import os 13 | from pathlib import Path 14 | 15 | from appimagebuilder.utils.finder import Finder 16 | from .base_helper import BaseHelper 17 | from ..environment import Environment 18 | 19 | 20 | class Python(BaseHelper): 21 | def configure(self, env: Environment, preserve_files): 22 | python_path = self.finder.find_one( 23 | "*/bin/python?", [Finder.is_file, Finder.is_executable] 24 | ) 25 | if python_path: 26 | python_home = Path(python_path).parent.parent 27 | env.set("PYTHONHOME", str(python_home)) 28 | -------------------------------------------------------------------------------- /appimagebuilder/modules/test/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | from .execution_test import ExecutionTest, TestFailed 14 | -------------------------------------------------------------------------------- /appimagebuilder/modules/test/dependencies_test.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import logging 13 | import os 14 | import re 15 | 16 | import docker 17 | 18 | from appimagebuilder.modules.analisys.inspector import Inspector 19 | from appimagebuilder.modules.test.errors import TestFailed 20 | 21 | 22 | class DependenciesTest: 23 | def __init__(self, appdir, docker_image): 24 | self.appdir = appdir 25 | self.docker_image = docker_image 26 | self.logger = logging.getLogger("Dependencies test on '%s'" % self.docker_image) 27 | 28 | self.tests_utils_dir = os.path.realpath( 29 | os.path.join(os.path.dirname(__file__), "utils") 30 | ) 31 | self.client = docker.from_env() 32 | 33 | def run(self): 34 | self.logger.info("Looking for missing dependencies") 35 | need_libs = self._list_needed_libs() 36 | container_libs = self._list_container_libs() 37 | 38 | missing_libs = [lib for lib in need_libs if lib not in container_libs] 39 | for lib in missing_libs: 40 | self.logger.error("Missing library '%s'" % lib) 41 | 42 | if missing_libs: 43 | raise TestFailed("Some libraries cannot be located in the docker image.") 44 | else: 45 | self.logger.info("Success, all dependencies were found!") 46 | 47 | def _list_needed_libs(self): 48 | inspector = Inspector(self.appdir) 49 | return inspector.get_bundle_needed_libs() 50 | 51 | def _list_container_libs(self): 52 | output = self.client.containers.run( 53 | self.docker_image, 54 | "/sbin/ldconfig -p", 55 | tty=True, 56 | auto_remove=True, 57 | ) 58 | 59 | results = re.findall(".*\s=>\s/.*/(.*)", output.decode("utf-8")) 60 | container_libs = set([result.strip() for result in results]) 61 | 62 | return container_libs 63 | -------------------------------------------------------------------------------- /appimagebuilder/modules/test/errors.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | 14 | class TestFailed(RuntimeError): 15 | pass 16 | -------------------------------------------------------------------------------- /appimagebuilder/recipe/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | from .loader import Loader 14 | from .roamer import Roamer 15 | from .schema import RecipeSchema as Schema 16 | -------------------------------------------------------------------------------- /appimagebuilder/recipe/errors.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | 14 | class RecipeError(RuntimeError): 15 | pass 16 | -------------------------------------------------------------------------------- /appimagebuilder/recipe/roamer.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import os 13 | import re 14 | 15 | import roam 16 | 17 | 18 | class Roamer(roam.Roamer): 19 | """ 20 | Extends the roam.Roamer class adding support for resolving environment variables. 21 | 22 | The Roamer class acts as a Shim over the data objects easing the access and 23 | traversal operations. 24 | """ 25 | 26 | def __call__( 27 | self, 28 | resolve_variables=True, 29 | *args, 30 | _raise=False, 31 | _roam=False, 32 | _invoke=None, 33 | **kwargs 34 | ): 35 | result = super().__call__( 36 | *args, _raise=_raise, _roam=_roam, _invoke=_invoke, **kwargs 37 | ) 38 | 39 | if resolve_variables: 40 | return self._resolve_variables(result) 41 | else: 42 | return result 43 | 44 | def __getattr__(self, attr_name): 45 | result = super().__getattr__(attr_name) 46 | return Roamer(result) 47 | 48 | def _resolve_variables(self, variable): 49 | if isinstance(variable, str): 50 | return self._replace_env_variables_in_str(variable) 51 | 52 | if isinstance(variable, list): 53 | new_list = [] 54 | for v in variable: 55 | new_list.append(self._resolve_variables(v)) 56 | return new_list 57 | 58 | if isinstance(variable, dict): 59 | new_dict = {} 60 | for k, v in variable.items(): 61 | new_dict[k] = self._resolve_variables(v) 62 | 63 | return new_dict 64 | 65 | return variable 66 | 67 | def _replace_env_variables_in_str(self, variable): 68 | new_val = variable 69 | for item in re.findall(r"{{\s?\w+\s?}}", variable): 70 | var_name = item[2:-2] 71 | var_name = var_name.strip() 72 | if var_name not in os.environ: 73 | raise RuntimeError("Missing environment variable: '%s'" % var_name) 74 | value = os.environ[var_name] 75 | new_val = new_val.replace(item, value, 1) 76 | 77 | return new_val 78 | -------------------------------------------------------------------------------- /appimagebuilder/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AppImageCrafters/appimage-builder/bf6123ee43715e52d2a73639f9acb1251e8af640/appimagebuilder/utils/__init__.py -------------------------------------------------------------------------------- /appimagebuilder/utils/appimagetool.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | 14 | import logging 15 | import pathlib 16 | 17 | from .command import Command 18 | 19 | 20 | class AppImageToolCommand(Command): 21 | def __init__(self, app_dir, target_file): 22 | super().__init__("appimagetool") 23 | 24 | self.app_dir = pathlib.Path(app_dir).absolute() 25 | self.runtime_file = None 26 | self.update_information = None 27 | self.guess_update_information = False 28 | self.sign_key = None 29 | self.target_file = pathlib.Path(target_file).absolute() 30 | self.target_arch = None 31 | 32 | def run(self): 33 | logging.info("Generating AppImage from %s" % self.app_dir) 34 | command = self._generate_command() 35 | 36 | if self.target_arch: 37 | self.env["ARCH"] = self.target_arch 38 | 39 | self._run(command) 40 | if self.return_code != 0: 41 | logging.error("AppImage generation failed") 42 | else: 43 | logging.info("AppImage created successfully") 44 | 45 | def _generate_command(self): 46 | command = ["appimagetool"] 47 | if self.runtime_file: 48 | command.extend(["--runtime-file", self.runtime_file]) 49 | 50 | if self.sign_key: 51 | command.extend(["--sign", "--sign-key", self.sign_key]) 52 | 53 | if self.update_information: 54 | command.extend(["--updateinformation", self.update_information]) 55 | 56 | if self.guess_update_information: 57 | command.extend(["--guess"]) 58 | 59 | # appstreamcli calls from 60 | command.extend(["--no-appstream"]) 61 | 62 | command.extend([str(self.app_dir), str(self.target_file)]) 63 | return command 64 | -------------------------------------------------------------------------------- /appimagebuilder/utils/dpkg_architecture.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | 14 | import subprocess 15 | from .command import Command 16 | 17 | 18 | class DpkgArchitecture(Command): 19 | def __init__(self): 20 | super().__init__("dpkg-architecture") 21 | 22 | def get_deb_host_arch(self): 23 | return self._query("DEB_HOST_ARCH") 24 | 25 | def _query(self, var_name): 26 | result = subprocess.run( 27 | ["dpkg-architecture", "-q", var_name], 28 | stdout=subprocess.PIPE, 29 | stderr=subprocess.PIPE, 30 | ) 31 | if result.returncode == 0: 32 | return result.stdout.decode("utf-8").strip() 33 | else: 34 | return None 35 | -------------------------------------------------------------------------------- /appimagebuilder/utils/dpkg_query.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import os 13 | 14 | from .command import Command 15 | 16 | 17 | class DpkgQueryError(RuntimeError): 18 | pass 19 | 20 | 21 | class DpkgQuery(Command): 22 | def __init__(self): 23 | super().__init__("dpkg-query") 24 | self.log_stdout = False 25 | 26 | def search(self, files): 27 | command = [self.runnable, "-S"] 28 | command.extend(files) 29 | self._run(command) 30 | 31 | packages = set() 32 | for line in self.stdout: 33 | split = line.find(":") 34 | packages.add(line[:split]) 35 | 36 | missing = [] 37 | for line in self.stderr: 38 | if "no path found" in line: 39 | parts = line.split(" ") 40 | missing.append(parts[-1]) 41 | 42 | return packages, missing 43 | 44 | def list_files(self, packages): 45 | command = [self.runnable, "-L"] 46 | command.extend(packages) 47 | self._run(command) 48 | 49 | files = set() 50 | for line in self.stdout: 51 | if os.path.isabs(line) and os.path.isfile(line): 52 | files.add(line) 53 | 54 | return files 55 | 56 | def depends(self, packages): 57 | command = [self.runnable, "-W", "-f=${binary:Package}: ${Depends}\\n"] 58 | command.extend(packages) 59 | 60 | self._run(command) 61 | 62 | if self.return_code != 0: 63 | raise DpkgQueryError("Package lockup failed") 64 | 65 | dependencies = dict() 66 | for line in self.stdout: 67 | line = line.strip() 68 | line = line.strip("\\") 69 | pkg_name_end = line.find(":") 70 | pkg_name = line[:pkg_name_end] 71 | dependencies[pkg_name] = [] 72 | 73 | deps_start = line.find(" ") 74 | deps = line[deps_start:] 75 | deps = deps.strip() 76 | 77 | for dep in deps.split(","): 78 | dep = dep.strip() 79 | dep_name_end = dep.find(" ") 80 | dep_name = dep[:dep_name_end] 81 | dependencies[pkg_name].append(dep_name) 82 | 83 | return dependencies 84 | -------------------------------------------------------------------------------- /appimagebuilder/utils/file_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import os 13 | import stat 14 | 15 | 16 | def set_permissions_rx_all(path): 17 | os.chmod( 18 | path, 19 | stat.S_IRUSR 20 | | stat.S_IRGRP 21 | | stat.S_IROTH 22 | | stat.S_IXUSR 23 | | stat.S_IXGRP 24 | | stat.S_IXOTH 25 | | stat.S_IWUSR, 26 | ) 27 | -------------------------------------------------------------------------------- /appimagebuilder/utils/shell.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import shutil 3 | 4 | 5 | class CommandNotFoundError(RuntimeError): 6 | pass 7 | 8 | 9 | def require_executables(executables: [str]): 10 | """ 11 | Iterates through all items in searching for their paths 12 | :return: map with the command name and its path 13 | """ 14 | paths = {} 15 | for dep in executables: 16 | paths[dep] = require_executable(dep) 17 | return paths 18 | 19 | 20 | def require_executable(tool): 21 | tool_path = shutil.which(tool) 22 | if not tool_path: 23 | raise CommandNotFoundError("Could not find '{exe}' on $PATH.".format(exe=tool)) 24 | 25 | return tool_path 26 | 27 | 28 | def assert_successful_result(proc): 29 | if proc.returncode: 30 | logging.error('"%s" execution failed' % proc.args) 31 | if proc.stderr: 32 | for line in proc.stderr.decode().splitlines(): 33 | logging.error(line) 34 | 35 | raise RuntimeError( 36 | '"%s" execution failed with code %s' % (proc.args, proc.returncode) 37 | ) 38 | -------------------------------------------------------------------------------- /appimagebuilder/utils/symlinks.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | import logging 14 | import os 15 | 16 | 17 | def make_symlinks_relative(file): 18 | if os.path.islink(file): 19 | link_target = os.readlink(file) 20 | if os.path.isabs(link_target): 21 | os.unlink(file) 22 | 23 | new_link_target = os.path.relpath( 24 | link_target, os.path.join("/", os.path.dirname(file)) 25 | ) 26 | logging.info( 27 | "Fixing symlink %s target: from %s to %s" 28 | % (file, link_target, new_link_target) 29 | ) 30 | os.symlink(new_link_target, file) 31 | -------------------------------------------------------------------------------- /recipes/bash-files/AppImageBuilder.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | script: 3 | - rm -rf $TARGET_APPDIR | true 4 | 5 | AppDir: 6 | app_info: 7 | id: org.gnu.bash 8 | version: 4.4.20 9 | exec: bin/bash 10 | 11 | files: 12 | include: 13 | - /bin/bash 14 | - /usr/bin/bash 15 | exclude: 16 | - etc/** 17 | - usr/share/doc/**/recipes/** 18 | - usr/include/** 19 | - usr/lib/*/gconv/** 20 | - usr/share/man/** 21 | - usr/share/doc/*/README.* 22 | - usr/share/doc/*/changelog.* 23 | - usr/share/doc/*/NEWS.* 24 | - usr/share/doc/*/TODO.* 25 | 26 | runtime: 27 | arch: [ x86_64, i386 ] 28 | version: continuous 29 | 30 | test: 31 | debian: 32 | image: appimagecrafters/tests-env:debian-stable 33 | before_command: "pwd" 34 | command: "./AppRun --version" 35 | centos: 36 | image: appimagecrafters/tests-env:centos-7 37 | command: "./AppRun --version" 38 | arch: 39 | image: appimagecrafters/tests-env:archlinux-latest 40 | command: "./AppRun --version" 41 | fedora: 42 | image: appimagecrafters/tests-env:fedora-30 43 | command: "./AppRun --version" 44 | ubuntu: 45 | image: appimagecrafters/tests-env:ubuntu-xenial 46 | command: "./AppRun --version" 47 | 48 | 49 | AppImage: 50 | arch: x86_64 51 | -------------------------------------------------------------------------------- /recipes/bash-pacman/AppImageBuilder.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | script: 3 | - rm -rf "$TARGET_APPDIR" || true 4 | 5 | AppDir: 6 | app_info: 7 | id: org.gnu.bash 8 | name: bash 9 | icon: utilities-terminal 10 | version: 5.0.18 11 | exec: bin/bash 12 | exec_args: $@ 13 | 14 | pacman: 15 | Architecture: aarch64 16 | repositories: 17 | core: 18 | - http://mirror.archlinuxarm.org/$arch/$repo 19 | include: 20 | - bash 21 | exclude: 22 | - perl 23 | options: 24 | SigLevel: "Optional TrustAll" 25 | 26 | files: 27 | exclude: 28 | - usr/lib/x86_64-linux-gnu/gconv 29 | - usr/share/man 30 | - usr/share/doc/*/README.* 31 | - usr/share/doc/*/changelog.* 32 | - usr/share/doc/*/NEWS.* 33 | - usr/share/doc/*/TODO.* 34 | 35 | test: 36 | debian: 37 | image: appimagecrafters/tests-env:debian-stable 38 | command: "./AppRun --version" 39 | centos: 40 | image: appimagecrafters/tests-env:centos-7 41 | command: "./AppRun --version" 42 | arch: 43 | image: appimagecrafters/tests-env:archlinux-latest 44 | command: "./AppRun --version" 45 | fedora: 46 | image: appimagecrafters/tests-env:fedora-30 47 | command: "./AppRun --version" 48 | ubuntu: 49 | image: appimagecrafters/tests-env:ubuntu-xenial 50 | command: "./AppRun --version" 51 | 52 | 53 | AppImage: 54 | update-information: None 55 | sign-key: None 56 | arch: x86_64 -------------------------------------------------------------------------------- /recipes/bash/AppImageBuilder.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | script: 3 | - echo $PWD 4 | - rm -rf $TARGET_APPDIR | true 5 | - mkdir -p $TARGET_APPDIR/bin 6 | - cp run_tests.sh $TARGET_APPDIR 7 | - cp -r tests $TARGET_APPDIR 8 | - ln -s ../usr/bin/env $TARGET_APPDIR/tests/test_internal_binary_env 9 | - ln -s /usr/bin/env $TARGET_APPDIR/tests/test_external_binary_env 10 | - ln -s bash $TARGET_APPDIR/bin/nubash 11 | 12 | AppDir: 13 | app_info: 14 | id: org.gnu.bash 15 | version: 4.4.20 16 | exec: bin/bash 17 | 18 | apt: 19 | arch: [ amd64, i386 ] 20 | allow_unauthenticated: true 21 | sources: 22 | - sourceline: 'deb http://archive.ubuntu.com/ubuntu bionic main' 23 | key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32' 24 | 25 | include: 26 | - bash 27 | - coreutils 28 | - libc6 29 | - libc6:i386 30 | exclude: 31 | - libpcre3 32 | 33 | files: 34 | exclude: 35 | - etc/** 36 | - usr/share/doc/**/recipes/** 37 | - usr/include/** 38 | - usr/lib/*/gconv/** 39 | - usr/share/man/** 40 | - usr/share/doc/*/README.* 41 | - usr/share/doc/*/changelog.* 42 | - usr/share/doc/*/NEWS.* 43 | - usr/share/doc/*/TODO.* 44 | 45 | runtime: 46 | arch: [ x86_64, i386 ] 47 | version: continuous 48 | 49 | test: 50 | debian: 51 | image: appimagecrafters/tests-env:debian-stable 52 | before_command: "pwd" 53 | command: "./AppRun ./run_tests.sh" 54 | centos: 55 | image: appimagecrafters/tests-env:centos-7 56 | command: "./AppRun ./run_tests.sh" 57 | arch: 58 | image: appimagecrafters/tests-env:archlinux-latest 59 | command: "./AppRun ./run_tests.sh" 60 | fedora: 61 | image: appimagecrafters/tests-env:fedora-30 62 | command: "./AppRun ./run_tests.sh" 63 | ubuntu: 64 | image: appimagecrafters/tests-env:ubuntu-xenial 65 | command: "./AppRun ./run_tests.sh" 66 | 67 | 68 | AppImage: 69 | arch: x86_64 70 | -------------------------------------------------------------------------------- /recipes/bash/bash-apprun-v3.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | script: 3 | - echo $PWD 4 | - rm -rf $TARGET_APPDIR | true 5 | - mkdir -p $TARGET_APPDIR/bin 6 | - cp run_tests.sh $TARGET_APPDIR 7 | - cp -r tests $TARGET_APPDIR 8 | - ln -s ../usr/bin/env $TARGET_APPDIR/tests/test_internal_binary_env 9 | - ln -s /usr/bin/env $TARGET_APPDIR/tests/test_external_binary_env 10 | - ln -s bash $TARGET_APPDIR/bin/nubash 11 | 12 | AppDir: 13 | app_info: 14 | id: org.gnu.bash 15 | version: 4.4.20 16 | exec: bin/bash 17 | 18 | apt: 19 | arch: [ amd64, i386 ] 20 | allow_unauthenticated: true 21 | sources: 22 | - sourceline: 'deb http://archive.ubuntu.com/ubuntu bionic main' 23 | key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32' 24 | 25 | include: 26 | - bash 27 | - coreutils 28 | - libc6 29 | - libc6:i386 30 | - libpcre3 31 | 32 | files: 33 | exclude: 34 | - etc/** 35 | - usr/share/doc/**/recipes/** 36 | - usr/include/** 37 | - usr/lib/*/gconv/** 38 | - usr/share/man/** 39 | - usr/share/doc/*/README.* 40 | - usr/share/doc/*/changelog.* 41 | - usr/share/doc/*/NEWS.* 42 | - usr/share/doc/*/TODO.* 43 | 44 | runtime: 45 | arch: [ x86_64, i386 ] 46 | version: v3.0.0-devel-1 47 | debug: true 48 | 49 | test: 50 | debian: 51 | image: appimagecrafters/tests-env:debian-stable 52 | before_command: "pwd" 53 | command: "./AppRun ./run_tests.sh" 54 | centos: 55 | image: appimagecrafters/tests-env:centos-7 56 | command: "./AppRun ./run_tests.sh" 57 | arch: 58 | image: appimagecrafters/tests-env:archlinux-latest 59 | command: "./AppRun ./run_tests.sh" 60 | fedora: 61 | image: appimagecrafters/tests-env:fedora-30 62 | command: "./AppRun ./run_tests.sh" 63 | ubuntu: 64 | image: appimagecrafters/tests-env:ubuntu-xenial 65 | command: "./AppRun ./run_tests.sh" 66 | 67 | 68 | AppImage: 69 | arch: x86_64 70 | -------------------------------------------------------------------------------- /recipes/bash/run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) 4 | 5 | echo "Running tests" 6 | 7 | for entry in "$SCRIPT_DIR/tests"/*; do 8 | echo "Running: $entry" 9 | $entry 10 | done 11 | -------------------------------------------------------------------------------- /recipes/bash/tests/exec_script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/nubash 2 | 3 | echo "Script Ran Successfully" 4 | -------------------------------------------------------------------------------- /recipes/bash/tests/exec_script_with_env_at_shebang.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env nubash 2 | 3 | echo "Script Ran Successfully" 4 | -------------------------------------------------------------------------------- /recipes/bash/tests/exec_script_with_external_shell.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Execution successful" -------------------------------------------------------------------------------- /recipes/gnome-calculator/AppImageBuilder.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | script: 3 | - rm -rf "$TARGET_APPDIR" || true 4 | 5 | AppDir: 6 | app_info: 7 | id: org.gnome.Calculator 8 | name: gnome-calculator 9 | icon: gnome-calculator 10 | version: 3.28.0 11 | exec: usr/bin/gnome-calculator 12 | 13 | apt: 14 | arch: amd64 15 | sources: 16 | - sourceline: 'deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ bionic main restricted universe multiverse' 17 | key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32' 18 | 19 | include: 20 | - gnome-calculator 21 | - librsvg2-common 22 | exclude: 23 | - adwaita-icon-theme 24 | - humanity-icon-theme 25 | - sensible-utils 26 | - dconf-service 27 | - ubuntu-mono 28 | - fonts-*-core 29 | 30 | runtime: 31 | version: "continuous" 32 | 33 | files: 34 | exclude: 35 | - usr/lib/x86_64-linux-gnu/gconv 36 | - usr/share/man 37 | - usr/share/doc/*/README.* 38 | - usr/share/doc/*/changelog.* 39 | - usr/share/doc/*/NEWS.* 40 | - usr/share/doc/*/TODO.* 41 | 42 | test: 43 | debian: 44 | image: appimagecrafters/tests-env:debian-stable 45 | command: "./AppRun" 46 | centos: 47 | image: appimagecrafters/tests-env:centos-7 48 | command: "./AppRun" 49 | arch: 50 | image: appimagecrafters/tests-env:archlinux-latest 51 | command: "./AppRun" 52 | fedora: 53 | image: appimagecrafters/tests-env:fedora-30 54 | command: "./AppRun" 55 | ubuntu: 56 | image: appimagecrafters/tests-env:ubuntu-xenial 57 | command: "./AppRun" 58 | 59 | 60 | AppImage: 61 | update-information: None 62 | sign-key: None 63 | arch: x86_64 64 | -------------------------------------------------------------------------------- /recipes/hello-world-gtk/AppImageBuilder.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | script: 3 | - gcc -o hello-world-gtk main.cpp `pkg-config --cflags --libs gtk+-3.0` 4 | - rm -rf ./AppDir || true 5 | - mkdir -p ./AppDir/usr/bin 6 | - mv hello-world-gtk ./AppDir/usr/bin 7 | 8 | 9 | AppDir: 10 | app_info: 11 | id: org.gtkmm.example.HelloApp 12 | name: hello-world-gtk 13 | icon: application-vnd.appimage 14 | version: 0.0.1 15 | exec: usr/bin/hello-world-gtk 16 | 17 | apt: 18 | arch: amd64 19 | sources: 20 | - sourceline: 'deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse' 21 | key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32' 22 | 23 | include: 24 | - libgtk-3-0 25 | - librsvg2-common 26 | exclude: 27 | - adwaita-icon-theme 28 | - humanity-icon-theme 29 | - sensible-utils 30 | - dconf-service 31 | - ubuntu-mono 32 | - fonts-*-core 33 | 34 | runtime: 35 | version: "continuous" 36 | 37 | files: 38 | exclude: 39 | - usr/lib/x86_64-linux-gnu/gconv 40 | - usr/share/man 41 | - usr/share/doc/*/README.* 42 | - usr/share/doc/*/changelog.* 43 | - usr/share/doc/*/NEWS.* 44 | - usr/share/doc/*/TODO.* 45 | 46 | test: 47 | ubuntu: 48 | image: appimagecrafters/tests-env:ubuntu-xenial 49 | command: "./AppRun" 50 | env: 51 | LD_DEBUG: libs 52 | debian: 53 | image: appimagecrafters/tests-env:debian-stable 54 | command: "./AppRun" 55 | centos: 56 | image: appimagecrafters/tests-env:centos-7 57 | command: "./AppRun" 58 | arch: 59 | image: appimagecrafters/tests-env:archlinux-latest 60 | command: "./AppRun" 61 | fedora: 62 | image: appimagecrafters/tests-env:fedora-30 63 | command: "./AppRun" 64 | 65 | 66 | AppImage: 67 | update-information: None 68 | sign-key: None 69 | arch: x86_64 70 | -------------------------------------------------------------------------------- /recipes/hello-world-gtk/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // callback function which is called when button is clicked 4 | static void on_button_clicked(GtkButton *btn, gpointer data) { 5 | // change button label when it's clicked 6 | gtk_button_set_label(btn, "Hello World"); 7 | } 8 | 9 | // callback function which is called when application is first started 10 | static void on_app_activate(GApplication *app, gpointer data) { 11 | // create a new application window for the application 12 | // GtkApplication is sub-class of GApplication 13 | // downcast GApplication* to GtkApplication* with GTK_APPLICATION() macro 14 | GtkWidget *window = gtk_application_window_new(GTK_APPLICATION(app)); 15 | // a simple push button 16 | GtkWidget *btn = gtk_button_new_with_label("Click Me!"); 17 | // connect the event-handler for "clicked" signal of button 18 | g_signal_connect(btn, "clicked", G_CALLBACK(on_button_clicked), NULL); 19 | // add the button to the window 20 | gtk_container_add(GTK_CONTAINER(window), btn); 21 | // display the window 22 | gtk_widget_show_all(GTK_WIDGET(window)); 23 | } 24 | 25 | int main(int argc, char *argv[]) { 26 | // create new GtkApplication with an unique application ID 27 | GtkApplication *app = gtk_application_new( 28 | "org.gtkmm.example.HelloApp", 29 | G_APPLICATION_FLAGS_NONE 30 | ); 31 | // connect the event-handler for "activate" signal of GApplication 32 | // G_CALLBACK() macro is used to cast the callback function pointer 33 | // to generic void pointer 34 | g_signal_connect(app, "activate", G_CALLBACK(on_app_activate), NULL); 35 | // start the application, terminate by closing the window 36 | // GtkApplication* is upcast to GApplication* with G_APPLICATION() macro 37 | int status = g_application_run(G_APPLICATION(app), argc, argv); 38 | // deallocate the application object 39 | g_object_unref(app); 40 | return status; 41 | } -------------------------------------------------------------------------------- /recipes/hello-world-qt5/AppImageBuilder.yml: -------------------------------------------------------------------------------- 1 | # appimage-builder recipe see https://appimage-builder.readthedocs.io for details 2 | version: 1 3 | script: 4 | - rm -rf $TARGET_APPDIR 5 | - mkdir -p $BUILD_DIR/build 6 | - cd $BUILD_DIR/build 7 | - cmake $SOURCE_DIR/src -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr 8 | - make install DESTDIR=$TARGET_APPDIR 9 | AppDir: 10 | app_info: 11 | id: hello_world_qt5 12 | name: hello_world_qt5 13 | icon: application-vnd.appimage 14 | version: latest 15 | exec: usr/bin/hello_world_qt5 16 | exec_args: $@ 17 | apt: 18 | arch: 19 | - amd64 20 | allow_unauthenticated: true 21 | sources: 22 | - sourceline: deb http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse 23 | - sourceline: deb http://security.ubuntu.com/ubuntu/ focal-security main restricted universe multiverse 24 | - sourceline: deb http://archive.ubuntu.com/ubuntu/ focal-updates main restricted universe multiverse 25 | - sourceline: deb http://archive.neon.kde.org/user focal main 26 | include: 27 | - libbz2-1.0 28 | - libcom-err2 29 | - libdbus-1-3 30 | - libgpg-error0 31 | - libkeyutils1 32 | - liblzma5 33 | - libmount1 34 | - libpcre3 35 | - libqt5svg5 36 | - libtinfo6 37 | - libuuid1 38 | - qml-module-qtquick-window2 39 | - qml-module-qtquick2 40 | - qt5-gtk-platformtheme 41 | - qtwayland5 42 | files: 43 | exclude: 44 | - usr/share/man 45 | - usr/share/doc/*/README.* 46 | - usr/share/doc/*/changelog.* 47 | - usr/share/doc/*/NEWS.* 48 | - usr/share/doc/*/TODO.* 49 | test: 50 | fedora-30: 51 | image: appimagecrafters/tests-env:fedora-30 52 | command: ./AppRun 53 | debian-stable: 54 | image: appimagecrafters/tests-env:debian-stable 55 | command: ./AppRun 56 | archlinux-latest: 57 | image: appimagecrafters/tests-env:archlinux-latest 58 | command: ./AppRun 59 | centos-7: 60 | image: appimagecrafters/tests-env:centos-7 61 | command: ./AppRun 62 | ubuntu-xenial: 63 | image: appimagecrafters/tests-env:ubuntu-xenial 64 | command: ./AppRun 65 | AppImage: 66 | arch: x86_64 67 | update-information: guess 68 | -------------------------------------------------------------------------------- /recipes/hello-world-qt5/recipe-with-apprun-v3.yml: -------------------------------------------------------------------------------- 1 | # appimage-builder recipe see https://appimage-builder.readthedocs.io for details 2 | version: 1 3 | script: 4 | - rm -rf $TARGET_APPDIR 5 | - mkdir -p $BUILD_DIR/build 6 | - cd $BUILD_DIR/build 7 | - cmake $SOURCE_DIR/src -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr 8 | - make install DESTDIR=$TARGET_APPDIR 9 | AppDir: 10 | app_info: 11 | id: hello_world_qt5 12 | name: hello_world_qt5 13 | icon: application-vnd.appimage 14 | version: latest 15 | exec: usr/bin/hello_world_qt5 16 | exec_args: '$@' 17 | apt: 18 | arch: 19 | - amd64 20 | allow_unauthenticated: true 21 | sources: 22 | - sourceline: deb http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse 23 | - sourceline: deb http://security.ubuntu.com/ubuntu/ focal-security main restricted universe multiverse 24 | - sourceline: deb http://archive.ubuntu.com/ubuntu/ focal-updates main restricted universe multiverse 25 | - sourceline: deb http://archive.neon.kde.org/user focal main 26 | include: 27 | - libbz2-1.0 28 | - libcom-err2 29 | - libdbus-1-3 30 | - libgpg-error0 31 | - libkeyutils1 32 | - liblzma5 33 | - libmount1 34 | - libpcre3 35 | - libqt5svg5 36 | - libtinfo6 37 | - libuuid1 38 | - qml-module-qtquick-window2 39 | - qml-module-qtquick2 40 | - qt5-gtk-platformtheme 41 | - qtwayland5 42 | exclude: 43 | - adwaita-icon-theme 44 | files: 45 | exclude: 46 | - usr/share/man 47 | - usr/share/doc/*/README.* 48 | - usr/share/doc/*/changelog.* 49 | - usr/share/doc/*/NEWS.* 50 | - usr/share/doc/*/TODO.* 51 | 52 | runtime: 53 | version: v3.0.0-devel-1 54 | debug: true 55 | test: 56 | fedora-30: 57 | image: appimagecrafters/tests-env:fedora-30 58 | command: ./AppRun 59 | debian-stable: 60 | image: appimagecrafters/tests-env:debian-stable 61 | command: ./AppRun 62 | archlinux-latest: 63 | image: appimagecrafters/tests-env:archlinux-latest 64 | command: ./AppRun 65 | centos-7: 66 | image: appimagecrafters/tests-env:centos-7 67 | command: ./AppRun 68 | ubuntu-xenial: 69 | image: appimagecrafters/tests-env:ubuntu-xenial 70 | command: ./AppRun 71 | AppImage: 72 | arch: x86_64 73 | update-information: guess 74 | -------------------------------------------------------------------------------- /recipes/hello-world-qt5/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | 3 | project(hello_world_qt5 LANGUAGES CXX) 4 | 5 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 6 | 7 | set(CMAKE_AUTOUIC ON) 8 | set(CMAKE_AUTOMOC ON) 9 | set(CMAKE_AUTORCC ON) 10 | 11 | set(CMAKE_CXX_STANDARD 11) 12 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 13 | 14 | find_package(Qt5 COMPONENTS Core Quick REQUIRED) 15 | 16 | add_executable(hello_world_qt5 main.cpp qml.qrc) 17 | 18 | 19 | target_link_libraries(hello_world_qt5 PRIVATE Qt5::Core Qt5::Quick) 20 | 21 | 22 | install(TARGETS hello_world_qt5 DESTINATION bin) 23 | -------------------------------------------------------------------------------- /recipes/hello-world-qt5/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 8 | QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 9 | #endif 10 | 11 | QGuiApplication app(argc, argv); 12 | 13 | QQmlApplicationEngine engine; 14 | const QUrl url(QStringLiteral("qrc:/main.qml")); 15 | QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, 16 | &app, [url](QObject *obj, const QUrl &objUrl) { 17 | if (!obj && url == objUrl) 18 | QCoreApplication::exit(-1); 19 | }, Qt::QueuedConnection); 20 | engine.load(url); 21 | 22 | QTimer::singleShot(2000, &app, &QGuiApplication::quit); 23 | return app.exec(); 24 | } 25 | -------------------------------------------------------------------------------- /recipes/hello-world-qt5/src/main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Window 2.15 3 | 4 | Window { 5 | width: 640 6 | height: 480 7 | visible: true 8 | title: qsTr("Hello World") 9 | 10 | Rectangle { 11 | anchors.fill: parent 12 | 13 | Text { 14 | text: "Hello World!" 15 | anchors.centerIn: parent 16 | 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /recipes/hello-world-qt5/src/qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | main.qml 4 | 5 | 6 | -------------------------------------------------------------------------------- /recipes/hello-world-qt6/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | 3 | project(hello_world_qt6 VERSION 0.1 LANGUAGES CXX) 4 | 5 | set(CMAKE_AUTOMOC ON) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | 8 | find_package(Qt6 6.2 COMPONENTS Quick REQUIRED) 9 | 10 | qt_add_executable(hello_world_qt6 main.cpp) 11 | 12 | qt_add_qml_module(hello_world_qt6 13 | URI hello_world_qt6_qml 14 | VERSION 1.0 15 | QML_FILES main.qml 16 | ) 17 | 18 | target_link_libraries(hello_world_qt6 PRIVATE Qt6::Quick) 19 | install(TARGETS hello_world_qt6 DESTINATION bin) -------------------------------------------------------------------------------- /recipes/hello-world-qt6/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | QGuiApplication app(argc, argv); 8 | 9 | QQmlApplicationEngine engine; 10 | const QUrl url(u"qrc:/hello_world_qt6_qml/main.qml"_qs); 11 | 12 | QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { 13 | if (!obj && url == objUrl) 14 | QCoreApplication::exit(-1); 15 | }, Qt::QueuedConnection); 16 | engine.load(url); 17 | 18 | return app.exec(); 19 | } 20 | -------------------------------------------------------------------------------- /recipes/hello-world-qt6/src/main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2 | 3 | Window { 4 | width: 640 5 | height: 480 6 | visible: true 7 | title: qsTr("Hello World") 8 | 9 | Rectangle { 10 | anchors.fill: parent 11 | 12 | Text { 13 | text: "Hello World!" 14 | anchors.centerIn: parent 15 | 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /recipes/kcalc-nbc/AppImageBuilder.yml: -------------------------------------------------------------------------------- 1 | # non backward compatible recipe 2 | version: 1 3 | script: 4 | - rm -rf $TARGET_APPDIR || true 5 | 6 | AppDir: 7 | app_info: 8 | id: org.kde.kcalc 9 | name: kcalc 10 | icon: accessories-calculator 11 | version: 17.12.3 12 | exec: usr/bin/kcalc 13 | 14 | apt: 15 | arch: amd64 16 | sources: 17 | - sourceline: 'deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ xenial main restricted universe multiverse' 18 | key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32' 19 | 20 | include: 21 | - kcalc 22 | - libpulse0 23 | exclude: 24 | - phonon4qt5 25 | - libkf5service-bin 26 | - perl 27 | - perl-base 28 | - libpam-runtime 29 | - procps 30 | - dh-python 31 | - samba-libs 32 | - docbook-xml 33 | - sound-theme-freedesktop 34 | 35 | files: 36 | exclude: 37 | # exclude glibc for a smaller but non backward compatible bundles 38 | - opt/libc 39 | 40 | runtime: 41 | version: "continuous" 42 | 43 | test: 44 | debian: 45 | image: appimagecrafters/tests-env:debian-stable 46 | command: "./AppRun" 47 | centos: 48 | image: appimagecrafters/tests-env:centos-7 49 | command: "./AppRun" 50 | arch: 51 | image: appimagecrafters/tests-env:archlinux-latest 52 | command: "./AppRun" 53 | fedora: 54 | image: appimagecrafters/tests-env:fedora-30 55 | command: "./AppRun" 56 | ubuntu: 57 | image: appimagecrafters/tests-env:ubuntu-xenial 58 | command: "./AppRun" 59 | 60 | 61 | AppImage: 62 | update-information: None 63 | sign-key: None 64 | arch: x86_64 65 | -------------------------------------------------------------------------------- /recipes/kcalc/AppImageBuilder.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | script: 3 | - rm -rf "$TARGET_APPDIR" || true 4 | 5 | AppDir: 6 | app_info: 7 | id: org.kde.kcalc 8 | name: kcalc 9 | icon: accessories-calculator 10 | version: 17.12.3 11 | exec: usr/bin/kcalc 12 | 13 | after_runtime: 14 | - echo "HI! $USER" 15 | - ls 16 | apt: 17 | arch: amd64 18 | sources: 19 | - sourceline: 'deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse' 20 | key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32' 21 | - sourceline: 'deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ focal-updates main restricted universe multiverse' 22 | - sourceline: 'deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ focal-backports main restricted universe multiverse' 23 | 24 | include: 25 | - kcalc 26 | - libpulse0 27 | exclude: 28 | - phonon4qt5 29 | - libkf5service-bin 30 | - perl 31 | - perl-base 32 | - libpam-runtime 33 | - procps 34 | 35 | files: 36 | exclude: 37 | - usr/lib/x86_64-linux-gnu/gconv 38 | - usr/share/man 39 | - usr/share/doc/*/README.* 40 | - usr/share/doc/*/changelog.* 41 | - usr/share/doc/*/NEWS.* 42 | - usr/share/doc/*/TODO.* 43 | - usr/share/metainfo/org.kde.kcalc.appdata.xml 44 | runtime: 45 | version: "continuous" 46 | 47 | test: 48 | debian: 49 | image: appimagecrafters/tests-env:debian-stable 50 | command: "./AppRun" 51 | centos: 52 | image: appimagecrafters/tests-env:centos-7 53 | command: "./AppRun" 54 | arch: 55 | image: appimagecrafters/tests-env:archlinux-latest 56 | command: "./AppRun" 57 | fedora: 58 | image: appimagecrafters/tests-env:fedora-30 59 | command: "./AppRun" 60 | ubuntu: 61 | image: appimagecrafters/tests-env:ubuntu-xenial 62 | command: "./AppRun" 63 | 64 | 65 | AppImage: 66 | update-information: None 67 | sign-key: None 68 | arch: x86_64 69 | -------------------------------------------------------------------------------- /recipes/parole/AppImageBuilder.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | script: 3 | - rm -rf $TARGET_APPDIR || true 4 | 5 | AppDir: 6 | app_info: 7 | id: org.xfce.Parole 8 | name: parole 9 | icon: parole 10 | version: latest 11 | exec: usr/bin/parole 12 | 13 | apt: 14 | arch: amd64 15 | sources: 16 | - sourceline: 'deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse' 17 | key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32' 18 | 19 | include: 20 | - parole 21 | - gstreamer1.0-x 22 | - gstreamer1.0-alsa 23 | - gstreamer1.0-plugins-base 24 | - gstreamer1.0-plugins-good 25 | - gstreamer1.0-plugins-bad 26 | - gstreamer1.0-plugins-ugly 27 | - gstreamer1.0-pulseaudio 28 | - coreutils 29 | - dash 30 | - dbus 31 | - libdbus-1-3 32 | - libsystemd0 33 | 34 | files: 35 | exclude: 36 | - usr/lib/x86_64-linux-gnu/gconv 37 | - usr/share/man 38 | - usr/share/doc/*/README.* 39 | - usr/share/doc/*/changelog.* 40 | - usr/share/doc/*/NEWS.* 41 | - usr/share/doc/*/TODO.* 42 | - usr/share/metainfo/org.kde.kcalc.appdata.xml 43 | test: 44 | debian: 45 | image: appimagecrafters/tests-env:debian-stable 46 | command: "dbus-launch ./AppRun" 47 | centos: 48 | image: appimagecrafters/tests-env:centos-7 49 | command: "dbus-launch ./AppRun" 50 | arch: 51 | image: appimagecrafters/tests-env:archlinux-latest 52 | command: "dbus-launch ./AppRun" 53 | fedora: 54 | image: appimagecrafters/tests-env:fedora-30 55 | command: "dbus-launch ./AppRun" 56 | ubuntu: 57 | image: appimagecrafters/tests-env:ubuntu-xenial 58 | command: "dbus-launch ./AppRun" 59 | 60 | AppImage: 61 | arch: x86_64 62 | -------------------------------------------------------------------------------- /recipes/pyqt5/AppImageBuilder.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | script: 3 | # Remove any previous build 4 | - rm -rf $TARGET_APPDIR | true 5 | # Make usr and icons dirs 6 | - mkdir -p $TARGET_APPDIR/usr/src 7 | # Copy the python application code into the AppDir 8 | - cp main.py $TARGET_APPDIR/usr/src -r 9 | # Install application dependencies 10 | - python3 -m pip install --ignore-installed --prefix=/usr --root=$TARGET_APPDIR -r ./requirements.txt 11 | 12 | 13 | AppDir: 14 | app_info: 15 | id: org.appimage-crafters.python-appimage-example 16 | name: python appimage hello world 17 | icon: utilities-terminal 18 | version: 0.1.0 19 | # Set the python executable as entry point 20 | exec: usr/bin/python3 21 | # Set the application main script path as argument. Use '$@' to forward CLI parameters 22 | exec_args: "$APPDIR/usr/src/main.py $@" 23 | 24 | apt: 25 | arch: amd64 26 | sources: 27 | - sourceline: 'deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse' 28 | key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32' 29 | 30 | include: 31 | - python3 32 | - python3-pkg-resources 33 | - python3-pyqt5 34 | - libfreetype6 35 | - libfontconfig1 36 | exclude: [] 37 | 38 | runtime: 39 | version: "continuous" 40 | env: 41 | PATH: '${APPDIR}/usr/bin:${PATH}' 42 | # Set python home 43 | # See https://docs.python.org/3/using/cmdline.html#envvar-PYTHONHOME 44 | PYTHONHOME: '${APPDIR}/usr' 45 | # Path to the site-packages dir or other modules dirs 46 | # See https://docs.python.org/3/using/cmdline.html#envvar-PYTHONPATH 47 | PYTHONPATH: '${APPDIR}/usr/lib/python3.8/site-packages' 48 | 49 | test: 50 | fedora: 51 | image: appimagecrafters/tests-env:fedora-30 52 | command: ./AppRun 53 | debian: 54 | image: appimagecrafters/tests-env:debian-stable 55 | command: ./AppRun 56 | arch: 57 | image: appimagecrafters/tests-env:archlinux-latest 58 | command: ./AppRun 59 | centos: 60 | image: appimagecrafters/tests-env:centos-7 61 | command: ./AppRun 62 | ubuntu: 63 | image: appimagecrafters/tests-env:ubuntu-xenial 64 | command: ./AppRun 65 | 66 | AppImage: 67 | update-information: 'gh-releases-zsync|AppImageCrafters|python-appimage-example|latest|python-appimage-*x86_64.AppImage.zsync' 68 | sign-key: None 69 | arch: x86_64 -------------------------------------------------------------------------------- /recipes/pyqt5/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow 5 | from PyQt5.QtCore import Qt 6 | from PyQt5 import QtGui 7 | from pyfiglet import Figlet 8 | 9 | 10 | # Subclass QMainWindow to customise your application's main window 11 | class MainWindow(QMainWindow): 12 | def __init__(self, *args, **kwargs): 13 | super(MainWindow, self).__init__(*args, **kwargs) 14 | 15 | self.setWindowTitle("My Awesome App") 16 | f = Figlet(font="digital") 17 | label = QLabel(f.renderText("Hello World!")) 18 | label.setFont(QtGui.QFont("monospace", 14, QtGui.QFont.Black)) 19 | 20 | label.setAlignment(Qt.AlignCenter) 21 | 22 | self.setCentralWidget(label) 23 | 24 | 25 | app = QApplication(sys.argv) 26 | 27 | window = MainWindow() 28 | window.show() 29 | 30 | app.exec_() 31 | -------------------------------------------------------------------------------- /recipes/pyqt5/requirements.txt: -------------------------------------------------------------------------------- 1 | pyfiglet -------------------------------------------------------------------------------- /recipes/python/AppImageBuilder.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | script: 3 | # Remove any previous build 4 | - rm -rf $TARGET_APPDIR | true 5 | # Make usr and icons dirs 6 | - mkdir -p $TARGET_APPDIR/usr/src 7 | # Copy the python application code into the AppDir 8 | - cp *.py $TARGET_APPDIR/usr/src 9 | 10 | 11 | AppDir: 12 | app_info: 13 | id: org.appimage-crafters.python-appimage-example 14 | name: hello world 15 | icon: utilities-terminal 16 | version: 0.1.0 17 | exec: "usr/bin/python3" 18 | exec_args: "$APPDIR/usr/src/one.py $@" 19 | 20 | apt: 21 | arch: amd64 22 | sources: 23 | - sourceline: 'deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse' 24 | key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32' 25 | 26 | include: 27 | - python3 28 | - coreutils 29 | exclude: [ ] 30 | 31 | runtime: 32 | version: "continuous" 33 | env: 34 | EXPORTED_BINARIES: "$APPDIR/usr/bin/env" 35 | 36 | test: 37 | fedora: 38 | image: appimagecrafters/tests-env:fedora-30 39 | command: "./AppRun" 40 | arch: 41 | image: appimagecrafters/tests-env:archlinux-latest 42 | command: "./AppRun" 43 | centos: 44 | image: appimagecrafters/tests-env:centos-7 45 | command: "./AppRun" 46 | ubuntu: 47 | image: appimagecrafters/tests-env:ubuntu-xenial 48 | command: "./AppRun" 49 | debian: 50 | image: appimagecrafters/tests-env:debian-stable 51 | command: "./AppRun" 52 | 53 | 54 | AppImage: 55 | update-information: 'gh-releases-zsync|AppImageCrafters|python-appimage-example|latest|python-appimage-*x86_64.AppImage.zsync' 56 | sign-key: None 57 | arch: x86_64 -------------------------------------------------------------------------------- /recipes/python/one.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import os 4 | import subprocess 5 | 6 | print("ONE!") 7 | 8 | for k, v in os.environ.items(): 9 | print("%s: %s" % (k, v)) 10 | 11 | path = os.path.abspath(__file__) 12 | path = os.path.dirname(path) 13 | output = subprocess.check_output([os.path.join(path, "two.py")]) 14 | print("exec two from one: " + output.decode()) 15 | -------------------------------------------------------------------------------- /recipes/python/two.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | print("TWO!") 4 | -------------------------------------------------------------------------------- /recipes/qmlscene/AppImageBuilder.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | script: 3 | - rm -rf $TARGET_APPDIR 4 | - mkdir -p $TARGET_APPDIR 5 | - cp -f main.qml $TARGET_APPDIR/ 6 | 7 | AppDir: 8 | app_info: 9 | id: org.qt.qmlscene 10 | name: qmlscene 11 | icon: text-x-qml 12 | version: 19.08.02 13 | exec: usr/lib/qt5/bin/qmlscene 14 | exec_args: $@ $APPDIR/main.qml 15 | 16 | apt: 17 | arch: amd64 18 | sources: 19 | - sourceline: 'deb [arch=amd64] http://mx.archive.ubuntu.com/ubuntu/ bionic main restricted universe multiverse' 20 | - sourceline: 'deb [arch=amd64] http://mx.archive.ubuntu.com/ubuntu/ bionic-updates main restricted universe multiverse' 21 | key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32' 22 | - sourceline: 'deb http://archive.neon.kde.org/user bionic main' 23 | key_url: 'http://archive.neon.kde.org/public.key' 24 | 25 | include: 26 | - qmlscene 27 | - qml-module-qtquick2 28 | - qtwayland5 29 | - libgcrypt20 30 | - libgpg-error0 31 | - liblz4-1 32 | - liblzma5 33 | - libbsd0 34 | - libpng16-16 35 | - libxdamage1 36 | - libxxf86vm1 37 | - libxshmfence1 38 | - libxfixes3 39 | - libxcursor1 40 | exclude: 41 | - perl-base 42 | 43 | files: 44 | include: 45 | - bin/ln 46 | - bin/cp 47 | - bin/cat 48 | - bin/grep 49 | - bin/echo 50 | - bin/readlink 51 | - usr/bin/rev 52 | - usr/bin/dirname 53 | - usr/bin/[ 54 | exclude: 55 | - usr/lib/x86_64-linux-gnu/gconv 56 | - usr/share/man 57 | - usr/share/doc/*/README.* 58 | - usr/share/doc/*/changelog.* 59 | - usr/share/doc/*/NEWS.* 60 | - usr/share/doc/*/TODO.* 61 | - bin/* 62 | - sbin/* 63 | - usr/bin/* 64 | - usr/sbin/* 65 | 66 | test: 67 | debian: 68 | image: appimagecrafters/tests-env:debian-stable 69 | command: "./AppRun" 70 | centos: 71 | image: appimagecrafters/tests-env:centos-7 72 | command: "./AppRun" 73 | arch: 74 | image: appimagecrafters/tests-env:archlinux-latest 75 | command: "./AppRun" 76 | fedora: 77 | image: appimagecrafters/tests-env:fedora-30 78 | command: "./AppRun" 79 | ubuntu: 80 | image: appimagecrafters/tests-env:ubuntu-xenial 81 | command: "./AppRun" 82 | 83 | AppImage: 84 | update-information: None 85 | sign-key: None 86 | arch: x86_64 -------------------------------------------------------------------------------- /recipes/qmlscene/main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | id: page 5 | width: 320; height: 480 6 | color: "lightgray" 7 | 8 | Text { 9 | id: helloText 10 | text: "Hello world!" 11 | y: 30 12 | anchors.horizontalCenter: page.horizontalCenter 13 | font.pointSize: 24; font.bold: true 14 | } 15 | } -------------------------------------------------------------------------------- /recipes/tkinter/AppImageBuilder.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | script: 3 | # Remove any previous build 4 | - rm -rf $TARGET_APPDIR | true 5 | # Make usr and icons dirs 6 | - mkdir -p $TARGET_APPDIR/usr/src 7 | # Copy the python application code into the AppDir 8 | - cp main.py $TARGET_APPDIR/usr/src -r 9 | # Install application dependencies 10 | - python3 -m pip install --ignore-installed --prefix=/usr --root=$TARGET_APPDIR -r ./requirements.txt 11 | 12 | 13 | AppDir: 14 | app_info: 15 | id: org.appimage-crafters.tkinter-appimage-example 16 | name: hello-tkinter 17 | icon: utilities-terminal 18 | version: 0.1.0 19 | # Set the python executable as entry point 20 | exec: usr/bin/python3 21 | # Set the application main script path as argument. Use '$@' to forward CLI parameters 22 | exec_args: "$APPDIR/usr/src/main.py $@" 23 | 24 | apt: 25 | arch: amd64 26 | sources: 27 | - sourceline: 'deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ bionic main restricted universe multiverse' 28 | key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32' 29 | 30 | include: 31 | - libpng16-16 32 | - libglib2.0-0 33 | - libgraphite2-3 34 | - python3-tk 35 | exclude: [] 36 | 37 | runtime: 38 | env: 39 | PATH: '${APPDIR}/usr/bin:${PATH}' 40 | # Set python home 41 | # See https://docs.python.org/3/using/cmdline.html#envvar-PYTHONHOME 42 | PYTHONHOME: '${APPDIR}/usr' 43 | # Path to the site-packages dir or other modules dirs 44 | # See https://docs.python.org/3/using/cmdline.html#envvar-PYTHONPATH 45 | PYTHONPATH: '${APPDIR}/usr/lib/python3.7/tkinter:' 46 | # Set tkinter lib path 47 | # https://docs.python.org/3/faq/gui.html?highlight=tcl_library#how-do-i-freeze-tkinter-applications 48 | APPDIR_LIBRARY_PATH: '${APPDIR}/usr/lib:${APPDIR}/usr/lib/x86_64-linux-gnu:${APPDIR}/lib/x86_64-linux-gnu' 49 | TCL_LIBRARY: '${APPDIR}/usr/share/tcltk/tcl8.6' 50 | TK_LIBRARY: '${APPDIR}/usr/lib/tcltk/x86_64-linux-gnu/tk8.6' 51 | TKPATH: '{APPDIR}/usr/lib/tcltk/x86_64-linux-gnu/tk8.6' 52 | test: 53 | arch: 54 | image: appimagecrafters/tests-env:archlinux-latest 55 | command: "LD_DEBUG=libs ./AppRun 2>&1 | grep 'init: '" 56 | fedora: 57 | image: appimagecrafters/tests-env:fedora-30 58 | command: ./AppRun 59 | debian: 60 | image: appimagecrafters/tests-env:debian-stable 61 | command: ./AppRun 62 | centos: 63 | image: appimagecrafters/tests-env:centos-7 64 | command: ./AppRun 65 | ubuntu: 66 | image: appimagecrafters/tests-env:ubuntu-xenial 67 | command: ./AppRun 68 | 69 | AppImage: 70 | update-information: 'gh-releases-zsync|AppImageCrafters|python-appimage-example|latest|python-appimage-*x86_64.AppImage.zsync' 71 | sign-key: None 72 | arch: x86_64 -------------------------------------------------------------------------------- /recipes/tkinter/main.py: -------------------------------------------------------------------------------- 1 | from tkinter import * 2 | from tkinter import ttk 3 | 4 | root = Tk() 5 | ttk.Button(root, text="Hello World").grid() 6 | root.mainloop() 7 | -------------------------------------------------------------------------------- /recipes/tkinter/requirements.txt: -------------------------------------------------------------------------------- 1 | pyfiglet -------------------------------------------------------------------------------- /recipes/vlc/AppImageBuilder.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | 3 | script: 4 | - rm -r ./AppDir || true 5 | 6 | AppDir: 7 | app_info: 8 | id: vlc 9 | name: VLC media player 10 | icon: vlc 11 | version: 3.0.8-0-gf350b6b5a7 12 | exec: usr/bin/vlc 13 | 14 | apt: 15 | arch: amd64 16 | sources: 17 | - sourceline: 'deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ bionic main restricted universe multiverse' 18 | key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32' 19 | - sourceline: 'deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ bionic-updates main restricted universe multiverse' 20 | 21 | include: 22 | - vlc 23 | 24 | test: 25 | debian: 26 | image: appimagecrafters/tests-env:debian-stable 27 | command: "./AppRun" 28 | centos: 29 | image: appimagecrafters/tests-env:centos-7 30 | command: "./AppRun" 31 | arch: 32 | image: appimagecrafters/tests-env:archlinux-latest 33 | command: "./AppRun" 34 | fedora: 35 | image: appimagecrafters/tests-env:fedora-30 36 | command: "./AppRun" 37 | ubuntu: 38 | image: appimagecrafters/tests-env:ubuntu-xenial 39 | command: "./AppRun" 40 | 41 | AppImage: 42 | arch: x86_64 43 | update-information: None 44 | sign-key: None 45 | -------------------------------------------------------------------------------- /recipes/wget/AppImageBuilder.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | script: 3 | - rm -r ./$TARGET_APPDIR || true 4 | 5 | AppDir: 6 | app_info: 7 | id: org.gnu.wget 8 | version: !ENV '${APP_VERSION}' 9 | name: wget 10 | icon: utilities-terminal 11 | exec: usr/bin/wget 12 | 13 | apt: 14 | arch: !ENV ${TARGET_ARCH} 15 | sources: 16 | - sourceline: !ENV 'deb [arch=${TARGET_ARCH}] http://archive.ubuntu.com/ubuntu/ xenial main restricted universe multiverse' 17 | key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32' 18 | 19 | include: 20 | - wget 21 | - libssl1.0.0 22 | # Domain name resolution lib 23 | - libnss-mdns 24 | 25 | files: 26 | exclude: 27 | - usr/lib/x86_64-linux-gnu/gconv 28 | - usr/share/man 29 | - usr/share/doc/*/README.* 30 | - usr/share/doc/*/changelog.* 31 | - usr/share/doc/*/NEWS.* 32 | - usr/share/doc/*/TODO.* 33 | 34 | runtime: 35 | env: 36 | PATH: '${APPDIR}/usr/bin:${APPDIR}/bin:${PATH}' 37 | 38 | test: 39 | debian: 40 | image: appimagecrafters/tests-env:debian-stable 41 | command: "./AppRun --version" 42 | centos: 43 | image: appimagecrafters/tests-env:centos-7 44 | command: "./AppRun --version" 45 | arch: 46 | image: appimagecrafters/tests-env:archlinux-latest 47 | command: "./AppRun --version" 48 | fedora: 49 | image: appimagecrafters/tests-env:fedora-30 50 | command: "./AppRun --version" 51 | ubuntu: 52 | image: appimagecrafters/tests-env:ubuntu-xenial 53 | command: "./AppRun --version" 54 | 55 | AppImage: 56 | arch: x86_64 57 | update-information: None 58 | sign-key: None 59 | file_name: !ENV 'wget-${APP_VERSION}-${TARGET_ARCH}.AppImage' 60 | -------------------------------------------------------------------------------- /recipes/wine/AppImageBuilder.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | 3 | AppDir: 4 | app_info: 5 | id: org.winehq.wine 6 | name: wine 7 | icon: wine 8 | version: stable 9 | exec: opt/wine-stable/bin/wine64 10 | 11 | apt: 12 | arch: [amd64, i386] 13 | sources: 14 | - sourceline: 'deb http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse' 15 | - sourceline: 'deb http://archive.ubuntu.com/ubuntu/ focal-updates main restricted universe multiverse' 16 | - sourceline: 'deb http://archive.ubuntu.com/ubuntu/ focal-backports main restricted universe multiverse' 17 | key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32' 18 | - sourceline: 'deb https://dl.winehq.org/wine-builds/ubuntu/ focal main' 19 | key_url: 'https://dl.winehq.org/wine-builds/winehq.key' 20 | 21 | include: 22 | - winehq-stable 23 | - libfreetype6 24 | - libfontconfig1 25 | exclude: 26 | - dpkg 27 | files: 28 | exclude: 29 | - usr/lib/x86_64-linux-gnu/gconv 30 | - usr/share/man 31 | - usr/share/doc/*/README.* 32 | - usr/share/doc/*/changelog.* 33 | - usr/share/doc/*/NEWS.* 34 | - usr/share/doc/*/TODO.* 35 | runtime: 36 | path_mappings: 37 | - /opt/wine-stable:$APPDIR/opt/wine-stable 38 | 39 | test: 40 | debian: 41 | image: appimagecrafters/tests-env:debian-stable 42 | command: "./AppRun --version" 43 | centos: 44 | image: appimagecrafters/tests-env:centos-7 45 | command: "./AppRun --version" 46 | arch: 47 | image: appimagecrafters/tests-env:archlinux-latest 48 | command: "./AppRun --version" 49 | fedora: 50 | image: appimagecrafters/tests-env:fedora-30 51 | command: "./AppRun --version" 52 | ubuntu: 53 | image: appimagecrafters/tests-env:ubuntu-xenial 54 | command: "./AppRun --version" 55 | 56 | AppImage: 57 | update-information: None 58 | sign-key: None 59 | arch: x86_64 60 | 61 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | arpy==2.3.0 2 | certifi==2023.7.22 3 | cffi==1.16.0 4 | charset-normalizer==3.3.0 5 | configparser==6.0.0 6 | contextlib2==21.6.0 7 | cryptography==42.0.0 8 | decorator==5.1.1 9 | distlib==0.3.7 10 | docker==6.1.3 11 | emrichen==0.4.0 12 | filelock==3.12.4 13 | idna==3.4 14 | jsonpath-rw==1.4.0 15 | libconf==2.0.1 16 | lief==0.12.2 17 | packaging==23.2 18 | PGPy==0.6.0 19 | pipenv==2023.10.3 20 | platformdirs==3.11.0 21 | ply==3.11 22 | prompt-toolkit==3.0.36 23 | pyaml==21.10.1 24 | pyasn1==0.5.0 25 | pycparser==2.21 26 | pydpkg==1.9.2 27 | PyMySQL==1.1.0 28 | python-gnupg==0.4.9 29 | PyYAML==6.0.1 30 | questionary==2.0.1 31 | requests==2.31.0 32 | roam==0.3.1 33 | ruamel.yaml==0.17.35 34 | ruamel.yaml.clib==0.2.8 35 | schema==0.7.5 36 | shutils==0.1.0 37 | six==1.16.0 38 | urllib3==1.26.9 39 | virtualenv==20.24.5 40 | wcwidth==0.2.8 41 | websocket-client==1.6.4 42 | zstandard==0.19.0 43 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Copyright 2020 Alexis Lopez Zubieta 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a 6 | # copy of this software and associated documentation files (the "Software"), 7 | # to deal in the Software without restriction, including without limitation the 8 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9 | # sell copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | 15 | import setuptools 16 | 17 | with open("README.md", "r", encoding="utf-8") as fh: 18 | long_description = fh.read() 19 | 20 | setuptools.setup( 21 | name="appimage_builder", 22 | use_scm_version=True, 23 | setup_requires=["setuptools_scm"], 24 | author="Alexis Lopez Zubieta", 25 | author_email="contact@azubieta.net", 26 | description="Recipe based AppImage creation meta-tool", 27 | long_description=long_description, 28 | long_description_content_type="text/markdown", 29 | entry_points={ 30 | "console_scripts": [ 31 | "appimage-builder = appimagebuilder.__main__:__main__", 32 | ] 33 | }, 34 | url="https://github.com/AppImageCrafters/appimage-builder", 35 | project_urls={ 36 | "Bug Tracker": "https://github.com/AppImageCrafters/appimage-builder/issues", 37 | "Documentation": "https://appimage-builder.readthedocs.io", 38 | "Source Code": "https://github.com/AppImageCrafters/appimage-builder", 39 | }, 40 | packages=setuptools.find_packages(), 41 | classifiers=[ 42 | "Programming Language :: Python :: 3", 43 | "License :: OSI Approved :: MIT License", 44 | ], 45 | license="MIT", 46 | install_requires=[ 47 | "pyyaml>=5", 48 | "docker", 49 | "requests", 50 | "schema", 51 | "packaging", 52 | "questionary", 53 | "emrichen", 54 | "ruamel.yaml", 55 | "roam", 56 | "urllib3", 57 | "lief", 58 | "python-gnupg", 59 | "libconf", 60 | "pydpkg", 61 | ], 62 | python_requires=">=3.6", 63 | package_data={"": []}, 64 | include_package_data=True, 65 | ) 66 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AppImageCrafters/appimage-builder/bf6123ee43715e52d2a73639f9acb1251e8af640/tests/__init__.py -------------------------------------------------------------------------------- /tests/builder/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AppImageCrafters/appimage-builder/bf6123ee43715e52d2a73639f9acb1251e8af640/tests/builder/__init__.py -------------------------------------------------------------------------------- /tests/builder/runtime/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AppImageCrafters/appimage-builder/bf6123ee43715e52d2a73639f9acb1251e8af640/tests/builder/runtime/__init__.py -------------------------------------------------------------------------------- /tests/builder/runtime/test_environment.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | from unittest import TestCase 14 | 15 | from appimagebuilder.modules.setup.environment import Environment 16 | 17 | 18 | class TestEnvironment(TestCase): 19 | def test_serialize(self): 20 | env = Environment( 21 | { 22 | "APPDIR": "$ORIGIN/..", 23 | "APPIMAGE_UUID": "123", 24 | "APPDIR_EXEC_ARGS": ["-f", "$@"], 25 | "LIST": ["1", "2"], 26 | "DICT": { 27 | "a": "b", 28 | "c": "d", 29 | }, 30 | "APPDIR_LIBRARY_PATH": ["/AppDir/usr/lib"], 31 | "APPDIR_PATH_MAPPINGS": ["a:b", "c:d"], 32 | "NONE": None, 33 | } 34 | ) 35 | result = env.serialize() 36 | 37 | expected = ( 38 | "APPDIR=$ORIGIN/..\n" 39 | "APPIMAGE_UUID=123\n" 40 | "APPDIR_EXEC_ARGS=-f $@\n" 41 | "LIST=1:2\n" 42 | "DICT=a:b;c:d;\n" 43 | "APPDIR_LIBRARY_PATH=/AppDir/usr/lib\n" 44 | "APPDIR_PATH_MAPPINGS=a:b;c:d;\n" 45 | 'NONE=""\n' 46 | ) 47 | 48 | self.assertEqual(expected, result) 49 | -------------------------------------------------------------------------------- /tests/builder/runtime/test_executables.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | from pathlib import Path 14 | from unittest import TestCase 15 | 16 | from appimagebuilder.modules.setup.apprun_2.executables import ( 17 | InterpretedExecutable, 18 | ) 19 | 20 | 21 | class TestInterpretedExecutable(TestCase): 22 | def setUp(self) -> None: 23 | self.data_dir = Path(__file__).parent / "data" 24 | 25 | def test_read_shebang_absolute_path(self): 26 | file_path = self.data_dir / "script_shebang_abs.py" 27 | 28 | expected = InterpretedExecutable(file_path, ["/usr/bin/python3"]) 29 | 30 | self.assertEqual(expected.path, file_path) 31 | self.assertEqual(expected.shebang, ["/usr/bin/python3"]) 32 | 33 | def test_read_shebang_relative_path(self): 34 | file_path = self.data_dir / "script_shebang_rel.py" 35 | expected = InterpretedExecutable(file_path, ["/usr/bin/env", "python3"]) 36 | self.assertEqual(expected.path, file_path) 37 | self.assertEqual(expected.shebang, ["/usr/bin/env", "python3"]) 38 | -------------------------------------------------------------------------------- /tests/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AppImageCrafters/appimage-builder/bf6123ee43715e52d2a73639f9acb1251e8af640/tests/commands/__init__.py -------------------------------------------------------------------------------- /tests/modules/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | -------------------------------------------------------------------------------- /tests/modules/deploy/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | -------------------------------------------------------------------------------- /tests/modules/deploy/apt/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | -------------------------------------------------------------------------------- /tests/modules/deploy/apt/test_deploy.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | import logging 14 | import shutil 15 | from pathlib import Path 16 | from unittest import TestCase, skipIf 17 | from appimagebuilder.modules.deploy.apt import Deploy 18 | from appimagebuilder.modules.deploy.apt.venv import Venv 19 | 20 | 21 | @skipIf(not shutil.which("apt-get"), reason="requires apt-get") 22 | class TestDeploy(TestCase): 23 | venv_path = None 24 | appdir_path = None 25 | 26 | @classmethod 27 | def setUpClass(cls): 28 | cls.venv_path = "/tmp/apt-venv" 29 | cls.appdir_path = Path("/tmp/AppDir") 30 | cls.apt_venv = Venv( 31 | cls.venv_path, 32 | ["deb [arch=amd64] http://deb.debian.org/debian/ bullseye main"], 33 | ["https://ftp-master.debian.org/keys/archive-key-10.asc"], 34 | ["amd64"], 35 | ) 36 | 37 | @classmethod 38 | def tearDownClass(cls): 39 | pass 40 | # shutil.rmtree(cls.venv_path) 41 | # shutil.rmtree(cls.appdir_path) 42 | 43 | def test_deploy(self): 44 | logging.basicConfig(level=0) 45 | 46 | apt_deploy = Deploy(self.apt_venv) 47 | apt_deploy.deploy(["perl", "util-linux"], self.appdir_path) 48 | self.assertTrue(next(self.appdir_path.glob("usr"))) 49 | -------------------------------------------------------------------------------- /tests/modules/deploy/apt/test_package.py: -------------------------------------------------------------------------------- 1 | import shutil 2 | from unittest import TestCase, skipIf 3 | 4 | from appimagebuilder.modules.deploy.apt.package import Package 5 | 6 | 7 | @skipIf(not shutil.which("apt-get"), reason="requires apt-get") 8 | class TestPackage(TestCase): 9 | 10 | def test_compare_versions(self): 11 | package_a = Package("test", "1.19.7ubuntu3", "aarch64") 12 | package_b = Package("test", "1.19.8", "aarch64") 13 | 14 | self.assertGreater(package_b, package_a) 15 | 16 | package_a = Package("test", "1.19.7", "aarch64") 17 | package_b = Package("test", "1.19.8", "aarch64") 18 | 19 | self.assertGreater(package_b, package_a) 20 | 21 | package_a = Package("test", "1.19.7ubuntu3", "aarch64") 22 | package_b = Package("test", "1.19.7ubuntu3", "aarch64") 23 | 24 | self.assertEqual(package_b, package_a) 25 | 26 | package_a = Package("test", "0", "aarch64") 27 | package_b = Package("test", "10", "aarch64") 28 | 29 | self.assertGreater(package_b, package_a) -------------------------------------------------------------------------------- /tests/modules/deploy/apt/test_venv.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | import shutil 14 | from unittest import TestCase, skipIf 15 | 16 | from appimagebuilder.modules.deploy.apt.venv import Venv 17 | 18 | 19 | @skipIf(not shutil.which("apt-get"), reason="requires apt-get") 20 | class TestVenv(TestCase): 21 | venv_path = None 22 | 23 | @classmethod 24 | def setUpClass(cls): 25 | cls.venv_path = "/tmp/apt-venv" 26 | cls.apt_venv = Venv( 27 | cls.venv_path, 28 | ["deb http://deb.debian.org/debian/ bullseye main"], 29 | ["https://ftp-master.debian.org/keys/archive-key-10.asc"], 30 | ["amd64"], 31 | ) 32 | cls.apt_venv.update() 33 | 34 | @classmethod 35 | def tearDownClass(cls): 36 | shutil.rmtree(cls.venv_path) 37 | 38 | def test_search_names(self): 39 | self.assertEqual(self.apt_venv.search_names(["perl"]), ["perl"]) 40 | self.assertGreater(self.apt_venv.search_names(["perl*"]), ["perl"]) 41 | 42 | def test_search_packages(self): 43 | self.assertTrue(self.apt_venv.search_packages(["dpkg", "debconf"])) 44 | 45 | def test_set_installed_packages(self): 46 | packages = self.apt_venv.search_packages(["dpkg", "debconf"]) 47 | # dpkg and debconf need to be set as installed or the configuration step of apt-get install will fail 48 | self.apt_venv.set_installed_packages(packages) 49 | with open(self.apt_venv._dpkg_status_path, "r") as f: 50 | file_contents = f.read() 51 | 52 | self.assertIn( 53 | "Package: dpkg\n" "Status: install ok installed\n", file_contents 54 | ) 55 | 56 | self.assertIn( 57 | "Package: debconf\n" "Status: install ok installed\n", file_contents 58 | ) 59 | 60 | def test_resolve_packages(self): 61 | packages = self.apt_venv.search_packages(["dpkg", "debconf"]) 62 | # dpkg and debconf need to be set as installed or the configuration step of apt-get install will fail 63 | self.apt_venv.set_installed_packages(packages) 64 | 65 | packages = self.apt_venv.resolve_packages(["libc6"]) 66 | self.assertTrue(packages) 67 | 68 | def test_resolve_archive_paths(self): 69 | packages = self.apt_venv.search_packages(["tar"]) 70 | paths = self.apt_venv.resolve_archive_paths(packages) 71 | self.assertTrue(paths) 72 | -------------------------------------------------------------------------------- /tests/modules/deploy/file/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | -------------------------------------------------------------------------------- /tests/modules/deploy/file/dependencies_resolver/TestElfResolver.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import pathlib 13 | import unittest 14 | from shutil import which 15 | 16 | from appimagebuilder.modules.deploy.files.dependencies_resolver.elf_resolver import ( 17 | ElfResolver, 18 | ) 19 | 20 | 21 | class ElfResolverTestCase(unittest.TestCase): 22 | def setUp(self) -> None: 23 | self.bash_path = pathlib.Path(which("bash")) 24 | self.resolver = ElfResolver() 25 | 26 | def test_resolve_needed_recursively(self): 27 | results = self.resolver.resolve_needed_recursively(self.bash_path) 28 | self.assertIn("/lib/x86_64-linux-gnu/libdl.so.2", results) 29 | self.assertIn("/lib/x86_64-linux-gnu/libc.so.6", results) 30 | 31 | 32 | if __name__ == "__main__": 33 | unittest.main() 34 | -------------------------------------------------------------------------------- /tests/modules/deploy/file/dependencies_resolver/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | -------------------------------------------------------------------------------- /tests/modules/deploy/pacman/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | -------------------------------------------------------------------------------- /tests/modules/deploy/pacman/test_deploy.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | # Copyright 2021 Alexis Lopez Zubieta 14 | # 15 | # Permission is hereby granted, free of charge, to any person obtaining a 16 | # copy of this software and associated documentation files (the "Software"), 17 | # to deal in the Software without restriction, including without limitation the 18 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 19 | # sell copies of the Software, and to permit persons to whom the Software is 20 | # furnished to do so, subject to the following conditions: 21 | # 22 | # The above copyright notice and this permission notice shall be included in 23 | # all copies or substantial portions of the Software. 24 | 25 | import shutil 26 | from pathlib import Path 27 | from unittest import TestCase, skipIf 28 | 29 | from appimagebuilder.modules.deploy.pacman.venv import Venv 30 | from appimagebuilder.modules.deploy.pacman.deploy import Deploy 31 | 32 | 33 | @skipIf(not shutil.which("pacman"), reason="requires pacman") 34 | class TestDeploy(TestCase): 35 | venv_path = None 36 | appdir_path = None 37 | 38 | @classmethod 39 | def setUpClass(cls): 40 | cls.appdir_path = Path("/tmp/AppDir") 41 | cls.venv_path = Path("/tmp/pacman-venv") 42 | cls.pacman_venv = Venv(cls.venv_path) 43 | cls.pacman_venv.update() 44 | cls.appdir_path.mkdir(parents=True, exist_ok=True) 45 | 46 | @classmethod 47 | def tearDownClass(cls): 48 | shutil.rmtree(cls.venv_path) 49 | shutil.rmtree(cls.appdir_path) 50 | 51 | def test_deploy(self): 52 | deploy = Deploy(self.pacman_venv) 53 | deployed_packages = deploy.deploy(["bash"], self.appdir_path) 54 | print("Deployed packages:") 55 | for package in deployed_packages: 56 | print(package) 57 | 58 | self.assertTrue(next(self.appdir_path.glob("usr"))) 59 | self.assertTrue(next(self.appdir_path.glob("runtime/compat/usr"))) 60 | -------------------------------------------------------------------------------- /tests/modules/deploy/pacman/test_file_package_resolver.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import pathlib 13 | from unittest import TestCase 14 | 15 | from appimagebuilder.modules.generate.package_managers.pacman.file_package_resolver import ( 16 | FilePackageResolver, 17 | ) 18 | 19 | 20 | class TestFilePackageResolver(TestCase): 21 | def test__parse_pacman_f_output(self): 22 | sample_pacman_output = """ 23 | usr/bin/xmllint is owned by extra/libxml2 2.9.10-9 24 | usr/bin/xmlwf is owned by core/expat 2.3.0-1 25 | usr/bin/xtables-legacy-multi is owned by core/iptables 1:1.8.7-1 26 | """ 27 | result = FilePackageResolver._parse_pacman_f_output(sample_pacman_output) 28 | expected = { 29 | pathlib.Path("usr/bin/xmllint"): "libxml2", 30 | pathlib.Path("usr/bin/xmlwf"): "expat", 31 | pathlib.Path("usr/bin/xtables-legacy-multi"): "iptables", 32 | } 33 | self.assertEqual(result, expected) 34 | -------------------------------------------------------------------------------- /tests/modules/deploy/pacman/test_venv.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | # Copyright 2021 Alexis Lopez Zubieta 14 | # 15 | # Permission is hereby granted, free of charge, to any person obtaining a 16 | # copy of this software and associated documentation files (the "Software"), 17 | # to deal in the Software without restriction, including without limitation the 18 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 19 | # sell copies of the Software, and to permit persons to whom the Software is 20 | # furnished to do so, subject to the following conditions: 21 | # 22 | # The above copyright notice and this permission notice shall be included in 23 | # all copies or substantial portions of the Software. 24 | 25 | import shutil 26 | from pathlib import Path 27 | from unittest import TestCase, skipIf 28 | 29 | from appimagebuilder.modules.deploy.pacman.venv import Venv 30 | 31 | 32 | @skipIf(not shutil.which("pacman"), reason="requires pacman") 33 | class TestVenv(TestCase): 34 | venv_path = None 35 | appdir_path = None 36 | 37 | @classmethod 38 | def setUpClass(cls): 39 | cls.appdir_path = Path("/tmp/AppDir") 40 | cls.venv_path = Path("/tmp/pacman-venv") 41 | cls.pacman_venv = Venv( 42 | cls.venv_path, 43 | repositories={ 44 | "core": ["https://mirror.rackspace.com/archlinux/$repo/os/$arch"] 45 | }, 46 | architecture="auto", 47 | ) 48 | cls.pacman_venv.update() 49 | cls.appdir_path.mkdir(parents=True, exist_ok=True) 50 | 51 | @classmethod 52 | def tearDownClass(cls): 53 | pass 54 | # shutil.rmtree(cls.venv_path) 55 | # shutil.rmtree(cls.appdir_path) 56 | 57 | def test_retrieve(self): 58 | self.pacman_venv.retrieve( 59 | ["bash"], ["tzdata", "filesystem", "linux-api-headers"] 60 | ) 61 | 62 | def test_extract(self): 63 | files = self.pacman_venv.retrieve( 64 | ["bash"], ["tzdata", "filesystem", "linux-api-headers"] 65 | ) 66 | self.pacman_venv.extract(files[0], self.appdir_path) 67 | 68 | def test_read_package_data(self): 69 | files = self.pacman_venv.retrieve( 70 | ["bash"], ["tzdata", "filesystem", "linux-api-headers"] 71 | ) 72 | self.assertTrue(self.pacman_venv.read_package_data(files[0])) 73 | -------------------------------------------------------------------------------- /tests/modules/generate/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | -------------------------------------------------------------------------------- /tests/modules/generate/fake_bundle_info_gatherer.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import pathlib 13 | 14 | from appimagebuilder.context import BundleInfo 15 | from appimagebuilder.modules.generate.bundle_info_gatherer import BundleInfoGatherer 16 | 17 | 18 | class FakeBundleInfoGatherer(BundleInfoGatherer): 19 | def __init__(self, preset_bundle_info): 20 | self.preset_bundle_info = preset_bundle_info 21 | 22 | def gather_info(self, app_dir: pathlib.Path) -> BundleInfo: 23 | return self.preset_bundle_info 24 | -------------------------------------------------------------------------------- /tests/modules/generate/fake_bundle_info_gatherer_ui.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | from appimagebuilder.modules.generate.bundle_info_gatherer_ui import ( 13 | BundleInfoGathererUi, 14 | ) 15 | 16 | 17 | class FakeBundleInfoGathererUi(BundleInfoGathererUi): 18 | default_result = "fake input" 19 | edit_postfix = " edited" 20 | 21 | def ask_text(self, text, default=None): 22 | if default: 23 | return default + self.edit_postfix 24 | else: 25 | return self.default_result 26 | 27 | def ask_select(self, text, choices, default=None): 28 | if default: 29 | return default 30 | else: 31 | return choices[-1] 32 | -------------------------------------------------------------------------------- /tests/modules/generate/fake_desktop_entry_parser.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | from appimagebuilder.context import AppInfo 13 | from appimagebuilder.modules.generate.desktop_entry_parser import DesktopEntryParser 14 | 15 | 16 | class FakeDesktopEntryParser(DesktopEntryParser): 17 | def __init__(self, app_info: AppInfo): 18 | self.app_info = app_info 19 | 20 | def parse(self, entry_path) -> AppInfo: 21 | return self.app_info 22 | -------------------------------------------------------------------------------- /tests/modules/generate/fake_file_package_resolver.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | from appimagebuilder.modules.generate.package_managers.apt import FilePackageResolver 13 | 14 | 15 | class FakeFilePackageResolver(FilePackageResolver): 16 | def __init__(self, presets: {}): 17 | self.presets = presets 18 | 19 | def resolve(self, files) -> {}: 20 | results = {} 21 | 22 | for file in files: 23 | if file in self.presets: 24 | results[file] = self.presets[file] 25 | 26 | return results 27 | -------------------------------------------------------------------------------- /tests/modules/generate/fake_package_manager_section_generator.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | from appimagebuilder.context import BundleInfo 13 | from appimagebuilder.modules.generate.recipe_sections.package_manager_recipe_section_generator import ( 14 | PackageManagerSectionGenerator, 15 | ) 16 | 17 | 18 | class FakePackageManagerSectionGenerator(PackageManagerSectionGenerator): 19 | def __init__(self, id, preset_section, missing): 20 | self.preset_section = preset_section 21 | self.missing = missing 22 | self._id = id 23 | 24 | def id(self) -> str: 25 | return self._id 26 | 27 | def generate(self, dependencies: [str], bundle_info: BundleInfo) -> ({}, [str]): 28 | return self.preset_section, self.missing 29 | -------------------------------------------------------------------------------- /tests/modules/generate/fake_package_repository_resolver.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | from appimagebuilder.modules.generate.package_managers.apt import ( 13 | PackageRepositoryResolver, 14 | ) 15 | 16 | 17 | class FakePackageRepositoryResolver(PackageRepositoryResolver): 18 | def resolve_source_lines(self, packages) -> []: 19 | return [ 20 | "deb http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse" 21 | ] 22 | -------------------------------------------------------------------------------- /tests/modules/generate/fake_path.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import fnmatch 13 | import os.path 14 | 15 | 16 | class FakePath: 17 | """Mocks pathlib.Path""" 18 | 19 | def __init__(self, path: str, children: [str] = None): 20 | self.path = path 21 | self.children = children 22 | 23 | def glob(self, pattern): 24 | results = [] 25 | for file in self.children: 26 | if fnmatch.fnmatch(file, pattern): 27 | results.append(FakePath(file, [])) 28 | 29 | return results 30 | 31 | def relative_to(self, fake_path): 32 | return os.path.relpath(self.path, fake_path.path) 33 | 34 | def __str__(self): 35 | return self.path 36 | 37 | def __eq__(self, o: object) -> bool: 38 | return self.__class__ == o.__class__ and self.path == o.path 39 | -------------------------------------------------------------------------------- /tests/modules/generate/fake_runtime_analyser.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | import pathlib 13 | 14 | from appimagebuilder.modules.analisys.app_runtime_analyser import AppRuntimeAnalyser 15 | 16 | 17 | class FakeAppRuntimeAnalyser(AppRuntimeAnalyser): 18 | def __init__(self, expected_result): 19 | self.expected_result = expected_result 20 | 21 | def run_app_analysis(self, app_dir: pathlib.Path, exec: str, exec_args: str): 22 | return self.expected_result 23 | -------------------------------------------------------------------------------- /tests/modules/generate/test_apt_section_generator.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | 13 | # Copyright 2021 Alexis Lopez Zubieta 14 | # 15 | # Permission is hereby granted, free of charge, to any person obtaining a 16 | # copy of this software and associated documentation files (the "Software"), 17 | # to deal in the Software without restriction, including without limitation the 18 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 19 | # sell copies of the Software, and to permit persons to whom the Software is 20 | # furnished to do so, subject to the following conditions: 21 | # 22 | # The above copyright notice and this permission notice shall be included in 23 | # all copies or substantial portions of the Software. 24 | import pathlib 25 | import shutil 26 | from unittest import TestCase, skipIf 27 | 28 | from appimagebuilder.context import BundleInfo 29 | from appimagebuilder.modules.generate.recipe_sections.apt_section_generator import ( 30 | AptSectionGenerator, 31 | ) 32 | from tests.modules.generate.fake_file_package_resolver import FakeFilePackageResolver 33 | from tests.modules.generate.fake_package_repository_resolver import ( 34 | FakePackageRepositoryResolver, 35 | ) 36 | 37 | 38 | @skipIf(not shutil.which("apt-get"), reason="requires apt-get") 39 | class TestAptSectionGenerator(TestCase): 40 | def test_generate(self): 41 | generator = AptSectionGenerator( 42 | FakeFilePackageResolver({"/lib64/ld-linux-x86-64.so.2": "libc6:amd64"}), 43 | FakePackageRepositoryResolver(), 44 | ) 45 | 46 | result, missing_files = generator.generate( 47 | ["/lib64/ld-linux-x86-64.so.2", "/missing/file"], 48 | BundleInfo(app_dir=pathlib.Path("/tmp")), 49 | ) 50 | self.assertEqual(["/missing/file"], missing_files) 51 | self.assertEqual( 52 | { 53 | "arch": ["amd64"], 54 | "allow_unauthenticated": True, 55 | "sources": [ 56 | { 57 | "sourceline": "deb http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse" 58 | } 59 | ], 60 | "include": ["libc6:amd64"], 61 | }, 62 | result, 63 | ) 64 | -------------------------------------------------------------------------------- /tests/modules/setup/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | -------------------------------------------------------------------------------- /tests/modules/setup/test_executables_patcher.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pathlib 3 | import tempfile 4 | import unittest 5 | 6 | from appimagebuilder.modules.setup.apprun_2.executables_patcher import ( 7 | ExecutablesPatcher, 8 | ) 9 | 10 | 11 | class TestExecutablesPatcher(unittest.TestCase): 12 | def test_read_interpreter_path_from_shebang(self): 13 | r = ExecutablesPatcher.read_interpreter_path_from_shebang("#!/bin/bash") 14 | self.assertEqual("/bin/bash", r) 15 | 16 | r = ExecutablesPatcher.read_interpreter_path_from_shebang("#! bin/bash") 17 | self.assertEqual("bin/bash", r) 18 | 19 | r = ExecutablesPatcher.read_interpreter_path_from_shebang("#! bin/env bash") 20 | self.assertEqual("bin/env", r) 21 | 22 | def test_make_bin_path_in_shebang_relative(self): 23 | orig = "#!/bin/env python3\n" 24 | patched = ExecutablesPatcher.make_bin_path_in_shebang_relative(orig) 25 | 26 | self.assertEqual(len(orig), len(patched)) 27 | self.assertEqual("#! bin/env python3\n", patched) 28 | 29 | def test_make_bin_path_in_shebang_relative_with_space(self): 30 | orig = "#! /bin/env python3\n" 31 | patched = ExecutablesPatcher.make_bin_path_in_shebang_relative(orig) 32 | 33 | self.assertEqual(len(orig), len(patched)) 34 | self.assertEqual("#! bin/env python3\n", patched) 35 | 36 | def test_patch_interpreted_executable(self): 37 | patcher = ExecutablesPatcher() 38 | 39 | with tempfile.NamedTemporaryFile("w+") as file_mock: 40 | file_mock.write("#!/bin/bash\n") 41 | file_mock.flush() 42 | os.fsync(file_mock) 43 | 44 | file_mock_path = pathlib.Path(file_mock.name) 45 | patcher.patch_interpreted_executable(file_mock_path) 46 | 47 | file_mock.seek(0) 48 | patched_shebang = file_mock.readline() 49 | 50 | expected_shebang = "#! bin/bash\n" 51 | self.assertEqual(expected_shebang, patched_shebang) 52 | self.assertEqual( 53 | "bin/bash", patcher.script_interpreters_paths[file_mock_path] 54 | ) 55 | 56 | 57 | if __name__ == "__main__": 58 | unittest.main() 59 | -------------------------------------------------------------------------------- /tests/recipe/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Alexis Lopez Zubieta 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining a 4 | # copy of this software and associated documentation files (the "Software"), 5 | # to deal in the Software without restriction, including without limitation the 6 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | # sell copies of the Software, and to permit persons to whom the Software is 8 | # furnished to do so, subject to the following conditions: 9 | # 10 | # The above copyright notice and this permission notice shall be included in 11 | # all copies or substantial portions of the Software. 12 | -------------------------------------------------------------------------------- /tests/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AppImageCrafters/appimage-builder/bf6123ee43715e52d2a73639f9acb1251e8af640/tests/utils/__init__.py -------------------------------------------------------------------------------- /tests/utils/test_elf.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | from unittest import TestCase, skipIf 3 | 4 | from appimagebuilder.utils.elf import get_arch 5 | 6 | 7 | class Test(TestCase): 8 | @skipIf(not os.path.isfile("/lib/ld-linux.so.2"), "/lib/ld-linux.so.2 is required") 9 | def test_read_elf_arch_i386(self): 10 | self.assertEqual("i386", get_arch("/lib/ld-linux.so.2")) 11 | 12 | @skipIf( 13 | not os.path.isfile("/lib64/ld-linux-x86-64.so.2"), 14 | "/lib64/ld-linux-x86-64.so.2 is required", 15 | ) 16 | def test_read_elf_arch_x86_64(self): 17 | self.assertEqual("x86_64", get_arch("/lib64/ld-linux-x86-64.so.2")) 18 | --------------------------------------------------------------------------------