diff --git a/.deepsource.toml b/.deepsource.toml new file mode 100644 index 000000000..21546280e --- /dev/null +++ b/.deepsource.toml @@ -0,0 +1,76 @@ +# SPDX-FileCopyrightText: None +# +# SPDX-License-Identifier: CC0-1.0 + +version = 1 + +# 全局排除配置 +exclude_patterns = [ + "external/**", + "build/**", + "obj-*/**", + ".cache/**", + ".obs/**", + ".tx/**", + "**/*.generated.*", + "**/CMakeCache.txt", + "**/compile_commands.json", + "debian/patches/**", + "po/*.po", + "po/*.pot", + "tools/openapi-c-libcurl-client/**", +] + +# C++ 分析器配置 +[[analyzers]] +name = "cxx" +enabled = true + +[analyzers.meta] +misra_compliance = true +cyclomatic_complexity_threshold = "medium" + +# Shell 脚本分析器配置 +[[analyzers]] +name = "shell" +enabled = true + +[analyzers.meta] +# 只保留官方支持的选项 +dialect = "bash" + +# 密钥检测分析器配置 +[[analyzers]] +name = "secrets" +enabled = true +# secrets 分析器不支持任何 meta 配置 + +# 测试覆盖率分析器配置 +[[analyzers]] +name = "test-coverage" +enabled = false + +# 代码格式化器配置 +[[transformers]] +name = "clang-format" +enabled = true + +[transformers.meta] +exclude_patterns = ["external/**", "build/**", "obj-*/**", "**/*.generated.*"] + +[[transformers]] +name = "prettier" +enabled = true + +[transformers.meta] +include_patterns = ["**/*.md", "**/*.json", "**/*.yaml", "**/*.yml"] +exclude_patterns = [ + "external/**", + "build/**", + "obj-*/**", + ".cache/**", + "po/**", + "**/*.generated.*", + "package-lock.json", + "yarn.lock", +] diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 000000000..1353a4d11 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,59 @@ +name: build +on: + pull_request_target: + push: + branches: + - master + - 'release/**' +jobs: + ubuntu2404: + name: ubuntu_24.04 + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + + - uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: cmake debhelper-compat erofs-utils erofsfuse intltool libcap-dev libcli11-dev libcurl4-openssl-dev libdeflate-dev libelf-dev libexpected-dev libfuse3-dev libglib2.0-dev libgmock-dev libgtest-dev liblz4-dev liblzma-dev libostree-dev libpcre2-dev libselinux1-dev libssl-dev libsystemd-dev libyaml-cpp-dev libzstd-dev nlohmann-json3-dev pkg-config qt6-base-dev qt6-base-private-dev zlib1g-dev + version: 1.0 + + - name: Build + run: | + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Release \ + -DCPM_LOCAL_PACKAGES_ONLY=ON \ + -DBUILD_SHARED_LIBS=OFF \ + .. + + make -j$(nproc) + - name: Run tests + run: | + ./build/libs/linglong/tests/ll-tests/ll-tests + + ubuntu2204: + name: ubuntu_22.04 + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + + - uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: cmake debhelper-compat erofs-utils erofsfuse intltool libcap-dev libcli11-dev libcurl4-openssl-dev libdeflate-dev libelf-dev libexpected-dev libfuse3-dev libglib2.0-dev libgmock-dev libgtest-dev liblz4-dev liblzma-dev libostree-dev libpcre2-dev libselinux1-dev libssl-dev libsystemd-dev libyaml-cpp-dev libzstd-dev nlohmann-json3-dev pkg-config qtbase5-dev qtbase5-private-dev systemd zlib1g-dev + version: 1.0 + + - name: Build + run: | + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=Release \ + -DCPM_LOCAL_PACKAGES_ONLY=ON \ + -DBUILD_SHARED_LIBS=OFF \ + -DENABLE_TESTING=OFF \ + .. + + make -j$(nproc) diff --git a/.github/workflows/codecov.yaml b/.github/workflows/codecov.yaml new file mode 100644 index 000000000..91ca71d9a --- /dev/null +++ b/.github/workflows/codecov.yaml @@ -0,0 +1,32 @@ +name: coverage +on: + pull_request_target: + push: + branches: + - master + - 'release/**' +jobs: + codecov: + name: codecov + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + + - uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: gcovr cmake debhelper-compat erofs-utils erofsfuse intltool libcap-dev libcli11-dev libcurl4-openssl-dev libdeflate-dev libelf-dev libexpected-dev libfuse3-dev libglib2.0-dev libgmock-dev libgtest-dev liblz4-dev liblzma-dev libostree-dev libpcre2-dev libselinux1-dev libssl-dev libsystemd-dev libyaml-cpp-dev libzstd-dev nlohmann-json3-dev pkg-config qtbase5-dev qtbase5-private-dev systemd zlib1g-dev + version: 1.0 + + - name: Generate coverage + run: | + ./tools/generate-coverage.sh + + - name: Upload Report to Codecov + uses: codecov/codecov-action@v5 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: ./build-generate-coverage/report/index.xml + disable_search: true + disable_telem: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..457696adf --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,35 @@ +# SPDX-FileCopyrightText: None +# +# SPDX-License-Identifier: CC0-1.0 + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-json + - id: check-toml + - id: check-added-large-files + - id: check-xml + + - repo: https://github.com/pre-commit/mirrors-clang-format + rev: v21.1.5 + hooks: + - id: clang-format + name: clang-format (C/C++) + files: \.(c|cc|cpp|cxx|h|hpp)$ + args: ['-i', '--sort-includes', '--style=file'] + exclude: | + (?x)^( + build/| + external/| + libs/api/src/linglong/api/types/v1/ + ) + + - repo: https://github.com/scop/pre-commit-shfmt + rev: v3.12.0-2 + hooks: + - id: shfmt + args: ['-i', '4', '-ci', '-sr'] diff --git a/.tx/config b/.tx/config new file mode 100755 index 000000000..df1682a36 --- /dev/null +++ b/.tx/config @@ -0,0 +1,9 @@ +[main] +host = https://www.transifex.com + +[o:linuxdeepin:p:linyaps:r:6e861fdc8edf8f03ac6f0b629a022f2f] +file_filter = po/.po +source_file = po/en_US.po +source_lang = en_US +type = PO + diff --git a/.tx/transifex.yaml b/.tx/transifex.yaml index 02858bedc..c1e9480c3 100644 --- a/.tx/transifex.yaml +++ b/.tx/transifex.yaml @@ -7,5 +7,10 @@ filters: file_format: PO source_language: en_US translation_files_expression: po/.po + - filter_type: file + source_file: misc/share/polkit-1/translations/policy.ts + file_format: QT + source_language: en_US + translation_files_expression: misc/share/polkit-1/translations/policy_.ts settings: pr_branch_name: transifex_update_ diff --git a/BUILD.md b/BUILD.md deleted file mode 100644 index cb784b053..000000000 --- a/BUILD.md +++ /dev/null @@ -1,83 +0,0 @@ -# Build instructions - -Before building Linglong, ensure that the following dependencies are installed: - -- cmake -- debhelper-compat (= 12) -- erofsfuse (>= 1.8.3) -- fuse-overlayfs -- intltool -- libcli11-dev (>= 2.4.1) -- libcurl4-openssl-dev -- libdeflate-dev -- libelf-dev -- libexpected-dev (>= 1.0.0~dfsg-2~bpo10+1) -- libfuse3-dev -- libglib2.0-dev -- libgmock-dev -- libgtest-dev -- liblz4-dev -- liblzma-dev -- libostree-dev -- libpcre2-dev -- libseccomp-dev -- libselinux1-dev -- libssl-dev -- libsystemd-dev -- libyaml-cpp-dev (>= 0.6.2) -- libzstd-dev -- nlohmann-json3-dev (>= 3.5.0) -- pkg-config -- qt5-qmake -- qtbase5-dev -- qtbase5-private-dev -- systemd -- zlib1g-dev -- libcap-dev - -linglong use [cmake presets], you can build and install linglong by running: - -```bash -cmake --workflow --preset release -sudo cmake --install build-release -``` - -For developing or debugging linglong: - -```bash - -# Use ccache and ninja if available. -# You might want add this to the rc file of your shell. -export CMAKE_CXX_COMPILER_LAUNCHER=="$(command -v ccache 2>/dev/null)" -if command -v ninja &>/dev/null; then - export CMAKE_GENERATOR="Ninja" -fi - -# configure, build and test -cmake --workflow --preset debug - -# configure only -cmake --preset debug - -# build only -cmake --build --preset debug - -# test only -ctest --preset debug -``` - -[cmake presets]: https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html - -## Packaging - -linglong use [CPM.cmake] to download dependencies not found locally. - -For packager want to disable this feature: - -```bash -export CPM_USE_LOCAL_PACKAGES=1 -``` - -For further information, check README of [CPM.cmake]. - -[CPM.cmake]: https://github.com/cpm-cmake/CPM.cmake diff --git a/BUILD.zh_CN.md b/BUILD.zh_CN.md deleted file mode 100644 index ced923c92..000000000 --- a/BUILD.zh_CN.md +++ /dev/null @@ -1,77 +0,0 @@ -# 构建指南 - -在构建linglong之前,确保已经安装以下依赖: - -- cmake -- debhelper-compat (= 12) -- erofsfuse (>= 1.8.3) -- fuse-overlayfs -- intltool -- libcli11-dev (>= 2.4.1) -- libcurl4-openssl-dev -- libdeflate-dev -- libelf-dev -- libexpected-dev (>= 1.0.0~dfsg-2~bpo10+1) -- libfuse3-dev -- libglib2.0-dev -- libgmock-dev -- libgtest-dev -- liblz4-dev -- liblzma-dev -- libostree-dev -- libpcre2-dev -- libseccomp-dev -- libselinux1-dev -- libssl-dev -- libsystemd-dev -- libyaml-cpp-dev (>= 0.6.2) -- libzstd-dev -- nlohmann-json3-dev (>= 3.5.0) -- pkg-config -- qt5-qmake -- qtbase5-dev -- qtbase5-private-dev -- systemd -- zlib1g-dev -- libcap-dev - -玲珑使用 [cmake 预设],你可以通过运行以下命令来构建和安装玲珑: - -```bash -cmake --workflow --preset release -sudo cmake --install build-release -``` - -如果你想开发或调试玲珑: - -```bash -export CMAKE_CXX_COMPILIER_LAUNCHER="$(command -v ccache)" - -# 配置,构建然后运行测试 -cmake --workflow --preset debug - -# 仅配置 -cmake --preset debug - -# 仅构建 -cmake --build --preset debug - -# 仅运行测试 -ctest --preset debug -``` - -[cmake 预设]: https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html - -## 打包 - -玲珑使用 [CPM.cmake] 来下载本地找不到的依赖项。 - -如果你想禁用这个功能: - -```bash -export CPM_USE_LOCAL_PACKAGES=1 -``` - -更多信息,请查看 [CPM.cmake] 的 README。 - -[CPM.cmake]: https://github.com/cpm-cmake/CPM.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index dfab3d132..b9203f1da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.11.4) project( linglong - VERSION 1.8.0 + VERSION 1.10.0 DESCRIPTION "a container based application package manager for Linux desktop" HOMEPAGE_URL "https://github.com/OpenAtom-Linyaps/linyaps" LANGUAGES CXX C) @@ -53,9 +53,39 @@ set(GETTEXT_DOMAIN_NAME "linyaps" CACHE STRING "The name of gettext domain.") set(QT_VERSION_MAJOR CACHE STRING "The major version of qt.") -set(LINGLONG_DESKTOP_EXPORT_PATH - "share/applications" - CACHE STRING "The path to export linglong desktop files.") +set(LINGLONG_EXPORT_PATH + "share" + CACHE STRING + "The path to export linglong config files, it must end with share.") + +if(NOT LINGLONG_EXPORT_PATH MATCHES ".*share$") + message( + WARNING + "LINGLONG_EXPORT_PATH '${LINGLONG_EXPORT_PATH}' must end with 'share'") + set(LINGLONG_EXPORT_PATH "share") +endif() + +set(LINGLONG_ENABLE_WAYLAND_SEC_CTX_SUPPORT + OFF + CACHE BOOL "enable linglong wayland security context support") + +# harden the build +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +set(CMAKE_EXE_LINKER_FLAGS + "${CMAKE_EXE_LINKER_FLAGS} -pie -Wl,-z,relro -Wl,-z,now") + +add_compile_options(-fstack-protector-strong) +if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + message(STATUS "Non-Debug build, enabling FORTIFY_SOURCE") + add_compile_definitions(_FORTIFY_SOURCE=2) +endif() + +string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" SYSTEM_PROC_LOWER) +if(SYSTEM_PROC_LOWER MATCHES "^mips") + message(STATUS "MIPS architecture detected. Adding -mxgot to C/CXX flags.") + add_compile_options(-mxgot) +endif() list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) include(PFL) @@ -76,11 +106,14 @@ if(ENABLE_CPM) include(CPM) CPMFindPackage( NAME tl-expected - VERSION 1.0.0 # NOTE: Upstream cmake version doesn't match git tag, we need - # https://github.com/TartanLlama/expected/pull/62 in v1.1.0, - # but cmake version of v1.1.0 is 1.0.0. + VERSION + 1.2.0 # NOTE: Upstream cmake version doesn't match git tag, we need + # https://github.com/TartanLlama/expected/pull/62 in v1.1.0, but + # cmake version of v1.1.0 is 1.0.0. upstream fix this issue in + # https://github.com/TartanLlama/expected/commit/17d0058a5a5d3e0ea647884f9b29c518dd06f26e + # so we require tl-expected >= 1.2.0 GITHUB_REPOSITORY TartanLlama/expected - GIT_TAG v1.1.0 + GIT_TAG v1.3.1 GIT_SHALLOW ON OPTIONS "EXPECTED_BUILD_TESTS OFF" EXCLUDE_FROM_ALL ON) @@ -102,7 +135,7 @@ if(ENABLE_CPM) NAME CLI11 VERSION 2.4.1 GITHUB_REPOSITORY CLIUtils/CLI11 - GIT_TAG v2.4.1 + GIT_TAG v2.6.1 EXCLUDE_FROM_ALL ON OPTIONS "CLI11_BUILD_TESTS OFF") @@ -122,9 +155,19 @@ endif() set(linglong_EXTERNALS "ytj ytj::ytj") +find_package(fmt 5.2.1 QUIET) +if(NOT fmt_FOUND) + message(STATUS "system fmt not found, using external fmt") + add_library(fmt-lib INTERFACE) + add_library(fmt::fmt ALIAS fmt-lib) + target_include_directories(fmt-lib INTERFACE external/fmt/include) + target_compile_definitions(fmt-lib INTERFACE FMT_HEADER_ONLY) +endif() + # NOTE: UOS v20 do not have tl-expected packaged. -find_package(tl-expected 1.0.0 QUIET) +find_package(tl-expected 1.2.0 QUIET) if(NOT tl-expected_FOUND) + message(STATUS "tl-expected not found, using external tl-expected") # list(APPEND linglong_EXTERNALS tl-expected) # tl-expected requires 3.14 add_library(tl-expected INTERFACE) add_library(tl::expected ALIAS tl-expected) @@ -142,7 +185,10 @@ endif() # NOTE: UOS v20 do not have cli11 packaged. find_package(CLI11 2.4.1 QUIET) if(NOT CLI11_FOUND) - list(APPEND linglong_EXTERNALS "CLI11 CLI11::CLI11") + message(STATUS "CLI11 not found, using external CLI11") + add_library(CLI11 INTERFACE) + add_library(CLI11::CLI11 ALIAS CLI11) + target_include_directories(CLI11 INTERFACE ./external/CLI11) endif() find_package(PkgConfig REQUIRED) @@ -158,6 +204,14 @@ if(ENABLE_TESTING) endif() endif() +if(LINGLONG_ENABLE_WAYLAND_SEC_CTX_SUPPORT) + message(STATUS "enable linglong wayland security context support") + pkg_search_module(WAYLAND_CLIENT REQUIRED IMPORTED_TARGET wayland-client) + pkg_search_module(WAYLAND_PROTOCOLS REQUIRED IMPORTED_TARGET + wayland-protocols) + find_program(WAYLAND_SCANNER wayland-scanner REQUIRED) +endif() + function(get_real_target_name output target) get_target_property("${output}" "${target}" ALIASED_TARGET) if("${output}" STREQUAL "") @@ -171,18 +225,24 @@ endfunction() set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) +include(GNUInstallDirs) +# depends on GNUInstallDirs +configure_file(configure.h.in ${CMAKE_CURRENT_BINARY_DIR}/configure.h @ONLY) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + # build ll-build-utils only if(BUILD_LINGLONG_BUILDER_UTILS_IN_BOX) - pfl_init(AUTO) - pfl_add_libraries( - LIBS - api - ocppi - oci-cfg-generators - APPS - ll-builder-utils - uab) - return() + pfl_init(AUTO) + pfl_add_libraries( + LIBS + api + common + ocppi + oci-cfg-generators + APPS + ll-builder-utils + uab) + return() endif() set(CMAKE_AUTOMOC ON) @@ -221,6 +281,9 @@ else() while(true) find_package(Qt6 COMPONENTS Core DBus) + if(Qt6_FOUND AND Qt6_VERSION VERSION_GREATER_EQUAL "6.10") + find_package(Qt6 COMPONENTS DBusPrivate) + endif() if(Qt6_FOUND) set(QT_VERSION_MAJOR "6") break() @@ -238,14 +301,12 @@ endif() message(STATUS "compiling with Qt${QT_VERSION_MAJOR}") -if("${QT_VERSION_MAJOR}" STREQUAL "6") - include(Qt6DBusMacro) -endif() - pkg_search_module(glib2 REQUIRED IMPORTED_TARGET glib-2.0) pkg_search_module(ostree1 REQUIRED IMPORTED_TARGET ostree-1) pkg_search_module(systemd REQUIRED IMPORTED_TARGET libsystemd) pkg_search_module(ELF REQUIRED IMPORTED_TARGET libelf) +pkg_search_module(cap REQUIRED IMPORTED_TARGET libcap) +pkg_search_module(uuid REQUIRED IMPORTED_TARGET uuid) set(ytj_ENABLE_TESTING NO) set(ytj_ENABLE_INSTALL NO) @@ -253,29 +314,28 @@ set(ytj_ENABLE_INSTALL NO) pfl_init(AUTO) add_subdirectory(external/http) -add_subdirectory(tools/qdbusxml2cpp) - -include(GNUInstallDirs) pfl_add_libraries( LIBS api + common dbus-api utils ocppi linglong oci-cfg-generators APPS - dumb-init + ll-init ll-dialog ll-builder ll-cli ll-package-manager llpkg - ll-session-helper) + ll-session-helper + ll-driver-detect) if(ENABLE_LINGLONG_APP_BUILDER_UTILS) - add_subdirectory(apps/ll-builder-utils) + add_subdirectory(apps/ll-builder-utils) endif() add_subdirectory(misc) diff --git a/CMakePresets.json b/CMakePresets.json index fe44525d8..2848be776 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -12,8 +12,7 @@ "description": "Configure linglong for installing from source.", "binaryDir": "${sourceDir}/build-release", "cacheVariables": { - "CMAKE_CXX_FLAGS": "-Wall -Wextra -Wpedantic -Wno-c++20-extensions -Wno-pessimizing-move -O2", - "CMAKE_COLOR_DIAGNOSTICS": true + "CMAKE_CXX_FLAGS": "-Wall -Wextra -Wpedantic -Wno-c++20-extensions -Wno-pessimizing-move -O2" } }, { @@ -24,8 +23,8 @@ "cacheVariables": { "CMAKE_CXX_FLAGS": "-Wall -Wextra -Wpedantic -Wno-c++20-extensions -Wno-pessimizing-move -Og -g -fsanitize=undefined", "CMAKE_EXPORT_COMPILE_COMMANDS": true, - "CMAKE_COLOR_DIAGNOSTICS": true, - "ENABLE_TESTING": true + "ENABLE_TESTING": true, + "CMAKE_INSTALL_PREFIX": "/usr" } }, { @@ -35,8 +34,7 @@ "binaryDir": "${sourceDir}/build-clang-tidy", "cacheVariables": { "CMAKE_CXX_CLANG_TIDY": "clang-tidy", - "CMAKE_CXX_COMPILER": "clang++", - "CMAKE_COLOR_DIAGNOSTICS": true + "CMAKE_CXX_COMPILER": "clang++" } } ], diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md new file mode 100644 index 000000000..2b46cd007 --- /dev/null +++ b/DEVELOPER_GUIDE.md @@ -0,0 +1,237 @@ +# Build Guide + +## Build Dependencies + +Before building Linglong, ensure the following dependencies are installed: + +- cmake +- debhelper-compat (= 12) +- intltool +- libcli11-dev (>= 2.4.1) | hello +- libcurl4-openssl-dev +- libdeflate-dev +- libelf-dev +- libexpected-dev (>= 1.0.0~dfsg-2~bpo10+1) | hello +- libfuse3-dev +- libglib2.0-dev +- libgmock-dev +- libgtest-dev +- liblz4-dev +- liblzma-dev +- libostree-dev +- libpcre2-dev +- libselinux1-dev +- libssl-dev +- libsystemd-dev +- libyaml-cpp-dev (>= 0.6.2) +- libzstd-dev +- nlohmann-json3-dev (>= 3.5.0) +- pkg-config +- qt6-base-dev | qtbase5-dev +- qt6-base-private-dev | qtbase5-private-dev +- systemd +- zlib1g-dev + +Linglong uses [cmake presets]. To build and install: + +```bash +cmake --workflow --preset release +sudo cmake --install build-release +``` + +For development/debugging: + +```bash +export CMAKE_CXX_COMPILER_LAUNCHER="$(command -v ccache)" + +# Configure, build and test +cmake --workflow --preset debug + +# Configure only +cmake --preset debug + +# Build only +cmake --build --preset debug + +# Test only +ctest --preset debug +``` + +[cmake presets]: https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html + +## Packaging + +Linglong uses [CPM.cmake] to download missing dependencies locally. + +To disable this feature: + +```bash +export CPM_USE_LOCAL_PACKAGES=1 +``` + +See [CPM.cmake] README for more information. + +[CPM.cmake]: https://github.com/cpm-cmake/CPM.cmake + +## Internationalization (i18n) Management + +Linglong uses GNU gettext toolchain and Transifex platform for internationalization. + +### Translation Workflow + +```mermaid +graph TD + A[Mark Source Code] --> B[Generate POT Template] + B --> C[Create/Update PO Files] + C --> D[Translate PO Files] + D --> E[Compile MO Files] + E --> F[Runtime Usage] + C --> G[Upload to Transifex] + G --> H[Translator Collaboration] + H --> C +``` + +### 1. Environment Setup + +#### 1.1 Install Transifex CLI + +```bash +wget https://github.com/transifex/cli/releases/download/v1.6.17/tx-linux-amd64.tar.gz +tar -xzf tx-linux-amd64.tar.gz -C $HOME/.local/bin/ +tx -v # Verify version +``` + +#### 1.2 Configure Transifex + +1. Create ~/.transifexrc: + +```plaintext +[https://www.transifex.com] +rest_hostname = https://rest.api.transifex.com +api_hostname = https://api.transifex.com +hostname = https://www.transifex.com +token = +``` + +2. Configure project .tx/config: + +```plaintext +[main] +host = https://www.transifex.com + +[o:linuxdeepin:p:linyaps:r:6e861fdc8edf8f03ac6f0b629a022f2f] +file_filter = po/.po +source_file = po/en_US.po +source_lang = en_US +type = PO +``` + +### 2. Translation File Management + +#### 2.1 Generate POT Template + +```bash +# In build directory +make pot # Generates po/linyaps.pot +``` + +#### 2.2 Update PO Files + +```bash +make po # Update all PO files +make linyaps_zh_CN.po # Update specific language +``` + +#### 2.3 Translation Collaboration + +1. Push translation files to git repository: + +```bash +git add po/linyaps.pot po/en_US.po +git push $(REMOTE) $(BRANCH) +``` + +2. Upload translation files to Transifex: + +```bash +tx push -a # Push all languages +tx push --translation -f --languages zh_CN # Push specific language +``` + +**TIPS:** Typically we only push translations for the current system language, while translators will collaborate on other languages in Transifex. + +3. Download translations: + +```bash +tx pull -a # All languages +tx pull -l zh_CN # Specific language +``` + +### 3. Compilation & Testing + +1. Compile PO to MO: + +```bash +msgfmt po/zh_CN.po -o share/locale/zh_CN/LC_MESSAGES/linyaps.mo +``` + +2. Test translations: + +```bash +LANG=zh_CN.UTF-8 ll-cli --help +``` + +### Best Practices + +1. String Marking: + +```cpp +// Use gettext macros +#include +#define _(str) gettext(str) + +printf(_("Hello World")); +``` + +2. Translation Context: + +```cpp +/// TRANSLATORS: System username, max 20 chars +printf(_("User")); + +// Plural forms +printf(ngettext("%d file", "%d files", count), count); +``` + +3. Quality Checks: + +```bash +# Check untranslated strings +msgfmt --statistics po/zh_CN.po + +# Validate format +msgfmt -cv po/zh_CN.po +``` + +4. Collaboration Standards: + - Preserve source context + - Avoid variable placeholders (e.g. %s) + - Maintain terminology consistency + - Use full-width punctuation for Chinese + +5. Regular Sync: + - Weekly POT updates to Transifex + - Monthly full translation pulls + - Pre-release testing: + +```bash +for lang in $(cat po/LINGUAS); do + LANG=$lang.UTF-8 ll-cli --help > /dev/null || echo "$lang test failed" +done +``` + +6. Common Issues: + - Outdated translations: Use `msgmerge` + - Format errors: Check quotes/special chars + - Variable order: Use positional params (%1$s) + - Length constraints: Chinese is typically shorter diff --git a/LICENSES/GPL-3.0-only.txt b/LICENSES/GPL-3.0-only.txt deleted file mode 100644 index f6cdd22a6..000000000 --- a/LICENSES/GPL-3.0-only.txt +++ /dev/null @@ -1,232 +0,0 @@ -GNU GENERAL PUBLIC LICENSE -Version 3, 29 June 2007 - -Copyright © 2007 Free Software Foundation, Inc. - -Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - -Preamble - -The GNU General Public License is a free, copyleft license for software and other kinds of works. - -The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. - -When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. - -To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. - -For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. - -Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. - -For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. - -Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. - -Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. - -The precise terms and conditions for copying, distribution and modification follow. - -TERMS AND CONDITIONS - -0. Definitions. - -“This License” refers to version 3 of the GNU General Public License. - -“Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. - -“The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations. - -To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work. - -A “covered work” means either the unmodified Program or a work based on the Program. - -To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. - -To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. - -An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. - -1. Source Code. -The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work. - -A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. - -The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. - -The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. - -The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. - -The Corresponding Source for a work in source code form is that same work. - -2. Basic Permissions. -All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. - -You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. - -Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. - -3. Protecting Users' Legal Rights From Anti-Circumvention Law. -No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. - -When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. - -4. Conveying Verbatim Copies. -You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. - -You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. - -5. Conveying Modified Source Versions. -You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”. - - c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. - -A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. - -6. Conveying Non-Source Forms. -You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: - - a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. - - d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. - -A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. - -A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. - -“Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. - -If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). - -The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. - -Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. - -7. Additional Terms. -“Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. - -When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. - -Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or authors of the material; or - - e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. - -All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. - -If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. - -Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. - -8. Termination. -You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). - -However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. - -Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. - -Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. - -9. Acceptance Not Required for Having Copies. -You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. - -10. Automatic Licensing of Downstream Recipients. -Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. - -An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. - -You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. - -11. Patents. -A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”. - -A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. - -Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. - -In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. - -If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. - -If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. - -A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. - -Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. - -12. No Surrender of Others' Freedom. -If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. - -13. Use with the GNU Affero General Public License. -Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. - -14. Revised Versions of this License. -The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. - -If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. - -Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. - -15. Disclaimer of Warranty. -THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - -16. Limitation of Liability. -IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -17. Interpretation of Sections 15 and 16. -If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Programs - -If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. - -To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - -If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”. - -You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . - -The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . diff --git a/LICENSES/LicenseRef-Qt-Commercial.txt b/LICENSES/LicenseRef-Qt-Commercial.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/LICENSES/Qt-GPL-exception-1.0.txt b/LICENSES/Qt-GPL-exception-1.0.txt deleted file mode 100644 index 761d0327a..000000000 --- a/LICENSES/Qt-GPL-exception-1.0.txt +++ /dev/null @@ -1,21 +0,0 @@ -The Qt Company GPL Exception 1.0 - -Exception 1: - -As a special exception you may create a larger work which contains the -output of this application and distribute that work under terms of your -choice, so long as the work is not otherwise derived from or based on -this application and so long as the work does not in itself generate -output that contains the output from this application in its original -or modified form. - -Exception 2: - -As a special exception, you have permission to combine this application -with Plugins licensed under the terms of your choice, to produce an -executable, and to copy and distribute the resulting executable under -the terms of your choice. However, the executable must be accompanied -by a prominent notice offering all users of the executable the entire -source code to this application, excluding the source code of the -independent modules, but including any changes you have made to this -application, under the terms of this license. diff --git a/README.md b/README.md index 0a511a74f..0caedc542 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,15 @@ [![Latest Release](https://img.shields.io/github/v/release/OpenAtom-Linyaps/linyaps?style=flat&color=brightgreen)](https://github.com/OpenAtom-Linyaps/linyaps/releases) [![Powered by Linyaps](https://img.shields.io/badge/powered%20by-Linyaps-ff69b4)](https://github.com/OpenAtom-Linyaps/linyaps) [![Build Status](https://build.deepin.com/projects/linglong:CI:latest/packages/linyaps/badge.svg?type=default)](https://build.deepin.com/projects/linglong:CI:latest) +[![DeepSource](https://app.deepsource.com/gh/OpenAtom-Linyaps/linyaps.svg/?label=active+issues&show_trend=true&token=REPLACE_WITH_TOKEN)](https://app.deepsource.com/gh/OpenAtom-Linyaps/linyaps/) [![GitHub Stars](https://img.shields.io/github/stars/OpenAtom-Linyaps/linyaps?style=social)](https://github.com/OpenAtom-Linyaps/linyaps/stargazers) [![GitHub Forks](https://img.shields.io/github/forks/OpenAtom-Linyaps/linyaps?style=social&label=Fork)](https://github.com/OpenAtom-Linyaps/linyaps/network/members) [![Code Size](https://img.shields.io/github/languages/code-size/OpenAtom-Linyaps/linyaps)](https://github.com/OpenAtom-Linyaps/linyaps) [![GitHub Issues](https://img.shields.io/github/issues/OpenAtom-Linyaps/linyaps?style=social)](https://github.com/OpenAtom-Linyaps/linyaps/issues) +[![Packaging status](https://repology.org/badge/vertical-allrepos/linyaps.svg)](https://repology.org/project/linyaps/versions) + **Linyaps** (Linyaps Is Not Yet Another Packaging System) is a **cross-distribution Linux package format** developed and open-sourced by the Linyaps community. It implements application packaging, management, and distribution through independent sandbox containers, aiming to replace traditional package managers like deb and rpm. Linyaps ensures Linux software runs with better compatibility, security, and efficiency. ### :sparkles: Highlights @@ -143,79 +146,118 @@ For assistance, use the following channels: ### Command-line Tools -- [Introduction](./docs/pages/en/guide/ll-cli/introduction.md) -- [Install](./docs/pages/en/guide/ll-cli/install.md) -- [Run](./docs/pages/en/guide/ll-cli/run.md) -- [Uninstall](./docs/pages/en/guide/ll-cli/uninstall.md) -- [Upgrade](./docs/pages/en/guide/ll-cli/update.md) -- [List](./docs/pages/en/guide/ll-cli/list.md) -- [Prune](./docs/pages/en/guide/ll-cli/prune.md) -- [Exec](./docs/pages/en/guide/ll-cli/exec.md) -- [Content](./docs/pages/en/guide/ll-cli/content.md) -- [Info](./docs/pages/en/guide/ll-cli/info.md) -- [PS](./docs/pages/en/guide/ll-cli/ps.md) -- [Kill](./docs/pages/en/guide/ll-cli/kill.md) -- [Search](./docs/pages/en/guide/ll-cli/query.md) +- [Introduction](./docs/pages/en/guide/reference/commands/ll-cli/ll-cli.md) +- [Install](./docs/pages/en/guide/reference/commands/ll-cli/install.md) +- [Run](./docs/pages/en/guide/reference/commands/ll-cli/run.md) +- [Uninstall](./docs/pages/en/guide/reference/commands/ll-cli/uninstall.md) +- [Upgrade](./docs/pages/en/guide/reference/commands/ll-cli/upgrade.md) +- [List](./docs/pages/en/guide/reference/commands/ll-cli/list.md) +- [Prune](./docs/pages/en/guide/reference/commands/ll-cli/prune.md) +- [Enter](./docs/pages/en/guide/reference/commands/ll-cli/enter.md) +- [Content](./docs/pages/en/guide/reference/commands/ll-cli/content.md) +- [Info](./docs/pages/en/guide/reference/commands/ll-cli/info.md) +- [PS](./docs/pages/en/guide/reference/commands/ll-cli/ps.md) +- [Kill](./docs/pages/en/guide/reference/commands/ll-cli/kill.md) +- [Search](./docs/pages/en/guide/reference/commands/ll-cli/search.md) ### Build Tools -- [Introduction](./docs/pages/en/guide/ll-builder/introduction.md) -- [Demo](./docs/pages/en/guide/ll-builder/demo.md) -- [Create](./docs/pages/en/guide/ll-builder/create.md) -- [Run](./docs/pages/en/guide/ll-builder/run.md) -- [Push](./docs/pages/en/guide/ll-builder/push.md) -- [Export](./docs/pages/en/guide/ll-builder/export.md) +- [Introduction](./docs/pages/en/guide/reference/commands/ll-builder/ll-builder.md) +- [Demo](./docs/pages/en/guide/building/demo.md) +- [Create](./docs/pages/en/guide/reference/commands/ll-builder/create.md) +- [Run](./docs/pages/en/guide/reference/commands/ll-builder/run.md) +- [Push](./docs/pages/en/guide/reference/commands/ll-builder/push.md) +- [Export](./docs/pages/en/guide/reference/commands/ll-builder/export.md) +- [Build](./docs/pages/en/guide/reference/commands/ll-builder/build.md) +- [Extract](./docs/pages/en/guide/reference/commands/ll-builder/extract.md) +- [Import](./docs/pages/en/guide/reference/commands/ll-builder/import.md) +- [List](./docs/pages/en/guide/reference/commands/ll-builder/list.md) +- [Remove](./docs/pages/en/guide/reference/commands/ll-builder/remove.md) +- [Repository](./docs/pages/en/guide/reference/commands/ll-builder/repo.md) ### Package Conversion Tools #### deb Conversion -- [Introduction](./docs/pages/en/guide/ll-pica/introduction.md) -- [Init](./docs/pages/en/guide/ll-pica/init.md) -- [Convert](./docs/pages/en/guide/ll-pica/convert.md) -- [Adep](./docs/pages/en/guide/ll-pica/adep.md) +- [Introduction](./docs/pages/en/guide/reference/commands/ll-pica/ll-pica.md) +- [Init](./docs/pages/en/guide/reference/commands/ll-pica/ll-pica-init.md) +- [Convert](./docs/pages/en/guide/reference/commands/ll-pica/ll-pica-convert.md) +- [Adep](./docs/pages/en/guide/reference/commands/ll-pica/ll-pica-adep.md) #### AppImage Conversion -- [Introduction](./docs/pages/en/guide/ll-appimage-convert/introduction.md) -- [Convert](./docs/pages/en/guide/ll-appimage-convert/convert-appimage.md) +- [Introduction](./docs/pages/en/guide/reference/commands/ll-appimage-convert/ll-appimage-convert.md) +- [Convert](./docs/pages/en/guide/reference/commands/ll-appimage-convert/ll-appimage-convert-convert.md) #### Flatpak Conversion -- [Introduction](./docs/pages/en/guide/ll-flatpak-convert/introduction.md) -- [Convert](./docs/pages/en/guide/ll-flatpak-convert/convert-flatpak.md) +- [Introduction](./docs/pages/en/guide/reference/commands/ll-pica-flatpak/ll-pica-flatpak.md) +- [Convert](./docs/pages/en/guide/reference/commands/ll-pica-flatpak/ll-pica-flatpak-convert.md) ### Debugging -- [Debug](/docs/pages/en/guide/debug/debug.md) +- [Debug](./docs/pages/en/guide/debug/debug.md) ### FAQs -- [Runtime FAQs](/docs/pages/en/guide/debug/faq.md) -- [Linyaps Builder FAQs](/docs/pages/en/guide/debug/ll-builder-faq.md) -- [Linyaps Conversion Tool FAQs](/docs/pages/en/guide/debug/ll-pica-faq.md) +- [Runtime FAQs](./docs/pages/en/guide/tips-and-faq/faq.md) +- [Linyaps Builder FAQs](./docs/pages/en/guide/tips-and-faq/ll-builder-faq.md) +- [Linyaps Conversion Tool FAQs](./docs/pages/en/guide/tips-and-faq/ll-pica-faq.md) ## :book: Learning Resources +### Getting Started + +- [Overview](./docs/pages/en/guide/start/whatis.md) - Introduction to Linyaps basic concepts +- [Installation](./docs/pages/en/guide/start/install.md) - Detailed installation guide +- [Build Your First App](./docs/pages/en/guide/start/build_your_first_app.md) - Complete tutorial for beginners + +### Building and Packaging + +- [Package Specification](./docs/pages/en/guide/building/linyaps_package_spec.md) - Detailed packaging standards +- [Build Configuration](./docs/pages/en/guide/building/manifests.md) - Understanding linglong.yaml +- [Module Management](./docs/pages/en/guide/building/modules.md) - Module splitting and management +- [Multi-architecture Support](./docs/pages/en/guide/building/multiarch.md) - Cross-platform building +- [Demo Examples](./docs/pages/en/guide/building/demo.md) - Practical build demonstrations + +### Reference Documentation + +- [Basic Concepts](./docs/pages/en/guide/reference/basic-concepts.md) - Core concepts and terminology +- [Runtime Component](./docs/pages/en/guide/reference/runtime.md) - Runtime system details +- [Driver Documentation](./docs/pages/en/guide/reference/driver.md) - Driver-related information + +### Advanced Topics + +- [Desktop Integration](./docs/pages/en/guide/desktop-integration/README.md) - Desktop environment integration +- [Unit Testing](./docs/pages/en/guide/extra/unit-testing.md) - Testing frameworks and practices +- [Bundle Format](./docs/pages/en/guide/extra/bundle-format.md) - Package format specifications +- [System Helper](./docs/pages/en/guide/extra/system-helper.md) - System utility documentation +- [Application Configuration](./docs/pages/en/guide/extra/app-conf.md) - App configuration guide +- [Root Filesystem](./docs/pages/en/guide/extra/rootfs.md) - Root filesystem management +- [UAB Build](./docs/pages/en/guide/extra/uab-build.md) - UAB format building +- [Repository Management](./docs/pages/en/guide/publishing/repositories.md) - Repository operations +- [UAB Publishing](./docs/pages/en/guide/publishing/uab.md) - UAB format publishing +- [Mirror Sites](./docs/pages/en/guide/publishing/mirrors.md) - Mirror configuration + +### Tutorial Series + +- [Linyaps Packaging Basics](./docs/pages/en/guide/lessons/basic-notes.md) +- [Manual Compilation in Container](./docs/pages/en/guide/lessons/build-in-env.md) +- [Offline Source Compilation](./docs/pages/en/guide/lessons/build-offline-src.md) +- [Compilation with Git & Patch](./docs/pages/en/guide/lessons/build-git-patch.md) +- [Automated Testing Suite](./docs/pages/en/guide/lessons/test-with-toolchains.md) + ### Related Projects - [OSTree](https://github.com/ostreedev/ostree) - [Linyaps Packaging Tool - ll-killer-go](https://github.com/System233/ll-killer-go) - [Linyaps Web Store](https://github.com/yoloke/Linglong-Shop) -### Tutorial Series - -- [Linyaps Packaging Basics](/docs/pages/guide/lessons/basic-notes.md) -- [Manual Compilation in Container](/docs/pages/guide/lessons/build-in-env.md) -- [Offline Source Compilation](/docs/pages/guide/lessons/build-offline-src.md) -- [Compilation with Git & Patch](/docs/pages/guide/lessons/build-git-patch.md) -- [Automated Testing Suite](/docs/pages/guide/lessons/test-with-toolchains.md) - Explore more tutorials at [Linyaps Official Website](https://linyaps.org.cn/learn). ## :hammer_and_pick: Contribution -We welcome issue reports and contributions. See the [Build Guide](./BUILD.md) for instructions on building Linyaps from source. +We welcome issue reports and contributions. See the [Developer Guide](./DEVELOPER_GUIDE.md) for instructions on building Linyaps from source. Start discussions on [GitHub Discussions](https://github.com/OpenAtom-Linyaps/linyaps/discussions). diff --git a/README.zh_CN.md b/README.zh_CN.md index ea6830570..3ffbea4f0 100644 --- a/README.zh_CN.md +++ b/README.zh_CN.md @@ -1,4 +1,5 @@ + # 如意玲珑图标如意玲珑:更先进的 Linux 跨发行版软件包管理工具集 ## :package: 介绍 @@ -9,18 +10,21 @@ [![Latest Release](https://img.shields.io/github/v/release/OpenAtom-Linyaps/linyaps?style=flat&color=brightgreen)](https://github.com/OpenAtom-Linyaps/linyaps/releases) [![Powered by Linyaps](https://img.shields.io/badge/powered%20by-Linyaps-ff69b4)](https://github.com/OpenAtom-Linyaps/linyaps) [![Build Status](https://build.deepin.com/projects/linglong:CI:latest/packages/linyaps/badge.svg?type=default)](https://build.deepin.com/projects/linglong:CI:latest) +[![DeepSource](https://app.deepsource.com/gh/OpenAtom-Linyaps/linyaps.svg/?label=active+issues&show_trend=true&token=REPLACE_WITH_TOKEN)](https://app.deepsource.com/gh/OpenAtom-Linyaps/linyaps/) [![GitHub Stars](https://img.shields.io/github/stars/OpenAtom-Linyaps/linyaps?style=social)](https://github.com/OpenAtom-Linyaps/linyaps/stargazers) [![GitHub Forks](https://img.shields.io/github/forks/OpenAtom-Linyaps/linyaps?style=social&label=Fork)](https://github.com/OpenAtom-Linyaps/linyaps/network/members) [![Code Size](https://img.shields.io/github/languages/code-size/OpenAtom-Linyaps/linyaps)](https://github.com/OpenAtom-Linyaps/linyaps) [![GitHub Issues](https://img.shields.io/github/issues/OpenAtom-Linyaps/linyaps?style=social)](https://github.com/OpenAtom-Linyaps/linyaps/issues) +[![Packaging status](https://repology.org/badge/vertical-allrepos/linyaps.svg)](https://repology.org/project/linyaps/versions) + **如意玲珑**(Linyaps Is Not Yet Another Packaging System)是由如意玲珑社区团队开发并开源共建的**Linux 跨发行版软件包格式**,项目以独立沙盒容器的形式实现应用包的开发、管理、分发,用于替代 deb、rpm 等传统包管理工具,让 Linux 软件运行更兼容、更安全、更高效。 ### :sparkles: 亮点 - **独创的非全量运行时(Runtime)设计**:基于标准化沙箱 Runtime,应用一次构建即可覆盖所有 Linux 发行版。Runtime 多版本共存且文件共享减少冗余,启动时通过动态库共享复用已加载资源,**速度提升显著,避免依赖冲突**。 -- **非特权沙箱与双层隔离**:默认无 root 权限运行,通过内核 Namespace 隔离(进程/文件系统/网络等)构建**安全沙箱**。通过 OSTree 仓库提供原子化增量更新与版本回滚,相比全量沙箱方案,**资源占用更低**。 +- **非特权沙箱与双层隔离**:默认无 root 权限运行,通过内核 Namespace 隔离(进程/文件系统/网络等)构建**安全沙箱**。通过 OSTree 仓库提供原子化增量更新与版本回滚,相比全量沙箱方案,**资源占用更低**。 ### :flags: 进展 @@ -121,16 +125,16 @@ ll-cli run cn.org.linyaps.demo 由于在运行时和沙箱上的优化,玲珑有着比较显著的启动时间优势: | 测试次数 | linyaps 间隔帧数 | linyaps 启动耗时(ms) | Flatpak 间隔帧数 | Flatpak 启动耗时(ms) | AppImage 间隔帧数 | AppImage 启动耗时(ms) | Snap 间隔帧数 | Snap 启动耗时(ms) | -| -------- | ----------------- | ----------------------- | ---------------- | ---------------------- | ----------------- | ----------------------- | ------------- | ------------------- | -| 1 | 9 | 149.4 | 14 | 232.4 | 16 | 265.6 | 42 | 697.2 | -| 2 | 9 | 149.4 | 13 | 215.8 | 17 | 282.2 | 41 | 680.6 | -| 3 | 8 | 132.8 | 9 | 149.4 | 15 | 249 | 40 | 664 | -| 4 | 9 | 149.4 | 13 | 215.8 | 15 | 249 | 41 | 680.6 | -| 5 | 8 | 132.8 | 14 | 232.4 | 16 | 265.6 | 42 | 697.2 | -| 6 | 8 | 132.8 | 13 | 215.8 | 15 | 249 | 39 | 664 | -| 7 | 9 | 149.4 | 12 | 199.2 | 15 | 249 | 39 | 647.4 | -| 8 | 8 | 132.8 | 14 | 232.4 | 16 | 265.6 | 40 | 680.6 | -| 平均 | 8.5 | 141.1 | 12.8 | 213.7 | 15.6 | 261.6 | 40.5 | 676.2 | +| -------- | ---------------- | ---------------------- | ---------------- | ---------------------- | ----------------- | ----------------------- | ------------- | ------------------- | +| 1 | 9 | 149.4 | 14 | 232.4 | 16 | 265.6 | 42 | 697.2 | +| 2 | 9 | 149.4 | 13 | 215.8 | 17 | 282.2 | 41 | 680.6 | +| 3 | 8 | 132.8 | 9 | 149.4 | 15 | 249 | 40 | 664 | +| 4 | 9 | 149.4 | 13 | 215.8 | 15 | 249 | 41 | 680.6 | +| 5 | 8 | 132.8 | 14 | 232.4 | 16 | 265.6 | 42 | 697.2 | +| 6 | 8 | 132.8 | 13 | 215.8 | 15 | 249 | 39 | 664 | +| 7 | 9 | 149.4 | 12 | 199.2 | 15 | 249 | 39 | 647.4 | +| 8 | 8 | 132.8 | 14 | 232.4 | 16 | 265.6 | 40 | 680.6 | +| 平均 | 8.5 | 141.1 | 12.8 | 213.7 | 15.6 | 261.6 | 40.5 | 676.2 | ## :incoming_envelope: 获取帮助 @@ -144,79 +148,118 @@ ll-cli run cn.org.linyaps.demo ### 命令行工具 -- [introduction](./docs/pages/en/guide/ll-cli/introduction.md) -- [install](./docs/pages/en/guide/ll-cli/install.md) -- [run](./docs/pages/en/guide/ll-cli/run.md) -- [uninstall](./docs/pages/en/guide/ll-cli/uninstall.md) -- [upgrade](./docs/pages/en/guide/ll-cli/update.md) -- [list](./docs/pages/en/guide/ll-cli/list.md) -- [prune](./docs/pages/en/guide/ll-cli/prune.md) -- [exec](./docs/pages/en/guide/ll-cli/exec.md) -- [content](./docs/pages/en/guide/ll-cli/content.md) -- [info](./docs/pages/en/guide/ll-cli/info.md) -- [ps](./docs/pages/en/guide/ll-cli/ps.md) -- [kill](./docs/pages/en/guide/ll-cli/kill.md) -- [search](./docs/pages/en/guide/ll-cli/query.md) +- [介绍](./docs/pages/guide/reference/commands/ll-cli/ll-cli.md) +- [安装](./docs/pages/guide/reference/commands/ll-cli/install.md) +- [运行](./docs/pages/guide/reference/commands/ll-cli/run.md) +- [卸载](./docs/pages/guide/reference/commands/ll-cli/uninstall.md) +- [升级](./docs/pages/guide/reference/commands/ll-cli/upgrade.md) +- [列表](./docs/pages/guide/reference/commands/ll-cli/list.md) +- [清理](./docs/pages/guide/reference/commands/ll-cli/prune.md) +- [进入](./docs/pages/guide/reference/commands/ll-cli/enter.md) +- [内容](./docs/pages/guide/reference/commands/ll-cli/content.md) +- [信息](./docs/pages/guide/reference/commands/ll-cli/info.md) +- [进程](./docs/pages/guide/reference/commands/ll-cli/ps.md) +- [终止](./docs/pages/guide/reference/commands/ll-cli/kill.md) +- [搜索](./docs/pages/guide/reference/commands/ll-cli/search.md) ### 构建工具 -- [introduction](./docs/pages/en/guide/ll-builder/introduction.md) -- [demo](./docs/pages/en/guide/ll-builder/demo.md) -- [create](./docs/pages/en/guide/ll-builder/create.md) -- [run](./docs/pages/en/guide/ll-builder/run.md) -- [push](./docs/pages/en/guide/ll-builder/push.md) -- [export](./docs/pages/en/guide/ll-builder/export.md) +- [介绍](./docs/pages/guide/reference/commands/ll-builder/ll-builder.md) +- [演示](./docs/pages/guide/building/demo.md) +- [创建](./docs/pages/guide/reference/commands/ll-builder/create.md) +- [运行](./docs/pages/guide/reference/commands/ll-builder/run.md) +- [推送](./docs/pages/guide/reference/commands/ll-builder/push.md) +- [导出](./docs/pages/guide/reference/commands/ll-builder/export.md) +- [构建](./docs/pages/guide/reference/commands/ll-builder/build.md) +- [提取](./docs/pages/guide/reference/commands/ll-builder/extract.md) +- [导入](./docs/pages/guide/reference/commands/ll-builder/import.md) +- [列表](./docs/pages/guide/reference/commands/ll-builder/list.md) +- [删除](./docs/pages/guide/reference/commands/ll-builder/remove.md) +- [仓库](./docs/pages/guide/reference/commands/ll-builder/repo.md) ### 包转换工具 #### deb 包转换 -- [introduction](./docs/pages/en/guide/ll-pica/introduction.md) -- [init](./docs/pages/en/guide/ll-pica/init.md) -- [convert](./docs/pages/en/guide/ll-pica/convert.md) -- [adep](./docs/pages/en/guide/ll-pica/adep.md) +- [介绍](./docs/pages/guide/reference/commands/ll-pica/ll-pica.md) +- [初始化](./docs/pages/guide/reference/commands/ll-pica/ll-pica-init.md) +- [转换](./docs/pages/guide/reference/commands/ll-pica/ll-pica-convert.md) +- [依赖](./docs/pages/guide/reference/commands/ll-pica/ll-pica-adep.md) #### AppImage 包转换 -- [introduction](./docs/pages/en/guide/ll-appimage-convert/introduction.md) -- [convert](./docs/pages/en/guide/ll-appimage-convert/convert-appimage.md) +- [介绍](./docs/pages/guide/reference/commands/ll-appimage-convert/ll-appimage-convert.md) +- [转换](./docs/pages/guide/reference/commands/ll-appimage-convert/ll-appimage-convert-convert.md) #### Flatpak 包转换 -- [introduction](./docs/pages/en/guide/ll-flatpak-convert/introduction.md) -- [convert](./docs/pages/en/guide/ll-flatpak-convert/convert-flatpak.md) +- [介绍](./docs/pages/guide/reference/commands/ll-pica-flatpak/ll-pica-flatpak.md) +- [转换](./docs/pages/guide/reference/commands/ll-pica-flatpak/ll-pica-flatpak-convert.md) ### 调试 -- [debug](/docs/pages/en/guide/debug/debug.md) +- [调试指南](./docs/pages/guide/debug/debug.md) ### 常见问题 -- [运行相关常见问题](/docs/pages/en/guide/debug/faq.md) -- [如意玲珑构建工具常见问题](/docs/pages/en/guide/debug/ll-builder-faq.md) -- [如意玲珑转换工具常见问题](/docs/pages/en/guide/debug/ll-pica-faq.md) +- [运行相关常见问题](./docs/pages/guide/tips-and-faq/faq.md) +- [如意玲珑构建工具常见问题](./docs/pages/guide/tips-and-faq/ll-builder-faq.md) +- [如意玲珑转换工具常见问题](./docs/pages/guide/tips-and-faq/ll-pica-faq.md) ## :book: 学习和参考 +### 入门指南 + +- [概述](./docs/pages/guide/start/whatis.md) - 如意玲珑基本概念介绍 +- [安装指南](./docs/pages/guide/start/install.md) - 详细安装说明 +- [构建第一个应用](./docs/pages/guide/start/build_your_first_app.md) - 初学者完整教程 + +### 构建和打包 + +- [包规范](./docs/pages/guide/building/linyaps_package_spec.md) - 详细打包标准 +- [构建配置](./docs/pages/guide/building/manifests.md) - 理解 linglong.yaml +- [模块管理](./docs/pages/guide/building/modules.md) - 模块拆分和管理 +- [多架构支持](./docs/pages/guide/building/multiarch.md) - 多架构构建 +- [演示示例](./docs/pages/guide/building/demo.md) - 实际构建演示 + +### 参考文档 + +- [基本概念](./docs/pages/guide/reference/basic-concepts.md) - 核心概念和术语 +- [运行时组件](./docs/pages/guide/reference/runtime.md) - 运行时系统详情 +- [驱动文档](./docs/pages/guide/reference/driver.md) - 驱动相关信息 + +### 高级主题 + +- [桌面集成](./docs/pages/guide/desktop-integration/README.md) - 桌面环境集成 +- [单元测试](./docs/pages/guide/extra/unit-testing.md) - 测试框架和实践 +- [包格式](./docs/pages/guide/extra/bundle-format.md) - 包格式规范 +- [系统助手](./docs/pages/guide/extra/system-helper.md) - 系统工具文档 +- [应用配置](./docs/pages/guide/extra/app-conf.md) - 应用配置指南 +- [根文件系统](./docs/pages/guide/extra/rootfs.md) - 根文件系统管理 +- [UAB 构建](./docs/pages/guide/extra/uab-build.md) - UAB 格式构建 +- [仓库管理](./docs/pages/guide/publishing/repositories.md) - 仓库操作 +- [UAB 发布](./docs/pages/guide/publishing/uab.md) - UAB 格式发布 +- [镜像站点](./docs/pages/guide/publishing/mirrors.md) - 镜像配置 + +### 系列教程 + +- [玲珑应用构建工程基础知识](./docs/pages/guide/lessons/basic-notes.md) +- [容器内手动编译应用](./docs/pages/guide/lessons/build-in-env.md) +- [本地源码手动编译应用](./docs/pages/guide/lessons/build-offline-src.md) +- [使用 git&patch 编译应用](./docs/pages/guide/lessons/build-git-patch.md) +- [玲珑应用自动化测试套件](./docs/pages/guide/lessons/test-with-toolchains.md) + ### 相关项目 - [OStree](https://github.com/ostreedev/ostree) - [如意玲珑打包工具 - ll-killer-go](https://github.com/System233/ll-killer-go) - [如意玲珑网页商店](https://github.com/yoloke/Linglong-Shop) -### 系列教程 - -- [玲珑应用构建工程基础知识](/docs/pages/guide/lessons/basic-notes.md) -- [容器内手动编译应用](/docs/pages/guide/lessons/build-in-env.md) -- [本地源码手动编译应用](/docs/pages/guide/lessons/build-offline-src.md) -- [使用 git&patch 编译应用](/docs/pages/guide/lessons/build-git-patch.md) -- [玲珑应用自动化测试套件](/docs/pages/guide/lessons/test-with-toolchains.md) - 更多课程可参考如意玲珑官网: ## :hammer_and_pick: 参与 -我们鼓励您报告问题并贡献更改。查看 [构建指南](./BUILD.zh_CN.md) 以获取从源代码构建 linyaps 的说明。 +我们鼓励您报告问题并贡献更改。查看 [开发者指南](./开发者指南.md) 以获取从源代码构建 linyaps 的说明。 您可以在 [Discussions](https://github.com/OpenAtom-Linyaps/linyaps/discussions) 上发起话题讨论。 diff --git a/REUSE.toml b/REUSE.toml index e563847a1..ae65f3d85 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -4,7 +4,7 @@ SPDX-PackageSupplier = "UnionTech Software Technology Co., Ltd. <>" SPDX-PackageDownloadLocation = "https://github.com/OpenAtom-Linyaps/linyaps" [[annotations]] -path = [".github/**", ".obs/**", "OWNERS"] +path = [".github/**", ".obs/**", "OWNERS", ".tx/config"] precedence = "aggregate" SPDX-FileCopyrightText = "None" SPDX-License-Identifier = "CC0-1.0" @@ -21,6 +21,12 @@ precedence = "aggregate" SPDX-FileCopyrightText = "2017-2024 University of Cincinnati, developed by Henry" SPDX-License-Identifier = "BSD-3-Clause" +[[annotations]] +path = "external/fmt/**" +precedence = "aggregate" +SPDX-FileCopyrightText = "Copyright (c) 2012 - present, Victor Zverovich" +SPDX-License-Identifier = "MIT" + [[annotations]] path = "external/ytj/**" precedence = "aggregate" @@ -117,18 +123,6 @@ precedence = "aggregate" SPDX-FileCopyrightText = "None" SPDX-License-Identifier = "CC0-1.0" -[[annotations]] -path = "tools/qdbusxml2cpp/qdbusxml2cpp_5.cpp" -precedence = "aggregate" -SPDX-FileCopyrightText = "2020 The Qt Company Ltd." -SPDX-License-Identifier = "GPL-3.0-only" - -[[annotations]] -path = "tools/qdbusxml2cpp/qdbusxml2cpp_6.h" -precedence = "aggregate" -SPDX-FileCopyrightText = "2021 The Qt Company Ltd." -SPDX-License-Identifier = "GPL-3.0-only" - [[annotations]] path = "libs/ocppi/**" precedence = "aggregate" @@ -142,7 +136,7 @@ SPDX-FileCopyrightText = "None" SPDX-License-Identifier = "CC0-1.0" [[annotations]] -path = "misc/share/linglong/**.json" +path = "misc/share/linglong/**.json" precedence = "aggregate" SPDX-FileCopyrightText = "None" SPDX-License-Identifier = "CC0-1.0" @@ -178,7 +172,7 @@ SPDX-FileCopyrightText = "2018 Xiphos Development Team" SPDX-License-Identifier = "GPL-2.0-or-later" [[annotations]] -path = ["po/**.po", "po/**.pot", "po/POTFILES.in", "po/LINGUAS"] +path = ["po/**.po", "po/**.pot", "po/POTFILES.in", "po/LINGUAS", "misc/share/polkit-1/translations/*.ts"] precedence = "aggregate" SPDX-FileCopyrightText = "UnionTech Software Technology Co., Ltd." SPDX-License-Identifier = "LGPL-3.0-only" @@ -196,13 +190,13 @@ SPDX-FileCopyrightText = "AppImageCommunity" SPDX-License-Identifier = "MIT" [[annotations]] -path = "apps/dumb-init/src/*" +path = "apps/ll-builder-utils/patch/libfuse.patch" precedence = "aggregate" -SPDX-FileCopyrightText = "Yelp Inc." -SPDX-License-Identifier = "MIT" +SPDX-FileCopyrightText = "UnionTech Software Technology Co., Ltd." +SPDX-License-Identifier = "LGPL-3.0-or-later" [[annotations]] -path = "apps/ll-builder-utils/patch/libfuse.patch" +path = ["misc/share/icons/**.svg"] precedence = "aggregate" SPDX-FileCopyrightText = "UnionTech Software Technology Co., Ltd." SPDX-License-Identifier = "LGPL-3.0-or-later" diff --git a/api/dbus/org.deepin.linglong.PackageManager1.xml b/api/dbus/org.deepin.linglong.PackageManager1.xml index bc4a73405..545b9e117 100644 --- a/api/dbus/org.deepin.linglong.PackageManager1.xml +++ b/api/dbus/org.deepin.linglong.PackageManager1.xml @@ -79,11 +79,6 @@ SPDX-License-Identifier: LGPL-3.0-or-later - - - - - diff --git a/api/dbus/org.deepin.linglong.Task1.xml b/api/dbus/org.deepin.linglong.Task1.xml index da6a9a60c..928a6cfef 100644 --- a/api/dbus/org.deepin.linglong.Task1.xml +++ b/api/dbus/org.deepin.linglong.Task1.xml @@ -8,7 +8,6 @@ SPDX-License-Identifier: LGPL-3.0-or-later - diff --git a/api/schema/v1.json b/api/schema/v1.json index a4faabb24..8dab9c130 100644 --- a/api/schema/v1.json +++ b/api/schema/v1.json @@ -125,6 +125,13 @@ }, "runtime": { "type": "string" + }, + "extensions": { + "type": "array", + "description": "extensions of container", + "items": { + "type": "string" + } } } }, @@ -348,6 +355,31 @@ "channel": { "type": "string", "description": "channel of package" + }, + "extension_of": { + "type": "string", + "description": "extension of whom" + }, + "libs": { + "description": "extra ld search path", + "type": "array", + "items": { + "type": "string" + } + }, + "env": { + "description": "Predefined environment variables when the extension is applied", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "deviceNodes": { + "description": "device nodes to be mounted", + "type": "array", + "items": { + "$ref": "#/$defs/DeviceNode" + } } } }, @@ -385,6 +417,10 @@ "type": "string", "description": "digest of source" }, + "name": { + "type": "string", + "description": "name of source" + }, "commit": { "type": "string", "description": "commit of source" @@ -393,9 +429,9 @@ "type": "string", "description": "version of source" }, - "name": { - "type": "string", - "description": "name of source" + "submodules": { + "type": "boolean", + "description": "whether to checkout submodules" } } } @@ -582,6 +618,10 @@ "priority": { "type": "integer", "description": "priority of repo" + }, + "mirror_enabled": { + "type": "boolean", + "description": "whether mirror is enabled for this repo" } } }, @@ -626,6 +666,27 @@ } } }, + "PackageInfoDisplay": { + "title": "PackageInfoDisplay", + "description": "this is the each item output of ll-cli list --json", + "allOf": [ + { + "$ref": "#/$defs/PackageInfoV2" + }, + { + "type": "object", + "requested": [ + "info" + ], + "properties": { + "install_time": { + "type": "integer", + "description": "package install time" + } + } + } + ] + }, "PackageInfoV2": { "title": "PackageInfoV2", "description": "this is the each item output of ll-cli list --json", @@ -711,6 +772,16 @@ "compatible_version": { "type": "string", "description": "record linyaps package is compatible with linyaps component version" + }, + "extensions": { + "type": "array", + "description": "description of extension", + "items": { + "$ref": "#/$defs/ExtensionDefine" + } + }, + "ext_impl": { + "$ref": "#/$defs/ExtensionImpl" } } }, @@ -879,26 +950,11 @@ "Queued", "Pending", "Processing", - "PartCompleted", "Succeed", "Failed", "Canceled" ] }, - "SubState": { - "description": "subState of current task,", - "enum": [ - "Unknown", - "PreAction", - "InstallRuntime", - "InstallBase", - "InstallApplication", - "PostAction", - "Uninstall", - "AllDone", - "PackageManagerDone" - ] - }, "PackageManager1InstallLayerFDResult": { "$ref": "#/$defs/CommonResult" }, @@ -961,11 +1017,15 @@ "type": "object", "description": "package manager uninstall parameters", "required": [ - "package" + "package", + "options" ], "properties": { "package": { "$ref": "#/$defs/PackageManager1Package" + }, + "options": { + "$ref": "#/$defs/CommonOptions" } } }, @@ -973,7 +1033,8 @@ "type": "object", "description": "package manager update result", "required": [ - "packages" + "packages", + "depsOnly" ], "properties": { "packages": { @@ -982,6 +1043,10 @@ "items": { "$ref": "#/$defs/PackageManager1Package" } + }, + "depsOnly": { + "type": "boolean", + "description": "upgrade dependencies only" } } }, @@ -1285,6 +1350,79 @@ } } } + }, + "ExtensionDefine": { + "type": "object", + "required": [ + "name", + "version", + "directory" + ], + "properties": { + "name": { + "description": "extension name", + "type": "string" + }, + "version": { + "description": "extension version", + "type": "string" + }, + "directory": { + "description": "where extension to be mount", + "type": "string" + }, + "allow_env": { + "description": "the environment variables allow extension to modify", + "type": "object", + "additionalProperties": { + "description": "default environment variable", + "type": "string" + } + } + } + }, + "ExtensionImpl": { + "type": "object", + "properties": { + "libs": { + "description": "extra ld search path", + "type": "array", + "items": { + "type": "string" + } + }, + "env": { + "description": "environment variables to set when extension effects", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "deviceNodes": { + "description": "device nodes to be mounted", + "type": "array", + "items": { + "$ref": "#/$defs/DeviceNode" + } + } + } + }, + "DeviceNode": { + "title": "DeviceNode", + "type": "object", + "required": [ + "path" + ], + "properties": { + "path": { + "description": "device node path", + "type": "string" + }, + "hostPath": { + "description": "host device node path", + "type": "string" + } + } } }, "type": "object", @@ -1340,6 +1478,9 @@ "PackageManager1Package": { "$ref": "#/$defs/PackageManager1Package" }, + "PackageInfoDisplay": { + "$ref": "#/$defs/PackageInfoDisplay" + }, "PackageInfoV2": { "$ref": "#/$defs/PackageInfoV2" }, @@ -1364,9 +1505,6 @@ "State": { "$ref": "#/$defs/State" }, - "SubState": { - "$ref": "#/$defs/SubState" - }, "PackageManager1InstallLayerFDResult": { "$ref": "#/$defs/PackageManager1InstallLayerFDResult" }, @@ -1417,6 +1555,15 @@ }, "ExportDirs": { "$ref": "#/$defs/ExportDirs" + }, + "ExtensionDefine": { + "$ref": "#/$defs/ExtensionDefine" + }, + "ExtensionImpl": { + "$ref": "#/$defs/ExtensionImpl" + }, + "DeviceNode": { + "$ref": "#/$defs/DeviceNode" } } } diff --git a/api/schema/v1.yaml b/api/schema/v1.yaml index 2f73efda8..4224060cb 100644 --- a/api/schema/v1.yaml +++ b/api/schema/v1.yaml @@ -113,6 +113,11 @@ $defs: type: string runtime: type: string + extensions: + type: array + description: extensions of container + items: + type: string InteractionRequest: description: | structured message which inspired by freedesktop Notification Spec. @@ -292,6 +297,24 @@ $defs: channel: type: string description: channel of package + extension_of: + type: string + description: extension of whom + libs: + description: extra ld search path + type: array + items: + type: string + env: + description: Predefined environment variables when the extension is applied + type: object + additionalProperties: + type: string + deviceNodes: + description: device nodes to be mounted + type: array + items: + $ref: '#/$defs/DeviceNode' permissions: $ref: '#/$defs/ApplicationConfigurationPermissions' runtime: @@ -319,15 +342,18 @@ $defs: digest: type: string description: digest of source + name: + type: string + description: name of source commit: type: string description: commit of source version: type: string description: version of source - name: - type: string - description: name of source + submodules: + type: boolean + description: whether to checkout submodules build: title: BuilderProjectBuildScript description: build script of builder project @@ -465,6 +491,9 @@ $defs: priority: type: integer description: priority of repo + mirror_enabled: + type: boolean + description: whether mirror is enabled for this repo LayerInfo: description: Meta information on the head of layer file. type: object @@ -495,6 +524,18 @@ $defs: module: type: string description: module of package manager + PackageInfoDisplay: + title: PackageInfoDisplay + description: this is the each item output of ll-cli list --json + allOf: + - $ref: '#/$defs/PackageInfoV2' + - type: object + requested: + - info + properties: + install_time: + type: integer + description: package install time PackageInfoV2: title: PackageInfoV2 description: this is the each item output of ll-cli list --json @@ -563,6 +604,13 @@ $defs: compatible_version: type: string description: record linyaps package is compatible with linyaps component version + extensions: + type: array + description: description of extension + items: + $ref: '#/$defs/ExtensionDefine' + ext_impl: + $ref: '#/$defs/ExtensionImpl' PackageInfo: title: PackageInfo description: this is the each item output of ll-cli list --json @@ -685,25 +733,10 @@ $defs: 'Queued', 'Pending', 'Processing', - 'PartCompleted', 'Succeed', 'Failed', 'Canceled', ] - SubState: - description: subState of current task, - enum: - [ - 'Unknown', - 'PreAction', - 'InstallRuntime', - 'InstallBase', - 'InstallApplication', - 'PostAction', - 'Uninstall', - 'AllDone', - 'PackageManagerDone', - ] PackageManager1InstallLayerFDResult: $ref: '#/$defs/CommonResult' PackageManager1InstallParameters: @@ -747,20 +780,27 @@ $defs: description: package manager uninstall parameters required: - package + - options properties: package: $ref: '#/$defs/PackageManager1Package' + options: + $ref: '#/$defs/CommonOptions' PackageManager1UpdateParameters: type: object description: package manager update result required: - packages + - depsOnly properties: packages: type: array description: packages of package manager update items: $ref: '#/$defs/PackageManager1Package' + depsOnly: + type: boolean + description: upgrade dependencies only PackageManager1ModifyRepoParameters: type: object required: @@ -986,6 +1026,58 @@ $defs: items: type: string description: path to export + ExtensionDefine: + type: object + required: + - name + - version + - directory + properties: + name: + description: extension name + type: string + version: + description: extension version + type: string + directory: + description: where extension to be mount + type: string + allow_env: + description: the environment variables allow extension to modify + type: object + additionalProperties: + description: default environment variable + type: string + ExtensionImpl: + type: object + properties: + libs: + description: extra ld search path + type: array + items: + type: string + env: + description: environment variables to set when extension effects + type: object + additionalProperties: + type: string + deviceNodes: + description: device nodes to be mounted + type: array + items: + $ref: '#/$defs/DeviceNode' + DeviceNode: + title: DeviceNode + type: object + required: + - path + properties: + path: + description: device node path + type: string + hostPath: + description: host device node path + type: string type: object properties: # NOTE: "properties" is auto generated by referring all types is $defs diff --git a/apps/dumb-init/CMakeLists.txt b/apps/dumb-init/CMakeLists.txt deleted file mode 100644 index 1edc4980b..000000000 --- a/apps/dumb-init/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -# SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. -# -# SPDX-License-Identifier: LGPL-3.0-or-later - -pfl_add_executable( - SOURCES - ./src/dumb-init.c - OUTPUT_NAME - dumb-init - LIBEXEC - linglong -) - -set(DUMB_INIT_TARGET) - -get_real_target_name(DUMB_INIT_TARGET linglong::dumb-init) - -target_link_options(${DUMB_INIT_TARGET} PRIVATE -static) diff --git a/apps/dumb-init/src/VERSION.h b/apps/dumb-init/src/VERSION.h deleted file mode 100644 index 2a4fbf0d9..000000000 --- a/apps/dumb-init/src/VERSION.h +++ /dev/null @@ -1,2 +0,0 @@ -unsigned char VERSION[] = { 0x31, 0x2e, 0x32, 0x2e, 0x35, 0x0a }; -unsigned int VERSION_len = 6; diff --git a/apps/dumb-init/src/dumb-init.c b/apps/dumb-init/src/dumb-init.c deleted file mode 100644 index 288159903..000000000 --- a/apps/dumb-init/src/dumb-init.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * dumb-init is a simple wrapper program designed to run as PID 1 and pass - * signals to its children. - * - * Usage: - * ./dumb-init python -c 'while True: pass' - * - * To get debug output on stderr, run with '-v'. - */ - -#include "VERSION.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PRINTERR(...) \ - do { \ - fprintf(stderr, "[dumb-init] " __VA_ARGS__); \ - } while (0) - -#define DEBUG(...) \ - do { \ - if (debug) { \ - PRINTERR(__VA_ARGS__); \ - } \ - } while (0) - -// Signals we care about are numbered from 1 to 31, inclusive. -// (32 and above are real-time signals.) -// TODO: this is likely not portable outside of Linux, or on strange architectures -#define MAXSIG 31 - -// Indices are one-indexed (signal 1 is at index 1). Index zero is unused. -// User-specified signal rewriting. -int signal_rewrite[MAXSIG + 1] = { [0 ... MAXSIG] = -1 }; -// One-time ignores due to TTY quirks. 0 = no skip, 1 = skip the next-received signal. -char signal_temporary_ignores[MAXSIG + 1] = { [0 ... MAXSIG] = 0 }; - -pid_t child_pid = -1; -char debug = 0; -char use_setsid = 1; - -int translate_signal(int signum) -{ - if (signum <= 0 || signum > MAXSIG) { - return signum; - } else { - int translated = signal_rewrite[signum]; - if (translated == -1) { - return signum; - } else { - DEBUG("Translating signal %d to %d.\n", signum, translated); - return translated; - } - } -} - -void forward_signal(int signum) -{ - signum = translate_signal(signum); - if (signum != 0) { - kill(use_setsid ? -child_pid : child_pid, signum); - DEBUG("Forwarded signal %d to children.\n", signum); - } else { - DEBUG("Not forwarding signal %d to children (ignored).\n", signum); - } -} - -/* - * The dumb-init signal handler. - * - * The main job of this signal handler is to forward signals along to our child - * process(es). In setsid mode, this means signaling the entire process group - * rooted at our child. In non-setsid mode, this is just signaling the primary - * child. - * - * In most cases, simply proxying the received signal is sufficient. If we - * receive a job control signal, however, we should not only forward it, but - * also sleep dumb-init itself. - * - * This allows users to run foreground processes using dumb-init and to - * control them using normal shell job control features (e.g. Ctrl-Z to - * generate a SIGTSTP and suspend the process). - * - * The libc manual is useful: - * https://www.gnu.org/software/libc/manual/html_node/Job-Control-Signals.html - * - */ -void handle_signal(int signum) -{ - DEBUG("Received signal %d.\n", signum); - - if (signal_temporary_ignores[signum] == 1) { - DEBUG("Ignoring tty hand-off signal %d.\n", signum); - signal_temporary_ignores[signum] = 0; - } else if (signum == SIGCHLD) { - int status, exit_status; - pid_t killed_pid; - while ((killed_pid = waitpid(-1, &status, WNOHANG)) > 0) { - if (WIFEXITED(status)) { - exit_status = WEXITSTATUS(status); - DEBUG("A child with PID %d exited with exit status %d.\n", killed_pid, exit_status); - } else { - assert(WIFSIGNALED(status)); - exit_status = 128 + WTERMSIG(status); - DEBUG("A child with PID %d was terminated by signal %d.\n", - killed_pid, - exit_status - 128); - } - - if (killed_pid == child_pid) { - forward_signal(SIGTERM); // send SIGTERM to any remaining children - DEBUG("Child exited with status %d. Goodbye.\n", exit_status); - exit(exit_status); - } - } - } else { - forward_signal(signum); - if (signum == SIGTSTP || signum == SIGTTOU || signum == SIGTTIN) { - DEBUG("Suspending self due to TTY signal.\n"); - kill(getpid(), SIGSTOP); - } - } -} - -void print_help(char *argv[]) -{ - fprintf(stderr, - "dumb-init v%.*s" - "Usage: %s [option] command [[arg] ...]\n" - "\n" - "dumb-init is a simple process supervisor that forwards signals to children.\n" - "It is designed to run as PID1 in minimal container environments.\n" - "\n" - "Optional arguments:\n" - " -c, --single-child Run in single-child mode.\n" - " In this mode, signals are only proxied to the\n" - " direct child and not any of its descendants.\n" - " -r, --rewrite s:r Rewrite received signal s to new signal r before proxying.\n" - " To ignore (not proxy) a signal, rewrite it to 0.\n" - " This option can be specified multiple times.\n" - " -v, --verbose Print debugging information to stderr.\n" - " -h, --help Print this help message and exit.\n" - " -V, --version Print the current version and exit.\n" - "\n" - "Full help is available online at https://github.com/Yelp/dumb-init\n", - VERSION_len, - VERSION, - argv[0]); -} - -void print_rewrite_signum_help() -{ - fprintf(stderr, - "Usage: -r option takes :, where " - "is between 1 and %d.\n" - "This option can be specified multiple times.\n" - "Use --help for full usage.\n", - MAXSIG); - exit(1); -} - -void parse_rewrite_signum(char *arg) -{ - int signum, replacement; - if (sscanf(arg, "%d:%d", &signum, &replacement) == 2 && (signum >= 1 && signum <= MAXSIG) - && (replacement >= 0 && replacement <= MAXSIG)) { - signal_rewrite[signum] = replacement; - } else { - print_rewrite_signum_help(); - } -} - -void set_rewrite_to_sigstop_if_not_defined(int signum) -{ - if (signal_rewrite[signum] == -1) { - signal_rewrite[signum] = SIGSTOP; - } -} - -char **parse_command(int argc, char *argv[]) -{ - int opt; - struct option long_options[] = { - { "help", no_argument, NULL, 'h' }, { "single-child", no_argument, NULL, 'c' }, - { "rewrite", required_argument, NULL, 'r' }, { "verbose", no_argument, NULL, 'v' }, - { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 }, - }; - while ((opt = getopt_long(argc, argv, "+hvVcr:", long_options, NULL)) != -1) { - switch (opt) { - case 'h': - print_help(argv); - exit(0); - case 'v': - debug = 1; - break; - case 'V': - fprintf(stderr, "dumb-init v%.*s", VERSION_len, VERSION); - exit(0); - case 'c': - use_setsid = 0; - break; - case 'r': - parse_rewrite_signum(optarg); - break; - default: - exit(1); - } - } - - if (optind >= argc) { - fprintf(stderr, - "Usage: %s [option] program [args]\n" - "Try %s --help for full usage.\n", - argv[0], - argv[0]); - exit(1); - } - - char *debug_env = getenv("DUMB_INIT_DEBUG"); - if (debug_env && strcmp(debug_env, "1") == 0) { - debug = 1; - DEBUG("Running in debug mode.\n"); - } - - char *setsid_env = getenv("DUMB_INIT_SETSID"); - if (setsid_env && strcmp(setsid_env, "0") == 0) { - use_setsid = 0; - DEBUG("Not running in setsid mode.\n"); - } - - if (use_setsid) { - set_rewrite_to_sigstop_if_not_defined(SIGTSTP); - set_rewrite_to_sigstop_if_not_defined(SIGTTOU); - set_rewrite_to_sigstop_if_not_defined(SIGTTIN); - } - - return &argv[optind]; -} - -// A dummy signal handler used for signals we care about. -// On the FreeBSD kernel, ignored signals cannot be waited on by `sigwait` (but -// they can be on Linux). We must provide a dummy handler. -// https://lists.freebsd.org/pipermail/freebsd-ports/2009-October/057340.html -void dummy(int signum) { } - -int main(int argc, char *argv[]) -{ - char **cmd = parse_command(argc, argv); - sigset_t all_signals; - sigfillset(&all_signals); - sigprocmask(SIG_BLOCK, &all_signals, NULL); - - int i = 0; - for (i = 1; i <= MAXSIG; i++) { - signal(i, dummy); - } - - /* - * Detach dumb-init from controlling tty, so that the child's session can - * attach to it instead. - * - * We want the child to be able to be the session leader of the TTY so that - * it can do normal job control. - */ - if (use_setsid) { - if (ioctl(STDIN_FILENO, TIOCNOTTY) == -1) { - DEBUG("Unable to detach from controlling tty (errno=%d %s).\n", errno, strerror(errno)); - } else { - /* - * When the session leader detaches from its controlling tty via - * TIOCNOTTY, the kernel sends SIGHUP and SIGCONT to the process - * group. We need to be careful not to forward these on to the - * dumb-init child so that it doesn't receive a SIGHUP and - * terminate itself (#136). - */ - if (getsid(0) == getpid()) { - DEBUG("Detached from controlling tty, ignoring the first SIGHUP and SIGCONT we " - "receive.\n"); - signal_temporary_ignores[SIGHUP] = 1; - signal_temporary_ignores[SIGCONT] = 1; - } else { - DEBUG("Detached from controlling tty, but was not session leader.\n"); - } - } - } - - child_pid = fork(); - if (child_pid < 0) { - PRINTERR("Unable to fork. Exiting.\n"); - return 1; - } else if (child_pid == 0) { - /* child */ - sigprocmask(SIG_UNBLOCK, &all_signals, NULL); - if (use_setsid) { - if (setsid() == -1) { - PRINTERR("Unable to setsid (errno=%d %s). Exiting.\n", errno, strerror(errno)); - exit(1); - } - - if (ioctl(STDIN_FILENO, TIOCSCTTY, 0) == -1) { - DEBUG("Unable to attach to controlling tty (errno=%d %s).\n", - errno, - strerror(errno)); - } - DEBUG("setsid complete.\n"); - } - execvp(cmd[0], &cmd[0]); - - // if this point is reached, exec failed, so we should exit nonzero - PRINTERR("%s: %s\n", cmd[0], strerror(errno)); - return 2; - } else { - /* parent */ - DEBUG("Child spawned with PID %d.\n", child_pid); - if (chdir("/") == -1) { - DEBUG("Unable to chdir(\"/\") (errno=%d %s)\n", errno, strerror(errno)); - } - for (;;) { - int signum; - sigwait(&all_signals, &signum); - handle_signal(signum); - } - } -} diff --git a/apps/ll-builder/src/command_options.h b/apps/ll-builder/src/command_options.h index 80f260760..3780fd9cd 100644 --- a/apps/ll-builder/src/command_options.h +++ b/apps/ll-builder/src/command_options.h @@ -9,8 +9,6 @@ #include "linglong/builder/linglong_builder.h" #include "linglong/cli/cli.h" -#include -#include #include #include @@ -31,6 +29,7 @@ struct RunCommandOptions std::vector execModules; std::vector commands; bool debugMode = false; + std::vector extensions; }; struct ListCommandOptions @@ -40,12 +39,13 @@ struct ListCommandOptions struct RemoveCommandOptions { + bool noCleanObjects = false; std::vector removeList; // List of apps to remove }; struct ExportCommandOptions { - linglong::builder::ExportOption exportSpecificOptions{ .exportI18n = true }; + linglong::builder::ExportOption exportSpecificOptions; bool layerMode = false; std::string outputFile; }; diff --git a/apps/ll-builder/src/main.cpp b/apps/ll-builder/src/main.cpp index eaf7223fa..bdb6169bc 100644 --- a/apps/ll-builder/src/main.cpp +++ b/apps/ll-builder/src/main.cpp @@ -5,6 +5,7 @@ */ #include "command_options.h" +#include "configure.h" #include "linglong/builder/config.h" #include "linglong/builder/linglong_builder.h" #include "linglong/cli/cli.h" @@ -13,11 +14,11 @@ #include "linglong/repo/client_factory.h" #include "linglong/repo/config.h" #include "linglong/repo/migrate.h" -#include "linglong/utils/command/env.h" -#include "linglong/utils/configure.h" #include "linglong/utils/error/error.h" #include "linglong/utils/gettext.h" #include "linglong/utils/global/initialize.h" +#include "linglong/utils/log/log.h" +#include "linglong/utils/namespace.h" #include "linglong/utils/serialize/yaml.h" #include "ocppi/cli/crun/Crun.hpp" @@ -86,7 +87,11 @@ void initDefaultBuildConfig() linglong::api::types::v1::BuilderConfig config; config.version = 1; config.repo = cacheLocation.filePath("linglong-builder").toStdString(); - linglong::builder::saveConfig(config, configFilePath); + auto ret = linglong::builder::saveConfig(config, configFilePath); + if (!ret) { + qCritical() << "failed to save default build config file" << configFilePath << ":" + << ret.error(); + } } std::string validateNonEmptyString(const std::string ¶meter) @@ -98,16 +103,16 @@ std::string validateNonEmptyString(const std::string ¶meter) } linglong::utils::error::Result -parseProjectConfig(const QString &filename) +parseProjectConfig(const std::filesystem::path &filename) { - LINGLONG_TRACE(QString("parse project config %1").arg(filename)); + LINGLONG_TRACE("parse project config " + filename.string()); + std::cerr << "Using project file " + filename.string() << std::endl; auto project = linglong::utils::serialize::LoadYAMLFile(filename); if (!project) { return project; } - auto version = - linglong::package::VersionV1::parse(QString::fromStdString(project->package.version)); + auto version = linglong::package::VersionV1::parse(project->package.version); if (!version || !version->tweak) { return LINGLONG_ERR("Please ensure the package.version number has three parts formatted as " "'MAJOR.MINOR.PATCH.TWEAK'"); @@ -149,6 +154,42 @@ parseProjectConfig(const QString &filename) return project; } +linglong::utils::error::Result +getProjectYAMLPath(const std::filesystem::path &projectDir, const std::string &usePath) +{ + LINGLONG_TRACE("get project yaml path"); + + std::error_code ec; + if (!usePath.empty()) { + std::filesystem::path path = std::filesystem::canonical(usePath, ec); + if (ec) { + return LINGLONG_ERR( + fmt::format("invalid file path {} error: {}", usePath, ec.message())); + } + return path; + } + + std::filesystem::path path = projectDir + / ("linglong." + linglong::package::Architecture::currentCPUArchitecture().toString() + + ".yaml"); + if (std::filesystem::exists(path, ec)) { + return path; + } + if (ec) { + return LINGLONG_ERR(fmt::format("path {} error: {}", path, ec.message())); + } + + path = projectDir / "linglong.yaml"; + if (std::filesystem::exists(path, ec)) { + return path; + } + if (ec) { + return LINGLONG_ERR(fmt::format("path {} error: {}", path, ec.message())); + } + + return LINGLONG_ERR("project yaml file not found"); +} + int handleCreate(const CreateCommandOptions &options) { qInfo() << "Handling create for project:" << QString::fromStdString(options.projectName); @@ -245,33 +286,27 @@ int handleBuild(linglong::builder::Builder &builder, const BuildCommandOptions & int handleRun(linglong::builder::Builder &builder, const RunCommandOptions &options) { - qInfo() << "Handling run command"; + LogI("Handling run command"); - QStringList modules = { "binary" }; + std::vector modules = { "binary" }; if (options.debugMode) { - modules.push_back("develop"); + modules.emplace_back("develop"); } if (!options.execModules.empty()) { - for (const std::string &module : options.execModules) { - modules.append(QString::fromStdString(module)); + for (const auto &module : options.execModules) { + if (std::find(modules.begin(), modules.end(), module) == modules.end()) { + modules.emplace_back(module); + } } } - modules.removeDuplicates(); // Ensure modules are unique - QStringList commandList; - if (!options.commands.empty()) { - for (const auto &command : options.commands) { - commandList.append(QString::fromStdString(command)); - } - } - - auto result = builder.run(modules, commandList, options.debugMode); + auto result = builder.run(modules, options.commands, options.debugMode, options.extensions); if (!result) { - qCritical() << "Run failed: " << result.error(); + LogE("Run failed: {}", result.error()); return result.error().code(); } - qInfo() << "Run completed successfully."; + LogI("Run completed successfully."); return 0; } @@ -279,35 +314,26 @@ int handleExport(linglong::builder::Builder &builder, const ExportCommandOptions { // Create a mutable copy of the export options to potentially modify defaults auto exportOpts = options.exportSpecificOptions; + // layer 默认使用lz4, 保持和之前版本的兼容 + if (exportOpts.compressor.empty()) { + qInfo() << "Compressor not specified, defaulting to lz4 for layer export."; + exportOpts.compressor = "lz4"; + } if (options.layerMode) { - qInfo() << "Exporting as layer file..."; - // layer 默认使用lzma有更高压缩率 - if (exportOpts.compressor.empty()) { - qInfo() << "Compressor not specified, defaulting to lzma for layer export."; - exportOpts.compressor = "lzma"; - } - auto result = builder.exportLayer(exportOpts); if (!result) { qCritical() << "Export layer failed: " << result.error(); return result.error().code(); } - qInfo() << "Layer export completed successfully."; - } else { - qInfo() << "Exporting as UAB file..."; - // uab 默认使用lz4可以更快解压速度,避免影响应用自运行 - if (exportOpts.compressor.empty()) { - qInfo() << "Compressor not specified, defaulting to lz4 for UAB export."; - exportOpts.compressor = "lz4"; - } - auto result = builder.exportUAB(exportOpts, options.outputFile); - if (!result) { - qCritical() << "Export UAB failed: " << result.error(); - return result.error().code(); - } - qInfo() << "UAB export completed successfully."; + return 0; + } + + auto result = builder.exportUAB(exportOpts, options.outputFile); + if (!result) { + qCritical() << "Export UAB failed: " << result.error(); + return result.error().code(); } return 0; @@ -345,7 +371,7 @@ int handleList(linglong::repo::OSTreeRepo &repo, [[maybe_unused]] const ListComm int handleRemove(linglong::repo::OSTreeRepo &repo, const RemoveCommandOptions &options) { - auto ret = linglong::builder::cmdRemoveApp(repo, options.removeList); + auto ret = linglong::builder::cmdRemoveApp(repo, options.removeList, !options.noCleanObjects); if (!ret.has_value()) { return -1; } @@ -444,7 +470,7 @@ int handleRepoAdd(linglong::repo::OSTreeRepo &repo, linglong::cli::RepoOptions & auto ret = repo.setConfig(newCfg); if (!ret) { - std::cerr << ret.error().message().toStdString() << std::endl; + std::cerr << ret.error().message() << std::endl; return -1; } @@ -454,7 +480,7 @@ int handleRepoAdd(linglong::repo::OSTreeRepo &repo, linglong::cli::RepoOptions & int handleRepoRemove(linglong::repo::OSTreeRepo &repo, linglong::cli::RepoOptions &options) { auto newCfg = repo.getConfig(); - const std::string &alias = options.repoAlias.value(); + const std::string &alias = options.repoAlias.value_or(options.repoName); auto existingRepo = std::find_if(newCfg.repos.begin(), newCfg.repos.end(), [&alias](const auto &r) { @@ -476,7 +502,7 @@ int handleRepoRemove(linglong::repo::OSTreeRepo &repo, linglong::cli::RepoOption newCfg.repos.erase(existingRepo); auto ret = repo.setConfig(newCfg); if (!ret) { - std::cerr << ret.error().message().toStdString() << std::endl; + std::cerr << ret.error().message() << std::endl; return -1; } @@ -487,7 +513,7 @@ int handleRepoRemove(linglong::repo::OSTreeRepo &repo, linglong::cli::RepoOption int handleRepoUpdate(linglong::repo::OSTreeRepo &repo, linglong::cli::RepoOptions &options) { auto newCfg = repo.getConfig(); - const std::string &alias = options.repoAlias.value(); + const std::string &alias = options.repoAlias.value_or(options.repoName); if (options.repoUrl.empty()) { std::cerr << "url is empty." << std::endl; @@ -508,7 +534,7 @@ int handleRepoUpdate(linglong::repo::OSTreeRepo &repo, linglong::cli::RepoOption auto ret = repo.setConfig(newCfg); if (!ret) { - std::cerr << ret.error().message().toStdString() << std::endl; + std::cerr << ret.error().message() << std::endl; return -1; } @@ -519,7 +545,7 @@ int handleRepoUpdate(linglong::repo::OSTreeRepo &repo, linglong::cli::RepoOption int handleRepoSetDefault(linglong::repo::OSTreeRepo &repo, linglong::cli::RepoOptions &options) { auto newCfg = repo.getConfig(); - const std::string &alias = options.repoAlias.value(); + const std::string &alias = options.repoAlias.value_or(options.repoName); auto existingRepo = std::find_if(newCfg.repos.begin(), newCfg.repos.end(), [&alias](const auto &r) { @@ -535,7 +561,7 @@ int handleRepoSetDefault(linglong::repo::OSTreeRepo &repo, linglong::cli::RepoOp newCfg.defaultRepo = alias; auto ret = repo.setConfig(newCfg); if (!ret) { - std::cerr << ret.error().message().toStdString() << std::endl; + std::cerr << ret.error().message() << std::endl; return -1; } qInfo() << "Default repository set to" << QString::fromStdString(alias) << "successfully."; @@ -546,13 +572,66 @@ int handleRepoSetDefault(linglong::repo::OSTreeRepo &repo, linglong::cli::RepoOp return 0; } +int handleRepoEnableMirror(linglong::repo::OSTreeRepo &repo, linglong::cli::RepoOptions &options) +{ + auto newCfg = repo.getConfig(); + const std::string &alias = options.repoAlias.value_or(options.repoName); + + auto existingRepo = + std::find_if(newCfg.repos.begin(), newCfg.repos.end(), [&alias](const auto &r) { + return r.alias.value_or(r.name) == alias; + }); + + if (existingRepo == newCfg.repos.cend()) { + std::cerr << "the operated repo " + alias + " doesn't exist." << std::endl; + return -1; + } + + existingRepo->mirrorEnabled = true; + auto ret = repo.setConfig(newCfg); + if (!ret) { + std::cerr << ret.error().message() << std::endl; + return -1; + } + + std::cerr << "Repository " << alias << " mirror enabled successfully."; + return 0; +} + +int handleRepoDisableMirror(linglong::repo::OSTreeRepo &repo, linglong::cli::RepoOptions &options) +{ + auto newCfg = repo.getConfig(); + const std::string &alias = options.repoAlias.value_or(options.repoName); + + auto existingRepo = + std::find_if(newCfg.repos.begin(), newCfg.repos.end(), [&alias](const auto &r) { + return r.alias.value_or(r.name) == alias; + }); + + if (existingRepo == newCfg.repos.cend()) { + std::cerr << "the operated repo " + alias + " doesn't exist." << std::endl; + return -1; + } + + existingRepo->mirrorEnabled = false; + auto ret = repo.setConfig(newCfg); + if (!ret) { + std::cerr << ret.error().message() << std::endl; + return -1; + } + std::cerr << "Repository " << alias << " mirror disabled successfully."; + return 0; +} + int handleRepo(linglong::repo::OSTreeRepo &repo, const RepoSubcommandOptions &options, CLI::App *buildRepoShow, CLI::App *buildRepoAdd, CLI::App *buildRepoRemove, CLI::App *buildRepoUpdate, - CLI::App *buildRepoSetDefault) + CLI::App *buildRepoSetDefault, + CLI::App *buildRepoEnableMirror, + CLI::App *buildRepoDisableMirror) { if (buildRepoShow->parsed()) { return handleRepoShow(repo); @@ -586,6 +665,14 @@ int handleRepo(linglong::repo::OSTreeRepo &repo, return handleRepoSetDefault(repo, repoOptions); } + if (buildRepoEnableMirror->parsed()) { + return handleRepoEnableMirror(repo, repoOptions); + } + + if (buildRepoDisableMirror->parsed()) { + return handleRepoDisableMirror(repo, repoOptions); + } + std::cerr << "unknown repo operation, please see help information." << std::endl; return EINVAL; } @@ -607,22 +694,6 @@ std::vector getProjectModule(const linglong::api::types::v1::Builde return { modules.begin(), modules.end() }; } -std::optional getProjectDir(std::filesystem::path &yamlPath) -{ - std::error_code ec; - std::filesystem::path path = std::filesystem::canonical(yamlPath, ec); - if (ec) { - qCritical() << "invalid project file path: " << QString::fromStdString(yamlPath.string()) - << " error: " << ec.message().c_str(); - return std::nullopt; - } - - QDir projectDir(QString::fromStdString(path.parent_path().string())); - // put canonical path back - yamlPath = path; - return std::make_optional(projectDir); -} - std::optional backupFailedMigrationRepo(const std::filesystem::path &repoPath) { @@ -668,6 +739,7 @@ int main(int argc, char **argv) Q_INIT_RESOURCE(builder_releases); // 初始化应用,builder在非tty环境也输出日志 linglong::utils::global::applicationInitialize(true); + linglong::utils::global::initLinyapsLogSystem(linglong::utils::log::LogBackend::Console); CLI::App commandParser{ _("linyaps builder CLI \n" "A CLI program to build linyaps application\n") }; @@ -707,14 +779,13 @@ You can report bugs to the linyaps team under this project: https://github.com/O ->check(validatorString); // add builder build - std::string filePath{ "./linglong.yaml" }; + std::string filePath; // group empty will hide command std::string hiddenGroup = ""; auto buildBuilder = commandParser.add_subcommand("build", _("Build a linyaps project")); buildBuilder->usage(_("Usage: ll-builder build [OPTIONS] [COMMAND...]")); buildBuilder->add_option("-f, --file", filePath, _("File path of the linglong.yaml")) ->type_name("FILE") - ->capture_default_str() ->check(CLI::ExistingFile); buildBuilder->add_option( "COMMAND", @@ -756,13 +827,13 @@ You can report bugs to the linyaps team under this project: https://github.com/O buildRun->usage(_("Usage: ll-builder run [OPTIONS] [COMMAND...]")); buildRun->add_option("-f, --file", filePath, _("File path of the linglong.yaml")) ->type_name("FILE") - ->capture_default_str() ->check(CLI::ExistingFile); buildRun ->add_option("--modules", runOpts.execModules, _("Run specified module. eg: --modules binary,develop")) ->delimiter(',') + ->allow_extra_args(false) ->type_name("modules"); buildRun->add_option( "COMMAND", @@ -771,11 +842,22 @@ You can report bugs to the linyaps team under this project: https://github.com/O buildRun->add_flag("--debug", runOpts.debugMode, _("Run in debug mode (enable develop module)")); + buildRun + ->add_option("--extensions", + runOpts.extensions, + _("Specify extension(s) used by the app to run")) + ->type_name("REF") + ->delimiter(',') + ->allow_extra_args(false) + ->check(validatorString); auto buildList = commandParser.add_subcommand("list", _("List built linyaps app")); buildList->usage(_("Usage: ll-builder list [OPTIONS]")); auto buildRemove = commandParser.add_subcommand("remove", _("Remove built linyaps app")); buildRemove->usage(_("Usage: ll-builder remove [OPTIONS] [APP...]")); + buildRemove->add_flag("--no-clean-objects", + removeOpts.noCleanObjects, + _("Do not clean objects files before remove apps")); buildRemove->add_option("APP", removeOpts.removeList); // build export @@ -784,30 +866,26 @@ You can report bugs to the linyaps team under this project: https://github.com/O buildExport->add_option("-f, --file", filePath, _("File path of the linglong.yaml")) ->type_name("FILE") - ->capture_default_str() ->check(CLI::ExistingFile); buildExport ->add_option("-z, --compressor", exportOpts.exportSpecificOptions.compressor, - "supported compressors are: lz4(uab default), lzam(layer default), zstd") + "supported compressors are: lz4(default), lzma, zstd") ->type_name("X"); auto *iconOpt = buildExport ->add_option("--icon", exportOpts.exportSpecificOptions.iconPath, _("Uab icon (optional)")) ->type_name("FILE") ->check(CLI::ExistingFile); - auto *fullOpt = - buildExport->add_flag("--full", exportOpts.exportSpecificOptions.full, _("Export uab fully")) - ->group(hiddenGroup); auto *layerFlag = buildExport ->add_flag("--layer", exportOpts.layerMode, _("Export to linyaps layer file (deprecated)")) - ->excludes(iconOpt, fullOpt); + ->excludes(iconOpt); buildExport ->add_option("--loader", exportOpts.exportSpecificOptions.loader, _("Use custom loader")) ->type_name("FILE") ->check(CLI::ExistingFile) - ->excludes(layerFlag, fullOpt); + ->excludes(layerFlag); buildExport ->add_flag("--no-develop", exportOpts.exportSpecificOptions.noExportDevelop, @@ -816,6 +894,17 @@ You can report bugs to the linyaps team under this project: https://github.com/O buildExport->add_option("-o, --output", exportOpts.outputFile, _("Output file")) ->type_name("FILE") ->excludes(layerFlag); + buildExport + ->add_option("--ref", exportOpts.exportSpecificOptions.ref, _("Reference of the package")) + ->type_name("REF") + ->check(validatorString) + ->excludes(layerFlag); + buildExport + ->add_option("--modules", exportOpts.exportSpecificOptions.modules, _("Modules to export")) + ->type_name("MODULES") + ->delimiter(',') + ->check(validatorString) + ->excludes(layerFlag); // build push std::string pushModule; @@ -823,7 +912,6 @@ You can report bugs to the linyaps team under this project: https://github.com/O buildPush->usage(_("Usage: ll-builder push [OPTIONS]")); buildPush->add_option("-f, --file", filePath, _("File path of the linglong.yaml")) ->type_name("FILE") - ->capture_default_str() ->check(CLI::ExistingFile); buildPush->add_option("--repo-url", pushOpts.repoOptions.repoUrl, _("Remote repo url")) ->type_name("URL") @@ -908,6 +996,24 @@ You can report bugs to the linyaps team under this project: https://github.com/O ->required() ->check(validatorString); + // add repo sub command enable mirror + auto buildRepoEnableMirror = + buildRepo->add_subcommand("enable-mirror", _("Enable mirror for the repo")); + buildRepoEnableMirror->usage(_("Usage: ll-builder repo enable-mirror [OPTIONS] ALIAS")); + buildRepoEnableMirror + ->add_option("ALIAS", repoCmdOpts.repoOptions.repoAlias, _("Alias of the repo name")) + ->required() + ->check(validatorString); + + // add repo sub command disable mirror + auto buildRepoDisableMirror = + buildRepo->add_subcommand("disable-mirror", _("Disable mirror for the repo")); + buildRepoDisableMirror->usage(_("Usage: ll-builder repo disable-mirror [OPTIONS] ALIAS")); + buildRepoDisableMirror + ->add_option("ALIAS", repoCmdOpts.repoOptions.repoAlias, _("Alias of the repo name")) + ->required() + ->check(validatorString); + // add repo sub command show auto buildRepoShow = buildRepo->add_subcommand("show", _("Show repository information")); buildRepoShow->usage(_("Usage: ll-builder repo show [OPTIONS]")); @@ -919,6 +1025,28 @@ You can report bugs to the linyaps team under this project: https://github.com/O return 0; } + // build command need run in namespace because: + // 1. fuse-overlayfs should run in new user_namespaces and + // run with CAP_DAC_OVERRIDE capbilities. + // 2. mount needs CAP_SYS_ADMIN capbilities in the + // user_namespaces associated with current mount_namespaces, + if (buildBuilder->parsed()) { + auto res = linglong::utils::needRunInNamespace(); + if (!res) { + LogE("failed to check need run in namespace {}", res.error()); + return -1; + } + + if (*res) { + auto res = linglong::utils::runInNamespace(argc, argv); + if (!res) { + LogE("failed to run in namespace {}", res.error()); + return -1; + } + return *res; + } + } + if (buildCreate->parsed()) { return handleCreate(createOpts); } @@ -948,14 +1076,6 @@ You can report bugs to the linyaps team under this project: https://github.com/O return -1; } - // To avoid glib start thread - // set GIO_USE_VFS to local and GVFS_REMOTE_VOLUME_MONITOR_IGNORE to 1 - auto gioGuard = - std::make_unique("GIO_USE_VFS", "local"); - auto gvfsGuard = std::make_unique( - "GVFS_REMOTE_VOLUME_MONITOR_IGNORE", - "1"); - auto result = linglong::repo::tryMigrate(builderCfg->repo, *repoCfg); if (result == linglong::repo::MigrateResult::Failed) { if (!backupFailedMigrationRepo(builderCfg->repo)) { @@ -963,19 +1083,13 @@ You can report bugs to the linyaps team under this project: https://github.com/O } } - const auto defaultRepo = linglong::repo::getDefaultRepo(*repoCfg); - linglong::repo::ClientFactory clientFactory(defaultRepo.url); auto repoRoot = QDir{ QString::fromStdString(builderCfg->repo) }; if (!repoRoot.exists() && !repoRoot.mkpath(".")) { qCritical() << "failed to create the repository of builder."; return -1; } - linglong::repo::OSTreeRepo repo(repoRoot, *repoCfg, clientFactory); - - // restore to original value - gioGuard.reset(); - gvfsGuard.reset(); + linglong::repo::OSTreeRepo repo(repoRoot, *repoCfg); if (buildRepo->parsed()) { return handleRepo(repo, @@ -984,7 +1098,9 @@ You can report bugs to the linyaps team under this project: https://github.com/O buildRepoAdd, buildRepoRemove, buildRepoUpdate, - buildRepoSetDefault); + buildRepoSetDefault, + buildRepoEnableMirror, + buildRepoDisableMirror); } if (buildImport->parsed()) { @@ -1023,29 +1139,38 @@ You can report bugs to the linyaps team under this project: https://github.com/O auto *containerBuilder = new linglong::runtime::ContainerBuilder(**ociRuntime); containerBuilder->setParent(QCoreApplication::instance()); - std::filesystem::path canonicalYamlPath{ filePath }; - auto optProjectDir = getProjectDir(canonicalYamlPath); - if (!optProjectDir) { + // use the current directory as the project(working) directory + std::error_code ec; + auto cwd = std::filesystem::current_path(ec); + if (ec) { + LogE("invalid current directory: {}", ec.message()); return -1; } - const auto &projectDir = *optProjectDir; - auto project = parseProjectConfig(QString::fromStdString(canonicalYamlPath.string())); - if (!project) { - qCritical() << project.error(); + auto canonicalYamlPath = getProjectYAMLPath(cwd, filePath); + if (canonicalYamlPath && canonicalYamlPath->string().rfind(cwd.string(), 0) != 0) { + LogE("the project file {} is not under the current working directory {}", + canonicalYamlPath->string(), + cwd.string()); return -1; } - linglong::builder::Builder builder(*project, projectDir, repo, *containerBuilder, *builderCfg); - builder.projectYamlFile = canonicalYamlPath; + std::optional project; + if (canonicalYamlPath && std::filesystem::exists(*canonicalYamlPath, ec)) { + auto projectRet = parseProjectConfig(*canonicalYamlPath); + if (!projectRet) { + LogE("{}", projectRet.error()); + return -1; + } - if (buildBuilder->parsed()) { - return handleBuild(builder, buildOpts); + project = std::move(projectRet).value(); } - if (buildRun->parsed()) { - return handleRun(builder, runOpts); - } + linglong::builder::Builder builder(std::move(project), + cwd, + repo, + *containerBuilder, + *builderCfg); if (buildExport->parsed()) { return handleExport(builder, exportOpts); @@ -1060,6 +1185,20 @@ You can report bugs to the linyaps team under this project: https://github.com/O return handlePush(builder, pushOpts); } + if (!canonicalYamlPath) { + LogE("the project file is not found"); + return -1; + } + + builder.projectYamlFile = std::move(canonicalYamlPath).value(); + if (buildBuilder->parsed()) { + return handleBuild(builder, buildOpts); + } + + if (buildRun->parsed()) { + return handleRun(builder, runOpts); + } + std::cout << commandParser.help("", CLI::AppFormatMode::All); return 0; diff --git a/apps/ll-cli/src/main.cpp b/apps/ll-cli/src/main.cpp index a49ab7a63..6a3579c51 100644 --- a/apps/ll-cli/src/main.cpp +++ b/apps/ll-cli/src/main.cpp @@ -3,6 +3,7 @@ * * SPDX-License-Identifier: LGPL-3.0-or-later */ +#include "configure.h" #include "linglong/api/dbus/v1/dbus_peer.h" #include "linglong/cli/cli.h" #include "linglong/cli/cli_printer.h" @@ -13,10 +14,10 @@ #include "linglong/repo/config.h" #include "linglong/repo/ostree_repo.h" #include "linglong/runtime/container_builder.h" -#include "linglong/utils/configure.h" #include "linglong/utils/finally/finally.h" #include "linglong/utils/gettext.h" #include "linglong/utils/global/initialize.h" +#include "linglong/utils/log/log.h" #include "ocppi/cli/crun/Crun.hpp" #include @@ -137,90 +138,26 @@ int lockCheck() noexcept return lock_info.l_pid; } -} // namespace - -using namespace linglong::utils::global; +// Validator for string inputs +CLI::Validator validatorString{ + [](const std::string ¶meter) { + if (parameter.empty()) { + return std::string{ _( + "Input parameter is empty, please input valid parameter instead") }; + } + return std::string(); + }, + "" +}; -int main(int argc, char **argv) +// Function to add the run subcommand +void addRunCommand(CLI::App &commandParser, RunOptions &runOptions, const std::string &group) { - bindtextdomain(PACKAGE_LOCALE_DOMAIN, PACKAGE_LOCALE_DIR); - textdomain(PACKAGE_LOCALE_DOMAIN); - CLI::App commandParser{ _( - "linyaps CLI\n" - "A CLI program to run application and manage application and runtime\n") }; - argv = commandParser.ensure_utf8(argv); - - QCoreApplication app(argc, argv); - applicationInitialize(); - - if (argc == 1) { - std::cout << commandParser.help() << std::endl; - return 0; - } - - commandParser.get_help_ptr()->description(_("Print this help message and exit")); - commandParser.set_help_all_flag("--help-all", _("Expand all help")); - commandParser.usage(_("Usage: ll-cli [OPTIONS] [SUBCOMMAND]")); - commandParser.footer(_(R"(If you found any problems during use, -You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues)")); - - // group empty will hide command - constexpr auto CliHiddenGroup = ""; - - // add flags - const auto &versionDescription = std::string{ _("Show version") }; - auto *versionFlag = commandParser.add_flag("--version", versionDescription); - - const auto &noDBusDescription = std::string{ _( - "Use peer to peer DBus, this is used only in case that DBus daemon is not available") }; - auto *noDBusFlag = - commandParser.add_flag("--no-dbus", noDBusDescription)->group(CliHiddenGroup); - - const auto &jsonDescription = std::string{ _("Use json format to output result") }; - auto *jsonFlag = commandParser.add_flag("--json", jsonDescription); - - CLI::Validator validatorString{ - [](const std::string ¶meter) { - if (parameter.empty()) { - return std::string{ _( - "Input parameter is empty, please input valid parameter instead") }; - } - return std::string(); - }, - "" - }; - - CliOptions options{ .filePaths = {}, - .fileUrls = {}, - .workDir = "", - .appid = "", - .instance = "", - .module = "", - .type = "all", - .repoOptions = {}, - .commands = {}, - .showDevel = false, - .showAllVersion = false, - .showUpgradeList = false, - .forceOpt = false, - .confirmOpt = false, - .verbose = false }; - - commandParser.add_flag("-v,--verbose", options.verbose, _("Show debug info (verbose logs)")); - - // groups - auto *CliBuildInGroup = _("Managing installed applications and runtimes"); - auto *CliAppManagingGroup = _("Managing running applications"); - auto *CliSearchGroup = _("Finding applications and runtimes"); - auto *CliRepoGroup = _("Managing remote repositories"); - - // add sub command run - auto *cliRun = commandParser.add_subcommand("run", _("Run an application")) - ->group(CliAppManagingGroup) - ->fallthrough(); + auto *cliRun = + commandParser.add_subcommand("run", _("Run an application"))->group(group)->fallthrough(); // add sub command run options - cliRun->add_option("APP", options.appid, _("Specify the application ID")) + cliRun->add_option("APP", runOptions.appid, _("Specify the application ID")) ->required() ->check(validatorString); cliRun->usage(_(R"(Usage: ll-cli run [OPTIONS] APP [COMMAND...] @@ -233,72 +170,111 @@ ll-cli run org.deepin.demo bash ll-cli run org.deepin.demo -- bash ll-cli run org.deepin.demo -- bash -x /path/to/bash/script)")); cliRun - ->add_option("--file", options.filePaths, _("Pass file to applications running in a sandbox")) + ->add_option("--file", + runOptions.filePaths, + _("Pass file to applications running in a sandbox")) ->type_name("FILE") ->expected(0, -1); cliRun - ->add_option("--url", options.fileUrls, _("Pass url to applications running in a sandbox")) + ->add_option("--url", runOptions.fileUrls, _("Pass url to applications running in a sandbox")) ->type_name("URL") ->expected(0, -1); - cliRun->add_option("COMMAND", options.commands, _("Run commands in a running sandbox")); + cliRun->add_option("--env", runOptions.envs, _("Set environment variables for the application")) + ->type_name("ENV") + // vector parameter allow extra args by default, but we don't want it + ->allow_extra_args(false) + ->check([](const std::string &env) -> std::string { + if (env.find('=') == std::string::npos) { + return std::string{ _( + "Input parameter is invalid, please input valid parameter instead") }; + } + + return {}; + }); + cliRun + ->add_option("--base", runOptions.base, _("Specify the base used by the application to run")) + ->type_name("REF") + ->check(validatorString); + cliRun + ->add_option("--runtime", + runOptions.runtime, + _("Specify the runtime used by the application to run")) + ->type_name("REF") + ->check(validatorString); + cliRun + ->add_option("--extensions", + runOptions.extensions, + _("Specify extension(s) used by the application to run")) + ->type_name("REF") + ->delimiter(',') // 支持以逗号分隔 + ->allow_extra_args(false) // 避免吞掉后面的参数 + ->check(validatorString); + cliRun + ->add_flag("--privileged", runOptions.privileged, _("Run the application in privileged mode")) + ->group(""); + cliRun->add_option("--caps-add", runOptions.capsAdd, _("Add capabilities to the application")) + ->delimiter(',') + ->allow_extra_args(false) + ->group(""); + cliRun->add_option("COMMAND", runOptions.commands, _("Run commands in a running sandbox")); +} - // add sub command ps +// Function to add the ps subcommand +void addPsCommand(CLI::App &commandParser, const std::string &group) +{ commandParser.add_subcommand("ps", _("List running applications")) ->fallthrough() - ->group(CliAppManagingGroup) + ->group(group) ->usage(_("Usage: ll-cli ps [OPTIONS]")); +} - // add sub command exec - auto *cliExec = - commandParser.add_subcommand("exec", _("Execute commands in the currently running sandbox")) - ->fallthrough() - ->group(CliHiddenGroup); - cliExec - ->add_option("INSTANCE", - options.instance, - _("Specify the application running instance(you can get it by ps command)")) - ->required() - ->check(validatorString); - cliExec->add_option("--working-directory", options.workDir, _("Specify working directory")) - ->type_name("PATH") - ->check(CLI::ExistingDirectory); - cliExec->add_option("COMMAND", options.commands, _("Run commands in a running sandbox")); +// Function to add the exec subcommand +void addEnterCommand(CLI::App &commandParser, EnterOptions &enterOptions, const std::string &group) +{ - // add sub command enter auto *cliEnter = commandParser .add_subcommand("enter", _("Enter the namespace where the application is running")) - ->group(CliAppManagingGroup) - ->fallthrough(); - cliEnter->usage(_("Usage: ll-cli enter [OPTIONS] INSTANCE [COMMAND...]")); + ->fallthrough() + ->group(group); cliEnter ->add_option("INSTANCE", - options.instance, + enterOptions.instance, _("Specify the application running instance(you can get it by ps command)")) - ->required(); - cliEnter->add_option("--working-directory", options.workDir, _("Specify working directory")) + ->required() + ->check(validatorString); + cliEnter + ->add_option("--working-directory", enterOptions.workDir, _("Specify working directory")) ->type_name("PATH") ->check(CLI::ExistingDirectory); - cliEnter->add_option("COMMAND", options.commands, _("Run commands in a running sandbox")); + cliEnter->add_option("COMMAND", enterOptions.commands, _("Run commands in a running sandbox")); +} - // add sub command kill +// Function to add the kill subcommand +void addKillCommand(CLI::App &commandParser, KillOptions &killOptions, const std::string &group) +{ auto *cliKill = commandParser.add_subcommand("kill", _("Stop running applications")) - ->group(CliAppManagingGroup) + ->group(group) ->fallthrough(); cliKill->usage(_("Usage: ll-cli kill [OPTIONS] APP")); cliKill ->add_option("-s,--signal", - options.signal, + killOptions.signal, _("Specify the signal to send to the application")) ->default_val("SIGTERM"); - cliKill->add_option("APP", options.appid, _("Specify the running application")) + cliKill->add_option("APP", killOptions.appid, _("Specify the running application")) ->required() ->check(validatorString); +} - // add sub command install +// Function to add the install subcommand +void addInstallCommand(CLI::App &commandParser, + InstallOptions &installOptions, + const std::string &group) +{ auto *cliInstall = commandParser.add_subcommand("install", _("Installing an application or runtime")) - ->group(CliBuildInGroup) + ->group(group) ->fallthrough(); cliInstall->usage(_(R"(Usage: ll-cli install [OPTIONS] APP @@ -318,63 +294,83 @@ ll-cli install stable:org.deepin.demo/0.0.0.1/x86_64 )")); cliInstall ->add_option("APP", - options.appid, + installOptions.appid, _("Specify the application ID, and it can also be a .uab or .layer file")) ->required() ->check(validatorString); - cliInstall->add_option("--module", options.module, _("Install a specify module")) + cliInstall->add_option("--module", installOptions.module, _("Install a specify module")) ->type_name("MODULE") ->check(validatorString); - cliInstall->add_option("--repo", options.repo, _("Install from a specific repo")) + cliInstall->add_option("--repo", installOptions.repo, _("Install from a specific repo")) ->type_name("REPO") ->check(validatorString); - cliInstall->add_flag("--force", options.forceOpt, _("Force install the application")); - cliInstall->add_flag("-y", options.confirmOpt, _("Automatically answer yes to all questions")); + cliInstall->add_flag("--force", installOptions.forceOpt, _("Force install the application")); + cliInstall->add_flag("-y", + installOptions.confirmOpt, + _("Automatically answer yes to all questions")); +} - // add sub command uninstall - // These two options are used when uninstalling apps in the app Store and need to be - // retained but hidden. +// Function to add the uninstall subcommand +void addUninstallCommand(CLI::App &commandParser, + UninstallOptions &uninstallOptions, + const std::string &group) +{ auto *cliUninstall = commandParser.add_subcommand("uninstall", _("Uninstall the application or runtimes")) - ->group(CliBuildInGroup) + ->group(group) ->fallthrough(); cliUninstall->usage(_("Usage: ll-cli uninstall [OPTIONS] APP")); - cliUninstall->add_option("APP", options.appid, _("Specify the applications ID")) + cliUninstall->add_option("APP", uninstallOptions.appid, _("Specify the applications ID")) ->required() ->check(validatorString); - cliUninstall->add_option("--module", options.module, _("Uninstall a specify module")) + cliUninstall->add_option("--module", uninstallOptions.module, _("Uninstall a specify module")) ->type_name("MODULE") ->check(validatorString); + cliUninstall->add_flag("--force", + uninstallOptions.forceOpt, + _("Force uninstall base or runtime")); // below options are used for compatibility with old ll-cli const auto &pruneDescription = std::string{ _("Remove all unused modules") }; [[maybe_unused]] auto *pruneFlag = - cliUninstall->add_flag("--prune", pruneDescription)->group(CliHiddenGroup); + cliUninstall->add_flag("--prune", pruneDescription)->group(""); const auto &allDescription = std::string{ _("Uninstall all modules") }; - [[maybe_unused]] auto *allFlag = - cliUninstall->add_flag("--all", allDescription)->group(CliHiddenGroup); + [[maybe_unused]] auto *allFlag = cliUninstall->add_flag("--all", allDescription)->group(""); +} - // add sub command upgrade +// Function to add the upgrade subcommand +void addUpgradeCommand(CLI::App &commandParser, + UpgradeOptions &upgradeOptions, + const std::string &group) +{ auto *cliUpgrade = commandParser.add_subcommand("upgrade", _("Upgrade the application or runtimes")) - ->group(CliBuildInGroup) + ->group(group) ->fallthrough(); cliUpgrade->usage(_("Usage: ll-cli upgrade [OPTIONS] [APP]")); cliUpgrade ->add_option("APP", - options.appid, + upgradeOptions.appid, _("Specify the application ID. If it not be specified, all " "applications will be upgraded")) ->check(validatorString); + cliUpgrade->add_flag("--deps-only", + upgradeOptions.depsOnly, + _("Only upgrade dependencies of application")); +} - // add sub command search +// Function to add the search subcommand +void addSearchCommand(CLI::App &commandParser, + SearchOptions &searchOptions, + const std::string &group) +{ auto *cliSearch = commandParser .add_subcommand("search", _("Search the applications/runtimes containing the " "specified text from the remote repository")) ->fallthrough() - ->group(CliSearchGroup); + ->group(group); cliSearch->usage(_(R"(Usage: ll-cli search [OPTIONS] KEYWORDS Example: @@ -386,31 +382,36 @@ ll-cli search . ll-cli search . --type=base # find all of runtime(s) of remote ll-cli search . --type=runtime)")); - cliSearch->add_option("KEYWORDS", options.appid, _("Specify the Keywords")) + cliSearch->add_option("KEYWORDS", searchOptions.appid, _("Specify the Keywords")) ->required() ->check(validatorString); cliSearch ->add_option( "--type", - options.type, + searchOptions.type, _(R"(Filter result with specify type. One of "runtime", "base", "app" or "all")")) ->type_name("TYPE") ->capture_default_str() ->check(validatorString); - cliSearch->add_option("--repo", options.repo, _("Specify the repo")) + cliSearch->add_option("--repo", searchOptions.repo, _("Specify the repo")) ->type_name("REPO") ->check(validatorString); - cliSearch->add_flag("--dev", options.showDevel, _("Include develop application in result")); + cliSearch->add_flag("--dev", + searchOptions.showDevel, + _("Include develop application in result")); cliSearch->add_flag("--show-all-version", - options.showAllVersion, + searchOptions.showAllVersion, _("Show all versions of an application(s), base(s) or runtime(s)")); +} - // add sub command list +// Function to add the list subcommand +void addListCommand(CLI::App &commandParser, ListOptions &listOptions, const std::string &group) +{ auto *cliList = commandParser .add_subcommand("list", _("List installed application(s), base(s) or runtime(s)")) ->fallthrough() - ->group(CliBuildInGroup); + ->group(group); cliList->usage(_(R"(Usage: ll-cli list [OPTIONS] Example: @@ -426,52 +427,54 @@ ll-cli list --upgradable cliList ->add_option( "--type", - options.type, + listOptions.type, _(R"(Filter result with specify type. One of "runtime", "base", "app" or "all")")) ->type_name("TYPE") ->capture_default_str() ->check(validatorString); cliList->add_flag("--upgradable", - options.showUpgradeList, + listOptions.showUpgradeList, _("Show the list of latest version of the currently installed " "application(s), base(s) or runtime(s)")); +} - // add sub command repo +// Function to add the repo subcommand +void addRepoCommand(CLI::App &commandParser, RepoOptions &repoOptions, const std::string &group) +{ auto *cliRepo = commandParser .add_subcommand("repo", _("Display or modify information of the repository currently using")) - ->group(CliRepoGroup); + ->group(group); cliRepo->usage(_("Usage: ll-cli repo SUBCOMMAND [OPTIONS]")); cliRepo->require_subcommand(1); // add repo sub command add auto *repoAdd = cliRepo->add_subcommand("add", _("Add a new repository")); repoAdd->usage(_("Usage: ll-cli repo add [OPTIONS] NAME URL")); - repoAdd->add_option("NAME", options.repoOptions.repoName, _("Specify the repo name")) + repoAdd->add_option("NAME", repoOptions.repoName, _("Specify the repo name")) ->required() ->check(validatorString); - repoAdd->add_option("URL", options.repoOptions.repoUrl, _("Url of the repository")) + repoAdd->add_option("URL", repoOptions.repoUrl, _("Url of the repository")) ->required() ->check(validatorString); - repoAdd->add_option("--alias", options.repoOptions.repoAlias, _("Alias of the repo name")) + repoAdd->add_option("--alias", repoOptions.repoAlias, _("Alias of the repo name")) ->type_name("ALIAS") ->check(validatorString); // add repo sub command modify - auto *repoModify = - cliRepo->add_subcommand("modify", _("Modify repository URL"))->group(CliHiddenGroup); - repoModify->add_option("--name", options.repoOptions.repoName, _("Specify the repo name")) + auto *repoModify = cliRepo->add_subcommand("modify", _("Modify repository URL"))->group(""); + repoModify->add_option("--name", repoOptions.repoName, _("Specify the repo name")) ->type_name("REPO") ->check(validatorString); - repoModify->add_option("URL", options.repoOptions.repoUrl, _("Url of the repository")) + repoModify->add_option("URL", repoOptions.repoUrl, _("Url of the repository")) ->required() ->check(validatorString); // add repo sub command remove auto *repoRemove = cliRepo->add_subcommand("remove", _("Remove a repository")); repoRemove->usage(_("Usage: ll-cli repo remove [OPTIONS] NAME")); - repoRemove->add_option("ALIAS", options.repoOptions.repoAlias, _("Alias of the repo name")) + repoRemove->add_option("ALIAS", repoOptions.repoAlias, _("Alias of the repo name")) ->required() ->check(validatorString); @@ -479,10 +482,10 @@ ll-cli list --upgradable // TODO: add --repo and --url options auto *repoUpdate = cliRepo->add_subcommand("update", _("Update the repository URL")); repoUpdate->usage(_("Usage: ll-cli repo update [OPTIONS] NAME URL")); - repoUpdate->add_option("ALIAS", options.repoOptions.repoAlias, _("Alias of the repo name")) + repoUpdate->add_option("ALIAS", repoOptions.repoAlias, _("Alias of the repo name")) ->required() ->check(validatorString); - repoUpdate->add_option("URL", options.repoOptions.repoUrl, _("Url of the repository")) + repoUpdate->add_option("URL", repoOptions.repoUrl, _("Url of the repository")) ->required() ->check(validatorString); @@ -490,7 +493,7 @@ ll-cli list --upgradable auto *repoSetDefault = cliRepo->add_subcommand("set-default", _("Set a default repository name")); repoSetDefault->usage(_("Usage: ll-cli repo set-default [OPTIONS] NAME")); - repoSetDefault->add_option("Alias", options.repoOptions.repoAlias, _("Alias of the repo name")) + repoSetDefault->add_option("Alias", repoOptions.repoAlias, _("Alias of the repo name")) ->required() ->check(validatorString); @@ -502,297 +505,452 @@ ll-cli list --upgradable auto *repoSetPriority = cliRepo->add_subcommand("set-priority", _("Set the priority of the repo")); repoSetPriority->usage(_("Usage: ll-cli repo set-priority ALIAS PRIORITY")); - repoSetPriority->add_option("ALIAS", options.repoOptions.repoAlias, _("Alias of the repo name")) + repoSetPriority->add_option("ALIAS", repoOptions.repoAlias, _("Alias of the repo name")) ->required() ->check(validatorString); - repoSetPriority - ->add_option("PRIORITY", options.repoOptions.repoPriority, _("Priority of the repo")) + repoSetPriority->add_option("PRIORITY", repoOptions.repoPriority, _("Priority of the repo")) ->required() ->check(validatorString); + // add repo sub command enable mirror + auto *repoEnableMirror = + cliRepo->add_subcommand("enable-mirror", _("Enable mirror for the repo")); + repoEnableMirror->usage(_("Usage: ll-cli repo enable-mirror [OPTIONS] ALIAS")); + repoEnableMirror->add_option("ALIAS", repoOptions.repoAlias, _("Alias of the repo name")) + ->required() + ->check(validatorString); + // add repo sub command disable mirror + auto *repoDisableMirror = + cliRepo->add_subcommand("disable-mirror", _("Disable mirror for the repo")); + repoDisableMirror->usage(_("Usage: ll-cli repo disable-mirror [OPTIONS] ALIAS")); + repoDisableMirror->add_option("ALIAS", repoOptions.repoAlias, _("Alias of the repo name")) + ->required() + ->check(validatorString); +} - // add sub command info +// Function to add the info subcommand +void addInfoCommand(CLI::App &commandParser, InfoOptions &infoOptions, const std::string &group) +{ auto *cliInfo = commandParser .add_subcommand("info", _("Display information about installed apps or runtimes")) ->fallthrough() - ->group(CliBuildInGroup); + ->group(group); cliInfo->usage(_("Usage: ll-cli info [OPTIONS] APP")); cliInfo ->add_option("APP", - options.appid, + infoOptions.appid, _("Specify the application ID, and it can also be a .layer file")) ->required() ->check(validatorString); +} - // add sub command content +// Function to add the content subcommand +void addContentCommand(CLI::App &commandParser, + ContentOptions &contentOptions, + const std::string &group) +{ auto *cliContent = commandParser .add_subcommand("content", _("Display the exported files of installed application")) ->fallthrough() - ->group(CliBuildInGroup); + ->group(group); cliContent->usage(_("Usage: ll-cli content [OPTIONS] APP")); - cliContent->add_option("APP", options.appid, _("Specify the installed application ID")) + cliContent->add_option("APP", contentOptions.appid, _("Specify the installed application ID")) ->required() ->check(validatorString); +} - // add sub command prune +// Function to add the prune subcommand +void addPruneCommand(CLI::App &commandParser, const std::string &group) +{ commandParser.add_subcommand("prune", _("Remove the unused base or runtime")) - ->group(CliAppManagingGroup) + ->group(group) ->usage(_("Usage: ll-cli prune [OPTIONS]")); +} - // add sub command inspect +// Function to add the inspect subcommand +void addInspectCommand(CLI::App &commandParser, + InspectOptions &inspectOptions, + const std::string &group) +{ auto *cliInspect = commandParser - .add_subcommand("inspect", _("Display the information of installed application")) - ->group(CliHiddenGroup) - ->usage(_("Usage: ll-cli inspect [OPTIONS]")); - cliInspect->footer("This subcommand is for internal use only currently"); - cliInspect->add_option("-p,--pid", options.pid, _("Specify the process id")) - ->check([](const std::string &input) -> std::string { - if (input.empty()) { - return _("Input parameter is empty, please input valid parameter instead"); - } + .add_subcommand("inspect", + _("Display the inspect information of the installed application")) + ->group(group) + ->usage(_("Usage: ll-cli inspect SUBCOMMAND [OPTIONS]")); + + cliInspect->require_subcommand(1); + + // 创建 inspect dir 子命令 + auto *cliInspectDir = cliInspect->add_subcommand( + "dir", + _("Display the data(bundle) directory of the installed(running) application")); + cliInspectDir->usage(_("Usage: ll-cli inspect dir [OPTIONS] APP")); + cliInspectDir + ->add_option("APP", + inspectOptions.appid, + _("Specify the application ID, and it can also be reference")) + ->required() + ->check(validatorString); + cliInspectDir + ->add_option("-t, --type", + inspectOptions.dirType, + _("Specify the directory type (layer or bundle),the default is layer")) + ->type_name("TYPE") + ->capture_default_str() + ->check(validatorString); + cliInspectDir + ->add_option("-m, --module", + inspectOptions.module, + _("Specify the module type (binary or develop). Only works when type is layer")) + ->check(validatorString); +} - try { - auto pid = std::stoull(input); - if (pid <= 0) { - return _("Invalid process id"); - } - } catch (std::exception &e) { - return _("Invalid pid format"); - } +} // namespace - return {}; - }); +using namespace linglong::utils::global; - // add sub command dir - auto cliLayerDir = - commandParser.add_subcommand("dir", "Get the layer directory of app(base or runtime)") - ->group(CliHiddenGroup); - cliLayerDir->add_option("APP", options.appid, _("Specify the installed app(base or runtime)")) - ->required() - ->check(validatorString); +// 初始化仓库 +linglong::utils::error::Result initOSTreeRepo() +{ + LINGLONG_TRACE("initOSTreeRepo"); + // load repo config + auto repoConfig = linglong::repo::loadConfig( + { LINGLONG_ROOT "/config.yaml", LINGLONG_DATA_DIR "/config.yaml" }); + if (!repoConfig) { + return LINGLONG_ERR("load repo config failed", repoConfig); + } + + // check repo root + auto repoRoot = QDir(LINGLONG_ROOT); + if (!repoRoot.exists()) { + return LINGLONG_ERR("repo root doesn't exist" + repoRoot.absolutePath()); + } + + // create repo + auto repo = new linglong::repo::OSTreeRepo(repoRoot, std::move(*repoConfig)); + repo->setParent(QCoreApplication::instance()); + return repo; +} + +int runCliApplication(int argc, char **mainArgv) +{ + CLI::App commandParser{ _( + "linyaps CLI\n" + "A CLI program to run application and manage application and runtime\n") }; + auto argv = commandParser.ensure_utf8(mainArgv); + if (argc == 1) { + std::cout << commandParser.help() << std::endl; + return 0; + } + + commandParser.get_help_ptr()->description(_("Print this help message and exit")); + commandParser.set_help_all_flag("--help-all", _("Expand all help")); + commandParser.usage(_("Usage: ll-cli [OPTIONS] [SUBCOMMAND]")); + commandParser.footer(_(R"(If you found any problems during use, +You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues)")); + + // group empty will hide command + constexpr auto CliHiddenGroup = ""; + + // version flag + const auto &versionDescription = std::string{ _("Show version") }; + auto *versionFlag = commandParser.add_flag("--version", versionDescription); + + // no-dbus flag + const auto &noDBusDescription = std::string{ _( + "Use peer to peer DBus, this is used only in case that DBus daemon is not available") }; + auto *noDBusFlag = + commandParser.add_flag("--no-dbus", noDBusDescription)->group(CliHiddenGroup); + + // json flag + const auto &jsonDescription = std::string{ _("Use json format to output result") }; + auto *jsonFlag = commandParser.add_flag("--json", jsonDescription); + + // verbose flag + GlobalOptions globalOptions{ .verbose = false, .noProgress = false }; + commandParser.add_flag("-v,--verbose", + globalOptions.verbose, + _("Show debug info (verbose logs)")); + commandParser.add_flag("--no-progress", + globalOptions.noProgress, + _("Don't output progress information")); + + // subcommand options + RunOptions runOptions{}; + EnterOptions enterOptions{}; + KillOptions killOptions{}; + InstallOptions installOptions{}; + UpgradeOptions upgradeOptions{}; + SearchOptions searchOptions{}; + UninstallOptions uninstallOptions{}; + ListOptions listOptions{}; + InfoOptions infoOptions{}; + ContentOptions contentOptions{}; + RepoOptions repoOptions{}; + InspectOptions inspectOptions{}; + + // groups for subcommands + auto *CliBuildInGroup = _("Managing installed applications and runtimes"); + auto *CliAppManagingGroup = _("Managing running applications"); + auto *CliSearchGroup = _("Finding applications and runtimes"); + auto *CliRepoGroup = _("Managing remote repositories"); + + // add all subcommands using the new functions + addRunCommand(commandParser, runOptions, CliAppManagingGroup); + addPsCommand(commandParser, CliAppManagingGroup); + addEnterCommand(commandParser, enterOptions, CliAppManagingGroup); + addKillCommand(commandParser, killOptions, CliAppManagingGroup); + addInstallCommand(commandParser, installOptions, CliBuildInGroup); + addUninstallCommand(commandParser, uninstallOptions, CliBuildInGroup); + addUpgradeCommand(commandParser, upgradeOptions, CliBuildInGroup); + addSearchCommand(commandParser, searchOptions, CliSearchGroup); + addListCommand(commandParser, listOptions, CliBuildInGroup); + addRepoCommand(commandParser, repoOptions, CliRepoGroup); + addInfoCommand(commandParser, infoOptions, CliBuildInGroup); + addContentCommand(commandParser, contentOptions, CliBuildInGroup); + addPruneCommand(commandParser, CliAppManagingGroup); + addInspectCommand(commandParser, inspectOptions, CliHiddenGroup); auto res = transformOldExec(argc, argv); CLI11_PARSE(commandParser, std::move(res)); + // print version if --version flag is set if (*versionFlag) { if (*jsonFlag) { std::cout << nlohmann::json{ { "version", LINGLONG_VERSION } } << std::endl; } else { std::cout << _("linyaps CLI version ") << LINGLONG_VERSION << std::endl; } - return 0; } + // set log level if --verbose flag is set + if (globalOptions.verbose) { + linglong::utils::log::setLogLevel(linglong::utils::log::LogLevel::Debug); + } - auto config = linglong::repo::loadConfig( - { LINGLONG_ROOT "/config.yaml", LINGLONG_DATA_DIR "/config.yaml" }); - if (!config) { - qCritical() << config.error(); - return -1; + // check lock + while (true) { + auto lockOwner = lockCheck(); + if (lockOwner == -1) { + qCritical() << "lock check failed"; + return -1; + } + + if (lockOwner > 0) { + qInfo() << "\r\33[K" + << "\033[?25l" + << "repository is being operated by another process, waiting for" << lockOwner + << "\033[?25h"; + using namespace std::chrono_literals; + std::this_thread::sleep_for(1s); + continue; + } + + break; } - auto defaultRepo = linglong::repo::getDefaultRepo(*config); - linglong::repo::ClientFactory clientFactory(std::move(defaultRepo.url)); + // connect to package manager + auto pkgManConn = QDBusConnection::systemBus(); + auto *pkgMan = + new linglong::api::dbus::v1::PackageManager("org.deepin.linglong.PackageManager1", + "/org/deepin/linglong/PackageManager1", + pkgManConn, + QCoreApplication::instance()); + // if --no-dbus flag is set, start package manager in sudo mode + if (*noDBusFlag) { + if (getuid() != 0) { + qCritical() << "--no-dbus should only be used by root user."; + return -1; + } - auto ret = QMetaObject::invokeMethod( - QCoreApplication::instance(), - [&commandParser, - noDBus = !!*noDBusFlag, - json = !!*jsonFlag, - options = std::move(options), - repoConfig = std::move(config).value(), - &clientFactory]() mutable { - auto repoRoot = QDir(LINGLONG_ROOT); - if (!repoRoot.exists()) { - qCritical() << "underlying repository doesn't exist:" << repoRoot.absolutePath(); - QCoreApplication::exit(-1); - return; - } + qInfo() << "some subcommands will failed in --no-dbus mode."; + const auto pkgManAddress = QString("unix:path=/tmp/linglong-package-manager.socket"); + startProcess("sudo", + { "--user", + LINGLONG_USERNAME, + "--preserve-env=QT_FORCE_STDERR_LOGGING", + "--preserve-env=QDBUS_DEBUG", + LINGLONG_LIBEXEC_DIR "/ll-package-manager", + "--no-dbus" }); + QThread::sleep(1); + + pkgManConn = QDBusConnection::connectToPeer(pkgManAddress, "ll-package-manager"); + if (!pkgManConn.isConnected()) { + qCritical() << "Failed to connect to ll-package-manager:" << pkgManConn.lastError(); + return -1; + } - while (true) { - auto lockOwner = lockCheck(); - if (lockOwner == -1) { - qCritical() << "lock check failed"; - QCoreApplication::exit(-1); - return; - } - - if (lockOwner > 0) { - qInfo() << "\r\33[K" - << "\033[?25l" - << "repository is being operated by another process, waiting for" - << lockOwner << "\033[?25h"; - using namespace std::chrono_literals; - std::this_thread::sleep_for(1s); - continue; - } - - break; - } + pkgMan = new linglong::api::dbus::v1::PackageManager("", + "/org/deepin/linglong/PackageManager1", + pkgManConn, + QCoreApplication::instance()); + } else { + // ping package manager to make it initialize system linglong repository + auto peer = linglong::api::dbus::v1::DBusPeer("org.deepin.linglong.PackageManager1", + "/org/deepin/linglong/PackageManager1", + pkgManConn); + auto reply = peer.Ping(); + reply.waitForFinished(); + if (!reply.isValid()) { + qCritical() << "Failed to activate org.deepin.linglong.PackageManager1" + << reply.error(); + return -1; + } + } - auto pkgManConn = QDBusConnection::systemBus(); - auto *pkgMan = - new linglong::api::dbus::v1::PackageManager("org.deepin.linglong.PackageManager1", - "/org/deepin/linglong/PackageManager1", - pkgManConn, - QCoreApplication::instance()); - if (noDBus) { - if (getuid() != 0) { - qCritical() << "--no-dbus should only be used by root user."; - QCoreApplication::exit(-1); - return; - } - - qInfo() << "some subcommands will failed in --no-dbus mode."; - const auto pkgManAddress = QString("unix:path=/tmp/linglong-package-manager.socket"); - startProcess("sudo", - { "--user", - LINGLONG_USERNAME, - "--preserve-env=QT_FORCE_STDERR_LOGGING", - "--preserve-env=QDBUS_DEBUG", - LINGLONG_LIBEXEC_DIR "/ll-package-manager", - "--no-dbus" }); - QThread::sleep(1); - - pkgManConn = QDBusConnection::connectToPeer(pkgManAddress, "ll-package-manager"); - if (!pkgManConn.isConnected()) { - qCritical() << "Failed to connect to ll-package-manager:" - << pkgManConn.lastError(); - QCoreApplication::exit(-1); - return; - } - - pkgMan = - new linglong::api::dbus::v1::PackageManager("", - "/org/deepin/linglong/PackageManager1", - pkgManConn, - QCoreApplication::instance()); - } else { - // NOTE: We need to ping package manager to make it initialize system linglong - // repository. - auto peer = linglong::api::dbus::v1::DBusPeer("org.deepin.linglong.PackageManager1", - "/org/deepin/linglong/PackageManager1", - pkgManConn); - auto reply = peer.Ping(); - reply.waitForFinished(); - if (!reply.isValid()) { - qCritical() << "Failed to activate org.deepin.linglong.PackageManager1" - << reply.error(); - QCoreApplication::exit(-1); - return; - } - } + // create printer + std::unique_ptr printer; + if (*jsonFlag) { + printer = std::make_unique(); + } else { + printer = std::make_unique(); + } - std::unique_ptr printer; - if (json) { - printer = std::make_unique(); - } else { - printer = std::make_unique(); - } + // get oci runtime + auto ociRuntimeCLI = qgetenv("LINGLONG_OCI_RUNTIME"); + if (ociRuntimeCLI.isEmpty()) { + ociRuntimeCLI = LINGLONG_DEFAULT_OCI_RUNTIME; + } - auto *repo = - new linglong::repo::OSTreeRepo(repoRoot, std::move(repoConfig), clientFactory); - repo->setParent(QCoreApplication::instance()); + // check oci runtime + auto path = QStandardPaths::findExecutable(ociRuntimeCLI, { BINDIR }); + if (path.isEmpty()) { + qCritical() << ociRuntimeCLI << "not found"; + return -1; + } - auto ociRuntimeCLI = qgetenv("LINGLONG_OCI_RUNTIME"); - if (ociRuntimeCLI.isEmpty()) { - ociRuntimeCLI = LINGLONG_DEFAULT_OCI_RUNTIME; - } + // create oci runtime + auto ociRuntime = ocppi::cli::crun::Crun::New(path.toStdString()); + if (!ociRuntime) { + std::rethrow_exception(ociRuntime.error()); + } - auto path = QStandardPaths::findExecutable(ociRuntimeCLI); - if (path.isEmpty()) { - qCritical() << ociRuntimeCLI << "not found"; - QCoreApplication::exit(-1); - return; - } - auto ociRuntime = ocppi::cli::crun::Crun::New(path.toStdString()); - if (!ociRuntime) { - std::rethrow_exception(ociRuntime.error()); - } - auto *containerBuilder = new linglong::runtime::ContainerBuilder(**ociRuntime); - containerBuilder->setParent(QCoreApplication::instance()); - - std::unique_ptr notifier{ nullptr }; - - // if ll-cli is running in tty, should use terminalNotifier. - if (::isatty(STDIN_FILENO) != 0 && ::isatty(STDOUT_FILENO) != 0) { - notifier = std::make_unique(); - } else { - try { - notifier = std::make_unique(); - } catch (std::runtime_error &err) { - qInfo() << "initialize DBus notifier failed:" << err.what() - << "try to fallback to terminal notifier."; - } - } + // create container builder + auto *containerBuilder = new linglong::runtime::ContainerBuilder(**ociRuntime); + containerBuilder->setParent(QCoreApplication::instance()); + + // create notifier + std::unique_ptr notifier{ nullptr }; + + // if ll-cli is running in tty, should use terminalNotifier. + if (::isatty(STDIN_FILENO) != 0 && ::isatty(STDOUT_FILENO) != 0) { + notifier = std::make_unique(); + } else { + try { + notifier = std::make_unique(); + } catch (std::runtime_error &err) { + qInfo() << "initialize DBus notifier failed:" << err.what() + << "try to fallback to terminal notifier."; + } + } - if (!notifier) { - qInfo() << "Using DummyNotifier, expected interactions and prompts will not be " - "displayed."; - notifier = std::make_unique(); - } + if (!notifier) { + qInfo() << "Using DummyNotifier, expected interactions and prompts will not be " + "displayed."; + notifier = std::make_unique(); + } + auto repo = initOSTreeRepo(); + if (!repo.has_value()) { + qCritical() << "initOSTreeRepo failed" << repo.error(); + return -1; + } + // create cli + auto *cli = new linglong::cli::Cli(*printer, + **ociRuntime, + *containerBuilder, + *pkgMan, + **repo, + std::move(notifier), + QCoreApplication::instance()); + cli->setGlobalOptions(std::move(globalOptions)); + + // connect signal + if (QObject::connect(QCoreApplication::instance(), + &QCoreApplication::aboutToQuit, + cli, + &Cli::cancelCurrentTask) + == nullptr) { + qCritical() << "failed to connect signal: aboutToQuit"; + return -1; + } - auto *cli = new linglong::cli::Cli(*printer, - **ociRuntime, - *containerBuilder, - *pkgMan, - *repo, - std::move(notifier), - QCoreApplication::instance()); - cli->setCliOptions(std::move(options)); - std::unordered_map subcommandMap = { - { "run", &Cli::run }, - { "exec", &Cli::exec }, - { "enter", &Cli::exec }, - { "ps", &Cli::ps }, - { "kill", &Cli::kill }, - { "install", &Cli::install }, - { "upgrade", &Cli::upgrade }, - { "search", &Cli::search }, - { "uninstall", &Cli::uninstall }, - { "list", &Cli::list }, - { "info", &Cli::info }, - { "content", &Cli::content }, - { "prune", &Cli::prune }, - { "inspect", &Cli::inspect }, - { "repo", &Cli::repo }, - { "dir", &Cli::dir } - }; - - if (QObject::connect(QCoreApplication::instance(), - &QCoreApplication::aboutToQuit, - cli, - &Cli::cancelCurrentTask) - == nullptr) { - qCritical() << "failed to connect signal: aboutToQuit"; - QCoreApplication::exit(-1); - return; - } + // get subcommands + const auto &commands = commandParser.get_subcommands(); + auto ret = std::find_if(commands.begin(), commands.end(), [](CLI::App *app) { + return app->parsed(); + }); - const auto &commands = commandParser.get_subcommands(); - auto ret = - std::find_if(commands.begin(), commands.end(), [&subcommandMap](CLI::App *app) { - if (!app->parsed()) { - return false; - } + // if no subcommand is set, print help + if (ret == commands.end()) { + std::cout << commandParser.help("", CLI::AppFormatMode::All); + return -1; + } - return subcommandMap.find(app->get_name()) != subcommandMap.end(); - }); + // get subcommand name + const auto &name = (*ret)->get_name(); + int result = -1; + // call corresponding function according to subcommand name and pass corresponding options + if (name == "run") { + result = cli->run(runOptions); + } else if (name == "enter") { + result = cli->enter(enterOptions); + } else if (name == "ps") { + result = cli->ps(); + } else if (name == "kill") { + result = cli->kill(killOptions); + } else if (name == "install") { + result = cli->install(installOptions); + } else if (name == "upgrade") { + result = cli->upgrade(upgradeOptions); + } else if (name == "search") { + result = cli->search(searchOptions); + } else if (name == "uninstall") { + result = cli->uninstall(uninstallOptions); + } else if (name == "list") { + result = cli->list(listOptions); + } else if (name == "info") { + result = cli->info(infoOptions); + } else if (name == "content") { + result = cli->content(contentOptions); + } else if (name == "prune") { + result = cli->prune(); + } else if (name == "inspect") { + result = cli->inspect(*ret, inspectOptions); + } else if (name == "repo") { + result = cli->repo(*ret, repoOptions); + } else { + // if subcommand name is not found, print help + std::cout << commandParser.help("", CLI::AppFormatMode::All); + return -1; + } + // return result + return result; +} - if (ret == commands.end()) { - std::cout << commandParser.help("", CLI::AppFormatMode::All); - QCoreApplication::exit(-1); - return; - } +int main(int argc, char **argv) +{ + // bind text domain + bindtextdomain(PACKAGE_LOCALE_DOMAIN, PACKAGE_LOCALE_DIR); + // text domain + textdomain(PACKAGE_LOCALE_DOMAIN); + + QCoreApplication app(argc, argv); + // application initialize + applicationInitialize(); + initLinyapsLogSystem(linglong::utils::log::LogBackend::Journal); - const auto &name = (*ret)->get_name(); - // ll-cli repo need app to parse subcommand - QCoreApplication::exit(std::invoke(subcommandMap[name], cli, *ret)); + // invoke method + auto ret = QMetaObject::invokeMethod( + QCoreApplication::instance(), + [argc, argv]() { + QCoreApplication::exit(runCliApplication(argc, argv)); }, Qt::QueuedConnection); + // assert Q_ASSERT(ret); + // exec return QCoreApplication::exec(); } diff --git a/apps/ll-dialog/src/main.cpp b/apps/ll-dialog/src/main.cpp index a5e55de5c..612c6927b 100644 --- a/apps/ll-dialog/src/main.cpp +++ b/apps/ll-dialog/src/main.cpp @@ -3,7 +3,7 @@ // SPDX-License-Identifier: LGPL-3.0-or-later #include "cache_dialog.h" -#include "linglong/utils/configure.h" +#include "configure.h" #include "linglong/utils/gettext.h" #include "permissionDialog.h" #include "tl/expected.hpp" diff --git a/apps/ll-driver-detect/CMakeLists.txt b/apps/ll-driver-detect/CMakeLists.txt new file mode 100644 index 000000000..7481a2f01 --- /dev/null +++ b/apps/ll-driver-detect/CMakeLists.txt @@ -0,0 +1,20 @@ +# SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +pfl_add_executable( + OUTPUT_NAME + ll-driver-detect + LIBEXEC + linglong + SOURCES + ./src/main.cpp + ./src/driver_detection_config.cpp + ./src/nvidia_driver_detector.cpp + ./src/application_singleton.cpp + ./src/driver_detection_manager.cpp + ./src/dbus_notifier.cpp + LINK_LIBRARIES + PRIVATE + CLI11::CLI11 + linglong::utils) diff --git a/apps/ll-driver-detect/README.md b/apps/ll-driver-detect/README.md new file mode 100644 index 000000000..ff833b3bc --- /dev/null +++ b/apps/ll-driver-detect/README.md @@ -0,0 +1,120 @@ +# ll-driver-detect + +`ll-driver-detect` 是如意玲珑(Linyaps)的显卡驱动检测工具,用于自动检测系统中的可用显卡驱动,并为用户提供安装选项。 + +## 功能概述 + +- **可扩展的驱动检测**: 采用插件式架构 (`DriverDetectionManager`),可以轻松扩展以支持多种类型的显卡驱动(目前已支持 NVIDIA)。 +- **单例运行保证**: 通过文件锁 (`ApplicationSingleton`) 确保在任何时候只有一个检测进程在运行,避免资源浪费和重复通知。 +- **简化的用户配置**: 提供一个简单的配置选项,允许用户选择“不再提醒”,配置被保存在 `~/.config/linglong/driver_detection.json` 中。 +- **统一的用户通知**: 当检测到一个或多个可安装的驱动时,通过 DBus 向用户发送一个统一的通知。 +- **命令行支持**: 提供多种操作模式,包括全自动检测、仅检查和仅安装。 + +## 安装 + +该工具是如意玲珑的内置部分,会随 `linglong-bin` 一同安装。 + +## 使用方法 + +### 基本用法 + +```bash +# 运行驱动检测(默认进行检测并发送通知) +ll-driver-detect + +# 查看帮助信息 +ll-driver-detect --help +``` + +### 命令行选项 + +``` +用法: ll-driver-detect [选项] + +选项: + -h,--help 显示帮助信息 + -v,--version 显示版本信息 + -f,--force 强制检测和通知,即使配置为“不再提醒”。 + -c,--check-only 仅检查驱动,不进行安装或通知。 + -i,--install-only 仅安装驱动,不发送通知。 +``` + +### 配置管理 + +本工具的配置非常简单,存储在 `~/.config/linglong/driver_detection.json`。 + +```json +{ + "neverRemind": false +} +``` + +- `neverRemind`: 如果设置为 `true`,`ll-driver-detect` 将不会再发送通知。用户在通知中选择“不再提醒”时,此字段会自动设为 `true`。 + +## 工作原理 + +### 检测流程 + +1. **获取单例锁**: 程序启动时,`ApplicationSingleton` 会尝试在 `$XDG_CONFIG_HOME/linglong/ll-driver-detect.lock`(如果 `XDG_CONFIG_HOME` 未设置,则默认为 `~/.config/linglong/ll-driver-detect.lock`)获取文件锁。如果锁已被另一实例持有,则当前进程会安静地退出。 +2. **初始化驱动管理器**: 创建一个 `DriverDetectionManager` 实例。 +3. **注册与检测**: 管理器的构造函数会注册所有可用的 `DriverDetector` 子类(例如 `NVIDIADriverDetector`)。随后,管理器调用每个检测器的 `detect()` 方法。 +4. **结果聚合**: `detect()` 方法返回驱动信息(如果检测成功),包括驱动标识、版本、玲珑包名和当前安装状态。管理器收集所有成功检测到的驱动信息。 +5. **执行操作**: + - 如果没有检测到任何驱动,程序退出。 + - 默认情况下,它会检查配置文件,并决定是否发送通知。 + - 如果使用 `-c, --check-only`,程序会打印出检测到的驱动并退出。 + - 如果使用 `-i, --install-only`,程序会尝试安装所有检测到的驱动并退出。 + +### 通知机制 + +- 在默认模式下,如果检测到驱动并且配置文件中的 `neverRemind` 为 `false`(或使用了 `--force` 选项): + 1. `DBusNotifier` 会构造一个 DBus 消息。 + 2. 该消息被发送到系统的通知服务(`org.freedesktop.Notifications`)。 + 3. 通知中会包含“立即安装”和“不再提醒”两个选项。 + 4. 如果用户选择“安装”,程序会调用 `ll-cli install` 来安装所有检测到的驱动包。 + 5. 如果用户选择“不再提醒”,程序会将 `neverRemind` 设为 `true`并保存到配置文件。 + +## 开发信息 + +### 项目结构 + +``` +apps/ll-driver-detect/ +├── src/ +│ ├── main.cpp # 主程序入口 +│ ├── application_singleton.h/.cpp # 应用单例管理器 +│ ├── driver_detection_manager.h/.cpp # 驱动检测协调器 +│ ├── driver_detector.h/.cpp # 驱动检测器基类 +│ ├── nvidia_driver_detector.h/.cpp # NVIDIA 驱动检测器实现 +│ ├── driver_detection_config.h/.cpp # 配置管理 +│ └── dbus_notifier.h/.cpp # DBus 通知实现 +├── README.md # 本文档 +└── CMakeLists.txt # 构建配置 +``` + +### 核心类 + +- **`ApplicationSingleton`**: 通过文件锁确保全局只有一个实例在运行。 +- **`DriverDetectionManager`**: 负责注册和运行所有具体的驱动检测器。 +- **`DriverDetector`**: 驱动检测器的抽象基类,定义了 `detect()` 接口。 +- **`NVIDIADriverDetector`**: `DriverDetector` 的一个实现,专门用于检测 NVIDIA 驱动。 +- **`DriverDetectionConfigManager`**: 负责加载和保存 `driver_detection.json` 配置文件。 +- **`DBusNotifier`**: 封装了通过 DBus 发送通知的逻辑。 + +### 构建 + +```bash +# 切换到项目根目录 +cd ${LINGYAPS_ROOT} + +# 创建构建目录 +mkdir build && cd build + +# 配置和构建 +cmake .. +make ll-driver-detect +``` + +## 许可证 + +本项目遵循 LGPL-3.0-or-later 许可证。 \ No newline at end of file diff --git a/apps/ll-driver-detect/src/application_singleton.cpp b/apps/ll-driver-detect/src/application_singleton.cpp new file mode 100644 index 000000000..4875bf360 --- /dev/null +++ b/apps/ll-driver-detect/src/application_singleton.cpp @@ -0,0 +1,78 @@ +// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "application_singleton.h" + +#include "linglong/utils/log/log.h" + +#include +namespace linglong::driver::detect { + +ApplicationSingleton::ApplicationSingleton(const std::string &lockFilePath) + : lockFilePath_(lockFilePath) + , lockHeld_(false) +{ +} + +ApplicationSingleton::~ApplicationSingleton() +{ + releaseLock(); +} + +utils::error::Result ApplicationSingleton::tryAcquireLock() +{ + LINGLONG_TRACE("Try acquire lock") + + if (lockHeld_) { + return true; + } + + // Create directory if it doesn't exist + std::filesystem::path lockPath(lockFilePath_); + std::filesystem::path lockDir = lockPath.parent_path(); + + if (!lockDir.empty() && !std::filesystem::exists(lockDir)) { + std::error_code ec; + std::filesystem::create_directories(lockDir, ec); + if (ec) { + return LINGLONG_ERR("Failed to create lock directory: " + ec.message()); + } + } + + // Try to create file lock + auto fileLock = linglong::utils::filelock::FileLock::create(lockFilePath_, true); + if (!fileLock) { + return LINGLONG_ERR(fileLock); + } + + // Try to acquire write lock (exclusive) + auto lockResult = fileLock->tryLock(linglong::utils::filelock::LockType::Write); + if (!lockResult) { + return LINGLONG_ERR(lockResult); + } + + if (*lockResult) { + fileLock_ = std::make_unique(std::move(*fileLock)); + lockHeld_ = true; + return true; + } + + // Another instance is already running + return false; +} + +void ApplicationSingleton::releaseLock() +{ + if (lockHeld_ && fileLock_) { + auto result = fileLock_->unlock(); + if (!result) { + // Log error but don't throw - we're in destructor + LogF("Failed to release file lock: {}", result.error().message()); + } + fileLock_.reset(); + lockHeld_ = false; + } +} + +} // namespace linglong::driver::detect diff --git a/apps/ll-driver-detect/src/application_singleton.h b/apps/ll-driver-detect/src/application_singleton.h new file mode 100644 index 000000000..849554666 --- /dev/null +++ b/apps/ll-driver-detect/src/application_singleton.h @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#pragma once + +#include "linglong/utils/error/error.h" +#include "linglong/utils/filelock.h" + +#include + +namespace linglong::driver::detect { + +/** + * @brief Application singleton manager + * + * This class ensures only one instance of the driver detection application + * can run at a time, replacing the configuration-based frequency control. + */ +class ApplicationSingleton +{ +public: + /** + * @brief Constructor + * @param lockFilePath Path to the lock file + */ + explicit ApplicationSingleton(const std::string &lockFilePath); + + /** + * @brief Destructor - releases the lock + */ + ~ApplicationSingleton(); + + /** + * @brief Try to acquire the singleton lock + * @return true if lock acquired successfully, false if another instance is running + */ + utils::error::Result tryAcquireLock(); + + /** + * @brief Release the lock + */ + void releaseLock(); + + /** + * @brief Check if we currently hold the lock + * @return true if we hold the lock, false otherwise + */ + bool isLockHeld() const { return lockHeld_; } + + // Delete copy constructor and assignment operator + ApplicationSingleton(const ApplicationSingleton &) = delete; + ApplicationSingleton &operator=(const ApplicationSingleton &) = delete; + +private: + std::string lockFilePath_; + std::unique_ptr fileLock_; + bool lockHeld_; +}; + +} // namespace linglong::driver::detect diff --git a/apps/ll-driver-detect/src/dbus_notifier.cpp b/apps/ll-driver-detect/src/dbus_notifier.cpp new file mode 100644 index 000000000..1f7001f4b --- /dev/null +++ b/apps/ll-driver-detect/src/dbus_notifier.cpp @@ -0,0 +1,195 @@ +// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "dbus_notifier.h" + +#include "linglong/utils/log/log.h" + +#include +#include +#include + +namespace linglong::driver::detect { + +DBusNotifier::DBusNotifier(QObject *parent) + : QObject(parent) + , dbusInterface_("org.freedesktop.Notifications", + "/org/freedesktop/Notifications", + "org.freedesktop.Notifications") +{ +} + +utils::error::Result DBusNotifier::init() +{ + LINGLONG_TRACE("init dbus notifier") + + auto connection = dbusInterface_.connection(); + + if (!connection.connect(dbusInterface_.service(), + dbusInterface_.path(), + dbusInterface_.interface(), + "ActionInvoked", + this, + SLOT(forwardActionInvoked(quint32, QString)))) { + return LINGLONG_ERR("couldn't connect to signal ActionInvoked:" + + connection.lastError().message()); + } + + if (!connection.connect(dbusInterface_.service(), + dbusInterface_.path(), + dbusInterface_.interface(), + "NotificationClosed", + this, + SLOT(forwardNotificationClosed(quint32, quint32)))) { + return LINGLONG_ERR("couldn't connect to signal NotificationClosed:" + + connection.lastError().message()); + } + return LINGLONG_OK; +} + +utils::error::Result +DBusNotifier::sendInteractiveNotification(const NotificationRequest &request) +{ + LINGLONG_TRACE("send request through dbus notification") + + quint32 notificationID{ 0 }; + QString choice; + bool userInteracted = false; + QEventLoop loop; + + struct SignalGuard { + QMetaObject::Connection closeConn; + QMetaObject::Connection actionConn; + + ~SignalGuard() + { + QObject::disconnect(closeConn); + QObject::disconnect(actionConn); + } + } signalGuard{{}, {}}; + + // 连接信号处理函数 + signalGuard.closeConn = QObject::connect(this, + &DBusNotifier::notificationClosed, + [&](quint32 id, quint32 closeReason) { + if (notificationID != 0 && id == notificationID) { + LogD("Notification {} closed with reason: {}", id, closeReason); + loop.quit(); + } + }); + + signalGuard.actionConn = QObject::connect(this, + &DBusNotifier::actionInvoked, + [&](quint32 id, const QString &actionKey) { + if (notificationID != 0 && id == notificationID) { + LogD("Notification {} action invoked: {}", id, actionKey.toStdString()); + choice = actionKey; + userInteracted = true; + } + }); + + // 检查信号连接是否成功 + if (!signalGuard.closeConn || !signalGuard.actionConn) { + return LINGLONG_ERR("Failed to connect notification signals"); + } + + // 发送通知 + auto reply = sendDBusNotification(request.appName, + 0, // replaceId + request.icon, // icon + request.summary, + request.body, + request.actions, + QVariantMap(), // hints + request.timeout); + + if (!reply) { + return LINGLONG_ERR(reply.error().message()); + } + notificationID = *reply; + LogD("Interactive notification sent with ID: {}", notificationID); + + // 设置事件循环超时处理 + QTimer::singleShot(request.timeout, &loop, &QEventLoop::quit); + + // 运行事件循环等待用户交互 + loop.exec(); + + // 根据用户是否交互返回相应的结果 + if (userInteracted) { + LogD("User selected action: {}", choice.toStdString()); + return NotificationResult(choice, true); + } else { + LogD("Notification closed without user interaction"); + return NotificationResult(choice, false); + } +} + +utils::error::Result DBusNotifier::sendSimpleNotification(const NotificationRequest &request) +{ + LINGLONG_TRACE("sendSimpleNotification"); + + // 发送通知(无动作,简单通知) + auto notificationId = sendDBusNotification(request.appName, + 0, // replaceId + request.icon, // icon + request.summary, + request.body, + QStringList(), // no actions + QVariantMap(), // hints + request.timeout); + + if (!notificationId) { + return LINGLONG_ERR(notificationId.error().message()); + } + + LogD("Simple notification sent with ID: {}", *notificationId); + return LINGLONG_OK; +} + +utils::error::Result DBusNotifier::sendDBusNotification(const QString &appName, + quint32 replaceId, + const QString &icon, + const QString &summary, + const QString &body, + const QStringList &actions, + const QVariantMap &hints, + qint32 timeout) +{ + LINGLONG_TRACE("sendDBusNotification"); + + if (!dbusInterface_.isValid()) { + return LINGLONG_ERR("DBus interface is not valid"); + } + + // 调用Notify方法 + QDBusMessage message = + dbusInterface_ + .call("Notify", appName, replaceId, icon, summary, body, actions, hints, timeout); + + if (message.type() == QDBusMessage::ErrorMessage) { + return LINGLONG_ERR(QString("Failed to send notification: %1").arg(message.errorMessage())); + } + + if (message.arguments().isEmpty()) { + return LINGLONG_ERR("No notification ID returned"); + } + + quint32 notificationId = message.arguments().first().toUInt(); + LogD("Notification sent with ID: {}", notificationId); + + return notificationId; +} + +void DBusNotifier::forwardActionInvoked(quint32 ID, QString action) +{ + Q_EMIT actionInvoked(ID, action, QPrivateSignal{}); +} + +void DBusNotifier::forwardNotificationClosed(quint32 ID, quint32 reason) +{ + Q_EMIT notificationClosed(ID, reason, QPrivateSignal{}); +} + +} // namespace linglong::driver::detect diff --git a/apps/ll-driver-detect/src/dbus_notifier.h b/apps/ll-driver-detect/src/dbus_notifier.h new file mode 100644 index 000000000..51d3a0f70 --- /dev/null +++ b/apps/ll-driver-detect/src/dbus_notifier.h @@ -0,0 +1,124 @@ +// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#pragma once + +#include "linglong/utils/error/error.h" + +#include +#include + +namespace linglong::driver::detect { + +/** + * @brief DBus通知类 + * + * 该类提供DBus通知功能 + */ +class DBusNotifier final : public QObject +{ + Q_OBJECT + +public: + /** + * @brief 通知结果结构 + */ + struct NotificationResult + { + QString action; // 用户选择的动作 + bool success; // 通知是否成功发送 + + NotificationResult() + : success(false) + { + } + + NotificationResult(const QString &act, bool succ) + : action(act) + , success(succ) + { + } + }; + + /** + * @brief 通知请求结构 + */ + struct NotificationRequest + { + QString summary; // 通知标题 + QString body; // 通知内容 + QStringList actions; // 可用动作按钮文本(成对出现:id, 文本) + QString appName; // 应用名称 + QString icon; // 通知图标 + quint32 timeout; // 超时时间(毫秒) + }; + + /** + * @brief 构造函数 + */ + explicit DBusNotifier(QObject *parent = nullptr); + + /** + * @brief Initializes the DBus connection and signals + * @return A result object, holding an error if initialization fails + */ + utils::error::Result init(); + + /** + * @brief 发送交互式通知并等待用户响应 + * @param request 通知请求 + * @return 通知结果 + */ + utils::error::Result + sendInteractiveNotification(const NotificationRequest &request); + + /** + * @brief 发送简单通知 + * @param request 通知请求 + * @return 成功或错误信息 + */ + utils::error::Result sendSimpleNotification(const NotificationRequest &request); + +Q_SIGNALS: + void actionInvoked(quint32 ID, QString action, QPrivateSignal); + void notificationClosed(quint32 ID, quint32 reason, QPrivateSignal); + +private Q_SLOTS: + void forwardActionInvoked(quint32 ID, QString action); + void forwardNotificationClosed(quint32 ID, quint32 reason); + +private: + enum class CloseReason { + Expired = 1, // The notification expired. + Dismissed, // The notification was dismissed by the user. + CloseByCall, // The notification was closed by a call to CloseNotification. + Undefined, // Undefined/reserved reasons. + NoReason // custom defined for initializing variable + }; + + /** + * @brief 发送通知到DBus服务 + * @param appName 应用名称 + * @param replaceId 替换ID + * @param icon 图标 + * @param summary 标题 + * @param body 内容 + * @param actions 动作列表 + * @param hints 提示信息 + * @param timeout 超时时间 + * @return 通知ID + */ + utils::error::Result sendDBusNotification(const QString &appName, + quint32 replaceId, + const QString &icon, + const QString &summary, + const QString &body, + const QStringList &actions, + const QVariantMap &hints, + qint32 timeout); + + QDBusInterface dbusInterface_; ///< DBus接口 +}; + +} // namespace linglong::driver::detect diff --git a/apps/ll-driver-detect/src/driver_detection_config.cpp b/apps/ll-driver-detect/src/driver_detection_config.cpp new file mode 100644 index 000000000..78c51c9e5 --- /dev/null +++ b/apps/ll-driver-detect/src/driver_detection_config.cpp @@ -0,0 +1,78 @@ +// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "driver_detection_config.h" + +#include "linglong/utils/log/log.h" + +#include + +#include +#include + +namespace linglong::driver::detect { + +DriverDetectionConfigManager::DriverDetectionConfigManager(const std::string &configPath) + : configFilePath(configPath) +{ + // Try to load existing config, if it fails, use defaults + loadConfig(); +} + +bool DriverDetectionConfigManager::loadConfig() +{ + std::error_code ec; + if (!std::filesystem::exists(configFilePath, ec) || ec) { + // Config file doesn't exist or error checking, use defaults + return true; + } + + std::ifstream file(configFilePath); + if (!file.is_open()) { + return false; + } + + nlohmann::json jsonConfig = nlohmann::json::parse(file, nullptr, false); + file.close(); + + if (jsonConfig.is_discarded()) { + LogW("Failed to parse driver detection config, using defaults."); + return false; + } + + // Parse configuration + if (jsonConfig.contains("neverRemind") && jsonConfig["neverRemind"].is_boolean()) { + config.neverRemind = jsonConfig["neverRemind"]; + } + + return true; +} + +bool DriverDetectionConfigManager::saveConfig() +{ + nlohmann::json jsonConfig; + + jsonConfig["neverRemind"] = config.neverRemind; + + std::ofstream file(configFilePath); + if (!file.is_open()) { + return false; + } + + file << jsonConfig.dump(4); // Pretty print with 4 spaces + file.close(); + + return true; +} + +void DriverDetectionConfigManager::recordUserChoice(UserNotificationChoice choice) +{ + choice == UserNotificationChoice::InstallNow ? config.neverRemind = false + : config.neverRemind = true; + + // Save the updated configuration + saveConfig(); +} + +} // namespace linglong::driver::detect diff --git a/apps/ll-driver-detect/src/driver_detection_config.h b/apps/ll-driver-detect/src/driver_detection_config.h new file mode 100644 index 000000000..290d9b1a2 --- /dev/null +++ b/apps/ll-driver-detect/src/driver_detection_config.h @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#pragma once + +#include + +namespace linglong::driver::detect { + +enum class UserNotificationChoice { InstallNow, NeverRemind }; + +struct DriverDetectionConfig +{ + bool neverRemind = false; +}; + +class DriverDetectionConfigManager +{ +public: + explicit DriverDetectionConfigManager(const std::string &configPath); + ~DriverDetectionConfigManager() = default; + + // Load configuration from file + bool loadConfig(); + + // Save configuration to file + bool saveConfig(); + + // Get current configuration + DriverDetectionConfig getConfig() const { return config; } + + // Update configuration + void setConfig(const DriverDetectionConfig &newConfig) { config = newConfig; } + + // Check if we should show notification (simplified - no version-specific logic) + bool shouldShowNotification() const { return !config.neverRemind; } + + // Record user choice (simplified - no version parameter needed) + void recordUserChoice(UserNotificationChoice choice); + +private: + std::string configFilePath; + DriverDetectionConfig config; +}; + +} // namespace linglong::driver::detect diff --git a/apps/ll-driver-detect/src/driver_detection_manager.cpp b/apps/ll-driver-detect/src/driver_detection_manager.cpp new file mode 100644 index 000000000..b2759d291 --- /dev/null +++ b/apps/ll-driver-detect/src/driver_detection_manager.cpp @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "driver_detection_manager.h" + +#include "linglong/utils/log/log.h" +#include "nvidia_driver_detector.h" + +namespace linglong::driver::detect { + +DriverDetectionManager::DriverDetectionManager() +{ + registerDetectors(); +} + +utils::error::Result DriverDetectionManager::detectAllDrivers() +{ + DriverDetectionResult result; + + for (const auto &detector : detectors_) { + auto detectionResult = detector->detect(); + if (!detectionResult) { + LogE("Driver detection failed {}: {}", + detector->getDriverIdentify(), + detectionResult.error().message()); + continue; + } + + result.detectedDrivers.emplace_back(*detectionResult); + LogD("Detected driver: {} version: {}", + detectionResult->packageName, + detectionResult->version); + } + + return result; +} + +void DriverDetectionManager::registerDetectors() +{ + // Register NVIDIA detector + detectors_.push_back(std::make_unique()); + + // TODO: Add other driver detector + + LogD("Registered {} driver detectors", detectors_.size()); +} + +} // namespace linglong::driver::detect diff --git a/apps/ll-driver-detect/src/driver_detection_manager.h b/apps/ll-driver-detect/src/driver_detection_manager.h new file mode 100644 index 000000000..467a2a929 --- /dev/null +++ b/apps/ll-driver-detect/src/driver_detection_manager.h @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#pragma once + +#include "driver_detector.h" + +#include +#include + +namespace linglong::driver::detect { + +// Result of driver detection for all available drivers +struct DriverDetectionResult +{ + std::vector detectedDrivers; + + bool hasAvailableDrivers() const + { + return std::any_of(detectedDrivers.begin(), + detectedDrivers.end(), + [](const auto &driver) { + return !driver.isInstalled; + }); + } +}; + +// Manager class that coordinates detection of multiple graphics drivers +class DriverDetectionManager +{ +public: + DriverDetectionManager(); + virtual ~DriverDetectionManager() = default; + + // Detect all available graphics drivers on the system + // Returns all detected drivers, or empty vector if none found + utils::error::Result detectAllDrivers(); + +protected: + // Register all available driver detectors + virtual void registerDetectors(); + + std::vector> detectors_; +}; + +} // namespace linglong::driver::detect diff --git a/apps/ll-driver-detect/src/driver_detector.h b/apps/ll-driver-detect/src/driver_detector.h new file mode 100644 index 000000000..215fa5ec0 --- /dev/null +++ b/apps/ll-driver-detect/src/driver_detector.h @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#pragma once + +#include "linglong/utils/error/error.h" + +#include + +namespace linglong::driver::detect { + +struct GraphicsDriverInfo +{ + std::string identify; + std::string version; + std::string packageName; + bool isInstalled = false; +}; + +class DriverDetector +{ +public: + virtual ~DriverDetector() = default; + + // Main detection method - returns driver info if detected + virtual utils::error::Result detect() = 0; + + // Check if the driver package is installed + virtual utils::error::Result checkPackageInstalled(const std::string &packageName) = 0; + + // Get the Identify of driver this detector handles + virtual std::string getDriverIdentify() const = 0; +}; + +} // namespace linglong::driver::detect diff --git a/apps/ll-driver-detect/src/main.cpp b/apps/ll-driver-detect/src/main.cpp new file mode 100644 index 000000000..39d91c429 --- /dev/null +++ b/apps/ll-driver-detect/src/main.cpp @@ -0,0 +1,304 @@ +// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "application_singleton.h" +#include "configure.h" +#include "dbus_notifier.h" +#include "driver_detection_config.h" +#include "driver_detection_manager.h" +#include "driver_detector.h" +#include "linglong/utils/command/cmd.h" +#include "linglong/utils/error/error.h" +#include "linglong/utils/gettext.h" +#include "linglong/utils/global/initialize.h" +#include "tl/expected.hpp" + +#include + +#include + +#include +#include +#include + +namespace { + +using namespace linglong::driver::detect; + +constexpr auto kActionInstallNow = "install_now"; +constexpr auto kActionNotRemind = "not_remind"; +constexpr auto kNotificationIcon = "/usr/share/icons/hicolor/scalable/apps/linyaps.svg"; + +struct DriverDetectOptions +{ + std::string driverType; + std::string packageName; + bool force = false; + bool checkOnly = false; + bool installOnly = false; + int notificationIntervalMinutes = 5; // Kept for backward compatibility, but will be ignored +}; + +linglong::utils::error::Result getDefaultConfigPath() +{ + LINGLONG_TRACE("get default config path"); + + auto *homeEnv = ::getenv("HOME"); + if (homeEnv == nullptr) { + return LINGLONG_ERR("Couldn't get HOME env."); + } + + auto value = getenv("XDG_CONFIG_HOME"); + auto configDir = + value ? std::filesystem::path{ value } : std::filesystem::path{ homeEnv } / ".config"; + return configDir / "linglong/driver_detection.json"; +} + +// Sets up the configuration manager based on command-line options. +linglong::utils::error::Result setupConfigManager() +{ + LINGLONG_TRACE("setupConfigManager"); + + auto defaultConfigPathResult = getDefaultConfigPath(); + if (!defaultConfigPathResult) { + return LINGLONG_ERR(defaultConfigPathResult.error()); + } + + // Determine configuration path + std::filesystem::path configPath = *defaultConfigPathResult; + + // Ensure configuration directory exists + std::error_code ec; + std::filesystem::create_directories(configPath.parent_path(), ec); + if (ec) { + LogW("Failed to create config directory: {}", ec.message()); + } + + // Create driver detection config manager + DriverDetectionConfigManager configManager(configPath.string()); + + // Load configuration + if (!configManager.loadConfig()) { + LogW("Failed to load driver detection config, using defaults"); + } + + return configManager; +} + +linglong::utils::error::Result +installDriverPackage(const std::vector &drivers) +{ + LINGLONG_TRACE("installDriverPackage") + + try { + for (const auto &driverInfo : drivers) { + LogD("Processing driver: Identify={}, Version={}, Package={}, Installed={}", + driverInfo.identify, + driverInfo.version, + driverInfo.packageName, + driverInfo.isInstalled); + + if (driverInfo.isInstalled) { + LogD("Driver package is already installed: {}", driverInfo.packageName); + continue; + } + + // Execute ll-cli install command to install the package + auto ret = linglong::utils::command::Cmd("ll-cli").exec( + { "install", QString::fromStdString(driverInfo.packageName) }); + if (!ret) { + return LINGLONG_ERR("Installation command failed: " + ret.error().message()); + } + + LogD("Driver package installation command executed successfully: {}", *ret); + } + + return LINGLONG_OK; + } catch (const std::exception &e) { + return LINGLONG_ERR("Failed to install driver package: " + std::string(e.what())); + } + + return LINGLONG_OK; +} + +} // namespace + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + bindtextdomain(PACKAGE_LOCALE_DOMAIN, PACKAGE_LOCALE_DIR); + textdomain(PACKAGE_LOCALE_DOMAIN); + + linglong::utils::global::applicationInitialize(); + linglong::utils::global::initLinyapsLogSystem(linglong::utils::log::LogBackend::Console); + + DriverDetectOptions options; + CLI::App cliApp{ "Linglong Graphics Driver Detection Tool" }; + + // Define command line options + cliApp.add_flag("-f,--force", options.force, _("Force installation even if recently reminded")); + cliApp.add_flag("-c,--check-only", + options.checkOnly, + _("Check for drivers only without installing or notifying")); + cliApp.add_flag("-i,--install-only", + options.installOnly, + _("Only install drivers without notifications")); + + try { + cliApp.parse(argc, argv); + } catch (const CLI::ParseError &e) { + return cliApp.exit(e); + } + + LogD("Starting ll-driver-detect application"); + + // Initialize application singleton to ensure only one instance runs + auto defaultConfigPathResult = getDefaultConfigPath(); + if (!defaultConfigPathResult) { + LogF("Failed to get default config path: {}", defaultConfigPathResult.error().message()); + return 1; + } + + std::filesystem::path lockFilePath = *defaultConfigPathResult; + lockFilePath = lockFilePath.parent_path() / "ll-driver-detect.lock"; + + ApplicationSingleton singleton(lockFilePath.string()); + auto lockResult = singleton.tryAcquireLock(); + if (!lockResult) { + LogF("Failed to acquire singleton lock: {}", lockResult.error().message()); + return 1; + } + + if (!*lockResult) { + LogW("Another instance of ll-driver-detect is already running. Exiting."); + return 0; // Exit gracefully, not an error + } + + auto configManagerResult = setupConfigManager(); + if (!configManagerResult) { + LogF("Failed to set up configuration: {}", configManagerResult.error().message()); + return 1; + } + + auto configManager = *configManagerResult; + if (!options.force && !configManager.shouldShowNotification()) { + LogD("User has chosen not to be reminded about driver installation"); + return 0; + } + + // Create driver detection manager for multi-driver support + DriverDetectionManager detectionManager; + + // Run driver detection and handling for all available drivers + auto result = detectionManager.detectAllDrivers(); + + if (!result) { + LogF("Driver detection failed: {}", result.error().message()); + + return 1; + } + + const auto &detectionResult = *result; + + if (!detectionResult.hasAvailableDrivers()) { + std::cout << "No available graphics drivers detected or already installed" << std::endl; + return 0; + } + + if (options.checkOnly) { + std::cout << "CHECK ONLY: only check drivers, no notifications or installations " + "will be performed." + << std::endl; + std::cout << "Detected drivers:" << std::endl; + for (const auto &driverInfo : detectionResult.detectedDrivers) { + std::cout << "----------------------------------------" << std::endl; + std::cout << " Identify: " << driverInfo.identify << std::endl; + std::cout << " Version: " << driverInfo.version << std::endl; + std::cout << " Package: " << driverInfo.packageName << std::endl; + std::cout << " Installed: " << (driverInfo.isInstalled ? "Yes" : "No") << std::endl; + std::cout << "----------------------------------------" << std::endl; + } + return 0; + } + + LogD("Detected {} graphics driver(s)", detectionResult.detectedDrivers.size()); + + if (options.installOnly) { + std::cout << "Install-only: installing detected drivers without notifications" << std::endl; + auto installResult = installDriverPackage(detectionResult.detectedDrivers); + if (!installResult) { + LogW("Failed to install driver package {}: {}", + options.packageName, + installResult.error().message()); + } + + std::cout << "Successfully installed driver package" << std::endl; + + return 0; + } + + // Handle user notifications and installation for each driver + // Check if we should show notification for this driver + auto notifier = std::make_unique(); + auto initResult = notifier->init(); + if (!initResult) { + LogF("Failed to initialize DBus notifier: {}", initResult.error().message()); + return 1; + } + + // Create driver-specific notification + DBusNotifier::NotificationRequest request; + request.appName = "linyaps"; + request.summary = _("Graphics Driver Available"); + request.body = QString(_("Graphics driver package is available that can improve performance " + "for some Linyaps applications.\n" + "Would you like to install it?")); + request.actions = QStringList() + << kActionInstallNow << _("Install Now") << kActionNotRemind << _("Don't Remind"); + request.icon = kNotificationIcon; + request.timeout = 25000; // 25 seconds + + auto responseResult = notifier->sendInteractiveNotification(request); + if (!responseResult) { + LogW("Failed to send notification for driver: {}", responseResult.error().message()); + return 1; + } + + // Handle user response + const auto &response = *responseResult; + if (response.action == kActionInstallNow && response.success) { + LogD("User chose to install graphics driver"); + + auto installResult = installDriverPackage(detectionResult.detectedDrivers); + if (!installResult) { + LogW("Failed to install driver package: {}", installResult.error().message()); + return 1; + } + + LogD("Successfully installed driver package"); + + // Send success notification + DBusNotifier::NotificationRequest successRequest; + successRequest.appName = "linyaps"; + successRequest.summary = _("Graphics Driver Installation Completed"); + successRequest.body = + QString(_("Graphics driver package has been installed.\n" + "Restart the Linyaps app to experience the performance improvement.")); + successRequest.timeout = 5000; // 5 seconds + auto successResult = notifier->sendSimpleNotification(successRequest); + if (!successResult) { + LogW("Failed to send success notification: {}", successResult.error().message()); + } + } else if (response.action == kActionNotRemind && response.success) { + LogD("User chose not to be reminded again"); + configManager.recordUserChoice(UserNotificationChoice::NeverRemind); + configManager.saveConfig(); + } else { + LogD("User dismissed notification or timeout, no action taken"); + } + + LogD("Driver detection completed successfully"); + return 0; +} diff --git a/apps/ll-driver-detect/src/nvidia_driver_detector.cpp b/apps/ll-driver-detect/src/nvidia_driver_detector.cpp new file mode 100644 index 000000000..6524366ff --- /dev/null +++ b/apps/ll-driver-detect/src/nvidia_driver_detector.cpp @@ -0,0 +1,109 @@ +// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "nvidia_driver_detector.h" + +#include "linglong/utils/command/cmd.h" +#include "linglong/utils/error/error.h" +#include "linglong/utils/log/log.h" + +#include +#include + +namespace linglong::driver::detect { + +NVIDIADriverDetector::NVIDIADriverDetector(std::string versionFilePath) + : versionFilePath_(std::move(versionFilePath)) +{ +} + +utils::error::Result NVIDIADriverDetector::detect() +{ + LINGLONG_TRACE("NVIDIA driver detection started"); + + // Get driver version + auto version = getDriverVersion(); + if (version.empty()) { + return LINGLONG_ERR("Failed to get NVIDIA driver version"); + } + + auto linglongPackageName = getDriverIdentify() + "." + version; + + // Check if package exists in repo + auto existsResult = checkPackageExists(linglongPackageName); + if (!existsResult) { + return LINGLONG_ERR("Failed to check if package exists: " + existsResult.error().message()); + } + + // Check if package is installed + auto installedResult = checkPackageInstalled(linglongPackageName); + if (!installedResult) { + return LINGLONG_ERR("Failed to check package installation: " + + installedResult.error().message()); + } + + return GraphicsDriverInfo{ getDriverIdentify(), + version, + linglongPackageName, + *installedResult }; +} + +utils::error::Result NVIDIADriverDetector::checkPackageExists(const std::string &packageName) +{ + LINGLONG_TRACE("Check if NVIDIA driver package exists in repository"); + // Execute ll-cli search command to check driver package existence + auto ret = linglong::utils::command::Cmd("ll-cli").exec( + { "search", QString::fromStdString(packageName) }); + if (!ret) { + return LINGLONG_ERR("Search command failed: " + ret.error().message()); + } + + if (!ret->contains(QString::fromStdString(packageName))) { + return LINGLONG_ERR("Driver package not found in linglong repo: " + packageName); + } + return LINGLONG_OK; +} + +utils::error::Result +NVIDIADriverDetector::checkPackageInstalled(const std::string &packageName) +{ + LINGLONG_TRACE("Check if NVIDIA driver package is installed"); + + try { + // First execute ll-cli info to get the package info + auto listResult = + linglong::utils::command::Cmd("ll-cli").exec({ "info", packageName.c_str() }); + + if (!listResult) { + LogD("Can not get package info with `ll-cli info`, maybe the package is not installed: {}", + listResult.error().message()); + return false; + } + + return true; + } catch (const std::exception &e) { + return LINGLONG_ERR("Failed to check package installation: " + std::string(e.what())); + } +} + +std::string NVIDIADriverDetector::getDriverVersion() +{ + std::string version; + + if (!std::filesystem::exists(versionFilePath_)) { + LogW("NVIDIA version file not found: {}", versionFilePath_); + return version; + } + + std::ifstream versionFile(versionFilePath_); + if (versionFile) { + versionFile >> version; + + std::replace(version.begin(), version.end(), '.', '-'); + } + + return version; +} + +} // namespace linglong::driver::detect diff --git a/apps/ll-driver-detect/src/nvidia_driver_detector.h b/apps/ll-driver-detect/src/nvidia_driver_detector.h new file mode 100644 index 000000000..21c97735b --- /dev/null +++ b/apps/ll-driver-detect/src/nvidia_driver_detector.h @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#pragma once + +#include "driver_detector.h" + +#include + +namespace linglong::driver::detect { + +class NVIDIADriverDetector : public DriverDetector +{ +public: + static constexpr auto kNvidiaPackageIdentify = "org.deepin.driver.display.nvidia"; + static constexpr auto kDefaultNvidiaVersionFile = "/sys/module/nvidia/version"; + + explicit NVIDIADriverDetector(std::string versionFilePath = kDefaultNvidiaVersionFile); + ~NVIDIADriverDetector() override = default; + + // Main detection method - returns driver info if detected + utils::error::Result detect() override; + + // Check if the driver package is installed + utils::error::Result checkPackageInstalled(const std::string &packageName) override; + + // Check if the driver package exists in repo + virtual utils::error::Result checkPackageExists(const std::string &packageName); + + // Get the type of driver this detector handles + std::string getDriverIdentify() const override { return kNvidiaPackageIdentify; } + +private: + // Get driver version from the specified file path + std::string getDriverVersion(); + + std::string versionFilePath_; +}; + +} // namespace linglong::driver::detect diff --git a/apps/ll-init/CMakeLists.txt b/apps/ll-init/CMakeLists.txt new file mode 100644 index 000000000..d56cbc340 --- /dev/null +++ b/apps/ll-init/CMakeLists.txt @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +pfl_add_executable(SOURCES ./src/ll-init.cpp OUTPUT_NAME ll-init LIBEXEC + linglong) + +set(LL_INIT_TARGET) + +get_real_target_name(LL_INIT_TARGET linglong::ll-init) +target_link_libraries(${LL_INIT_TARGET} PRIVATE stdc++fs) +target_link_options(${LL_INIT_TARGET} PRIVATE -static -static-libgcc + -static-libstdc++) diff --git a/apps/ll-init/src/ll-init.cpp b/apps/ll-init/src/ll-init.cpp new file mode 100644 index 000000000..5690092f2 --- /dev/null +++ b/apps/ll-init/src/ll-init.cpp @@ -0,0 +1,715 @@ +// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +// no need to block these signals +constexpr std::array unblock_signals{ SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, + SIGSYS, SIGTRAP, SIGXCPU, SIGXFSZ }; + +// now, we just inherit the control terminal from the outside and put all the processes in the +// same process group. maybe we need refactor this in the future. + +namespace { + +struct WaitPidResult +{ + pid_t pid; + int status; +}; + +void print_sys_error(std::string_view msg) noexcept +{ + std::cerr << msg << ": " << ::strerror(errno) << std::endl; +} + +void print_sys_error(std::string_view msg, const std::error_code &ec) noexcept +{ + std::cerr << msg << ": " << ec.message() << std::endl; +} + +void print_info(std::string_view msg) noexcept +{ + static const auto is_debug = ::getenv("LINYAPS_INIT_VERBOSE_OUTPUT") != nullptr; + if (is_debug) { + std::cerr << msg << std::endl; + } +} + +class sigConf +{ +public: + sigConf() noexcept = default; + sigConf(const sigConf &) = delete; + sigConf(sigConf &&) = delete; + sigConf &operator=(const sigConf &) = delete; + sigConf &operator=(sigConf &&) = delete; + ~sigConf() noexcept = default; + + bool block_signals() noexcept + { + ::sigfillset(&cur_set); + for (auto signal : unblock_signals) { + ::sigdelset(&cur_set, signal); + } + + // ignore the rest of the signals + auto ret = ::sigprocmask(SIG_SETMASK, &cur_set, &old_set); + if (ret == -1) { + print_sys_error("Failed to set signal mask"); + return false; + } + + return true; + } + + [[nodiscard]] bool restore_signals() const noexcept + { + auto ret = ::sigprocmask(SIG_SETMASK, &old_set, nullptr); + if (ret == -1) { + print_sys_error("Failed to restore signal mask"); + return false; + } + + return true; + } + + [[nodiscard]] const sigset_t ¤t_sigset() const noexcept { return cur_set; } + +private: + sigset_t cur_set{}; + sigset_t old_set{}; +}; + +class file_descriptor_wrapper +{ +public: + explicit file_descriptor_wrapper(int fd) noexcept + : fd(fd) + { + } + + file_descriptor_wrapper() noexcept = default; + + file_descriptor_wrapper(const file_descriptor_wrapper &) = delete; + file_descriptor_wrapper &operator=(const file_descriptor_wrapper &) = delete; + + file_descriptor_wrapper(file_descriptor_wrapper &&other) noexcept + : fd(other.fd) + { + other.fd = -1; + } + + file_descriptor_wrapper &operator=(file_descriptor_wrapper &&other) noexcept + { + if (this == &other) { + return *this; + } + + close(); + fd = other.fd; + other.fd = -1; + + return *this; + } + + ~file_descriptor_wrapper() noexcept { close(); } + + void close() noexcept + { + if (fd != -1) { + ::close(fd); + fd = -1; + } + } + + explicit operator bool() const noexcept { return fd != -1; } + + operator int() const noexcept { return fd; } // NOLINT + +private: + int fd{ -1 }; +}; + +file_descriptor_wrapper create_signalfd(const sigset_t &sigset) noexcept +{ + auto fd = ::signalfd(-1, &sigset, SFD_NONBLOCK); + if (fd == -1) { + print_sys_error("Failed to create signalfd"); + } + + return file_descriptor_wrapper(fd); +} + +file_descriptor_wrapper create_timerfd() noexcept +{ + auto fd = ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); + if (fd == -1) { + print_sys_error("Failed to create timerfd"); + } + + return file_descriptor_wrapper(fd); +} + +file_descriptor_wrapper create_epoll() noexcept +{ + auto fd = ::epoll_create1(0); + if (fd == -1) { + print_sys_error("Failed to create epoll"); + } + + return file_descriptor_wrapper(fd); +} + +template +constexpr auto make_array(const char (&str)[N]) noexcept // NOLINT +{ + static_assert(N > 0, "N must be greater than 0"); + std::array arr{}; + for (std::size_t i = 0; i < N - 1; ++i) { + arr[i] = str[i]; + } + + return arr; +} + +std::pair get_socket_address() noexcept +{ + constexpr auto fs_addr{ make_array("/run/linglong/init/socket") }; + + struct sockaddr_un addr{}; + addr.sun_family = AF_UNIX; + + std::copy(fs_addr.cbegin(), fs_addr.cend(), &addr.sun_path[0]); + addr.sun_path[fs_addr.size()] = 0; + return std::make_pair(addr, offsetof(sockaddr_un, sun_path) + fs_addr.size()); +} + +file_descriptor_wrapper create_fs_uds() noexcept +{ + auto fd = ::socket(AF_UNIX, SOCK_NONBLOCK | SOCK_SEQPACKET, 0); + file_descriptor_wrapper socket_fd{ fd }; + if (fd == -1) { + print_sys_error("Failed to create unix domain socket"); + return socket_fd; + } + + auto [addr, len] = get_socket_address(); + if (len == 0) { + print_info("Failed to get socket address"); + return socket_fd; + } + + // just in case the socket file exists + ::unlink(addr.sun_path); + + auto ret = ::bind(socket_fd, reinterpret_cast(&addr), len); + if (ret == -1) { + print_sys_error("Failed to bind unix domain socket"); + return socket_fd; + } + + ret = ::listen(socket_fd, 1); + if (ret == -1) { + print_sys_error("Failed to listen on unix domain socket"); + return socket_fd; + } + + return socket_fd; +} + +std::vector parse_args(int argc, char *argv[]) noexcept +{ + std::vector args; + int idx{ 1 }; + + while (idx < argc) { + args.emplace_back(argv[idx++]); + } + args.emplace_back(nullptr); + + return args; +} + +void print_child_status(int status, const std::string &pid) noexcept +{ + if (WIFEXITED(status)) { + print_info("child " + pid + " exited with status " + std::to_string(WEXITSTATUS(status))); + } else if (WIFSIGNALED(status)) { + print_info("child " + pid + " exited with signal " + std::to_string(WTERMSIG(status))); + } else { + print_info("child " + pid + " exited with unknown status"); + } +} + +pid_t run(std::vector args, const sigConf &conf) noexcept +{ + auto pid = ::fork(); + if (pid == -1) { + print_sys_error("Failed to fork"); + return -1; + } + + if (pid == 0) { + auto ret = ::setpgid(0, 0); + if (ret == -1) { + print_sys_error("Failed to set process group"); + return -1; + } + + ret = ::tcsetpgrp(0, ::getpid()); + if (ret == -1 && errno != ENOTTY) { + print_sys_error("Failed to set terminal process group"); + return -1; + } + + if (!conf.restore_signals()) { + return -1; + } + + ::execvp(args[0], const_cast(args.data())); + print_sys_error("Failed to run process"); + ::_exit(EXIT_FAILURE); + } + + return pid; +} + +bool handle_sigevent(const file_descriptor_wrapper &sigfd, + pid_t child, + struct WaitPidResult &waitChild) noexcept +{ + while (true) { + signalfd_siginfo info{}; + auto ret = ::read(sigfd, &info, sizeof(info)); + if (ret == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + break; + } + + print_sys_error("Failed to read from signalfd"); + return false; + } + + if (info.ssi_signo != SIGCHLD) { + auto ret = ::kill(child, info.ssi_signo); + if (ret == -1) { + auto msg = std::string("Failed to forward signal ") + ::strsignal(info.ssi_signo); + print_sys_error(msg); + } + continue; + } + + while (true) { + int status{}; + auto ret = ::waitpid(-1, &status, WNOHANG); + if (ret == 0 || (ret == -1 && errno == ECHILD)) { + break; + } + + if (ret == -1) { + print_sys_error("Failed to wait for child"); + return false; + } + + print_child_status(status, std::to_string(ret)); + + if (ret == child) { + waitChild.pid = child; + waitChild.status = status; + } + } + } + + return true; +} + +bool shouldWait() noexcept +{ + std::error_code ec; + auto proc_it = std::filesystem::directory_iterator{ + "/proc", + std::filesystem::directory_options::skip_permission_denied, + ec + }; + + if (ec) { + print_sys_error("Failed to open /proc", ec); + return false; + } + + for (const auto &entry : proc_it) { + if (!entry.is_directory(ec)) { + continue; + } + + if (ec) { + print_sys_error("Failed to stat " + entry.path().string(), ec); + return false; + } + + pid_t pid{ -1 }; + try { + pid = std::stoi(entry.path().filename()); + } catch (...) { + continue; + } + + if (pid == 1) { // ignore init process + continue; + } + + // if we get here, it means some process is still alive + return true; + } + + return false; +} + +int handle_timerfdevent(const file_descriptor_wrapper &timerfd) noexcept +{ + // we don't care how many times we read from the timerfd + // just traversal the /proc directory once + while (true) { + uint64_t expir{}; + auto ret = ::read(timerfd, &expir, sizeof(expir)); + if (ret == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + break; + } + + print_sys_error("Failed to read from timerfd"); + return -1; + } + } + + return shouldWait() ? 1 : 0; +} + +file_descriptor_wrapper start_timer(const file_descriptor_wrapper &epfd) noexcept +{ + auto timerfd = create_timerfd(); + if (!timerfd) { + return timerfd; + } + + struct itimerspec timer_spec{}; + auto *interval = ::getenv("LINYAPS_INIT_WAIT_INTERVAL"); + constexpr auto default_interval{ 3 }; + if (interval != nullptr) { + try { + auto interval_int = std::stoi(interval); + timer_spec.it_interval.tv_sec = interval_int; + timer_spec.it_interval.tv_nsec = 0; + } catch (...) { + print_info("Invalid interval, using default 3 seconds"); + timer_spec.it_interval.tv_sec = default_interval; + timer_spec.it_interval.tv_nsec = 0; + } + } else { + timer_spec.it_interval.tv_sec = default_interval; + timer_spec.it_interval.tv_nsec = 0; + } + timer_spec.it_value.tv_sec = default_interval; + timer_spec.it_value.tv_nsec = 0; + + auto ret = ::timerfd_settime(timerfd, 0, &timer_spec, nullptr); + if (ret == -1) { + print_sys_error("Failed to set timerfd"); + return {}; + } + + struct epoll_event timer_ev{ .events = EPOLLIN | EPOLLET, .data = { .fd = timerfd } }; // NOLINT + ret = ::epoll_ctl(epfd, EPOLL_CTL_ADD, timerfd, &timer_ev); + if (ret == -1) { + print_sys_error("Failed to add timerfd to epoll"); + return {}; + } + + return timerfd; +} + +unsigned long get_arg_max() noexcept +{ + auto arg_max = sysconf(_SC_ARG_MAX); + if (arg_max == -1) { + return static_cast(256 * 1024); + } + + return arg_max - 4096; +} + +int delegate_run(const std::vector &args, const sigConf &conf) noexcept +{ + auto child = fork(); + if (child == -1) { + print_sys_error("Failed to fork child"); + return -1; + } + + if (child == 0) { + std::vector c_args; + c_args.reserve(args.size()); + for (const auto &arg : args) { + c_args.emplace_back(const_cast(arg.c_str())); + } + c_args.emplace_back(nullptr); + + if (!conf.restore_signals()) { + ::_exit(EXIT_FAILURE); + } + + ::execvp(c_args[0], c_args.data()); + print_sys_error("Failed to exec"); + ::_exit(EXIT_FAILURE); + } + + return 0; +} + +bool handle_client(const file_descriptor_wrapper &unix_socket, const sigConf &conf) noexcept +{ + static const unsigned long arg_max = get_arg_max(); + + const file_descriptor_wrapper client{ ::accept(unix_socket, nullptr, nullptr) }; + if (!client) { + print_sys_error("Failed to accept client"); + return false; + } + + const struct timeval tv{ 3, 0 }; + if (::setsockopt(client, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { + print_sys_error("Failed to set recv timeout"); + return false; + } + + std::uint64_t arg_len{ 0 }; + auto ret = ::recv(client, &arg_len, sizeof(arg_len), 0); + if (ret == -1) { + print_sys_error("Failed to read from client"); + return false; + } + + if (arg_len > arg_max) { + print_info("Command too long"); + return false; + } + + std::string command_buffer; + command_buffer.reserve(arg_len); + std::array buffer{}; + while (true) { + auto readBytes = ::recv(client, buffer.data(), buffer.size(), 0); + if (readBytes < 0) { + print_sys_error("Failed to read from client"); + return false; + } + + command_buffer.append(buffer.data(), readBytes); + + if (command_buffer.size() >= arg_len) { + break; + } + } + + if (command_buffer.empty()) { + print_info("Empty command"); + return false; + } + + if (command_buffer.back() != 0) { + command_buffer.push_back(0); + } + + std::vector commands; + auto start = command_buffer.cbegin(); + while (start != command_buffer.end()) { + auto end{ start }; + while (end != command_buffer.end() && *end != 0) { + ++end; + } + + commands.emplace_back(start, end); + start = end + 1; + } + + if (commands.empty()) { + print_info("Command may be invalid"); + return false; + } + + ret = delegate_run(commands, conf); + if (ret == -1) { + print_sys_error("Failed to delegate command"); + } + + if (::send(client, &ret, sizeof(ret), 0) == -1) { + print_sys_error("Failed to send result to client"); + } + + return true; +} + +bool register_event(const file_descriptor_wrapper &epfd, + const file_descriptor_wrapper &fd, + epoll_event ev) noexcept +{ + auto ret = ::epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev); + if (ret == -1) { + print_sys_error("Failed to add event to epoll"); + return false; + } + + return true; +} + +} // namespace + +int main(int argc, char **argv) // NOLINT +{ + sigConf conf; + if (!conf.block_signals()) { + return -1; + } + + auto ret = ::prctl(PR_SET_CHILD_SUBREAPER, 1); + if (ret == -1) { + print_sys_error("Failed to set child subreaper"); + return -1; + } + + auto args = parse_args(argc, argv); + if (args.empty()) { + print_info("No arguments provided"); + return -1; + } + + auto *singleModeEnv = ::getenv("LINYAPS_INIT_SINGLE_MODE"); + const bool singleMode = singleModeEnv != nullptr && std::string_view{ singleModeEnv } == "1"; + + auto child = run(args, conf); + if (child == -1) { + print_info("Failed to run child process"); + return -1; + } + + auto epfd = create_epoll(); + if (!epfd) { + return -1; + } + + auto sigfd = create_signalfd(conf.current_sigset()); + if (!sigfd) { + return -1; + } + + const struct epoll_event ev{ .events = EPOLLIN | EPOLLET, .data = { .fd = sigfd } }; + if (!register_event(epfd, sigfd, ev)) { + return -1; + } + + file_descriptor_wrapper unix_socket; + if (!singleMode) { + unix_socket = create_fs_uds(); + if (!unix_socket) { + return -1; + } + + const struct epoll_event ev{ .events = EPOLLIN | EPOLLET, + .data = { .fd = unix_socket } }; // NOLINT + if (!register_event(epfd, unix_socket, ev)) { + return -1; + } + } + + file_descriptor_wrapper timerfd; + bool done{ false }; + std::array events{}; + WaitPidResult waitChild{ .pid = child }; + int childExitCode = 0; + while (true) { + ret = ::epoll_wait(epfd, events.data(), events.size(), -1); + if (ret == -1) { + if (errno == EINTR) { + continue; + } + + print_sys_error("Failed to wait for events"); + return -1; + } + + for (auto i = 0; i < ret; ++i) { + const auto event = events.at(i); + if (event.data.fd == sigfd) { + if (!handle_sigevent(sigfd, waitChild.pid, waitChild)) { + return -1; + } + + if (waitChild.pid == child) { + // Init process will propagate received signals to all child processes (using + // pid -1) after initial child exits + if (WIFEXITED(waitChild.status)) { + waitChild.pid = -1; + childExitCode = WEXITSTATUS(waitChild.status); + } else if (WIFSIGNALED(waitChild.status)) { + waitChild.pid = -1; + childExitCode = 128 + WTERMSIG(waitChild.status); + } + + if (!shouldWait()) { + done = true; + } + timerfd = start_timer(epfd); + if (!timerfd) { + return -1; + } + } + + continue; + } + + if (event.data.fd == timerfd) { + ret = handle_timerfdevent(timerfd); + if (ret == -1) { + return -1; + } + + if (ret == 0) { + done = true; + } + + continue; + } + + if (unix_socket && event.data.fd == unix_socket) { + if (handle_client(unix_socket, conf)) { + done = false; + } + } + } + + if (done) { + unix_socket.close(); + break; + } + } + + return childExitCode; +} diff --git a/apps/ll-package-manager/src/main.cpp b/apps/ll-package-manager/src/main.cpp index eeb026cd2..cd5ddd6d2 100644 --- a/apps/ll-package-manager/src/main.cpp +++ b/apps/ll-package-manager/src/main.cpp @@ -4,12 +4,12 @@ * SPDX-License-Identifier: LGPL-3.0-or-later */ +#include "configure.h" #include "linglong/adaptors/package_manager/package_manager1.h" #include "linglong/package_manager/package_manager.h" #include "linglong/repo/config.h" #include "linglong/repo/migrate.h" #include "linglong/repo/ostree_repo.h" -#include "linglong/utils/configure.h" #include "linglong/utils/dbus/register.h" #include "linglong/utils/global/initialize.h" #include "ocppi/cli/CLI.hpp" @@ -32,10 +32,6 @@ void withDBusDaemon(ocppi::cli::CLI &cli) QCoreApplication::exit(-1); return; } - const auto defaultRepo = linglong::repo::getDefaultRepo(*config); - qWarning() << "server" << defaultRepo.url.c_str(); - auto *clientFactory = new linglong::repo::ClientFactory(defaultRepo.url); - clientFactory->setParent(QCoreApplication::instance()); auto repoRoot = QDir(LINGLONG_ROOT); if (!repoRoot.exists() && !repoRoot.mkpath(".")) { @@ -48,7 +44,7 @@ void withDBusDaemon(ocppi::cli::CLI &cli) qCritical() << "failed to migrate repository"; QCoreApplication::exit(-1); } - auto *ostreeRepo = new linglong::repo::OSTreeRepo(repoRoot, *config, *clientFactory); + auto *ostreeRepo = new linglong::repo::OSTreeRepo(repoRoot, *config); ostreeRepo->setParent(QCoreApplication::instance()); auto result = ostreeRepo->fixExportAllEntries(); if (!result.has_value()) { @@ -101,17 +97,13 @@ void withoutDBusDaemon(ocppi::cli::CLI &cli) return; } - const auto defaultRepo = linglong::repo::getDefaultRepo(*config); - auto *clientFactory = new linglong::repo::ClientFactory(defaultRepo.url); - clientFactory->setParent(QCoreApplication::instance()); - auto repoRoot = QDir(LINGLONG_ROOT); if (!repoRoot.exists() && !repoRoot.mkpath(".")) { qCritical() << "failed to create repository directory" << repoRoot.absolutePath(); std::abort(); } - auto *ostreeRepo = new linglong::repo::OSTreeRepo(repoRoot, *config, *clientFactory); + auto *ostreeRepo = new linglong::repo::OSTreeRepo(repoRoot, *config); ostreeRepo->setParent(QCoreApplication::instance()); auto result = ostreeRepo->fixExportAllEntries(); if (!result.has_value()) { @@ -159,6 +151,7 @@ auto main(int argc, char *argv[]) -> int QCoreApplication app(argc, argv); applicationInitialize(); + initLinyapsLogSystem(linglong::utils::log::LogBackend::Journal); auto ociRuntimeCLI = qgetenv("LINGLONG_OCI_RUNTIME"); if (ociRuntimeCLI.isEmpty()) { diff --git a/apps/uab/README.md b/apps/uab/README.md index 690e5c589..095d86e14 100644 --- a/apps/uab/README.md +++ b/apps/uab/README.md @@ -1,6 +1,6 @@ # uab-header -**uab-header** is a template binary which is used by ll-builder to build uab *(Universal Application Bundle)*. +**uab-header** is a template binary which is used by ll-builder to build uab _(Universal Application Bundle)_. Due to one of the goals of Uab is to depends as few runtime dependencies as possible, uab-header will **statically link all dependent libraries** at compile time. It is important to note that when some of the system's base libraries are upgraded, it may cause uab to fail to run properly diff --git a/apps/uab/header/src/light_elf.h b/apps/uab/header/src/light_elf.h index 106124f51..517a8d5a2 100644 --- a/apps/uab/header/src/light_elf.h +++ b/apps/uab/header/src/light_elf.h @@ -117,7 +117,7 @@ class Elf shdrstrndx = shdr.sh_link; } - auto shdrstrtab = elfHeader.e_shoff + shdrstrndx * elfHeader.e_shentsize; + auto shdrstrtab = elfHeader.e_shoff + (shdrstrndx * elfHeader.e_shentsize); bytesRead = ::pread(fd, &shdr, section_size, shdrstrtab); if (bytesRead == -1) { throw std::runtime_error("failed to read section header string table of" + path.string() diff --git a/apps/uab/header/src/main.cpp b/apps/uab/header/src/main.cpp index 64da70dce..36ecb2201 100644 --- a/apps/uab/header/src/main.cpp +++ b/apps/uab/header/src/main.cpp @@ -1,12 +1,11 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024 - 2025 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "light_elf.h" -#include "linglong/api/types/v1/Generators.hpp" +#include "linglong/api/types/v1/Generators.hpp" // IWYU pragma: keep #include "linglong/api/types/v1/UabMetaInfo.hpp" #include "sha256.h" -#include "utils.h" #include #include @@ -14,27 +13,29 @@ #include #include -#include #include #include -#include #include #include #include #include -#include #include +#include #include +#include #include #include #include extern "C" int erofsfuse_main(int argc, char **argv); -static std::atomic_bool mountFlag{ false }; // NOLINT -static std::atomic_bool createFlag{ false }; // NOLINT -static std::filesystem::path mountPoint; // NOLINT +namespace { + +std::atomic_bool mountFlag{ false }; // NOLINT +std::atomic_bool createFlag{ false }; // NOLINT +std::filesystem::path mountPoint; // NOLINT +constexpr std::size_t default_page_size = 4096; constexpr auto usage = u8R"(Linglong Universal Application Bundle @@ -45,11 +46,28 @@ uabBundle [uabOptions...] [-- loaderOptions...] Options: --extract=PATH extract the read-only filesystem image which is in the 'linglong.bundle' segment of uab to PATH. [exclusive] + --mount=PATH mount the read-only filesystem image which is in the 'linglong.bundle' segment of uab to PATH, use ctrl+c to stop. [exclusive] --print-meta print content of json which from the 'linglong.meta' segment of uab to STDOUT [exclusive] --help print usage of uab [exclusive] )"; -std::string resolveRealPath(std::string_view source) noexcept +enum uabOption : std::uint8_t { + Help = 1, + Extract, + Mount, + Meta, +}; + +struct argOption +{ + bool help{ false }; + bool printMeta{ false }; + std::string extractPath; + std::string mountPath; + std::vector loaderArgs; +}; + +std::string resolveRealPath(const std::string &source) noexcept { std::array resolvedPath{}; @@ -62,63 +80,121 @@ std::string resolveRealPath(std::string_view source) noexcept return { ptr }; } +std::size_t getChunkSize(std::size_t bundleSize) noexcept +{ + std::size_t page_size{ default_page_size }; + const auto ret = sysconf(_SC_PAGESIZE); + if (ret > 0) { + page_size = ret; + } + + std::size_t block_size{ 0 }; + struct statvfs fs_info{}; + if (statvfs(".", &fs_info) > 0) { + block_size = fs_info.f_bsize; + } + + const auto base_block = std::max(page_size, block_size); + if (bundleSize <= static_cast(10 * 1024 * 1024)) { + return 64 * base_block; + } + + if (bundleSize <= static_cast(100 * 1024 * 1024)) { + return 128 * base_block; + } + + return 256 * base_block; +} + std::string calculateDigest(int fd, std::size_t bundleOffset, std::size_t bundleLength) noexcept { digest::SHA256 sha256; - std::array buf{}; - std::array md_value{}; - auto expectedRead = buf.size(); - int readLength{ 0 }; - - while ((readLength = ::pread(fd, buf.data(), expectedRead, bundleOffset)) != 0) { - if (readLength == -1) { - if (errno == EINTR) { - continue; - } + std::array digest{}; + auto *mem = mmap(nullptr, bundleLength, PROT_READ, MAP_PRIVATE, fd, bundleOffset); + if (mem != MAP_FAILED) { + posix_madvise(mem, bundleLength, POSIX_FADV_WILLNEED | POSIX_FADV_SEQUENTIAL); + sha256.update(reinterpret_cast(mem), bundleLength); + if (munmap(mem, bundleLength) == -1) { + std::cerr << "munmap error:" << ::strerror(errno) << std::endl; + } + } else { + // fallback to read blocks + posix_fadvise(fd, bundleOffset, bundleLength, POSIX_FADV_WILLNEED | POSIX_FADV_SEQUENTIAL); + std::align_val_t alignment{ default_page_size }; + if (auto ret = sysconf(_SC_PAGESIZE); ret > 0) { + alignment = static_cast(ret); + } - std::cerr << "read uab error:" << ::strerror(errno) << std::endl; + auto chunkSize = getChunkSize(bundleLength); + auto *buf = ::operator new(chunkSize, alignment, std::nothrow); + if (buf == nullptr) { + std::cerr << "failed to allocate aligned memory" << std::endl; return {}; } - sha256.update(buf.data(), readLength); + auto deleter = [alignment](void *ptr) noexcept { + ::operator delete(ptr, alignment, std::nothrow); + }; + std::unique_ptr buffer{ reinterpret_cast(buf), + deleter }; + + std::size_t totalRead{ 0 }; + while (totalRead < bundleLength) { + auto remaining = bundleLength - totalRead; + auto readBytes = std::min(remaining, chunkSize); + + auto bytesRead = pread(fd, buffer.get(), readBytes, bundleOffset + totalRead); + if (bytesRead < 0) { + if (errno == EINTR) { + continue; + } + + std::cerr << "read uab error:" << ::strerror(errno) << std::endl; + return {}; + } - bundleLength -= readLength; - if (bundleLength == 0) { - sha256.final(md_value.data()); - break; - } + if (bytesRead == 0) { + break; + } - bundleOffset += readLength; - expectedRead = bundleLength > buf.size() ? buf.size() : bundleLength; + sha256.update(buffer.get(), bytesRead); + totalRead += bytesRead; + } } + sha256.final(digest.data()); + std::stringstream stream; stream << std::setfill('0') << std::hex; - for (auto v : md_value) { + for (auto v : digest) { stream << std::setw(2) << static_cast(v); } return stream.str(); } -std::string find_fusermount() +std::optional find_fusermount() noexcept { - std::string res; - - const char *path = getenv("PATH"); - if (!path) { - return res; + auto *pathEnv = getenv("PATH"); + if (pathEnv == nullptr) { + return std::nullopt; } - auto search_dir = [](std::filesystem::path dir, std::string &res) { + auto search_dir = [](const std::filesystem::path &dir) -> std::optional { std::error_code ec; - auto iter = std::filesystem::directory_iterator{ dir, ec }; + auto iter = std::filesystem::directory_iterator{ + dir, + std::filesystem::directory_options::skip_permission_denied, + ec + }; + if (ec) { std::cerr << "failed to open directory " << dir << ": " << ec.message() << std::endl; - return false; + return std::nullopt; } - for (auto const &entry : iter) { + + for (const auto &entry : iter) { std::string filename = entry.path().filename(); if (filename.rfind("fusermount", 0) != 0) { continue; @@ -128,7 +204,7 @@ std::string find_fusermount() continue; } - struct stat sb; + struct stat sb{}; if (stat(entry.path().c_str(), &sb) == -1) { std::cerr << "stat error: " << strerror(errno) << std::endl; continue; @@ -136,37 +212,25 @@ std::string find_fusermount() if (sb.st_uid != 0 || (sb.st_mode & S_ISUID) == 0) { std::cerr << "skip " << entry.path() << std::endl; - ; continue; } - res = entry.path(); - return true; + return entry.path(); } - return false; + return std::nullopt; }; - const char *begin = path; - const char *end = path + strlen(path); - - while (begin < end) { - const char *colon = std::strchr(begin, ':'); - if (!colon) { - colon = end; + std::stringstream ss{ pathEnv }; + std::string path; + while (std::getline(ss, path, ':')) { + auto res = search_dir(path); + if (res) { + return res; } - - std::string dir(begin, colon); - if (!dir.empty()) { - if (search_dir(dir, res)) { - return res; - } - } - - begin = colon + 1; } - return res; + return std::nullopt; } int mountSelfBundle(const lightElf::native_elf &elf, @@ -209,11 +273,11 @@ int mountSelfBundle(const lightElf::native_elf &elf, } } - if (!getenv("FUSERMOUNT_PROG")) { + if (getenv("FUSERMOUNT_PROG") == nullptr) { auto fuserMountProg = find_fusermount(); - if (!fuserMountProg.empty()) { - setenv("FUSERMOUNT_PROG", fuserMountProg.c_str(), 1); - std::cerr << "use fusermount:" << fuserMountProg << std::endl; + if (fuserMountProg) { + setenv("FUSERMOUNT_PROG", fuserMountProg.value().c_str(), 1); + std::cerr << "use fusermount:" << fuserMountProg->string() << std::endl; } else { std::cerr << "fusermount not found" << std::endl; } @@ -223,16 +287,25 @@ int mountSelfBundle(const lightElf::native_elf &elf, } int status{ 0 }; - auto ret = ::waitpid(fusePid, &status, 0); - if (ret == -1) { - std::cerr << "waitpid() failed:" << ::strerror(errno) << std::endl; - return -1; + while (true) { + auto ret = ::waitpid(fusePid, &status, 0); + if (ret < 0) { + if (errno == EINTR) { + continue; + } + std::cerr << "waitpid() failed:" << ::strerror(errno) << std::endl; + return -1; + } + break; } - ret = WEXITSTATUS(status); - if (ret != 0) { - std::cerr << "couldn't mount bundle, fuse error code:" << ret << std::endl; - ret = -1; + int ret{ -1 }; + if (WIFEXITED(status)) { + auto code = WEXITSTATUS(status); + ret = code; + } else if (WIFSIGNALED(status)) { + auto sig = WTERMSIG(status); + std::cerr << "erofsfuse terminated due to signal " << strsignal(sig) << std::endl; } return ret; @@ -240,58 +313,48 @@ int mountSelfBundle(const lightElf::native_elf &elf, void cleanResource() noexcept { - auto umountRet = [] { - if (!mountFlag.load(std::memory_order_relaxed)) { - return true; - } - - auto pid = fork(); - if (pid < 0) { - std::cerr << "fork() error" << ": " << ::strerror(errno) << std::endl; - return false; - } + if (!mountFlag.load(std::memory_order_relaxed)) { + return; + } - if (pid == 0) { - if (::execlp("fusermount", "fusermount", "-z", "-u", mountPoint.c_str(), nullptr) - == -1) { - std::cerr << "fusermount error: " << ::strerror(errno) << std::endl; - return false; - } - } + auto pid = fork(); + if (pid < 0) { + std::cerr << "fork() error" << ": " << ::strerror(errno) << std::endl; + return; + } - int status{ 0 }; - auto ret = ::waitpid(pid, &status, 0); - if (ret == -1) { - std::cerr << "wait failed:" << ::strerror(errno) << std::endl; - return false; + if (pid == 0) { + if (::execlp("fusermount", "fusermount", "-z", "-u", mountPoint.c_str(), nullptr) == -1) { + std::cerr << "fusermount error: " << ::strerror(errno) << std::endl; + ::_exit(1); } - mountFlag.store(false, std::memory_order_relaxed); - return true; - }(); - - if (umountRet && createFlag.load(std::memory_order_relaxed)) { - std::error_code ec; - if (!std::filesystem::exists(mountPoint, ec)) { - if (ec) { - std::cerr << "filesystem error " << mountPoint << ":" << ec.message() << std::endl; - return; - } + ::_exit(0); + } - createFlag.store(false, std::memory_order_relaxed); - return; - } + int status{ 0 }; + auto ret = ::waitpid(pid, &status, 0); + if (ret == -1) { + std::cerr << "wait failed:" << ::strerror(errno) << std::endl; + return; + } + mountFlag.store(false, std::memory_order_relaxed); - if (std::filesystem::remove_all(mountPoint, ec) == static_cast(-1) || ec) { - std::cerr << "failed to remove mount point:" << ec.message() << std::endl; - return; - } + if (!createFlag.load(std::memory_order_relaxed)) { + return; + } - createFlag.store(false, std::memory_order_relaxed); + // try to remove mount point + std::error_code ec; + if (std::filesystem::remove_all(mountPoint, ec) == static_cast(-1) && ec) { + std::cerr << "failed to remove mount point:" << ec.message() << std::endl; + return; } + + createFlag.store(false, std::memory_order_relaxed); } -[[noreturn]] static void cleanAndExit(int exitCode) noexcept +[[noreturn]] void cleanAndExit(int exitCode) noexcept { cleanResource(); ::_exit(exitCode); @@ -299,20 +362,19 @@ void cleanResource() noexcept void handleSig() noexcept { - auto handler = [](int sig) -> void { - cleanAndExit(sig); - }; - sigset_t blocking_mask; sigemptyset(&blocking_mask); - auto quitSignals = { SIGTERM, SIGINT, SIGQUIT, SIGHUP, SIGABRT, SIGSEGV }; + auto quitSignals = { SIGTERM, SIGINT, SIGQUIT, SIGHUP, SIGABRT }; for (auto sig : quitSignals) { sigaddset(&blocking_mask, sig); } struct sigaction sa{}; - sa.sa_handler = handler; + sa.sa_handler = [](int sig) -> void { + // TODO: maybe not async safe, find a better way to handle signal + cleanAndExit(128 + sig); + }; sa.sa_mask = blocking_mask; sa.sa_flags = 0; @@ -335,16 +397,17 @@ int createMountPoint(std::string_view uuid) noexcept runtimeDirPtr = "/tmp"; } - auto mountPointPath = - std::filesystem::path{ resolveRealPath(runtimeDirPtr) } / "linglong" / "UAB" / uuid; + auto runtimeDir = resolveRealPath(runtimeDirPtr); + if (runtimeDir.empty()) { + return -1; + } + auto mountPointPath = std::filesystem::path{ runtimeDir } / "linglong" / "UAB" / uuid; std::error_code ec; - if (!std::filesystem::create_directories(mountPointPath, ec)) { - if (ec.value() != EEXIST) { - std::cerr << "couldn't create mount point " << mountPoint << ": " << ec.message() - << std::endl; - return ec.value(); - } + if (!std::filesystem::create_directories(mountPointPath, ec) && ec) { + std::cerr << "couldn't create mount point " << mountPointPath << ": " << ec.message() + << std::endl; + return ec.value(); } mountPoint = std::move(mountPointPath); @@ -353,7 +416,8 @@ int createMountPoint(std::string_view uuid) noexcept return 0; } -std::optional getMetaInfo(const lightElf::native_elf &elf) +std::optional +getMetaInfo(const lightElf::native_elf &elf) noexcept { auto metaSh = elf.getSectionHeader("linglong.meta"); if (!metaSh) { @@ -367,11 +431,13 @@ std::optional getMetaInfo(const lightElf: return {}; } - nlohmann::json meta; + std::optional meta; try { - meta = nlohmann::json::parse(content); - } catch (const std::exception &ex) { - std::cerr << "exception: " << ex.what() << std::endl; + auto json = nlohmann::json::parse(content); + meta = json.get(); + } catch (const nlohmann::json::parse_error &e) { + std::cerr << "exception: " << e.what() << std::endl; + return std::nullopt; } return meta; @@ -397,23 +463,32 @@ int extractBundle(std::string_view destination) noexcept return 0; } -[[noreturn]] void runAppLoader(bool onlyApp, - const std::vector &loaderArgs) noexcept +int runAppLoader(const std::vector &loaderArgs) noexcept { auto loader = mountPoint / "loader"; - auto loaderStr = loader.string(); + std::error_code ec; + if (!std::filesystem::exists(loader, ec)) { + if (ec) { + std::cerr << "failed to get loader status" << std::endl; + return -1; + } + + std::cout << "This UAB is not support for runnning" << std::endl; + return 0; + } + auto argc = loaderArgs.size() + 2; auto *argv = new (std::nothrow) const char *[argc](); if (argv == nullptr) { std::cerr << "out of memory, exit." << std::endl; - cleanAndExit(ENOMEM); + return ENOMEM; } auto deleter = defer([argv] { delete[] argv; }); - argv[0] = loaderStr.c_str(); + argv[0] = loader.c_str(); argv[argc - 1] = nullptr; for (std::size_t i = 0; i < loaderArgs.size(); ++i) { argv[i + 1] = loaderArgs[i].data(); @@ -422,20 +497,19 @@ int extractBundle(std::string_view destination) noexcept auto loaderPid = fork(); if (loaderPid < 0) { std::cerr << "fork() error" << ": " << ::strerror(errno) << std::endl; - cleanAndExit(errno); + return errno; } if (loaderPid == 0) { - std::string_view newEnv{ "LINGLONG_UAB_LOADER_ONLY_APP=true" }; - if (onlyApp && ::putenv(const_cast(newEnv.data())) < 0) { - std::cerr << "putenv error: " << ::strerror(errno) << std::endl; - cleanAndExit(errno); + if (::setenv("LINGLONG_UAB_LOADER_ONLY_APP", "true", 1) < 0) { + std::cerr << "setenv error: " << ::strerror(errno) << std::endl; + return errno; } - if (::execv(loaderStr.c_str(), reinterpret_cast(const_cast(argv))) + if (::execv(loader.c_str(), reinterpret_cast(const_cast(argv))) == -1) { - std::cerr << "execv(" << loaderStr << ") error: " << ::strerror(errno) << std::endl; - cleanAndExit(errno); + std::cerr << "execv(" << loader << ") error: " << ::strerror(errno) << std::endl; + return errno; } } @@ -443,25 +517,21 @@ int extractBundle(std::string_view destination) noexcept auto ret = ::waitpid(loaderPid, &status, 0); if (ret == -1) { std::cerr << "waitpid failed:" << ::strerror(errno) << std::endl; - cleanAndExit(errno); + return errno; } - cleanAndExit(WEXITSTATUS(status)); -} + if (WIFEXITED(status)) { + return WEXITSTATUS(status); + } -enum uabOption { - Help = 1, - Extract, - Meta, -}; + if (WIFSIGNALED(status)) { + // maybe we runnning under a shell + return 128 + WTERMSIG(status); + } -struct argOption -{ - bool help{ false }; - bool printMeta{ false }; - std::string extractPath; - std::vector loaderArgs; -}; + std::cerr << "unknown exit state of loader" << std::endl; + return -1; +} argOption parseArgs(const std::vector &args) { @@ -476,9 +546,10 @@ argOption parseArgs(const std::vector &args) opts.loaderArgs.assign(splitter + 1, args.cend()); } - std::array long_options{ + std::array long_options{ { { "print-meta", no_argument, nullptr, uabOption::Meta }, { "extract", required_argument, nullptr, uabOption::Extract }, + { "mount", required_argument, nullptr, uabOption::Mount }, { "help", no_argument, nullptr, uabOption::Help }, { nullptr, 0, nullptr, 0 } } }; @@ -505,6 +576,10 @@ argOption parseArgs(const std::vector &args) opts.extractPath = optarg; ++counter; } break; + case uabOption::Mount: { + opts.mountPath = optarg; + ++counter; + } break; case uabOption::Help: { opts.help = true; ++counter; @@ -525,25 +600,41 @@ argOption parseArgs(const std::vector &args) } int mountSelf(const lightElf::native_elf &elf, - const linglong::api::types::v1::UabMetaInfo &metaInfo) noexcept + const linglong::api::types::v1::UabMetaInfo &metaInfo, + const std::filesystem::path &mp = {}) noexcept { if (mountFlag.load(std::memory_order_relaxed)) { std::cout << "bundle already has been mounted" << std::endl; return 0; } - const auto &uuid = metaInfo.uuid; - if (auto ret = createMountPoint(uuid); ret != 0) { - return ret; + if (mp.empty()) { + const auto &uuid = metaInfo.uuid; + if (auto ret = createMountPoint(uuid); ret != 0) { + return ret; + } + } else { + std::error_code ec; + auto state = std::filesystem::status(mp, ec); + if (ec) { + std::cerr << "failed to status " + mp.string() + ": " + ec.message() << std::endl; + return -1; + } + if (!std::filesystem::is_directory(state)) { + std::cerr << mp.string() << "is not a directory" << std::endl; + return -1; + } + mountPoint = mp; } if (auto ret = mountSelfBundle(elf, metaInfo); ret != 0) { - return -1; + return ret; } mountFlag.store(true, std::memory_order_relaxed); return 0; } +} // namespace int main(int argc, char **argv) { @@ -576,35 +667,59 @@ int main(int argc, char **argv) return 0; } - if (!opts.extractPath.empty()) { - if (mountSelf(elf, metaInfo) != 0) { - cleanAndExit(-1); + // for cleaning up mount point + if (std::atexit(cleanResource) != 0) { + std::cerr << "failed register exit handler" << std::endl; + return 1; + } + + std::set_terminate([]() { + cleanResource(); + std::abort(); + }); + + if (auto ret = mountSelf(elf, metaInfo, opts.mountPath); ret != 0) { + return ret; + } + + bool mountOnly = !opts.mountPath.empty(); + if (mountOnly) { + while (true) { + pause(); } + } - cleanAndExit(extractBundle(opts.extractPath)); + if (!opts.extractPath.empty()) { + return extractBundle(opts.extractPath); } - if (mountSelf(elf, metaInfo) != 0) { - cleanAndExit(-1); + const bool onlyApp = metaInfo.onlyApp.value_or(false); + + if (!onlyApp) { + std::cout << "This UAB is not support for runnning" << std::endl; + return 0; } - bool onlyApp = metaInfo.onlyApp.value_or(false); - if (onlyApp) { - std::string appID, module; - for (const auto &layer : metaInfo.layers) { - if (layer.info.kind == "app") { - appID = layer.info.id; - module = layer.info.packageInfoV2Module; - break; - } - } - std::string envAppRoot = - std::string(mountPoint) + "/layers/" + appID + "/" + module + "/files"; - if (-1 == ::setenv("LINGLONG_UAB_APPROOT", const_cast(envAppRoot.data()), 1)) { - std::cerr << "setenv error: " << ::strerror(errno) << std::endl; - cleanAndExit(errno); + std::string appID; + std::string module; + for (const auto &layer : metaInfo.layers) { + if (layer.info.kind == "app") { + appID = layer.info.id; + module = layer.info.packageInfoV2Module; + break; } } - runAppLoader(onlyApp, opts.loaderArgs); + if (appID.empty() || module.empty()) { + std::cerr << "failed to find appID and module" << std::endl; + return 1; + } + + std::string envAppRoot = std::string(mountPoint) + "/layers/" + appID + "/" + module + "/files"; + if (::setenv("LINGLONG_UAB_APPROOT", const_cast(envAppRoot.data()), 1) == -1) { + std::cerr << "setenv error: " << ::strerror(errno) << std::endl; + return 1; + } + + return runAppLoader(opts.loaderArgs); } diff --git a/apps/uab/header/src/sha256.h b/apps/uab/header/src/sha256.h index 0c1291078..dc04da73e 100644 --- a/apps/uab/header/src/sha256.h +++ b/apps/uab/header/src/sha256.h @@ -9,16 +9,17 @@ #include #include #include +#include namespace digest { namespace details { -constexpr static inline uint32_t rotate_right(uint32_t x, unsigned n) noexcept +constexpr static uint32_t rotate_right(uint32_t x, unsigned n) noexcept { return (x >> n) | (x << (32 - n)); } -constexpr static inline uint32_t to_big_endian(uint32_t val) noexcept +constexpr static uint32_t to_big_endian(uint32_t val) noexcept { #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ return x; @@ -28,7 +29,7 @@ constexpr static inline uint32_t to_big_endian(uint32_t val) noexcept #endif } -constexpr static inline uint64_t to_big_endian(uint64_t val) noexcept +constexpr static uint64_t to_big_endian(uint64_t val) noexcept { #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ return x; @@ -40,32 +41,32 @@ constexpr static inline uint64_t to_big_endian(uint64_t val) noexcept #endif } -constexpr static inline uint32_t sum0(uint32_t x) noexcept +constexpr static uint32_t sum0(uint32_t x) noexcept { return rotate_right(x, 2) ^ rotate_right(x, 13) ^ rotate_right(x, 22); } -constexpr static inline uint32_t sum1(uint32_t x) noexcept +constexpr static uint32_t sum1(uint32_t x) noexcept { return rotate_right(x, 6) ^ rotate_right(x, 11) ^ rotate_right(x, 25); } -constexpr static inline uint32_t sigma0(uint32_t x) noexcept +constexpr static uint32_t sigma0(uint32_t x) noexcept { return rotate_right(x, 7) ^ rotate_right(x, 18) ^ (x >> 3); } -constexpr static inline uint32_t sigma1(uint32_t x) noexcept +constexpr static uint32_t sigma1(uint32_t x) noexcept { return rotate_right(x, 17) ^ rotate_right(x, 19) ^ (x >> 10); } -constexpr static inline uint32_t Ch(uint32_t x, uint32_t y, uint32_t z) noexcept +constexpr static uint32_t Ch(uint32_t x, uint32_t y, uint32_t z) noexcept { return (x & y) ^ ((~x) & z); } -constexpr static inline uint32_t Maj(uint32_t x, uint32_t y, uint32_t z) noexcept +constexpr static uint32_t Maj(uint32_t x, uint32_t y, uint32_t z) noexcept { return (x & y) ^ (x & z) ^ (y & z); } @@ -149,7 +150,9 @@ class SHA256 for (std::size_t i = 0; i < block_num; ++i) { std::array M{}; for (int j = 0; j < 16; ++j) { - M[j] = details::to_big_endian(reinterpret_cast(data)[i * 16 + j]); + uint32_t tmp = 0; + std::memcpy(&tmp, &data[i * 64 + j * 4], 4); + M[j] = details::to_big_endian(tmp); } std::array W{}; diff --git a/apps/uab/loader/CMakeLists.txt b/apps/uab/loader/CMakeLists.txt index 118304880..5f795839f 100644 --- a/apps/uab/loader/CMakeLists.txt +++ b/apps/uab/loader/CMakeLists.txt @@ -10,8 +10,8 @@ pfl_add_executable( uab-loader LINK_LIBRARIES PRIVATE - linglong::oci-cfg-generators - nlohmann_json::nlohmann_json) + linglong::api + linglong::oci-cfg-generators) set(UAB_LOADER_TARGET) get_real_target_name(UAB_LOADER_TARGET linglong::loader) diff --git a/apps/uab/loader/src/main.cpp b/apps/uab/loader/src/main.cpp index 67effbbdf..321114d3e 100644 --- a/apps/uab/loader/src/main.cpp +++ b/apps/uab/loader/src/main.cpp @@ -2,12 +2,12 @@ // // SPDX-License-Identifier: LGPL-3.0-or-later -#include "linglong/api/types/v1/Generators.hpp" -#include "linglong/oci-cfg-generators/builtins.h" -#include "ocppi/runtime/config/types/Config.hpp" -#include "ocppi/runtime/config/types/Generators.hpp" +#include "linglong/api/types/v1/Generators.hpp" // IWYU pragma: keep +#include "linglong/common/strings.h" +#include "linglong/oci-cfg-generators/container_cfg_builder.h" +#include "ocppi/runtime/config/types/Generators.hpp" // IWYU pragma: keep #include "ocppi/runtime/config/types/Hook.hpp" -#include "ocppi/runtime/config/types/Mount.hpp" +#include "ocppi/runtime/config/types/Linux.hpp" #include @@ -27,21 +27,9 @@ #include #include -static std::filesystem::path containerBundle; +namespace { -template -struct defer -{ - explicit defer(Func newF) - : f(std::move(newF)) - { - } - - ~defer() { f(); } - -private: - Func f; -}; +std::filesystem::path containerBundle; std::string genRandomString() noexcept { @@ -67,50 +55,39 @@ void cleanResource() return; } - containerBundle.clear(); if (::getenv("LINGLONG_UAB_DEBUG") != nullptr) { return; } std::error_code ec; - if (!std::filesystem::exists(containerBundle, ec)) { - if (ec) { - std::cerr << "filesystem error:" << containerBundle << " " << ec.message() << std::endl; - return; - } - - return; - } - - if (std::filesystem::remove_all(containerBundle, ec) == static_cast(-1)) { + if (std::filesystem::remove_all(containerBundle, ec) == static_cast(-1) && ec) { std::cerr << "failed to remove directory " << containerBundle << ":" << ec.message() << std::endl; return; } + containerBundle.clear(); } -[[noreturn]] static void cleanAndExit(int exitCode) noexcept +[[noreturn]] void cleanAndExit(int exitCode) noexcept { cleanResource(); - ::exit(exitCode); + ::_exit(exitCode); } void handleSig() noexcept { - auto handler = [](int sig) -> void { - cleanAndExit(sig); - }; - sigset_t blocking_mask; sigemptyset(&blocking_mask); - auto quitSignals = { SIGTERM, SIGINT, SIGQUIT, SIGHUP, SIGABRT, SIGSEGV }; + auto quitSignals = { SIGTERM, SIGINT, SIGQUIT, SIGHUP, SIGABRT }; for (auto sig : quitSignals) { sigaddset(&blocking_mask, sig); } struct sigaction sa{}; - sa.sa_handler = handler; + sa.sa_handler = [](int sig) -> void { + cleanAndExit(128 + sig); + }; sa.sa_mask = blocking_mask; sa.sa_flags = 0; @@ -119,58 +96,6 @@ void handleSig() noexcept } } -void applyPatches(ocppi::runtime::config::types::Config &config) noexcept -{ - const auto &builtins = linglong::generator::builtin_generators(); - for (const auto &[name, gen] : builtins) { - if (!gen->generate(config)) { - std::cerr << "generator " << name << " failed" << std::endl; - } - } -} - -[[nodiscard]] bool prepareRootfs(std::filesystem::path baseDir, - ocppi::runtime::config::types::Config &config) noexcept -{ - if (baseDir.empty()) { - baseDir = "/"; - - // this is used to skipping some oci-cfg-generators - config.annotations.value()["org.deepin.linglong.onlyApp"] = "true"; - } - - std::error_code ec; - auto fsIter = std::filesystem::directory_iterator{ baseDir, ec }; - if (ec) { - std::cerr << "couldn't get directory iterator:" << ec.message() << std::endl; - return false; - } - - auto mounts = config.mounts.value_or(std::vector{}); - for (const auto &file : fsIter) { - auto path = file.path(); - std::vector options{ "rbind" }; - if (std::filesystem::is_symlink(path, ec)) { - options.emplace_back("copy-symlink"); - } - - if (ec) { - std::cerr << "filesystem error:" << ec.message() << std::endl; - return false; - } - - mounts.push_back(ocppi::runtime::config::types::Mount{ - .destination = "/" / path.lexically_relative(baseDir), - .options = std::move(options), - .source = path, - .type = "bind", - }); - } - - config.mounts = std::move(mounts); - return true; -} - std::optional loadPackageInfoFromJson(const std::filesystem::path &json) noexcept { @@ -220,83 +145,167 @@ loadPackageInfoFromJson(const std::filesystem::path &json) noexcept return std::nullopt; } -bool processCaches(ocppi::runtime::config::types::Config &config, - const std::filesystem::path &extraDir, - bool onlyApp) noexcept +bool processLDConfig(linglong::generator::ContainerCfgBuilder &builder, + const std::string &arch) noexcept { - std::error_code ec; - auto cacheDir = containerBundle / "cache"; - auto ldCacheDir = cacheDir / "ld.so.cache.d"; - if (!std::filesystem::create_directories(ldCacheDir, ec)) { - std::cerr << "failed to create ld cache directory:" << ec.message() << std::endl; - return -1; + std::optional triplet; + if (arch == "x86_64") { + triplet = "x86_64-linux-gnu"; + } else if (arch == "arm64") { + triplet = "aarch64-linux-gnu"; + } else if (arch == "loong64" || arch == "loongarch64") { + triplet = "loongarch64-linux-gnu"; + } else if (arch == "sw64") { + triplet = "sw_64-linux-gnu"; + } else if (arch == "mips64") { + triplet = "mips64el-linux-gnuabi64"; + } + + if (!triplet) { + std::cerr << "unsupported architecture" << std::endl; + return false; + } + + auto content = builder.ldConf(triplet.value()); + auto ldConf = builder.getBundlePath() / "ld.so.conf"; + { + std::ofstream stream{ ldConf }; + if (!stream.is_open()) { + std::cout << "failed to open " << ldConf.string() << std::endl; + return false; + } + + stream << content; + } + + // trigger fixMount + auto randomFile = builder.getBundlePath() / genRandomString(); + { + std::ofstream stream{ randomFile }; + if (!stream.is_open()) { + std::cout << "failed to open " << ldConf.string() << std::endl; + return false; + } } - config.mounts->push_back(ocppi::runtime::config::types::Mount{ - .destination = "/run/linglong/cache", - .options = { { "rbind", "rw" } }, - .source = ldCacheDir, + builder.addExtraMounts(std::vector{ + ocppi::runtime::config::types::Mount{ + .destination = "/etc/" + randomFile.filename().string(), + .options = { { "ro", "bind" } }, + .source = randomFile, + .type = "bind", + }, + ocppi::runtime::config::types::Mount{ + .destination = "/etc/ld.so.conf.d/zz_deepin-linglong.ld.so.conf", + .options = { { "ro", "bind" } }, + .source = ldConf, + .type = "bind", + } }); + + builder.setStartContainerHooks(std::vector{ + ocppi::runtime::config::types::Hook{ + .args = std::vector{ "/sbin/ldconfig", "-C", "/tmp/ld.so.cache" }, + .path = "/sbin/ldconfig", + }, + ocppi::runtime::config::types::Hook{ + .args = + std::vector{ "/bin/sh", "-c", "cat /tmp/ld.so.cache > /etc/ld.so.cache" }, + .path = "/bin/sh", + } }); + + return true; +} + +bool processProfile(const std::filesystem::path &extraDir, + linglong::generator::ContainerCfgBuilder &builder) +{ + std::error_code ec; + + auto tripletFile = extraDir / "linglong-triplet-list"; + if (!std::filesystem::exists(tripletFile, ec)) { + if (ec) { + std::cerr << "failed to get directory " << extraDir << ":" << ec.message() + << " code:" << ec.value() << std::endl; + return false; + } + + return true; + } + builder.addExtraMount(ocppi::runtime::config::types::Mount{ + .destination = "/etc/linglong-triplet-list", + .options = { { "ro", "bind" } }, + .source = tripletFile, .type = "bind", }); - // append ld conf - auto ldConfDir = extraDir / "ld.conf.d"; - if (!std::filesystem::exists(ldConfDir, ec)) { + auto profile = extraDir / "profile"; + if (!std::filesystem::exists(profile, ec)) { if (ec) { - std::cerr << "failed to check ld conf directory " << ldConfDir << ":" << ec.message() + std::cerr << "failed to get directory " << extraDir << ":" << ec.message() << " code:" << ec.value() << std::endl; - return -1; + return false; } - std::cerr << ldConfDir << " not exist." << std::endl; - return -1; + return true; } - - config.mounts->push_back(ocppi::runtime::config::types::Mount{ - .destination = "/run/linglong/cache/ld.so.conf", - .options = { { "ro", "rbind" } }, - .source = ldConfDir / "zz_deepin-linglong-app.ld.so.conf", + builder.addExtraMount(ocppi::runtime::config::types::Mount{ + .destination = "/etc/profile", + .options = { { "ro", "bind" } }, + .source = profile, .type = "bind", }); - auto hooks = config.hooks.value_or(ocppi::runtime::config::types::Hooks{}); - auto startHooks = - hooks.startContainer.value_or(std::vector{}); - startHooks.push_back(ocppi::runtime::config::types::Hook{ - .args = std::vector{ "/sbin/ldconfig", - "-f", - "/run/linglong/cache/ld.so.conf", - "-C", - "/run/linglong/cache/ld.so.cache" }, - .path = "/sbin/ldconfig", - }); + return true; +} - if (!onlyApp) { - auto fontCacheDir = cacheDir / "fontconfig"; - if (!std::filesystem::create_directories(fontCacheDir, ec)) { - std::cerr << "failed to create font cache directory:" << ec.message() << std::endl; - return -1; +bool generateEntrypoint(linglong::generator::ContainerCfgBuilder &builder, + std::vector originalArgs) noexcept +{ + std::string content = "#!/usr/bin/env bash\nsource /etc/profile\nexec "; + for (const auto &arg : originalArgs) { + content.append(linglong::common::strings::quoteBashArg(arg)); + content.push_back(' '); + } + + const auto entryPoint = containerBundle / "entrypoint.sh"; + { + std::ofstream stream{ entryPoint }; + if (!stream.is_open()) { + std::cerr << "failed to open file " + << containerBundle / "entrypoint.sh:" << ::strerror(errno) << std::endl; + return false; } - config.mounts->push_back(ocppi::runtime::config::types::Mount{ - .destination = "/var/cache/fontconfig", - .options = { { "rbind", "rw" } }, - .source = fontCacheDir, - .type = "bind", - }); + stream << content; + if (stream.fail()) { + std::cerr << "failed to write entrypoint to " << entryPoint << std::endl; + return false; + } + } - startHooks.push_back(ocppi::runtime::config::types::Hook{ - .args = std::vector{ "/bin/fc-cache", "-f" }, - .path = "/bin/fc-cache", - }); + std::error_code ec; + std::filesystem::permissions(entryPoint, + std::filesystem::perms::owner_exec, + std::filesystem::perm_options::add, + ec); + if (ec) { + std::cerr << "failed to set permission of " << entryPoint << ":" << ec.message() + << std::endl; + return false; } - hooks.startContainer = std::move(startHooks); - config.hooks = std::move(hooks); + builder.addExtraMount(ocppi::runtime::config::types::Mount{ + .destination = "/entrypoint.sh", + .options = { { "bind", "ro" } }, + .source = entryPoint, + .type = "bind", + }); return true; } +} // namespace + // DO NOT USE LOADER DIRECTLY int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv) // NOLINT { @@ -368,23 +377,8 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv) // NOLINT return -1; } - const auto &baseStr = appInfo->base; - auto splitSlash = std::find(baseStr.cbegin(), baseStr.cend(), '/'); - auto splitColon = std::find(baseStr.cbegin(), baseStr.cend(), ':'); - auto baseID = - baseStr.substr(std::distance(baseStr.cbegin(), splitColon) + 1, splitSlash - splitColon - 1); - - std::string runtimeID; - if (appInfo->runtime) { - const auto &runtimeStr = appInfo->runtime.value(); - auto splitSlash = std::find(runtimeStr.cbegin(), runtimeStr.cend(), '/'); - auto splitColon = std::find(runtimeStr.cbegin(), runtimeStr.cend(), ':'); - runtimeID = runtimeStr.substr(std::distance(runtimeStr.cbegin(), splitColon) + 1, - splitSlash - splitColon - 1); - } - auto containerID = genRandomString(); - auto containerBundleDir = bundleDir.parent_path().parent_path() / containerID; + auto containerBundleDir = bundleDir.parent_path() / containerID; if (!std::filesystem::create_directories(containerBundleDir, ec) && ec) { std::cerr << "couldn't create directory " << containerBundleDir << " :" << ec.message() << std::endl; @@ -392,7 +386,50 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv) // NOLINT } containerBundle = std::move(containerBundleDir); - defer removeContainerBundleDir{ cleanResource }; + + if (std::atexit(cleanResource) != 0) { + std::cerr << "failed register exit handler" << std::endl; + return 1; + } + + std::set_terminate([]() { + cleanResource(); + std::abort(); + }); + + auto uid = ::getuid(); + auto gid = ::getgid(); + linglong::generator::ContainerCfgBuilder builder; + + auto runtimeLD = containerBundle / "ld.so.cache"; + { + std::ofstream stream{ runtimeLD }; + if (!stream) { + std::cerr << "failed to open file " << runtimeLD << std::endl; + return -1; + } + } + + builder.setBundlePath(containerBundle) + .setBasePath("/", false) + .enableSelfAdjustingMount() + .forwardEnv() + .addUIdMapping(uid, uid, 1) + .addGIdMapping(gid, gid, 1) + .addExtraMounts( + std::vector{ ocppi::runtime::config::types::Mount{ + .destination = "/etc/ld.so.cache", + .options = { { "bind" } }, + .source = runtimeLD, + .type = "bind", + }, + ocppi::runtime::config::types::Mount{ + .destination = "/tmp", + .options = { { "rbind" } }, + .source = "/tmp", + .type = "bind", + } }) + .appendEnv("LINGLONG_APPID", builder.getAppId()); auto extraDir = bundleDir / "extra"; if (!std::filesystem::exists(extraDir, ec)) { @@ -418,16 +455,7 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv) // NOLINT return -1; } - ocppi::runtime::config::types::Config config; - try { - auto content = nlohmann::json::parse(linglong::generator::initConfig); - config = content.get(); - } catch (std::exception &e) { - std::cerr << "catch an exception:" << e.what() << std::endl; - return -1; - } - - auto compatibleFilePath = [&bundleDir](std::string_view layerID) -> std::string { + auto compatibleFilePath = [&bundleDir](std::string_view layerID) -> std::filesystem::path { std::error_code ec; auto layerDir = bundleDir / "layers" / layerID; if (!std::filesystem::exists(layerDir, ec)) { @@ -442,11 +470,11 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv) // NOLINT } // ignore error code when directory doesn't exist - if (auto runtime = layerDir / "runtime/files"; std::filesystem::exists(runtime, ec)) { + if (auto runtime = layerDir / "runtime" / "files"; std::filesystem::exists(runtime, ec)) { return runtime.string(); } - if (auto binary = layerDir / "binary/files"; std::filesystem::exists(binary, ec)) { + if (auto binary = layerDir / "binary" / "files"; std::filesystem::exists(binary, ec)) { return binary.string(); } @@ -460,27 +488,31 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv) // NOLINT return -1; } - config.root->path = rootfs; - config.root->readonly = true; + const auto &appID = appInfo->id; + builder.setAppId(appID); + + std::string runtimeID; + if (appInfo->runtime) { + const auto &runtimeStr = appInfo->runtime.value(); + + std::size_t begin{ 0 }; + auto splitColon = std::find(runtimeStr.cbegin(), runtimeStr.cend(), ':'); + if (splitColon != runtimeStr.cend()) { + begin = std::distance(runtimeStr.cbegin(), splitColon) + 1; + } - auto appID = appInfo->id; - auto annotations = config.annotations.value_or(std::map{}); - annotations["org.deepin.linglong.appID"] = appID; + auto splitSlash = std::find(runtimeStr.cbegin(), runtimeStr.cend(), '/'); + auto len = std::distance(runtimeStr.cbegin(), splitSlash) - begin; - bool onlyApp = ::getenv("LINGLONG_UAB_LOADER_ONLY_APP") != nullptr; - std::string baseLayerFilesDir; - if (!onlyApp) { - baseLayerFilesDir = compatibleFilePath(baseID); - if (baseLayerFilesDir.empty()) { - std::cerr << "couldn't get compatiblePath of base" << std::endl; + if (begin + len > runtimeStr.size()) { + std::cerr << "runtime may not valid: " << runtimeStr << std::endl; return -1; } - annotations["org.deepin.linglong.baseDir"] = - std::filesystem::path{ baseLayerFilesDir }.parent_path(); + runtimeID = runtimeStr.substr(begin, len); } - std::string runtimeLayerFilesDir; + std::filesystem::path runtimeLayerFilesDir; if (!runtimeID.empty()) { runtimeLayerFilesDir = compatibleFilePath(runtimeID); if (runtimeLayerFilesDir.empty()) { @@ -488,8 +520,7 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv) // NOLINT return -1; } - annotations["org.deepin.linglong.runtimeDir"] = - std::filesystem::path{ runtimeLayerFilesDir }.parent_path(); + builder.setRuntimePath(runtimeLayerFilesDir); } auto appLayerFilesDir = compatibleFilePath(appID); @@ -497,52 +528,68 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv) // NOLINT std::cerr << "couldn't get compatiblePath of application" << std::endl; return -1; } - auto appDir = std::filesystem::path{ appLayerFilesDir }.parent_path(); - - annotations["org.deepin.linglong.appDir"] = appDir.string(); - annotations["org.deepin.linglong.bundleDir"] = containerBundle.string(); - config.annotations = std::move(annotations); + builder.setAppPath(appLayerFilesDir); - if (!prepareRootfs(baseLayerFilesDir, config)) { - std::cerr << "couldn't prepare rootfs" << std::endl; + // generate ld.so.cache and font cache at runtime + if (!processLDConfig(builder, appInfo->arch[0])) { + std::cerr << "failed to processing ld config" << std::endl; return -1; } - // replace commands - if (!appInfo->command || appInfo->command->empty()) { - std::cerr << "couldn't find command of application" << std::endl; + // add extra profile + if (!processProfile(extraDir, builder)) { + std::cerr << "failed to processing profile" << std::endl; return -1; } - config.process->args = appInfo->command.value(); - - applyPatches(config); - auto env = config.process->env.value_or(std::vector{}); - std::string curPath = ::getenv("PATH"); - auto appBin = std::string{ "/opt/apps/" + appID + "/files/bin:" }; - curPath.insert(curPath.begin(), appBin.begin(), appBin.end()); - env.push_back("PATH=" + curPath); - config.process->env = std::move(env); - - // generate ld.so.cache and font cache at runtime - if (!processCaches(config, extraDir, onlyApp)) { + // generate entrypoint + auto command = appInfo->command.value_or(std::vector{ "/bin/bash" }); + for (int i = 1; i < argc; ++i) { + command.push_back(argv[i]); + } + if (!generateEntrypoint(builder, command)) { + std::cerr << "failed to generate entrypoint" << std::endl; return -1; } // dump to bundle auto bundleCfg = containerBundle / "config.json"; - std::ofstream cfgStream{ bundleCfg.string() }; - if (!cfgStream.is_open()) { - std::cerr << "couldn't create bundle config.json" << std::endl; - return -1; - } + nlohmann::json json; + { + std::ofstream cfgStream{ bundleCfg.string() }; + if (!cfgStream.is_open()) { + std::cerr << "couldn't create bundle config.json" << std::endl; + return -1; + } + + if (!builder.build()) { + std::cerr << "failed to generate OCI config:" << builder.getError().reason << std::endl; + return -1; + } - nlohmann::json json = config; - cfgStream << json.dump() << std::endl; - cfgStream.close(); + // for only-App, we need adjust some config + json = builder.getConfig(); + auto process = json["process"].get(); + process.terminal = (::isatty(STDOUT_FILENO) == 1); + process.user = ocppi::runtime::config::types::User{ .gid = getgid(), .uid = getuid() }; + process.args = std::vector{ "/entrypoint.sh" }; + json["process"] = std::move(process); + + auto linux_ = json["linux"].get(); + linux_.namespaces = std::vector{ + ocppi::runtime::config::types::NamespaceReference{ + .type = ocppi::runtime::config::types::NamespaceType::User }, + ocppi::runtime::config::types::NamespaceReference{ + .type = ocppi::runtime::config::types::NamespaceType::Mount } + }; + json["linux"] = std::move(linux_); + + cfgStream << json.dump() << std::endl; + cfgStream.close(); + } if (::getenv("LINGLONG_UAB_DEBUG") != nullptr) { - std::cout << "dump container:" << std::endl; + std::cout << "dump container config:" << std::endl; std::cout << json.dump(4) << std::endl; } @@ -564,11 +611,22 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv) // NOLINT nullptr); } - int wstatus{ -1 }; + int wstatus{ 0 }; if (auto ret = ::waitpid(pid, &wstatus, 0); ret == -1) { std::cerr << "waitpid() err:" << ::strerror(errno) << std::endl; return -1; } - return WEXITSTATUS(wstatus); + if (WIFEXITED(wstatus)) { + std::cerr << "loader: container exit: " << WEXITSTATUS(wstatus) << std::endl; + return WEXITSTATUS(wstatus); + } + + if (WIFSIGNALED(wstatus)) { + std::cerr << "loader: container exit with signal: " << WTERMSIG(wstatus) << std::endl; + return WTERMSIG(wstatus) + 128; + } + + std::cerr << "unknow exit status" << std::endl; + return -1; } diff --git a/cmake.external/Findcli11.cmake b/cmake.external/Findcli11.cmake index 1961f759c..596386982 100644 --- a/cmake.external/Findcli11.cmake +++ b/cmake.external/Findcli11.cmake @@ -1,4 +1,4 @@ -lls# SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +# SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. # # SPDX-License-Identifier: LGPL-3.0-or-later diff --git a/cmake/Qt6DBusMacro.cmake b/cmake/Qt6DBusMacro.cmake deleted file mode 100644 index 3a7bca2eb..000000000 --- a/cmake/Qt6DBusMacro.cmake +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright 2005-2011 Kitware, Inc. -# Copyright (C) 2022 The Qt Company Ltd. -# SPDX-License-Identifier: BSD-3-Clause - -include(MacroAddFileDependencies) - -function(qt6_add_dbus_interface_override _target _sources _interface _relativename) - get_filename_component(_infile ${_interface} ABSOLUTE) - get_filename_component(_basepath ${_relativename} DIRECTORY) - get_filename_component(_basename ${_relativename} NAME) - set(_header "${CMAKE_CURRENT_BINARY_DIR}/${_relativename}.h") - set(_impl "${CMAKE_CURRENT_BINARY_DIR}/${_relativename}.cpp") - if(_basepath) - set(_moc "${CMAKE_CURRENT_BINARY_DIR}/${_basepath}/moc_${_basename}.cpp") - else() - set(_moc "${CMAKE_CURRENT_BINARY_DIR}/moc_${_basename}.cpp") - endif() - - get_source_file_property(_nonamespace ${_interface} NO_NAMESPACE) - if(_nonamespace) - set(_params -N -m) - else() - set(_params -m) - endif() - - get_source_file_property(_classname ${_interface} CLASSNAME) - if(_classname) - set(_params ${_params} -c ${_classname}) - endif() - - get_source_file_property(_include ${_interface} INCLUDE) - if(_include) - set(_params ${_params} -i ${_include}) - endif() - - add_custom_command(OUTPUT "${_impl}" "${_header}" - COMMAND ${_target} ${_params} -p ${_relativename} ${_infile} - DEPENDS ${_infile} ${_target} - VERBATIM - ) - - set_source_files_properties("${_impl}" "${_header}" PROPERTIES - SKIP_AUTOMOC TRUE - SKIP_AUTOUIC TRUE - ) - - qt6_generate_moc("${_header}" "${_moc}") - - list(APPEND ${_sources} "${_impl}" "${_header}") - macro_add_file_dependencies("${_impl}" "${_moc}") - set(${_sources} ${${_sources}} PARENT_SCOPE) -endfunction() - -function(qt6_add_dbus_adaptor_override _target _sources _xml_file _include) # _optionalParentClass _optionalRelativename _optionalClassName) - get_filename_component(_infile ${_xml_file} ABSOLUTE) - - set(_optionalParentClass "${ARGV4}") - if(_optionalParentClass) - set(_parentClassOption "-l") - set(_parentClass "${_optionalParentClass}") - endif() - - set(_optionalRelativename "${ARGV5}") - if(_optionalRelativename) - set(_relativename ${_optionalRelativename}) - else() - string(REGEX REPLACE "(.*[/\\.])?([^\\.]+)\\.xml" "\\2adaptor" _relativename ${_infile}) - string(TOLOWER ${_relativename} _relativename) - endif() - get_filename_component(_basepath ${_relativename} DIRECTORY) - get_filename_component(_basename ${_relativename} NAME) - - set(_optionalClassName "${ARGV6}") - set(_header "${CMAKE_CURRENT_BINARY_DIR}/${_relativename}.h") - set(_impl "${CMAKE_CURRENT_BINARY_DIR}/${_relativename}.cpp") - if(_basepath) - set(_moc "${CMAKE_CURRENT_BINARY_DIR}/${_basepath}/moc_${_basename}.cpp") - else() - set(_moc "${CMAKE_CURRENT_BINARY_DIR}/moc_${_basename}.cpp") - endif() - - if(_optionalClassName) - add_custom_command(OUTPUT "${_impl}" "${_header}" - COMMAND ${_target} -m -a ${_relativename} -c ${_optionalClassName} -i ${_include} ${_parentClassOption} ${_parentClass} ${_infile} - DEPENDS ${_infile} ${_target} - VERBATIM - ) - else() - add_custom_command(OUTPUT "${_impl}" "${_header}" - COMMAND ${_target} -m -a ${_relativename} -i ${_include} ${_parentClassOption} ${_parentClass} ${_infile} - DEPENDS ${_infile} ${_target} - VERBATIM - ) - endif() - - qt6_generate_moc("${_header}" "${_moc}") - set_source_files_properties("${_impl}" "${_header}" PROPERTIES - SKIP_AUTOMOC TRUE - SKIP_AUTOUIC TRUE - ) - macro_add_file_dependencies("${_impl}" "${_moc}") - - list(APPEND ${_sources} "${_impl}" "${_header}") - set(${_sources} ${${_sources}} PARENT_SCOPE) -endfunction() diff --git a/libs/utils/src/linglong/utils/configure.h.in b/configure.h.in similarity index 79% rename from libs/utils/src/linglong/utils/configure.h.in rename to configure.h.in index c3d23b2c2..ed27e087d 100644 --- a/libs/utils/src/linglong/utils/configure.h.in +++ b/configure.h.in @@ -18,12 +18,14 @@ #define LINGLONG_DEFAULT_OCI_RUNTIME "@LINGLONG_DEFAULT_OCI_RUNTIME@" #define LINGLONG_UAB_DATA_LOCATION "@CMAKE_INSTALL_FULL_LIBDIR@/linglong/builder/uab" #define LINGLONG_BUILDER_HELPER LINGLONG_LIBEXEC_DIR "/builder/helper" -#define LINGLONG_CONTAINER_INIT LINGLONG_LIBEXEC_DIR "/dumb-init" +#define LINGLONG_CONTAINER_INIT LINGLONG_LIBEXEC_DIR "/ll-init" #define LINGLONG_CLIENT_NAME "@LINGLONG_CLI_BIN@" #define LINGLONG_CLIENT_PATH "@CMAKE_INSTALL_FULL_BINDIR@/@LINGLONG_CLI_BIN@" -#define LINGLONG_DESKTOP_EXPORT_PATH "@LINGLONG_DESKTOP_EXPORT_PATH@" +#define LINGLONG_EXPORT_PATH "@LINGLONG_EXPORT_PATH@" +// The directory where the package install hooks reside. +#define LINGLONG_INSTALL_HOOKS_DIR "@CMAKE_INSTALL_FULL_SYSCONFDIR@/linglong/config.d" -#define LINGLONG_EXPORT_VERSION "1.0.0.1" +#define LINGLONG_EXPORT_VERSION "1.0.0.2" // The package's locale domain. #define PACKAGE_LOCALE_DOMAIN "@GETTEXT_DOMAIN_NAME@" diff --git a/docs/bundle-format.md b/docs/bundle-format.md deleted file mode 100644 index 5a1ac6713..000000000 --- a/docs/bundle-format.md +++ /dev/null @@ -1,52 +0,0 @@ -# Bundle Format - -## Introduce - -Green software, known as some binary does not install any file to the system. - -The base constraint of green software is: - -- Path unrelated, means has nothing to do with local files. - -- highly compatibility, so the software should contain all dependencies that the system does not have. - -The famous technology to build green software is AppImage on Linux. - -However, there are many problems with that technology, the biggest problem is that the host system ABI can not stay stable and differ from one another. The linglong can not solve that problem either. We should keep a baseline of support system or ABI. - -A trick on uniontech os or deepin is just support system after uniontech os 1020, which reduces the testing work for the different base systems. - -## Target - -The green bundle is not just simple support for application run path independently. It is also designed to be the offline maintainer package format on office system service package support self-run and install. so keep the changeability of the bundle format when designing. - -When a user has internet, we mostly use online diff update or install by repo. we do not use bundle if we can access the repo when distributing applications. - -## Specification - -The spec of the export bundle: - -- MUST be an ELF, can be FlatELF -- MUST be statically-linked -- MUST contain a data segment that can mount with fuse -- MUST contain a loader executable on the root of fuse mount filesystem - -## Implementation - -**The implementation change with time,If you change the implement, update this selection as soon as possible !!!** - -### prototype - -- The bundle is a sample elf loader that joins a readonly filesystem with cat. -- The loader simply calls read_elf64 to calc the offset of readonly filesystem. -- The loader mount readonly filesystem with `squashfuse -o ro,offset=xxx` -- The filesystem now is readonly filesystem - - The root of the filesystem should contain a file name loader(by the way, now is .loader) - - the directory structure should be: /{id}/{version}/{arch}/ -- The readonly filesystem should support erofs, and MAY support suqashfs - -a full example of the filesystem is: - -```bash - -``` diff --git a/docs/pages/README.zh_CN.md b/docs/pages/README.zh_CN.md new file mode 100644 index 000000000..1c0fd4e45 --- /dev/null +++ b/docs/pages/README.zh_CN.md @@ -0,0 +1,3 @@ +# 通知 + +这些文件将通过 GitHub Action 自动同步到另一个 GitHub 仓库 [linglong-homepage](https://github.com/OpenAtom-Linyaps/linyaps-doc)。 diff --git a/docs/pages/en/guide/building/demo.md b/docs/pages/en/guide/building/demo.md new file mode 100644 index 000000000..b18d88f42 --- /dev/null +++ b/docs/pages/en/guide/building/demo.md @@ -0,0 +1,156 @@ + + +# Building Example Demonstration + +## Initialize a Linyaps Application Project + +```bash +ll-builder create org.deepin.demo +``` + +## Edit linglong.yaml Configuration File + +### Configure Package Metadata Information + +```yaml +package: + id: org.deepin.demo + name: demo + kind: app + version: 1.0.0.0 + description: | + A simple demo app. +``` + +### Configure Application Launch Command + +```yaml +command: + - demo +``` + +### Configure Base System and Runtime Environment + +```yaml +base: org.deepin.base/23.1.0 +runtime: org.deepin.runtime.dtk/23.1.0 +``` + +### Configure Source Code Information + +Fetch source code using Git + +```yaml +sources: + - kind: git + url: "https://github.com/linuxdeepin/linglong-builder-demo.git" + commit: master + name: linglong-builder-demo +``` + +### Configure Build Rules + +```yaml +build: | + cd /project/linglong/sources/linglong-builder-demo + rm -rf build || true + mkdir build + cd build + qmake .. + make + make install +``` + +### Complete linglong.yaml Configuration File + +```yaml +version: "1" + +package: + id: org.deepin.demo + name: demo + kind: app + version: 1.0.0.0 + description: | + A simple demo app. + +command: + - demo + +base: org.deepin.base/23.1.0 +runtime: org.deepin.runtime.dtk/23.1.0 + +sources: + - kind: git + url: "https://github.com/linuxdeepin/linglong-builder-demo.git" + commit: master + name: linglong-builder-demo + +build: | + cd /project/linglong/sources/linglong-builder-demo + rm -rf build || true + mkdir build + cd build + qmake .. + make + make install +``` + +For more configuration file field definitions, refer to [Configuration File Reference](./manifests.md) + +## Execute the Build Process + +Execute the build command in the Linyaps project root directory: + +```bash +ll-builder build +``` + +## Run the Application + +After successful build, execute the run command in the Linyaps project directory to directly run the application without installation. + +```bash +ll-builder run +``` + +## Export Build Artifacts + +Execute the export command in the Linyaps project root directory to export the build contents. + +```bash +ll-builder export --layer +``` + +The exported directory structure is as follows: + +```text +├── linglong +├── linglong.yaml +├── org.deepin.demo_1.0.0.0_x86_64_binary.layer +└── org.deepin.demo_1.0.0.0_x86_64_develop.layer +``` + +## Additional Reference Examples + +[qt5](https://github.com/linglongdev/cn.org.linyaps.demo.qt5) - qt5 program + +[dtk5](https://github.com/linglongdev/cn.org.linyaps.demo.dtk5.qmake) - dtk5 + qmake + +[dtk5](https://github.com/linglongdev/cn.org.linyaps.demo.dtk5.cmake) - dtk5 + cmake + +[dtkdeclarative5](https://github.com/linglongdev/cn.org.linyaps.demo.dtkdeclarative5) - dtk5 + qml + +[electron](https://github.com/myml/electron-vue-linyaps-app) - electron + vue example + +[plantuml](https://github.com/linglongdev/com.plantuml.gpl) - a Java application for programmatic flowchart creation + +[org.sumatrapdfreader](https://github.com/linglongdev/org.sumatrapdfreader) - a Wine application, PDF reader + +## More Complete Example + +[Complete Example](../start/build_your_first_app.md) - Contains a complete workflow example of how to build applications, export build contents, install, and run. diff --git a/docs/pages/en/guide/building/linyaps_package_spec.md b/docs/pages/en/guide/building/linyaps_package_spec.md new file mode 100644 index 000000000..98e4e557b --- /dev/null +++ b/docs/pages/en/guide/building/linyaps_package_spec.md @@ -0,0 +1,900 @@ +# Linyaps Application Packaging Specification + +The keywords **MUST**, **MUST NOT**, **REQUIRED**, **SHALL**, **SHALL NOT**, **RECOMMENDED**, **MAY**, and **OPTIONAL**[^rfc2119-keywords] in this document shall be interpreted as described in [RFC 2119][rfc-2119]. + +The correspondence between these keywords and their English counterparts is shown in the following table: + +| Chinese | English | +| ---------- | ----------- | +| **必须** | MUST | +| **禁止** | MUST NOT | +| **必要的** | REQUIRED | +| **应当** | SHALL | +| **不应** | SHALL NOT | +| **推荐的** | RECOMMENDED | +| **允许** | MAY | +| **可选的** | OPTIONAL | + +[rfc-2119]: https://datatracker.ietf.org/doc/html/rfc2119 + +This document aims to help application developers standardize application building processes to migrate to the Linyaps package management system. + +## General + +This section mainly records some general specifications that almost all projects should follow. + +### Application Name + +Application names **SHALL** use [reverse domain name notation](https://en.wikipedia.org/wiki/Reverse_domain_name_notation), such as `org.deepin.demo`. + +This application name is mainly used for desktop file naming, DBus service naming, etc. + +- Developers **SHALL** use the reverse of a domain they actually own as the application name prefix, followed by the application name + + **Note**: If a developer cannot prove they actually own the domain, it may result in the application package being removed from the repository. + +- For third-party applications developed on GitHub, if the organization hosting the application has an additional domain, it **SHALL** be preferred; otherwise, `io.github..` **SHALL** be used as the prefix. + + Particularly, if the application's organization name and application name are the same, such as , packagers **SHALL NOT** omit the repeated application name and organization name. The application ID **SHALL** be `io.github.neovim.neovim`. + + **Note**: In reality, the organization owns the domain `neovim.io`, so the most reasonable application name **SHALL** be `io.neovim.neovim`. + +- Application names containing `-` are **NOT RECOMMENDED**. If a domain/application name genuinely contains `-`, using `_` **IS RECOMMENDED** instead. + +- Application names ending with `.desktop` are **NOT RECOMMENDED** + +These specifications come from the [Desktop Entry Specification][desktop-entry-specification]. + +[desktop-entry-specification]: https://specifications.freedesktop.org/desktop-entry-spec/latest + +Further reading: + +### `prefix` and `$DESTDIR` + +When writing an application's build process, developers **SHALL NOT** assume a fixed installation location. Installing executables to hardcoded paths in Makefile/CMakeLists.txt, such as `/usr/bin`, is non-compliant behavior. + +When developers write build/install processes, they **SHALL** respect the build system's `prefix` configuration and the value of the `$DESTDIR` environment variable to allow packagers to conveniently configure the application's specific installation location during packaging. + +`prefix` refers to the specific location in the system where the application will ultimately be installed, as specified to the build system during build/install time. + +When developers do not specify an installation location, its default value **SHALL** be `/usr/local`. When packaging through the package management system, the package management system configures this value. When using dpkg-related tools for packaging, the value is configured as `/usr`. However, when writing build/install processes, developers should consider that `prefix` may be configured to any value. + +`$DESTDIR` is an environment variable agreed upon for the build system's installation process to facilitate distribution packaging and other processes. Its general working logic is as follows: + +If the build system completes the build work and during the installation process is specified `prefix=/usr` and `$DESTDIR=./tmp`, after completing installation, all product files should appear in the `./tmp/usr` directory. Packaging tools will then treat `./tmp` as the root directory for compression, packaging, and other work on the files contained within. + +Here we use common build systems as examples to show **RECOMMENDED** ways of writing common file installation processes. These writing methods all respect the `prefix` configuration and `$DESTDIR`: + +#### Makefile + +This section is mainly referenced from content in and . + +Here we define default values for some variables and other common parts for writing examples later. Explanations of these variable defaults can be found in the links above. + +```makefile +DESTDIR ?= + +prefix ?= /usr/local +bindir ?= $(prefix)/bin +libdir ?= $(prefix)/lib +libexecdir ?= $(prefix)/libexec +datarootdir ?= $(prefix)/share + +INSTALL ?= install +INSTALL_PROGRAM ?= $(INSTALL) +INSTALL_DATA ?= $(INSTALL) -m 644 + +# The above defined variables with default values are recommended behaviors in the above specifications and should not be modified. + +PKG_CONFIG ?= pkg-config + +.PHONY: install +``` + +- Executable files + + ```makefile + install: + $(INSTALL) -d "$(DESTDIR)$(bindir)" + $(INSTALL_PROGRAM) path/to/your/executable "$(DESTDIR)$(bindir)"/executable + ``` + +- Internal executables + + Refers to executables that should not be directly invoked by users in the terminal. These executables **SHALL NOT** be accessible via `$PATH`. + + ```makefile + install: + $(INSTALL) -d "$(DESTDIR)$(libexecdir)" + $(INSTALL_PROGRAM) path/to/my/internal/executable "$(DESTDIR)$(libexecdir)"/executable + ``` + +- Static libraries + + ```makefile + install: + $(INSTALL) -d "$(DESTDIR)$(libdir)" + $(INSTALL_DATA) path/to/my/library.a "$(DESTDIR)$(libdir)"/library.a + ``` + +- pkg-config configuration files + + ```makefile + pc_dir ?= $(libdir)/pkgconfig + ifeq ($(findstring $(pc_dir), $(subst :, , $(shell \ + $(PKG_CONFIG) --variable=pc_path)), ) + $(warning pc_dir="$(pc_dir)" \ + is not in the search path of current pkg-config installation) + endif + + .PHONY: install-pkg-config + install-pkg-config: + $(INSTALL) -d "$(DESTDIR)$(pc_dir)" + $(INSTALL_DATA) path/to/your.pc "$(DESTDIR)$(pc_dir)"/your.pc + ``` + + If it can be determined that the file is cross-architecture compatible, `$(datarootdir)` **MAY** be used instead of `$(libdir)`. + +- System-level systemd units + + ```makefile + systemd_system_unit_dir ?= $(shell \ + $(PKG_CONFIG) --define-variable=prefix=$(prefix) \ + systemd --variable=systemd_system_unit_dir) + ifeq ($(findstring $(systemd_system_unit_dir), $(subst :, , $(shell \ + $(PKG_CONFIG) systemd --variable=systemd_system_unit_path))), ) + $(warning systemd_system_unit_dir="$(systemd_system_unit_dir)" \ + is not in the system unit search path of current systemd installation) + endif + + .PHONY: install-systemd-system-unit + install-systemd-system-unit: + $(INSTALL) -d "$(DESTDIR)$(systemd_system_unit_dir)" + $(INSTALL_DATA) path/to/your.service "$(DESTDIR)$(systemd_system_unit_dir)"/your.service + ``` + +- User-level systemd units + + ```makefile + systemd_user_unit_dir ?= $(shell \ + $(PKG_CONFIG) --define-variable=prefix=$(prefix) \ + systemd --variable=systemd_user_unit_dir) + ifeq ($(findstring $(systemd_user_unit_dir), $(subst :, , $(shell \ + $(PKG_CONFIG) systemd --variable=systemd_user_unit_path))), ) + $(warning systemd_user_unit_dir="$(systemd_user_unit_dir)" \ + is not in the user unit search path of current systemd installation) + endif + + .PHONY: install-systemd-user-unit + install-systemd-user-unit: + $(INSTALL) -d "$(DESTDIR)$(systemd_user_unit_dir)" + $(INSTALL_DATA) path/to/your.service "$(DESTDIR)$(systemd_user_unit_dir)"/your.service + ``` + +- Desktop files + + ```makefile + install: + $(INSTALL) -d "$(DESTDIR)$(datarootdir)"/applications + $(INSTALL_PROGRAM) path/to/your.desktop "$(DESTDIR)$(datarootdir)"/applications/your.desktop + ``` + +- Desktop file icons + + See: + - If installing icons of fixed sizes, using PNG format **IS RECOMMENDED** + + At least a 48x48 PNG **MUST** be installed to ensure proper basic functionality of icon-related features in the desktop environment + + - If installing vector versions of icons, using SVG format **IS RECOMMENDED** + + ```makefile + install: + $(INSTALL) -d "$(DESTDIR)$(datarootdir)"/icons/hicolor/48x48/apps + $(INSTALL_DATA) path/to/your.png "$(DESTDIR)$(datarootdir)"/icons/hicolor/48x48/apps/your.png + # Add more sizes of .png icons here... + + $(INSTALL) -d "$(DESTDIR)$(datarootdir)"/icons/hicolor/scalable/apps + $(INSTALL_DATA) path/to/your.svg "$(DESTDIR)$(datarootdir)"/icons/hicolor/scalable/apps/your.svg + ``` + +#### CMake + +This section is mainly referenced from content in and . + +Here we define default values for some variables and other common parts for writing examples later. Explanations of these variable defaults can be found in the links above. + +The writing logic is consistent with the related content in the Makefile section. + +```cmake +include(GNUInstallDirs) +``` + +- Executable files + + See: + + ```cmake + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/path/to/your/executable TYPE BIN) + ``` + +- Internal executables + + Refers to executables that should not be directly invoked in the terminal. These executables **SHALL NOT** be accessible via `$PATH` + + See: + + ```cmake + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/path/to/your/executable DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}) + ``` + + Note: TYPE is not used because TYPE does not currently support LIBEXEC + +- Target files/Export files + + To be supplemented + +- pkg-config configuration files + + To be supplemented + +- System-level systemd units + + ```cmake + find_package(PkgConfig) + if(NOT SYSTEMD_SYSTEM_UNIT_DIR) + if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.28") + pkg_get_variable(SYSTEMD_SYSTEM_UNIT_DIR systemd systemd_system_unit_dir + DEFINE_VARIABLES prefix=${CMAKE_INSTALL_PREFIX}) + else() + pkg_get_variable(SYSTEMD_PREFIX systemd prefix) + pkg_get_variable(SYSTEMD_SYSTEM_UNIT_DIR systemd systemd_system_unit_dir) + string(REPLACE "${SYSTEMD_PREFIX}" "${CMAKE_INSTALL_PREFIX}" + SYSTEMD_SYSTEM_UNIT_DIR "${SYSTEMD_SYSTEM_UNIT_DIR}") + endif() + endif() + pkg_get_variable(SYSTEMD_SYSTEM_UNIT_PATH systemd systemd_system_unit_path) + if(NOT SYSTEMD_SYSTEM_UNIT_PATH MATCHES ".*:${SYSTEMD_SYSTEM_UNIT_DIR}:.*") + message(WARNING SYSTEMD_SYSTEM_UNIT_DIR="${SYSTEMD_SYSTEM_UNIT_DIR}" is not + in the system unit search path of + current systemd installation) + endif() + + install(FILES path/to/your.service + DESTINATION ${SYSTEMD_SYSTEM_UNIT_DIR}) + ``` + +- User-level systemd units + + ```cmake + find_package(PkgConfig) + if(NOT SYSTEMD_USER_UNIT_DIR) + if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.28") + pkg_get_variable(SYSTEMD_USER_UNIT_DIR systemd systemd_user_unit_dir + DEFINE_VARIABLES prefix=${CMAKE_INSTALL_PREFIX}) + else() + pkg_get_variable(SYSTEMD_PREFIX systemd prefix) + pkg_get_variable(SYSTEMD_USER_UNIT_DIR systemd systemd_user_unit_dir) + string(REPLACE "${SYSTEMD_PREFIX}" "${CMAKE_INSTALL_PREFIX}" + SYSTEMD_USER_UNIT_DIR "${SYSTEMD_USER_UNIT_DIR}") + endif() + endif() + pkg_get_variable(SYSTEMD_USER_UNIT_PATH systemd systemd_user_unit_path) + if(NOT SYSTEMD_USER_UNIT_PATH MATCHES ".*:${SYSTEMD_USER_UNIT_DIR}:.*") + message(WARNING SYSTEMD_USER_UNIT_DIR="${SYSTEMD_USER_UNIT_DIR}" is not + in the user unit search path of + current systemd installation) + endif() + + install(FILES path/to/your.service + DESTINATION ${SYSTEMD_USER_UNIT_DIR}) + ``` + +- Desktop files + + ```cmake + install(FILES path/to/your.desktop + DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) + ``` + +- Desktop file icons + + ```cmake + install(FILES path/to/your.png + DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/48x48/apps) + # Add more sizes of .png icons here... + + install(FILES path/to/your.svg + DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps) + ``` + +### Configuration Files + +#### Desktop files + +Desktop file names **SHALL NOT** contain `-`. After removing the `.desktop` suffix, they **SHALL** comply with the relevant specifications described in the Application Name section. + +- **RECOMMENDED** to fill the [`TryExec` field][key-tryexec] to ensure that the desktop file is no longer valid after the application has been uninstalled +- **RECOMMENDED** to fill the [`WMClass` field][key-startupwmclass] to ensure that desktop environment basic functions based on window and application matching, such as taskbar, work properly +- **RECOMMENDED** to use only the executable file name rather than absolute paths when filling the [`Exec` field][key-exec] +- **NOT RECOMMENDED** to use absolute paths when filling the [`Icon` field][key-icon] + +[key-tryexec]: https://specifications.freedesktop.org/desktop-entry-spec/latest/recognized-keys.html#key-tryexec +[key-startupwmclass]: https://specifications.freedesktop.org/desktop-entry-spec/latest/recognized-keys.html#key-startupwmclass +[key-exec]: https://specifications.freedesktop.org/desktop-entry-spec/latest/recognized-keys.html#key-exec +[key-icon]: https://specifications.freedesktop.org/desktop-entry-spec/latest/recognized-keys.html#key-icon + +#### DBus Services + +- **RECOMMENDED** that service file names match the Name field in the file +- **RECOMMENDED** to use absolute paths in the Exec field of service files +- **RECOMMENDED** to fill the SystemdService field +- **RECOMMENDED** that the service name in the SystemdService field matches the Name field +- **RECOMMENDED** that the Name field ends with a number + +#### Systemd Services + +- **RECOMMENDED** that service files with BusName have file names matching the BusName +- **RECOMMENDED** to use absolute paths in the ExecStart field + +When the above configuration files use absolute paths, **NOT RECOMMENDED** to hardcode paths. Their paths **SHALL** remain consistent with the final installation location. **RECOMMENDED** to first write template files in the project, using placeholders to represent absolute paths, and generate final configuration files after the build system replaces the placeholders. + +Here we use desktop files as examples to show how to generate final configuration files under several common build systems. + +Assume the final product `org.deepin.demo.desktop` content is as follows: + +```ini +[Desktop Entry] +Name=demo +Exec=/usr/bin/demo +Type=Application +Terminal=false +``` + +- Using Makefile as the build system. + 1. First, write the template file `org.deepin.demo.desktop.in` with the following content: + + ```ini + [Desktop Entry] + Name=demo + Exec=@BINDIR@/demo + Type=Application + Terminal=false + ``` + + 2. Write the corresponding makefile rules. + + ```makefile + DESKTOP_TEMPLATE = org.deepin.demo.desktop.in + DESKTOP_FILE = org.deepin.demo.desktop + + # Replace placeholders and generate the final .desktop file + desktop: $(DESKTOP_TEMPLATE) + sed -e "s/@BINDIR@/$(bindir)/g" \ + $(DESKTOP_TEMPLATE) > $(DESKTOP_FILE) + + install: + $(INSTALL) -d "$(DESTDIR)$(datarootdir)"/applications + $(INSTALL_PROGRAM) $(DESKTOP_FILE) "$(DESTDIR)$(datarootdir)"/applications/$(DESKTOP_FILE) + + clean: + rm -f $(DESKTOP_FILE) + + all: desktop + ``` + +- If using CMake as the build system. + 1. Write the desktop template file. + + ```desktop + [Desktop Entry] + Name=demo + Exec=@CMAKE_INSTALL_BINDIR@/demo + Type=Application + Terminal=false + ``` + + 2. Write the corresponding cmake rules. + + ```cmake + set(DESKTOP_FILE "org.deepin.demo.desktop") + # Use configure_file for placeholder replacement + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/org.deepin.demo.desktop.in + ${CMAKE_CURRENT_BINARY_DIR}/${DESKTOP_FILE} + @ONLY + ) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${DESKTOP_FILE} + DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) + ``` + +### Header Files and Libraries + +The Linyaps environment consists of up to three parts. Taking compiling `org.deepin.demo` under the `x86_64` architecture as an example, the default search paths for header files and library files include the following parts: + +| **Component** | **Package Name** | **Header Files** | **Library Files** | +| ------------------ | ---------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------- | +| base | org.deepin.base | /usr/include | /usr/lib
/usr/lib/x86_64-linux-gnu | +| runtime (optional) | org.deepin.runtime.dtk | /runtime/include | /runtime/lib
/runtime/lib/x86_64-linux-gnu | +| app | org.deepin.demo | /opt/apps/org.deepin.demo/files/include | /opt/apps/org.deepin.demo/files/lib
/opt/apps/org.deepin.demo/files/lib/x86_64-linux-gnu | + +Priority is arranged from top to bottom. If a header file exists in both `org.deepin.base` and `org.deepin.demo`, the file in `org.deepin.demo` will be matched with higher priority during use. The same applies to library files. + +Default search paths are suitable for standard libraries or development libraries without configuration files. In actual build scenarios, development libraries usually provide configuration files to facilitate users' compilation and linking. Developers **SHALL** use these files in their build systems rather than relying on default search paths. + +Common configuration files include `.pc`, `.cmake`, etc. How to use them specifically depends on the development library and build system. Here we give examples of using configuration files with several common build systems. + +#### Makefile + +##### Using `.pc` files + +```makefile +# Common variables, inherit CXXFLAGS environment variable and append content +CXX = g++ +CXXFLAGS = $(CXXFLAGS) -Wall -Wextra -std=c++11 +# Get .pc file content through pkg-config tool +# Return value is generally content of -I/path -lname type +PKG_CONFIG = pkg-config +LIBS = $(shell $(PKG_CONFIG) --cflags --libs libname) + +TARGET = demo + +SRCS = main.cpp + +all: $(TARGET) + +# Provide .pc information to compiler during build +$(TARGET): $(SRCS) + $(CXX) $(CXXFLAGS) $(LIBS) -o $@ $^ + +clean: + rm -f $(TARGET) +``` + +#### CMake + +##### Using `.pc` files + +```cmake +find_package(PkgConfig REQUIRED) +pkg_check_modules(PackageAliasName REQUIRED IMPORTED_TARGET PackageName) + +# Add executable +add_executable(demo main.cpp) + +# Set linking libraries. Header file search paths will be automatically expanded. +target_link_libraries(demo PRIVATE PkgConfig::PackageAliasName) +``` + +##### Using `.cmake` files + +```cmake +find_package( REQUIRED COMPONENTS ) + +# Add executable +add_executable(demo main.cpp) + +# Set linking libraries. Header file search paths will be automatically expanded. +target_link_libraries(demo PRIVATE PackageName::Component) +``` + +Note: + +**NOT RECOMMENDED** to directly hardcode the above default search paths in project build configuration files. +**NOT RECOMMENDED** to override environment variables such as CFLAGS/CXXFLAGS. If there are additional parameters, they **SHALL** be appended to these variables. + +### Dependency Introduction + +As mentioned in the "Header Files and Libraries" section, the Linyaps environment consists of multiple parts. If the content in base or even runtime cannot meet requirements, developers **SHALL** introduce missing dependencies on the APP side. The introduction method is to declare them under the `sources` field in the `linglong.yaml` file and write corresponding installation or compilation rules under the `build` field. + +`sources` supports multiple file types, **MAY** introduce source code or compiled binary files, even a deb. However, for introducing compiled binary files, developers **MUST** consider whether they are compatible with the current base or runtime. + +#### Using Source Code Introduction + +Introducing dependencies through source code is a **RECOMMENDED** practice, as it can greatly ensure the stability and maintainability of the build process. The downside is that it may take developers considerable time to write yaml files, as dependencies may have their own dependencies. + +_If developers find that dependencies are complex and repeatedly used by other applications, they **SHOULD** consider integrating the dependencies into a runtime-type package._ + +When dependencies are compiled under the Linyaps environment, their configuration files are usually "reliable". After compilation and installation, developers can directly use them in their projects. + +```yaml +sources: + - kind: git + url: # app source url + commit: # commit hash + - kind: git + url: # dependency source url + commit: # commit hash +build: + # Compile dependency + cd /project/your_dependency_name/ + cmake -Bbuild -DCMAKE_INSTALL_PREFIX=$PREFIX + make install + + # Compile and install APP + cd /project/your_app_name + cmake -Bbuild -DCMAKE_INSTALL_PREFIX=$PREFIX + make install +``` + +#### Using deb Introduction + +This is a "shortcut". If developers do not consider subsequent updates of the application, this method **MAY** be used. Developers can use auxiliary tools to analyze dependency relationships and batch import the involved dependencies into sources. + +##### Using VSCode Linyaps Extension + +1. Install the aptly command-line tool +2. Search for linglong in the VSCode extension store and install related plugins. +3. Place the sources field at the end of linglong.yaml +4. Add gen_deb_source comment at the end of sources +5. Press Ctrl+Shift+P and search for linglong: Gen deb sources command + +After execution, the yaml file will automatically write the following content: + +```yaml +build: + # Extract and import deb, install_dep file is automatically downloaded by the plugin + bash ./install_dep linglong/sources "$PREFIX" + + # Compile and install APP +sources: + # Source code + - kind: git + url: # app source url + commit: # commit hash + # The following comments are generated and used by the plugin, retrieving libical-dev from repository to analyze its dependencies, automatically generating sources below the comments + # linglong:gen_deb_source sources amd64 https://ci.deepin.com/repo/deepin/deepin-community/backup/rc2 beige main + # linglong:gen_deb_source install libical-dev +``` + +Note: +The compiled products of deb have an installation prefix of `/usr`. The `install_dep` script automatically handles `.pc` files in it, replacing `/usr` with `$PREFIX`. `xxx.cmake` type files cannot be batch processed. If there are hardcoded path behaviors, they may not work properly. + +## Linyaps + +This section mainly describes some special requirements of the Linyaps package management system for applications. + +### Limitations + +- Applications that need to be packaged through the Linyaps package management system **MUST** run as the user who started the Linyaps container (usually a regular user). Any form of privilege escalation mechanism is unavailable when the Linyaps package management system runs applications, including but not limited to SUID bits recorded in the file system and capabilities and other permission escalation mechanisms based on file system extended attributes. +- Linyaps currently does not support packaging applications containing system-level systemd units. +- **NOT RECOMMENDED** to package Desktop Environment components, such as launchers, file managers, resource managers, status bars, etc. + +### Specifications + +#### Application Package Name + +Linyaps application package names **MUST** fully comply with the relevant regulations in the "Application Name" section above. Additionally: + +- Application names are case-insensitive + +#### Application Version Number + +Linyaps package application version numbers **MUST** be four groups of decimal numbers separated by `.`, for example `1.0.0.0`. + +If the specified version number has fewer than four groups, zeros will be supplemented backward until the conditions are met, for example `1.90` will be automatically supplemented to `1.90.0.0`. + +The overall length of the version number after automatic supplementation to four groups **SHALL NOT** exceed 256 bytes in string meaning. + +#### Runtime Environment + +Linyaps applications **MUST** select a base as the basic runtime environment. Available bases: + +| **Base Library** | **Package Name/Version** | +| ---------------- | ------------------------ | +| glibc(2.38) | org.deepin.base/23.1.0.0 | + +If frameworks beyond the basic environment need to be used additionally, **SHALL** use appropriate runtime. Available runtime: + +| **Framework** | **Package Name/Version** | +| ------------------- | ------------------------------- | +| QT(5.15) + DTK(5.6) | org.deepin.runtime.dtk/23.1.0.0 | + +When using base or runtime, version numbers **SHALL** fill the first three digits, such as '23.1.0', to facilitate receiving updates later. Filling all four digits version means **FORBIDDEN** base or runtime updates. + +#### Installation Location + +During the build and installation process, Linyaps build tools will set the `$PREFIX` environment variable. The value of this environment variable **SHALL** be `/opt/apps/${APPID}/files`, but it is not recommended to directly use its common value when writing build and installation processes. **RECOMMENDED** to always read the `$PREFIX` environment variable. + +For the application's build and installation process, writable directories are only: + +1. The `/source` directory for placing source code required for building +2. The installation location, i.e., the location specified by `$PREFIX` + +Installing files to other locations in the build process is **FORBIDDEN**, which usually leads to write failures or applications being unable to find these files at runtime. + +The following are examples of using the `$PREFIX` environment variable to control application installation location when calling some common build systems: + +##### cmake + +```bash +cd path/to/build && cmake path/to/source -DCMAKE_INSTALL_PREFIX="$PREFIX" +``` + +##### make + +```bash +cd path/to/source && make prefix="$PREFIX" +``` + +##### meson + +```bash +cd path/to/source && meson configure --prefix="$PREFIX" path/to/build +``` + +## Build Artifacts + +This section mainly describes the composition and related functions of application build artifacts after successful build. + +### Directory Structure + +After successful application build, Linyaps build tools will submit the artifacts to local cache. When distributing offline, they should be exported as `.layer` or `.uab` type files. + +By extracting the build artifact layer file: + +```bash +ll-builder extract org.deepin.demo_0.0.0.1_x86_64_binary.layer ./tmp +``` + +The following directory structure can be obtained: + +```plain + ./tmp + ├── entries + │ └── share -> ../files/share + ├── files + │ ├── bin + │ │ └── demo + │ ├── share + │ │ ├── applications + │ │ │ └── org.deepin.demo.desktop + │ │ ├── icons + │ │ │ └── hicolor + │ │ │ └── scalable + │ │ │ └── apps + │ │ │ └── org.deepin.demo.svg + │ │ ├── doc + │ │ │ ├── changelog.gz + │ │ │ └── copyright + │ │ ├── mime + │ │ │ └── packages + │ │ │ └── org.deepin.demo.xml + │ │ ├── locale + │ │ │ └── zh_CN + │ │ │ └── info.json + │ │ └── services + │ │ └── org.deepin.demo.xml + │ └── libs + │ └── libdemo.so.5.2.1 + ├── info.json + └── org.deepin.demo.install +``` + +When the application runs, these files or directories will be mapped to the following paths in the container: + +```plain +/ +├── bin +├── ... +├── opt +│ └── apps +│ └── org.deepin.demo +│ ├── files +│ ├── entries +│ ├── info.json +│ └── org.deepin.demo.install +└── var +``` + +#### info.json file + +info.json is an application description file defined by Linyaps. This file is automatically generated by build tools and **SHALL NOT** be manually modified. Its content is as follows: + +```json +{ + "id": "org.deepin.demo", + "arch": ["x86_64"], + "base": "main:org.deepin.foundation/23.0.0/x86_64", + "channel": "main", + "command": ["/opt/apps/org.deepin.demo/files/bin/demo"], + "description": "simple Qt demo.\n", + "kind": "app", + "module": "runtime", + "name": "demo", + "runtime": "main:org.deepin.Runtime/23.0.1/x86_64", + "size": 118763, + "version": "0.0.0.1" +} +``` + +Below is a sequential explanation of each field in info.json: + +`id`: Software package identifier, i.e., application package name. + +`arch`: Supported architectures for the software package. Currently supports the following CPU architectures: + +- `amd64`: Applicable to `x86_64` architecture `CPU`. +- `loongarch64`: Applicable to new Loongson series `CPU`. +- `arm64`: Applicable to `ARM64` bit `CPU`. + +`base`: Basic environment used by the software package at runtime. + +`channel`: Software package distribution channel. + +`command`: Default startup command for the software package. + +`description`: Description information of the software package. + +`kind`: Software package category. + +`module`: Software package module. + +`name`: Common name of the software package. + +`runtime`: Environment used by the software package at runtime. + +`size`: Software package size. + +`version`: Application version, whose format shall meet the requirements described in the Application Version Number section. + +#### entries directory + +This directory is used to share application configuration files with the host (desktop environment). This directory usually has the following subdirectories: + +- entries/share/applications +- entries/share/dbus-1/services +- entries/share/systemd/user +- entries/share/icons +- entries/share/mime +- entries/share/fonts + +The entries directory is automatically generated by build tools. The directory only contains a soft link named share, which points to the files/share directory in the upper level directory. + +When an application is installed on the host, the Linyaps package manager will use this link file to link all files in it to the path added by Linyaps to the `$XDG_DATA_DIRS` variable. That is, `/var/lib/linglong/entries/share/`. + +```bash +$ ls /var/lib/linglong/entries/share/applications/ -l +lrwxrwxrwx 1 deepin-linglong deepin-linglong 101 July 30 11:13 org.deepin.demo.desktop -> ../../../layers/main/org.deepin.demo/0.0.0.1/x86_64/runtime/entries/share/applications/org.deepin.demo.desktop +``` + +##### applications directory + +Place application startup configuration files, i.e., .desktop files. + +```ini +[Desktop Entry] +Exec=demo +Name=demo +TryExec=demo +Type=Application +``` + +This file will be automatically modified during build to: + +```ini +[Desktop Entry] +Exec=/usr/bin/ll-cli run org.deepin.demo -- demo +Name=demo +TryExec=/usr/bin/ll-cli +Type=Application +``` + +Applications can have multiple desktop files. + +**Path correspondence:** + +| **Packaging Path** | **Installation Path** | +| -------------------------------------------------- | --------------------------------------------------------- | +| $PREFIX/share/applications/org.deepin.demo.desktop | $XDG_DATA_DIRS/share/applications/org.deepin.demo.desktop | + +##### dbus services directory + +Directory for dbus services registered by programs, for example: + +```ini +[D-BUS Service] +Name=org.deepin.demo +Exec=/opt/apps/org.deepin.demo/files/bin/demo --dbus +``` + +This file will be automatically modified during build to: + +```ini +[D-BUS Service] +Name=org.deepin.demo +Exec=/usr/bin/ll-cli run org.deepin.demo -- /opt/apps/org.deepin.demo/files/bin/demo --dbus +``` + +An application can configure multiple services. Service names must be subdomains. + +**Path correspondence:** + +| **Packaging Path** | **Installation Path** | +| ---------------------------------------------------- | ----------------------------------------------------------- | +| $PREFIX/share/services/org.deepin.demo.service | $XDG_DATA_DIRS/dbus-1/service/org.deepin.demo.service | +| $PREFIX/share/services/org.deepin.demo.hello.service | $XDG_DATA_DIRS/dbus-1/service/org.deepin.demo.hello.service | + +##### User-level systemd services + +Directory for user-level services registered by programs, for example: + +```ini +[Unit] +Description = demo service +After=user-session.target + +[Service] +Type = simple +ExecStart = demo + +[Install] +WantedBy=user-session.target +``` + +This file will be automatically modified during build to: + +```ini +[Unit] +Description = demo service +After=user-session.target + +[Service] +Type = simple +ExecStart = ll-cli run org.deepin.demo -- demo + +[Install] +WantedBy=user-session.target +``` + +Unlike dbus service, files installed to `$PREFIX/lib/systemd/user` will be automatically copied to `$PREFIX/share/systemd/user`. + +**Path correspondence:** + +| **Packaging Path** | **Installation Path** | +| ------------------------------------------------ | --------------------------------------------------- | +| $PREFIX/lib/systemd/user/org.deepin.demo.service | $XDG_DATA_DIRS/systemd/user/org.deepin.demo.service | + +##### icons directory + +Directory for application icons. The structure should be consistent with the system icons directory structure. + +**Path correspondence:** + +| **Packaging Path** | **Installation Path** | +| ------------------------------------------------------------- | -------------------------------------------------------------- | +| $PREFIX/share/icons/hicolor/scalable/apps/org.deepin.demo.svg | $XDG_DATA_DIRS/icons/hicolor/scalable/apps/org.deepin.demo.svg | +| $PREFIX/share/icons/hicolor/24x24/apps/org.deepin.demo.png | $XDG_DATA_DIRS/icons/hicolor/24x24/apps/org.deepin.demo.png | +| $PREFIX/share/icons/hicolor/16x16/apps/org.deepin.demo.png | $XDG_DATA_DIRS/icons/hicolor/16x16/apps/org.deepin.demo.png | + +##### mime directory + +MIME (Multipurpose Internet Mail Extensions) multipurpose internet mail extensions type. This directory is used to store mime configuration files, which are in XML format and end with .xml. + +**Path correspondence:** + +| **Packaging Path** | **Installation Path** | +| ----------------------------------------------- | ------------------------------------------------ | +| $PREFIX/share/mime/packages/org.deepin.demo.xml | $XDG_DATA_DIRS/mime/packages/org.deepin.demo.xml | + +##### fonts directory + +Font storage path. + +#### files directory + +Store various files required by the application. There are no restrictions on placing files in this directory, but it is recommended to place executable programs in the bin subdirectory. Third-party libraries that applications or plugins depend on are recommended to be placed in /opt/apps/${id}/files/lib directory. + +#### .install file + +The org.deepin.demo.install file in the above example org.deepin.demo is a file automatically generated during the build process. This file is used to define which files should be installed in the binary module and can be used for final software package artifact volume trimming. + +When this file is not defined in the same directory level as linglong.yaml, all content is installed to the binary module according to the rules under build in linglong.yaml. + +Usage method: + +After the first successful build, an .install file will be generated in the artifacts and record all files installed to the binary module. Copy this file to the directory level of linglong.yaml. After modifying the content in the .install file and building again, only the content noted in .install will be submitted to the binary module. + +## References + +[Desktop Application Packaging Specifications](https://github.com/linuxdeepin/deepin-specifications/blob/master/unstable/%E6%A1%8C%E9%9D%A2%E5%BA%94%E7%94%A8%E6%89%93%E5%8C%85%E8%A7%84%E8%8C%83.md) diff --git a/docs/pages/en/guide/building/manifests.md b/docs/pages/en/guide/building/manifests.md new file mode 100644 index 000000000..aae5161cf --- /dev/null +++ b/docs/pages/en/guide/building/manifests.md @@ -0,0 +1,361 @@ + + +# Build Configuration File Introduction + +`linglong.yaml` is the description file for Linyaps project engineering, which records relevant information needed for building, such as build artifact names, versions, source code addresses, build dependencies, etc. + +## Project Directory Structure + +```bash +{project-root} +├── linglong.yaml +└── linglong + +{user-home} +└── .cache + └── linglong-builder + ├── repo + └── layers +``` + +## Field Definitions + +The `linglong.yaml` file structure follows specific specifications. First, the version of the configuration file needs to be declared at the top level of the file: + +```yaml +version: "1" +``` + +| Name | Description | Required | +| ------- | ------------------------------------------------------ | -------- | +| version | Version of the build configuration file, currently '1' | Yes | + +Next are the main configuration blocks. Among them, `package`, `base`, and `build` must be defined. + +### Package Metadata Configuration (`package`) + +Defines basic information about build artifacts. This `package` configuration block is required. + +```yaml +package: + id: org.deepin.calculator + name: deepin-calculator + version: 5.7.21.0 + kind: app + description: | + calculator for deepin os. + architecture: x86_64 # Optional + channel: main # Optional +``` + +| Name | Description | Required | +| ------------ | -------------------------------------------------------------------------- | -------- | +| id | Unique name of build artifact (for example: `org.deepin.calculator`) | Yes | +| name | Name of build artifact (for example: `deepin-calculator`) | Yes | +| version | Version of build artifact, recommend four digits (for example: `5.7.21.0`) | Yes | +| kind | Type of build artifact: `app` (application), `runtime` (runtime) | Yes | +| description | Detailed description of build artifact | Yes | +| architecture | Target architecture of build artifact (for example: `x86_64`, `arm64`) | No | +| channel | Channel of build artifact (for example: `main`, `dev`) | No | + +### Command (`command`) + +Defines how to start the application. This is a list of strings. The first element in the list is usually the absolute path of the executable file (relative to inside the container), and subsequent elements are parameters passed to the executable. + +```yaml +command: + - /opt/apps/org.deepin.calculator/files/bin/deepin-calculator + # - --some-argument # Can add more parameters +``` + +| Name | Description | Required | +| ------- | ----------------------------------------------------------------------------------------------------------------------- | -------- | +| command | Defines the executable file path and its parameter list for starting the application. Usually required for `kind: app`. | No | + +### Base Environment (`base`) + +Specifies the minimal root filesystem required for building and running. This field is required. + +```bash +base: org.deepin.base/23.1.0 +``` + +| Name | Description | Required | +| ---- | ------------------------------------------------------------------------------------------------------- | -------- | +| base | Identifier of the base, in the format `id/version`. Version numbers support three-digit fuzzy matching. | Yes | + +### Runtime + +Application runtime dependencies, also build dependencies. + +```text +runtime: org.deepin.runtime.dtk/23.1.0 +``` + +| Name | Description | +| ------- | --------------------------------------------------------------- | +| id | Unique name of the runtime | +| version | Version of the runtime, three digits can fuzzy match the fourth | + +### Sources (`sources`) + +Describes source code information required by the project. `sources` is a list that can contain multiple source items. Fetched source code is stored by default in the `linglong/sources` directory at the same level as `linglong.yaml`. + +#### git Type + +```yaml +sources: + - kind: git + url: https://github.com/linuxdeepin/deepin-calculator.git + commit: d7e207b4a71bbd97f7d818de5044228c1a6e2c92 # Branch, tag or commit, used to precisely specify the commit + name: deepin-calculator.git # Optional, specify the directory name after download +``` + +| Name | Description | Required (within single source) | +| ------ | --------------------------------------------------------------------------------------------------- | ------------------------------- | +| kind | `git`, indicating using git tool to download. | Yes | +| url | Source code repository address | Yes | +| commit | Source code repository branch, tag or hash value of a specific commit, used for precise checkout | Yes | +| name | Optional, specify the subdirectory name in `linglong/sources` directory after source code download. | No | + +#### file Type + +```yaml +sources: + - kind: file + url: https://example.com/some-file.dat + digest: sha256:... # Recommend providing sha256 hash value + name: my-data.dat # Optional, specify the filename after download +``` + +| Name | Description | Required (within single source) | +| ------ | ------------------------------------------------------------------------------ | ------------------------------- | +| kind | `file`, indicating direct file download. | Yes | +| url | File download address | Yes | +| digest | Optional, sha256 hash value of the file, used for verification. | No | +| name | Optional, specify the filename in `linglong/sources` directory after download. | No | + +#### archive Type + +```yaml +sources: + - kind: archive + url: https://github.com/linuxdeepin/deepin-calculator/archive/refs/tags/6.5.4.tar.gz + digest: 9675e27395891da9d9ee0a6094841410e344027fd81265ab75f83704174bb3a8 # Recommend providing sha256 hash value + name: deepin-calculator-6.5.4 # Optional, specify the directory name after extraction +``` + +| Name | Description | Required (within single source) | +| ------ | ----------------------------------------------------------------------------------------------------- | ------------------------------- | +| kind | `archive`, download compressed package and automatically extract. Supports common compressed formats. | Yes | +| url | Compressed package download address | Yes | +| digest | Optional, sha256 hash value of the compressed package file, used for verification. | No | +| name | Optional, specify the directory name in `linglong/sources` directory after extraction. | No | + +#### dsc Type + +```yaml +sources: + - kind: dsc + url: https://cdn-community-packages.deepin.com/deepin/beige/pool/main/d/deepin-calculator/deepin-calculator_6.0.1.dsc + digest: ce47ed04a427a887a52e3cc098534bba53188ee0f38f59713f4f176374ea2141 # Recommend providing sha256 hash value + name: deepin-calculator-dsc # Optional, specify the directory name after download and extraction +``` + +| Name | Description | Required (within single source) | +| ------ | --------------------------------------------------------------------------------------------------- | ------------------------------- | +| kind | `dsc`, handle Debian source package description files and their associated files. | Yes | +| url | `.dsc` file download address | Yes | +| digest | Optional, sha256 hash value of the `.dsc` file, used for verification. | No | +| name | Optional, specify the directory name in `linglong/sources` directory after download and extraction. | No | + +### Export Trimming Rules (`exclude`/`include`) + +After building the application and exporting to UAB package, files that need to be trimmed are as follows: + +```yaml +exclude: + - /usr/share/locale # Trim entire folder + - /usr/lib/libavfs.a # Trim single file + +include: + - /usr/share/locale/zh_CN.UTF-8 # Work with exclude to only export certain files in a folder +``` + +| Name | Description | +| ------- | ----------------------------------------------------------------------------------------------------------------------- | +| exclude | Absolute paths inside the container, can be files or folders, used for exclusion. | +| include | Absolute paths inside the container, files that must be included in UAB package (even if parent directory is excluded). | + +### Build Rules (`build`) + +Describes how to compile and install the project in the build environment. This field is required, and its content is a multi-line string that will be executed as a shell script. + +Describe build rules. + +```yaml +build: | + qmake -makefile PREFIX=${PREFIX} LIB_INSTALL_DIR=${PREFIX}/lib/${TRIPLET} + make + make install +``` + +| Name | Description | Required | +| ----- | ---------------------------------------------------------------------------------------------------- | -------- | +| build | Shell script executed during build phase. Script is executed inside the container build environment. | Yes | + +### Build Extensions (`buildext`) + +Optional field, used to define extension behavior for specific build stages. Currently mainly supports `apt` extension, used to manage Debian package dependencies required for building and runtime. + +```yaml +buildext: + apt: + build_depends: # Build-time dependencies, only installed in build environment + - build-essential + - cmake + - qt6-base-dev + depends: # Runtime dependencies, will be included in final application or runtime + - libqt6widgets6 + - libglib2.0-0 +``` + +| Name | Description | Required | +| ------------- | ------------------------------------------------------------------------------------------------------------- | -------- | +| buildext | Container block for build extension configuration. | No | +| apt | Extension configuration using apt package manager. | No | +| build_depends | A list of strings, listing packages needed at build time, these packages will not enter the final artifact. | No | +| depends | A list of strings, listing packages needed at runtime, these packages will be included in the final artifact. | No | + +### Modules (`modules`) + +Optional field, used to split files installed to `${PREFIX}` directory into different modules. This is useful for on-demand downloads or providing optional functionality. + +```yaml +modules: + - name: main # Main module name, usually same or related to package.id + files: # List of files or directories included in this module (relative to ${PREFIX}) + - bin/ + - share/applications/ + - share/icons/ + - lib/ # Include all libraries + - name: translations # Translation module + files: + - share/locale/ + - name: extra-data # Optional data module + files: + - share/my-app/optional-data/ +``` + +| Name | Description | Required | +| ------- | ------------------------------------------------------------------------------------------------------------------ | ----------------------------- | +| modules | List of rules defining application module splitting. | No | +| name | Name of the module. Each module needs a unique name. | Yes (within each module item) | +| files | A list of strings, listing files or directories belonging to this module. Paths are relative to `${PREFIX}` paths. | Yes (within each module item) | + +**Note:** All files installed to `${PREFIX}` will be assigned to a module. When `modules` are not defined, the build system will automatically generate default `binary` and `develop` modules. + +### Variables + +Variables that can be used during the build process. + +| Name | Description | +| ------- | ------------------------------------------------------------------------------------------------------------------------------ | +| PREFIX | Environment variable used in the build field; provides installation path during build, such as /opt/apps/org.deepin.calculator | +| TRIPLET | Environment variable used in the build field; provides a triplet containing architecture information, such as x86_64-linux-gnu | + +## Complete Examples + +### Build Application + +#### Calculator + +```yaml +version: "1" + +package: + id: org.deepin.calculator + name: deepin-calculator + version: 5.7.21.0 + kind: app + description: | + calculator for deepin os. + +command: + - /opt/apps/org.deepin.calculator/files/bin/deepin-calculator + +base: org.deepin.base/23.1.0 +runtime: org.deepin.runtime.dtk/23.1.0 + +sources: + - kind: git + url: https://github.com/linuxdeepin/deepin-calculator.git + version: master + commit: d7e207b4a71bbd97f7d818de5044228c1a6e2c92 + + - kind: git + url: https://github.com/linuxdeepin/dde-qt-dbus-factory.git + version: master + commit: d952e1913172c5507af080f644a654f9ba5fed95 + +build: | + # build dde-qt-dbus-factory + cd /project/linglong/sources/dde-qt-dbus-factory.git + qmake -makefile \ + PREFIX=${PREFIX} \ + LIB_INSTALL_DIR=${PREFIX}/lib/${TRIPLET} \ + INSTALL_ROOT=${PREFIX} + + make + make install + + # build calculator + cd /project/linglong/sources/deepin-calculator.git + cmake -Bbuild \ + -DCMAKE_INSTALL_PREFIX=${PREFIX} \ + -DCMAKE_INSTALL_LIBDIR=${PREFIX}/lib/${TRIPLET} \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_SAFETYTEST_ARG="CMAKE_SAFETYTEST_ARG_OFF" \ + -DAPP_VERSION=5.7.21 \ + -DVERSION=5.7.21 + + cmake --build build + cmake --build build --target install + +buildext: + apt: + # Additional dependencies at build time + build_depends: [] + # Additional dependencies at runtime + depends: [] +``` + +### Build Root Filesystem + +```bash +git clone git@github.com:linglongdev/org.deepin.foundation.git +cd org.deepin.foundation +bash build_base.sh beige amd64 +``` + +This project is used to build the root filesystem used by Linyaps. beige refers to the distribution code name, amd64 refers to the architecture. + +| Distribution | Architecture | +| ----------------- | ------------------------- | +| eagle (UOS 20) | amd64、arm64、loongarch64 | +| beige (deepin 23) | amd64、arm64 | + +### Build Runtime + +```yaml +git clone git@github.com:linglongdev/org.deepin.Runtime.git -b v23 +cd org.deepin.Runtime +./depend-deb-list.sh | ./tools/download_deb_depend.bash +ll-builder build --skip-fetch-source +``` + +Adds Qt and other basic environments on top of the root filesystem. diff --git a/docs/pages/en/guide/building/modules.md b/docs/pages/en/guide/building/modules.md new file mode 100644 index 000000000..120404e04 --- /dev/null +++ b/docs/pages/en/guide/building/modules.md @@ -0,0 +1,73 @@ + + +# Module Splitting + +When building with Linyaps, an application can be split into multiple modules, each containing part of the build artifacts. For example, debug symbols go to the `develop` module, translation files go to `lang-*` modules, etc. This allows users to install on demand and reduce application size. + +## Module Files + +Developers add a modules field in linglong.yaml and configure as follows: + +```yaml +modules: + - name: module1 + files: + - /path/to/file1 + - /path/to/file2 + - ^/path/to/dir1/.* + - name: module2 + files: + - /path/to/files +``` + +Module names can be customized but cannot be duplicated. Some reserved module names have special meanings, such as `binary`, `develop`, `lang-*`, etc. It is recommended that developer-customized modules start with `x-` to avoid conflicts. + +`files` is a string array, each entry writes one file path, supporting regular expressions. File paths will automatically have the application installation path `$PREFIX` added as a prefix. So if a module wants to include the `$PREFIX/bin/demo` file, only `/bin/demo` needs to be written, and Linyaps will automatically convert it to paths like `/opt/apps/org.deepin.demo/files/bin/demo`. + +If the same file path is included by multiple modules, the file will only be moved to the first module (in the order of modules). When writing regular expressions in files, they need to start with `^`, otherwise they will be considered as ordinary file paths. Regular expressions will automatically add `$PREFIX` as a prefix after `^`, and packagers don't need to add it repeatedly. + +## Reserved Module Names + +### binary module + +_This is the default module and does not need to be declared in modules._ The binary module saves build artifacts not used by other modules. When the modules field does not exist, binary saves all build artifacts. + +When users install applications using ll-cli, the binary module is installed by default. Other modules can only be installed after installing the binary module. Uninstalling the binary module will uninstall other modules at the same time. + +### develop module + +This module can store debug symbols and development tools for applications. Linyaps will separate build artifact debug symbols to directories like `$PREFIX/lib/debug` and `$PREFIX/lib/include` after building. These directories are particularly suitable for storing in this module. So when Linyaps builds, if there is no modules field or the modules do not have a develop module, it will automatically create a develop module and use the following default values: + +```yaml +modules: + - name: develop + files: + # Separated debug symbols + - ^/lib/debug/.+ + # Header files + - ^/lib/include/.+ + # Static link libraries + - ^/lib/.+\.a$ +``` + +If you need to customize the develop module, you can add develop module configuration in the `modules` field to override the default values. + +### Packaging Testing + +The `ll-builder run` command can run compiled applications. You can use the `--modules` parameter to control which modules are used at runtime, which is convenient for packagers to test module combinations. Examples: + +Load multiple language modules: `ll-builder run --modules lang-zh_CN,lang-ru_RU` + +Load develop module: `ll-builder run --modules develop`, only as an example, not recommended for actual use, because the application's develop only has debug symbols without debugging tools. If you need to debug applications, you should use the --debug parameter, see [Debugging Applications in IDE](../debug/debug.md). + +### User Installation of Modules + +The `ll-cli install` command can install applications. By default, it will install the binary module of the application. If you need to install other modules, you can use the `--module` parameter. Note that unlike `ll-builder run --modules`, ll-cli can only install one module at a time. Examples: + +Install language module: `ll-cli install --module=lang-zh_CN org.xxx.xxx` + +Install develop module: `ll-cli install --module=develop org.xxx.xxx` diff --git a/docs/pages/en/guide/building/multiarch.md b/docs/pages/en/guide/building/multiarch.md new file mode 100644 index 000000000..4f2aa4d90 --- /dev/null +++ b/docs/pages/en/guide/building/multiarch.md @@ -0,0 +1,73 @@ +# Linyaps Multi-Architecture Build Guide + +## Supported Architectures + +The current Linyaps packaging tool supports the following CPU architectures: + +- x86_64 + +- arm64 (aarch64) + +- loong64 + +- loongarch64 (Loongson old world) + +- sw64 (Sunway) + +- mips64 + +## Build Limitation Description + +Cross-architecture cross-compilation is not supported: currently can only build packages for that architecture on machines of the corresponding architecture + +## Multi-Architecture Project Structure Recommendation + +It is recommended to use the following directory structure to manage multi-architecture builds: + +```txt +project-root/ +├── arm64 +│ └── linglong.yaml # arm64 architecture configuration file +├── linglong.yaml # x86_64 architecture configuration file +├── loong64 +│ └── linglong.yaml # loong64 architecture configuration file +├── resources # Shared resource files +└── src # Shared source code +``` + +Place source code, resource files, etc. in the project root directory. The build for different architectures is determined by the configuration files for the respective architectures. + +## Build Command Examples + +ll-builder will prioritize finding the project configuration file for the current architecture. Therefore, executing ll-builder on machines of different architectures will automatically use the configuration file corresponding to the current architecture. If the architecture configuration file is not in the default location, you can use the following method to specify the configuration file location: + +```bash +# Build arm64 architecture package +ll-builder -f arm64/linglong.yaml + +# Build loong64 architecture package +ll-builder -f loong64/linglong.yaml +``` + +Note that the project configuration file (the linglong.yaml file specified by -f) needs to be in the directory or subdirectory of the project directory (the current directory where ll-builder is run). + +## Loongson + +For differences between Loongson's old and new worlds, see [Are We Loong Yet](https://areweloongyet.com/docs/old-and-new-worlds/) + +> You can use the file tool to conveniently check which world a binary program belongs to. Suppose you want to check a file called someprogram, just execute file someprogram. If the output line contains these phrases: +> interpreter /lib64/ld.so.1, for GNU/Linux 4.15.0 +> it indicates this is an old world program. +> Accordingly, if the output line contains these phrases: +> interpreter /lib64/ld-linux-loongarch-lp64d.so.1, for GNU/Linux 5.19.0 + +Given that the differences between old and new worlds are quite significant, Linyaps divides old and new worlds into two architectures. The new world uses the more concise loong64 as the architecture code name. + +Considering that there are still some applications supporting Loongson on the market that have not been adapted to the new world, Linyaps has created old world bases (org.deepin.foundation/20.0.0) and runtime (org.deepin.Runtime/20.0.0.12) that can run on new world architectures to migrate applications supporting old world to new world. + +Migration steps: + +1. Prepare a new world architecture machine and install deepin or uos system. +2. Install the `liblol-dkms` kernel module on the host machine: `apt install liblol-dkms`. +3. Write a linglong.yaml file, fill in the base and runtime versions mentioned above. +4. Extract the old world application software package in linglong.yaml and copy it to the `$PREFIX` directory. diff --git a/docs/pages/en/guide/debug/debug.md b/docs/pages/en/guide/debug/debug.md index 8caba8f77..7028e65fb 100644 --- a/docs/pages/en/guide/debug/debug.md +++ b/docs/pages/en/guide/debug/debug.md @@ -4,74 +4,173 @@ SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. SPDX-License-Identifier: LGPL-3.0-or-later --> -# Debug App +# Debugging Linyaps Applications -The following tutorial uses the [linglong-builder-demo](https://github.com/linuxdeepin/linglong-builder-demo) project mentioned in the "Building Tools" section as an example. We put the project in `/path/to/project`. Make sure to **replace the path** when referring to this tutorial. +The following tutorial uses the org.deepin.demo project mentioned in the "Building Tools" section as an example. -Since the linyaps application runs in a container, we need to use `gdbserver` to run the application in the container to debug it on the host. So you'll need to install `gdbserver` first. +We place the project in `/tmp`. When following the tutorial, **pay attention to replace the paths**. -We can use the `gdbserver` provided by the distribution, using `apt` as an example: +## Debugging with gdb in Terminal -```bash -sudo apt install gdbserver gdb -y +### Running Application in Debug Environment + +In the [Running Compiled Applications](../reference/commands/ll-builder/run.md) section, we already know that using `ll-builder run --exec /bin/bash` can run the compiled application and enter the container terminal. Simply add the `--debug` parameter after `run` to run the container in debug environment and enter it. The main differences between debug environment and non-debug environment are as follows: + +1. Debug environment uses binary+develop modules of base and runtime, while non-debug environment uses binary modules. The gdb tool is in the develop module of base. +2. Debug environment uses binary+develop modules of app, while non-debug environment uses binary modules by default (debug symbols are usually saved to develop module). +3. Debug environment generates linglong/gdbinit file in project directory and mounts it to ~/.gdbinit path in container. + +Please execute `ll-builder run --debug --exec /bin/bash` in project directory to enter debug environment container, then execute `gdb /opt/apps/org.deepin.demo/binary/demo` to start application debugging, which is no different from using command line debugging externally. This is thanks to the debugging linglong/gdbinit file providing initial configuration for `gdb`. + +### Debugging Application in Runtime Environment + +There are minor differences between debug environment and normal user runtime environment. If you need to debug application directly in runtime environment, you can use `ll-builder run --exec /bin/bash` to enter container, then execute `gdbserver 127.0.0.1:12345 /opt/apps/org.deepin.demo/bin/demo`. gdbserver will use tcp protocol to listen on port 12345 and wait for gdb connection. + +Open another host terminal, execute `gdb` in project directory, and input the following commands line by line: + +```txt +set substitute-path /project /tmp/org.deepin.demo +set debug-file-directory /tmp/org.deepin.demo/linglong/output/develop/files/lib/debug +target remote 127.0.0.1:12345 ``` -Next, refer to the tutorial in "Run compiled App", run `bash` in the container through the `ll-build run` command, and run the application to be debugged through `gdbserver`: +Next, refer to the tutorial in "Run compiled App", run `bash` in the container through the `ll-builder run` command, and run the application to be debugged through `gdbserver`: + +_If runtime environment doesn't have gdbserver command, please check if application uses org.deepin.base as base and try upgrading to latest version of org.deepin.base._ + +## Debugging with gdb in vscode + +First install C/C++ extension for vscode. Since vscode runs on host machine, it also needs to provide debugging for Linyaps container application through gdbserver. Similar to previous step, start gdbserver in runtime environment first, then configure launch.json file in vscode. Configuration is as follows: + +```json +{ + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) linglong", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/linglong/output/binary/files/bin/demo", + "args": [], + "stopAtEntry": true, + "cwd": "${workspaceFolder}", + "MIMode": "gdb", + "miDebuggerServerAddress": "127.0.0.1:12345", + "setupCommands": [ + { + "text": "set substitute-path /project ${workspaceFolder}" + }, + { + "text": "set debug-file-directory ${workspaceFolder}/linglong/output/develop/files/lib/debug" + } + ] + } + ] +} +``` -```bash -ll-build run --exec /bin/bash +Some configurations need to be changed according to actual project: + +- "program": "${workspaceFolder}/linglong/output/binary/files/bin/demo", + + This is the binary file passed to gdb, `demo` needs to be changed to actual binary filename of project + +- "stopAtEntry": true + + This requires gdb to automatically stop at main function, can be set to false if not needed + +- "miDebuggerServerAddress": "127.0.0.1:12345" + + This is the remote address for gdb connection, if port is not default 12345 when starting gdbserver, need to modify to actual port. + +- "text": "set substitute-path /project ${workspaceFolder}" + + This sets source path substitution, `${workspaceFolder}` will be automatically replaced by vscode with current working directory, can be modified to actual path if needed. + +- "text": "set debug-file-directory ${workspaceFolder}/linglong/output/develop/files/lib/debug" + + This sets debug files directory, if debug symbols are not saved to `develop` module, need to modify to actual location. + +## Debugging with gdb in Qt Creator + +Qt Creator also integrates gdb support. After starting Qt Creator, open menu bar `Debug` -> `Start Debugging` -> `Connect to Debug Server`, and fill in the dialog that pops up: -# In the container: -gdbserver:10240 deepin-draw +```text +Server Port: `12345` + +Local Executable: `/tmp/org.deepin.demo/linglong/output/binary/files/bin/demo` + +Working Directory: `/tmp/org.deepin.demo` + +Init Commands: `set substitute-path /project /tmp/org.deepin.demo` + +Debug Information: `/tmp/org.deepin.demo/linglong/output/develop/files/lib/debug` ``` -In the above command, `:10240` is any tcp port that is not currently occupied. Then we need to do two more things: +Configuration is roughly as shown in figure: -1. Use `gdb` outside the container to connect to the `gdbserver` in the container; -2. Set the source map path. +![qt-creator](images/qt-creator.png) -## Debugging with gdb in terminal +After configuration, `QtCreator` can be used normally for debugging. -1. Find the location of the executable file executed in the container on the host. For the above project, the file is located in `/path/to/project/.linglong-target/overlayfs/up/opt/apps/org.deepin. demo/files/bin/demo`. +## Saving Debug Symbols - For applications installed via `ll-cli`, the executables are generally located under `$LINGLONG_ROOT/layers/[appid]/[version]/[arch]/files/bin`. +Linyaps automatically strips binary debug symbols after building applications and stores them in `$PREFIX/lib/debug` directory. However, some toolchains strip debug symbols during build process in advance, which causes Linyaps unable to find these symbols in binary files. If your project uses qmake, need to add following configuration in pro file: - Use `gdb` to load the program outside the container: +```bash +# Linyaps sets -g option in CFLAGS and CXXFLAGS environment variables, qmake needs to inherit this environment variable +QMAKE_CFLAGS += $$(CFLAGS) +QMAKE_CXXFLAGS += $$(CXXFLAGS) +# Use debug option to avoid qmake automatically stripping debug symbols +CONFIG += debug +``` - ```bash - gdb /path/to/project/.linglong-target/overlayfs/up/opt/apps/org.deepin.demo/files/bin/demo - ``` +cmake automatically uses cflags and cxxflags environment variables, so no additional configuration is needed. Other build tools can refer to their documentation. -2. Use the `target` command in `gdb` to connect to the `gdbserver` as follows: +## Downloading Debug Symbols from Debian Repository - ```bash - target remote :10240 - ``` +Since base images don't contain debug symbols, if you need to debug system dependency libraries of applications, you need to manually download debug symbol packages from corresponding Debian repository of base. Specific steps are as follows: -3. Enter the following command in `gdb` to set the path mapping and help `gdb` to find the corresponding source code, assuming the source code is placed in the `Desktop` of the host, the command is as follows: +1. Enter container command line environment using one of the following commands: ```bash - set substitute-path /source /path/to/project + ll-builder run --bash + # or + ll-cli run $appid --bash ``` -Then just use `gdb` normally. +2. Check repository address used by base image: -## QtCreator configuration + ```bash + cat /etc/apt/sources.list + ``` -Referring to the above process, we can easily complete the configuration of `QtCreator`: +3. Open repository address in host browser and locate directory where dependency library deb packages are located: + - Use command `apt-cache show | grep Filename` to check deb package path in repository + - Complete download address is: repository address + deb package path -Click: Debug > Start Debugging > Connect to the Running Debug Server, and fill in the dialog box: + For example, to download debug symbols package for libgtk-3-0: -```text -Server port: `10240` + ```bash + apt-cache show libgtk-3-0 | grep Filename + # Output: pool/main/g/gtk+3.0/libgtk-3-0_3.24.41-1deepin3_amd64.deb + # Complete directory: /pool/main/g/gtk+3.0/ + ``` -Local executable file: `/path/to/project/.linglong-target/overlayfs/up/opt/apps/org.deepin.demo/files/bin/demo` +4. Look for corresponding debug symbol packages in that directory, usually has two naming formats: + - `-dbgsym.deb` + - `-dbg.deb` -Init Commands: `set substitute-path /source /path/to/project` -``` +5. Download and extract debug symbol package: -The general configuration is shown in the following figure: + ```bash + dpkg-deb -R -dbgsym.deb /tmp/ + ``` -![qt-creator](images/qt-creator.jpg) +6. Configure debugger to find debug symbols: + When setting debug-file-directory in scenarios above, append extracted directory, separated by colon: + ``` + ${workspaceFolder}/linglong/output/develop/files/lib/debug:/tmp//usr/lib/debug + ``` -After the configuration is complete, you can use `QtCreator` to debug normally. +This way debugger can find debug symbols of system dependency libraries in extracted directory. diff --git a/docs/pages/en/guide/debug/faq.md b/docs/pages/en/guide/debug/faq.md deleted file mode 100644 index 17330a372..000000000 --- a/docs/pages/en/guide/debug/faq.md +++ /dev/null @@ -1,72 +0,0 @@ - - -# Run FAQ - -1. When the application runs to read the application installation resource file under `/usr/share`, why does the reading fail? - - linyaps applications run in a container, and the application data will be mounted to `/opt/apps/`/. Only system data will exist in the `/usr/share` directory, and there will be no application-related data. Therefore, reading directly from `/usr/share` will fail. Suggested processing: Use the `XDG_DATA_DIRS` environment variable to read resources, and `/opt/apps//files/share` will exist in this environment variable search path. -2. The font library file cannot be found when the application is running. Why can the corresponding font library be read when the `deb` package is installed? - - When the `deb` package is installed, it will depend on the corresponding font library file. The linyaps package format adopts a self-sufficient packaging format. Except for the basic system library, `Qt` library and `DTK` library files provided in `runtime`, do not need to be provided by yourself, other dependent data files need to be provided by yourself. It is recommended to put the corresponding data file under `files/share`, and use the environment variable `XDG_DATA_DIRS` to read the path. -3. What is in the linyaps application `runtime`? Can you add some library files to it? - - At present, the `runtime` that linyaps application depends on provides the `Qt` library and the `DTK` library. Because `runtime` has a strict size limit, adding additional library files to `runtime` is currently not allowed. -4. The application runs in the container. Can a configuration file be created in any path of the container during the running process? - - You can create configuration files under `XDG_CONFIG_HOME`. -5. Where is app data saved? Where can I find it outside the container? - - Because linyaps applications follow the principle of non-interference, the `XDG_DATA_HOME`, `XDG_CONFIG_HOME`, `XDG_CACHE_HOME` environment variables are defined in the corresponding path of the host machine, `~/.linglong/`/. So the user application data will be saved under this path. When writing data while the application is running, it should also be able to read the corresponding environment variable to write the data. Prohibit reading and writing configurations of other applications. -6. The application provides the `dbus service` file, where do I place it? What does the `Exec` field write? - - When the application provides the `dbus service` file, it needs to be placed in the `entries/dbus-1/services` directory. If `Exec` executes the binary in the linyaps package, use the `--exec` option parameter to execute the corresponding binary. -7. After the app is installed, the launcher cannot find it? - - TryExec=xxx, if xxx does not exist in the $PATH, the application is considered non-existent and will not be displayed. -8. Why is the Icon displayed as a small black dot? - - The desktop file has an 'Icon' field written, but the Icon field name is incorrect or an absolute path is being used."。 -9. Why is the Icon field as a gear? - - The desktop file does not provide Icon field. -10. Where are the icons stored? - - svg → $PREFIX/share/icons/hicolor/scalable/apps/ - - Other formats are stored according to resolution, such as 16x16. - - png/xpm → $PREFIX/share/icons/hicolor/16X16/apps/ -11. Why do `xdg-open` and `xdg-email` that come with the application fail? - - linyaps specially handles `xdg-open` and `xdg-email` in `runtime`, so the application is forbidden to execute the executable file or script of `xdg-open` and `xdg-email` that it carries. -12. Why doesn't the system environment variable used by the application take effect? - - When using environment variables, you need to confirm whether there are corresponding environment variables in the container. If not, you need to contact the linyaps team for processing. -13. The library files required for the application to run were not found. How can I provide them? - - The resource files that the application needs to use and the library files both need to be provided by the application itself. The library files are placed in the `$PREFIX/lib` path. -14. Why has the `Qt WebEngine` rendering process crashed when the application is running? - - Due to the system upgrade of `glibc`, the application fails to use the built-in browser, and the application needs to be re-adapted. A temporary solution is to set the environment variable: `export QTWEBENGINE_DISABLE_SANDBOX=1`. -15. When the application is running, the `libqxcb.so` library cannot be found or the `qtwebengine` error is reported. What can I do? - - When a `qt.conf` file exists, you need to configure the correct path in the file or use the `QTWEBENGINEPROCESS_PATH`, `QTWEBENGINE_RESOURCES_PATH`, `QT_QPA_PLATFORM_PLUGIN_PATH`, and `QT_PLUGIN_PATH` environment variables to configure the search path. -16. Can the application carry the database file by itself and write data to the database during operation? - - The file system in the container is a read-only file system and does not allow data to be written to application resource files. -17. Why does the execution of binary with `suid` and `guid` permissions fail? - - In order to ensure system security, linyaps container prohibits the execution of such permission binaries in the container. -18. Can the input method of uab offline package format not be used under Debian and Ubuntu? - - It is recommended to install the `fictx` input method to experience it. -19. How can I know which packages are installed in a container environment? - - Enter the container environment using the command `ll-builder run --exec bash`. To view the pre-installed packages, utilize the command `cat /var/lib/dpkg/status | grep "^Package: "`. Additionally, for libraries compiled from source code, you can inspect them using `cat /runtime/packages.list`. -20. Why is the application tray not displayed after the application is launched? - - This issue might be caused by applications registering to the system tray using the same service name. According to the KDE/freedesktop StatusNotifierItem specification, applications register with a service name in the format of org.kde.StatusNotifierItem-``-``. In the case of the linyaps application, the PID during runtime is 19. You can check whether there's a registered service using the following command: `dbus-send --session --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.NameHasOwner string:org.kde.StatusNotifierItem-19-1` If the reply contains boolean true, it indicates that the service has been registered. diff --git a/docs/pages/en/guide/debug/images/build_parameter_list.png b/docs/pages/en/guide/debug/images/build_parameter_list.png deleted file mode 100644 index 42d1f6940..000000000 Binary files a/docs/pages/en/guide/debug/images/build_parameter_list.png and /dev/null differ diff --git a/docs/pages/en/guide/debug/images/build_parameter_list.png.license b/docs/pages/en/guide/debug/images/build_parameter_list.png.license deleted file mode 100644 index 773bc0e03..000000000 --- a/docs/pages/en/guide/debug/images/build_parameter_list.png.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. - -SPDX-License-Identifier: LGPL-3.0-or-later diff --git a/docs/pages/en/guide/debug/images/node.png b/docs/pages/en/guide/debug/images/node.png deleted file mode 100644 index 5e78176a3..000000000 Binary files a/docs/pages/en/guide/debug/images/node.png and /dev/null differ diff --git a/docs/pages/en/guide/debug/images/node.png.license b/docs/pages/en/guide/debug/images/node.png.license deleted file mode 100644 index 773bc0e03..000000000 --- a/docs/pages/en/guide/debug/images/node.png.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. - -SPDX-License-Identifier: LGPL-3.0-or-later diff --git a/docs/pages/en/guide/debug/images/qt-creator.jpg b/docs/pages/en/guide/debug/images/qt-creator.jpg deleted file mode 100644 index 54e7edaeb..000000000 Binary files a/docs/pages/en/guide/debug/images/qt-creator.jpg and /dev/null differ diff --git a/docs/pages/en/guide/debug/images/qt-creator.jpg.license b/docs/pages/en/guide/debug/images/qt-creator.jpg.license deleted file mode 100644 index 773bc0e03..000000000 --- a/docs/pages/en/guide/debug/images/qt-creator.jpg.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. - -SPDX-License-Identifier: LGPL-3.0-or-later diff --git a/docs/pages/en/guide/debug/images/qt-creator.png b/docs/pages/en/guide/debug/images/qt-creator.png index 0631ac646..7810760f8 100644 Binary files a/docs/pages/en/guide/debug/images/qt-creator.png and b/docs/pages/en/guide/debug/images/qt-creator.png differ diff --git a/docs/pages/en/guide/debug/ll-builder-faq.md b/docs/pages/en/guide/debug/ll-builder-faq.md deleted file mode 100644 index 46c965b7c..000000000 --- a/docs/pages/en/guide/debug/ll-builder-faq.md +++ /dev/null @@ -1,29 +0,0 @@ - - -# Build FAQ - -1. `-lxxx` failed in `cmake` type build, but `ldconfig` and `pkg-config` can query the library information. - - The link library path is not a regular path, the new path is `/runtime/lib`. Add the environment variable `LIBRARY_PATH=`, which is included in the build environment by default. - -2. `link` static library failed when building, which requires re-build with `fPIC`. - - Use the `-fPIC` parameter when building a static library. - -3. Failed to start `box` during build, as shown below. - - ![ll-box start failed](images/ll-box-start-failed.png) - - The kernel does not support `unprivilege namespace`, please open `unprivilege namespace` to solve it. - - ```bash - sudo sysctl -w kernel.unprivileged_userns_clone=1 - ``` - -4. The build of `qtbase` is successful, but the `qt` application cannot be built, which prompts `module,mkspec` related errors. - - There is a problem in the lower version of `fuse-overlay mount`, which leads to the polluted file content when `qtbase commit`, and cannot be used. Use `fuse-overlayfs >= 1.8.2` version. diff --git a/docs/pages/en/guide/debug/ll-pica-faq.md b/docs/pages/en/guide/debug/ll-pica-faq.md deleted file mode 100644 index d04079285..000000000 --- a/docs/pages/en/guide/debug/ll-pica-faq.md +++ /dev/null @@ -1,18 +0,0 @@ -# FAQ - -1. Where is the default configuration located for the `linglong.yaml` file generated by `ll-pica`? - - The configuration file for `ll-pica` is located at `~/.pica/config.json`. -2. Does ll-pica fail to convert software such as Wine, Android apps, input methods, or security applications? - - linyaps applications currently do not support this type of application, and consequently, ll-pica cannot convert them either. -3. Why is there no sound from software that requires audio? - - Prompt "libpulsecommon-12.2.so not found" can be addressed by adding a line in the `build` section of the linglong.yaml file: `mv $PREFIX/lib/$TRIPLET/pulseaudio/* $PREFIX/lib/$TRIPLET`. -4. Why is the `command` field empty in the generated `linglong.yaml` file? - - ll-pica retrieves the 'Exec' field from the desktop file within the deb package. If the command is empty, please verify if the desktop file path - within the deb package exists in the following locations. - - - /opt/apps/$appid/entries/applications - - /usr/share/applications diff --git a/docs/pages/en/guide/desktop-integration/README.md b/docs/pages/en/guide/desktop-integration/README.md new file mode 100644 index 000000000..907060733 --- /dev/null +++ b/docs/pages/en/guide/desktop-integration/README.md @@ -0,0 +1 @@ +This directory contains documentation related to how Linyaps integrates with the desktop environment. (To be supplemented) - portals: Introduces how to create desktop portals for Linyaps to achieve seamless integration with the desktop environment. diff --git a/docs/pages/en/guide/docs-index.md b/docs/pages/en/guide/docs-index.md new file mode 100644 index 000000000..c21fe6ee7 --- /dev/null +++ b/docs/pages/en/guide/docs-index.md @@ -0,0 +1,187 @@ +# Linyaps Documentation Index + +This document provides a comprehensive index of all documentation files in the Linyaps project. + +## Directory Structure Overview + +``` +docs/pages/en/guide/ +├── building/ # Build-related documentation +├── debug/ # Debug-related documentation +├── desktop-integration/ # Desktop integration documentation +├── extra/ # Additional documentation +├── lessons/ # Tutorials and examples +├── linyaps-devel/ # Developer documentation +├── publishing/ # Publishing-related documentation +├── reference/ # Reference documentation +├── start/ # Getting started guide +└── tips-and-faq/ # Tips and FAQ +``` + +## Detailed Documentation Index + +### Getting Started (start/) + +| Document Name | File Path | Description | +| ---------------------------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| Overview | `start/whatis.md` | Introduction to Linyaps basic concepts, advantages, and comparison with other package management tools | +| Install Linyaps | `start/install.md` | Detailed steps for installing Linyaps on different Linux distributions | +| Build Your First Linyaps App | `start/build_your_first_app.md` | Complete tutorial for building Linyaps packages from source, including calculator example and deb package conversion | +| ll-pica Installation | `start/ll-pica-install.md` | Installation guide for ll-pica package conversion tool | +| Release Notes | `start/release_note.md` | Version release notes and changelog | + +### Build Related (building/) + +| Document Name | File Path | Description | +| ------------------------------------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | +| Linyaps Package Specification | `building/linyaps_package_spec.md` | Detailed application packaging specifications, including naming conventions, build configuration, directory structure, etc. | +| Build Configuration File Introduction | `building/manifests.md` | Detailed explanation and field definitions for `linglong.yaml` configuration file | +| Module Management | `building/modules.md` | Module splitting and management instructions | +| Multi-architecture Support | `building/multiarch.md` | Multi-architecture build support instructions | +| Demo Example | `building/demo.md` | Build demonstration example with practical use cases | + +### Debug Related (debug/) + +| Document Name | File Path | Description | +| -------------------------- | ---------------- | ----------------------------------------------------------------------------------------------- | +| Debug Linyaps Applications | `debug/debug.md` | Detailed guide for debugging Linyaps applications using gdb, vscode, Qt Creator and other tools | + +### Desktop Integration (desktop-integration/) + +| Document Name | File Path | Description | +| -------------------------------- | ------------------------------- | ----------------------------------------------------------------- | +| Desktop Integration Instructions | `desktop-integration/README.md` | Linyaps and desktop environment integration related documentation | + +### Tutorials and Examples (lessons/) + +| Document Name | File Path | Description | +| -------------------- | --------------------------------- | --------------------------------------------------------- | +| Basic Notes | `lessons/basic-notes.md` | Basic usage notes and best practices | +| Build Git Patches | `lessons/build-git-patch.md` | Git patch building tutorial for version management | +| Build in Environment | `lessons/build-in-env.md` | Tutorial for building in specific environments | +| Build Offline Source | `lessons/build-offline-src.md` | Tutorial for building source code in offline environments | +| Test with Toolchains | `lessons/test-with-toolchains.md` | Tutorial for testing with different toolchains | + +### Developer Documentation (linyaps-devel/) + +| Document Name | File Path | Description | +| ----------------------- | ------------------------- | -------------------------------------------------- | +| Developer Documentation | `linyaps-devel/README.md` | Developer-related documentation and API references | + +### Publishing Related (publishing/) + +| Document Name | File Path | Description | +| --------------------- | ---------------------------- | -------------------------------------------------------------------------------- | +| Repository Management | `publishing/repositories.md` | Linyaps repository basic concepts, management and publishing update instructions | +| UAB Format Publishing | `publishing/uab.md` | UAB format publishing instructions and best practices | +| Mirrors | `publishing/mirrors.md` | Mirror site configuration and management | + +### Additional Documentation (extra/) + +| Document Name | File Path | Description | +| ------------------------- | ------------------------ | ------------------------------------------------- | +| Unit Testing | `extra/unit-testing.md` | Unit testing documentation and testing frameworks | +| Bundle Format | `extra/bundle-format.md` | Bundle format documentation and specifications | +| System Helper | `extra/system-helper.md` | System helper documentation and utilities | +| Application Configuration | `extra/app-conf.md` | Application configuration documentation | +| Root Filesystem | `extra/rootfs.md` | Root filesystem documentation and management | +| Reference | `extra/ref.md` | Reference documentation and quick lookup guides | +| UAB Build | `extra/uab-build.md` | UAB build documentation and build process | +| README | `extra/README.md` | Additional documentation overview | + +### Reference Documentation (reference/) + +#### Basic Concepts + +| Document Name | File Path | Description | +| --------------------------- | ----------------------------- | --------------------------------------------------------------------------- | +| Basic Concepts Introduction | `reference/basic-concepts.md` | Introduction to core concepts like Base, Runtime, sandbox, repository, etc. | +| Runtime Component | `reference/runtime.md` | Detailed introduction to Runtime component | +| Driver | `reference/driver.md` | Driver-related documentation and specifications | + +#### Command Reference + +**ll-appimage-convert Command** + +- `reference/commands/ll-appimage-convert/ll-appimage-convert.md` - Main command description +- `reference/commands/ll-appimage-convert/ll-appimage-convert-convert.md` - convert subcommand + +**ll-builder Command** + +- `reference/commands/ll-builder/ll-builder.md` - Main command description +- `reference/commands/ll-builder/build.md` - build subcommand +- `reference/commands/ll-builder/create.md` - create subcommand +- `reference/commands/ll-builder/export.md` - export subcommand +- `reference/commands/ll-builder/extract.md` - extract subcommand +- `reference/commands/ll-builder/import.md` - import subcommand +- `reference/commands/ll-builder/list.md` - list subcommand +- `reference/commands/ll-builder/push.md` - push subcommand +- `reference/commands/ll-builder/remove.md` - remove subcommand +- `reference/commands/ll-builder/repo.md` - repo subcommand +- `reference/commands/ll-builder/run.md` - run subcommand + +**ll-cli Command** + +- `reference/commands/ll-cli/ll-cli.md` - Main command description +- `reference/commands/ll-cli/content.md` - content subcommand +- `reference/commands/ll-cli/enter.md` - enter subcommand +- `reference/commands/ll-cli/info.md` - info subcommand +- `reference/commands/ll-cli/install.md` - install subcommand +- `reference/commands/ll-cli/kill.md` - kill subcommand +- `reference/commands/ll-cli/list.md` - list subcommand +- `reference/commands/ll-cli/prune.md` - prune subcommand +- `reference/commands/ll-cli/ps.md` - ps subcommand +- `reference/commands/ll-cli/repo.md` - repo subcommand +- `reference/commands/ll-cli/run.md` - run subcommand +- `reference/commands/ll-cli/search.md` - search subcommand +- `reference/commands/ll-cli/uninstall.md` - uninstall subcommand +- `reference/commands/ll-cli/upgrade.md` - upgrade subcommand + +**ll-pica Command** + +- `reference/commands/ll-pica/ll-pica.md` - Main command description +- `reference/commands/ll-pica/install.md` - install subcommand +- `reference/commands/ll-pica/ll-pica-adep.md` - adep subcommand +- `reference/commands/ll-pica/ll-pica-convert.md` - convert subcommand +- `reference/commands/ll-pica/ll-pica-init.md` - init subcommand + +**ll-pica-flatpak Command** + +- `reference/commands/ll-pica-flatpak/ll-pica-flatpak.md` - Main command description +- `reference/commands/ll-pica-flatpak/ll-pica-flatpak-convert.md` - convert subcommand + +### Tips and FAQ (tips-and-faq/) + +| Document Name | File Path | Description | +| -------------- | -------------------------------- | -------------------------------------------- | +| Common Issues | `tips-and-faq/faq.md` | Common runtime issues and solutions | +| ll-builder FAQ | `tips-and-faq/ll-builder-faq.md` | Build tool common issues and troubleshooting | +| ll-pica FAQ | `tips-and-faq/ll-pica-faq.md` | Package conversion tool common issues | + +## Quick Navigation + +### Getting Started for New Users + +1. Read [`start/whatis.md`](start/whatis.md) to understand basic concepts +2. Follow [`start/install.md`](start/install.md) to install Linyaps +3. Follow [`start/build_your_first_app.md`](start/build_your_first_app.md) to build your first application + +### Developer Reference + +- Package Specification: [`building/linyaps_package_spec.md`](building/linyaps_package_spec.md) +- Configuration File: [`building/manifests.md`](building/manifests.md) +- Debug Guide: [`debug/debug.md`](debug/debug.md) + +### Command Reference + +- Build Tool: [`reference/commands/ll-builder/`](reference/commands/ll-builder/ll-builder.md) directory +- CLI Tool: [`reference/commands/ll-cli/`](reference/commands/ll-cli/ll-cli.md) directory +- Deb Package Conversion Tool: [`reference/commands/ll-pica/`](reference/commands/ll-pica/ll-pica.md) directory +- AppImage Conversion Tool: [`reference/commands/ll-appimage-convert/`](reference/commands/ll-appimage-convert/ll-appimage-convert.md) directory +- Flatpak Conversion Tool: [`reference/commands/ll-pica-flatpak/`](reference/commands/ll-pica-flatpak/ll-pica-flatpak.md) directory + +### Common Issues + +- Runtime Issues: [`tips-and-faq/faq.md`](tips-and-faq/faq.md) +- Build Issues: [`tips-and-faq/ll-builder-faq.md`](tips-and-faq/ll-builder-faq.md) +- Conversion Issues: [`tips-and-faq/ll-pica-faq.md`](tips-and-faq/ll-pica-faq.md) diff --git a/docs/pages/en/guide/extra/README.md b/docs/pages/en/guide/extra/README.md new file mode 100644 index 000000000..751760d45 --- /dev/null +++ b/docs/pages/en/guide/extra/README.md @@ -0,0 +1,18 @@ +This directory contains additional documentation and advanced topics for Linyaps development. + +# Additional Documentation Topics + +## Available Documents + +- [Bundle Format](bundle-format.md): Detailed information about the Linyaps bundle format +- [Unit Testing](unit-testing.md): Guidelines for writing unit tests in Linyaps projects +- [Application Configuration](app-conf.md): Configuration options for Linyaps applications +- [System Helper](system-helper.md): System helper utilities and integration +- [Reference](ref.md): API reference and detailed specifications +- [Root Filesystem](rootfs.md): Root filesystem management and customization + +## Development Notes + +This directory contains comprehensive documentation for advanced users and developers who need detailed information about specific aspects of the Linyaps platform. Each document provides in-depth coverage of its respective topic. + +For basic getting started information, please refer to the main documentation in the parent directory. diff --git a/docs/pages/en/guide/extra/app-conf.md b/docs/pages/en/guide/extra/app-conf.md new file mode 100644 index 000000000..4af11caac --- /dev/null +++ b/docs/pages/en/guide/extra/app-conf.md @@ -0,0 +1,51 @@ +# Application Runtime Configuration + +Application runtime configuration is the file that describes how the Linyaps runtime module loads the application. The configuration is machine-specific, and the user can set mount paths and permission control files for the application. + +## File Format + +Must be a YAML file. + +## Storage Location + +The configuration is highly user-specific and should be stored at `~/.linglong/{appid}/app.yaml` + +If it doesn't exist, it should be created first from `info.json`. + +## Content + +```yaml +# Should be 1.0 now +version: 1.0 + +package: + ref: com.qq.weixin.deepin/3.2.1.154deepin8/x86_64 + +runtime: + ref: org.deepin.Runtime/20/x86_64 + +# The section can only be set by developers and only works when debug is enabled +debug: + # Override entrypoint + args: + - /opt/apps/com.qq.weixin.work.deepin/files/run.sh + - --debug + # Override the base, carefully set the debug args + mount-bottom: + - /usr:/usr + +permissions: + # Mount after all runtime container builds + mounts: + - /etc/passwd:/etc/passwd + - /etc/group:/etc/group + - ${HOME}/Documents:${HOME}/Documents + - ${HOME}/Desktop:${HOME}/Desktop + - ${HOME}/Downloads:${HOME}/Downloads + # TODO: session and system bus + dbus: + owner: + - com.qq.weixin.work.deepin + talk: + - org.freedesktop.Notifications +``` diff --git a/docs/pages/en/guide/extra/bundle-format.md b/docs/pages/en/guide/extra/bundle-format.md new file mode 100644 index 000000000..2e65ad9f8 --- /dev/null +++ b/docs/pages/en/guide/extra/bundle-format.md @@ -0,0 +1,51 @@ +# Bundle Format + +## Introduction + +Green software refers to binaries that do not install any files to the system. + +The fundamental constraints of green software are: + +- **Path independence**: Has nothing to do with local files. +- **High compatibility**: The software should contain all dependencies that the system does not have. + +The well-known technology for building green software is AppImage on Linux. + +However, there are many problems with this technology. The biggest issue is that the host system ABI cannot remain stable and differs from one another. Linyaps cannot solve this problem either. We should maintain a baseline of supported systems or ABI. + +A strategy used on UnionTech OS or Deepin is to only support systems after UnionTech OS 1020, which reduces testing work for different base systems. + +## Target + +The green bundle is not just simple support for application runtime path independence. It is also designed to be the offline maintenance package format on the office system, supporting self-run and installation while maintaining the changeability of the bundle format when designing. + +When a user has internet access, we mostly use online differential updates or installation via repo. We do not use bundles if we can access the repo when distributing applications. + +## Specification + +The specifications for export bundles: + +- **MUST** be an ELF, can be FlatELF +- **MUST** be statically-linked +- **MUST** contain a data segment that can be mounted with FUSE +- **MUST** contain a loader executable at the root of the FUSE mount filesystem + +## Implementation + +**The implementation changes over time. If you change the implementation, update this section as soon as possible !!!** + +### Prototype + +- The bundle is a simple ELF loader that combines a readonly filesystem with cat. +- The loader simply calls read_elf64 to calculate the offset of the readonly filesystem. +- The loader mounts the readonly filesystem with `squashfuse -o ro,offset=xxx` +- The filesystem is now a readonly filesystem + - The root of the filesystem should contain a file named loader (currently .loader) + - The directory structure should be: `/{id}/{version}/{arch}/` +- The readonly filesystem should support EROFS, and MAY support SquashFS + +A full example of the filesystem is: + +```bash + +``` diff --git a/docs/pages/en/guide/extra/ref.md b/docs/pages/en/guide/extra/ref.md new file mode 100644 index 000000000..763323991 --- /dev/null +++ b/docs/pages/en/guide/extra/ref.md @@ -0,0 +1,89 @@ +# Reference (Ref) + +## Definition + +Component: A component is generally equivalent to artifacts/component/module/package in other systems. In Linyaps, we use "layer" to represent a component. + +## Format + +Ref is the unique identifier of a component in the storage repository (index information in the storage repository). A complete ref includes repository name, channel, ID, version number, architecture, branch name and other information. + +The ref format is as follows: + +```bash +${repo}/${channel}:${id}/${version}/${arch} +``` + +Examples: + +```bash +deepin/main:org.deepin.runtime/20/x86_64 + +deepin/project1:org.deepin.calculator/1.2.2/x86_64 +``` + +Where: + +- `deepin` is the name of the remote repository to which the software package belongs +- `main` and `project1` are distribution channels, which can be empty by default +- `org.deepin.calculator` is the ID +- `1.2.2` is the version +- `x86_64` is the architecture + +### Value Range + +| Field | Allowed Values | +| ------- | --------------------------------------------------------------------------------------------------------------- | +| repo | Lowercase letters + underscore | +| channel | Lowercase letters + underscore | +| id | Reverse domain name | +| version | 4 digits separated by `.`. Pad with 0 if less than 4 digits, append subsequent numeric strings to the 4th digit | +| arch | Architecture description string, currently supports x86_64/arm/loongarch | + +## Usage + +Ref contains two parts: remote address identifier and local identifier. The `:` separates the remote identifier from the local identifier. + +The remote identifier is mainly used to define how this layer is obtained. The channel is not currently used and can be empty. The repo represents an alias for the mapping of the remote repository (URL) locally. + +During installation, using a complete ref can uniquely identify a layer. For example: + +```bash +ll-cli install deepin/main:org.deepin.calculator/1.2.2/x86_64 +``` + +Once a layer is installed, all local operations on the layer will not change its remote properties, especially during upgrades. + +```bash +# Upgrade org.deepin.calculator from deepin/main, its version will change, but repo and channel will not +# Note: install will update the package here +ll-cli install org.deepin.calculator/1.2.2/x86_64 + +# This will use the layer from deepin/project channel to replace the local org.deepin.calculator/1.2.2/x86_64 +ll-cli install deepin/project:org.deepin.calculator/1.2.2/x86_64 +``` + +Notes: + +- When switching repo or channel, local versions need to be deleted, especially when there are multiple versions under an ID (the underlying layer can be considered for reuse, but logically ensure that layer versions are under the corresponding channel). + +### Shorthand + +Ref supports shorthand with the following main rules: + +1. Default repo is `deepin` +2. Default channel is `main` (currently not implemented, temporarily not considered) +3. Default version is the remote latest version or local latest version, inferred according to the scenario, error if ambiguous +4. Default architecture is the current ll-cli runtime architecture + +If any field in ref is explicitly specified, it takes precedence based on that field. + +## Implementation + +Currently, the layers storage path is: + +```bash +/deepin/linglong/layers +``` + +This path will definitely be replaced later, so please avoid hardcoding this field in too many places. diff --git a/docs/pages/en/guide/extra/rootfs.md b/docs/pages/en/guide/extra/rootfs.md new file mode 100644 index 000000000..6b115a24b --- /dev/null +++ b/docs/pages/en/guide/extra/rootfs.md @@ -0,0 +1,82 @@ +# Root Filesystem (Rootfs) + +As per the OCI runtime specification, the runtime starts from a rootfs, but in Linyaps, it prepares rootfs in ll-box. Therefore, we put the information for constructing rootfs in annotations to ll-box. + +The example of annotations is: + +```json + "annotations": { + "container_root_path": "/run/user/1000/linglong/375f5681145f4f4f9ffeb3a67aebd444", + "native": { + "mounts": [ + { + "destination": "/usr", + "options": [ + "ro" + ], + "source": "/usr", + "type": "bind" + }, + { + "destination": "/runtime", + "options": [ + "ro" + ], + "source": "/deepin/linglong/layers/org.deepin.Runtime/20/x86_64", + "type": "bind" + }, + { + "destination": "/opt/apps/org.deepin.music", + "options": [ + "ro" + ], + "source": "/deepin/linglong/layers/org.deepin.music/6.0.1.54/x86_64/", + "type": "bind" + } + ] + }, + "overlayfs": { + "lower_parent": "/run/user/1000/linglong/375f5681145f4f4f9ffeb3a67aebd444/.overlayfs/lower_parent", + "upper": "/run/user/1000/linglong/375f5681145f4f4f9ffeb3a67aebd444/.overlayfs/upper", + "workdir": "/run/user/1000/linglong/375f5681145f4f4f9ffeb3a67aebd444/.overlayfs/workdir", + "mounts": [ + { + "destination": "/usr", + "options": [ + "ro" + ], + "source": "/usr", + "type": "bind" + }, + { + "destination": "/usr", + "options": [ + "ro" + ], + "source": "/usr", + "type": "bind" + }, + { + "destination": "/opt", + "options": [ + "ro" + ], + "source": "/opt", + "type": "bind" + }, + { + "destination": "/opt/apps/com.qq.weixin.deepin", + "options": [ + "ro" + ], + "source": "/opt/apps/com.qq.weixin.work.deepin/", + "type": "bind" + } + ] + } + } +``` + +The ll-box supports two methods to build rootfs: using native read-only bind mounts or with overlayfs. + +`container_root_path` is the working directory of ll-box. diff --git a/docs/pages/en/guide/extra/system-helper.md b/docs/pages/en/guide/extra/system-helper.md new file mode 100644 index 000000000..211ad4006 --- /dev/null +++ b/docs/pages/en/guide/extra/system-helper.md @@ -0,0 +1,17 @@ +# System Helper + +Users without privileges can mount erofs filesystems to directories using the following D-Bus call: + +```bash +busctl --system call org.deepin.linglong.SystemHelper \ + /org/deepin/linglong/FilesystemHelper \ + org.deepin.linglong.FilesystemHelper \ + Mount \ + sssa{sv} \ + '/var/lib/linglong/vfs/blobs/6f6b34b09e8a72ec52013407289064f5' \ + '/run/user/1000/linglong/vfs/layers/com.qq.music/1.1.3/x86_64/' \ + 'erofs' \ + 0 +``` + +This command uses the SystemHelper D-Bus interface to mount an erofs filesystem without requiring elevated privileges. diff --git a/docs/pages/en/guide/extra/uab-build.md b/docs/pages/en/guide/extra/uab-build.md new file mode 100644 index 000000000..862794cb9 --- /dev/null +++ b/docs/pages/en/guide/extra/uab-build.md @@ -0,0 +1,19 @@ +# uab Build + +Creating a runnable uab file from a Linyaps-oriented project requires the following configuration files: + +1. **linglong.yaml**: The Linyaps project configuration file that determines how the package will be compiled and installed; +2. **loader**: An executable file that serves as the entry point for the uab. +3. **extra-files.txt**: A text file that specifies which files the application depends on from base and runtime. These files will be copied to the uab package and placed in their corresponding locations during application runtime. If the application can run without depending on other files from runtime and base, this file can be omitted. + +If you only want to export the project as a uab for submitting applications to the Linyaps store and don't need it to be runnable, you don't need to provide the loader and extra-files.txt. + +Example loader code: + +```bash +#!/bin/env sh +APPID=org.deepin.demo +./ll-box $APPID $PWD /opt/apps/$APPID/files/bin/demo +``` + +The last parameter passed to ll-box is the binary that needs to run in the container. diff --git a/docs/pages/en/guide/extra/unit-testing.md b/docs/pages/en/guide/extra/unit-testing.md new file mode 100644 index 000000000..c1e2ad6b3 --- /dev/null +++ b/docs/pages/en/guide/extra/unit-testing.md @@ -0,0 +1,11 @@ +# Unit Testing + +Linyaps utilizes GoogleTest (gtest) as its unit testing framework. Simply include your test code and test data in the `test/` directory at the project root. + +Since certain tests are challenging to execute in CI environments, they are disabled by default. + +The following environment variables control test execution. All are empty by default: + +| Variable Name | Value | Description | +| ----------------- | ------------------------------- | ------------------------------- | +| LINGLONG_TEST_ALL | If set, enables all unit tests | Executes complete unit test suite | diff --git a/docs/pages/en/guide/lessons/basic-notes.md b/docs/pages/en/guide/lessons/basic-notes.md new file mode 100755 index 000000000..e203c8072 --- /dev/null +++ b/docs/pages/en/guide/lessons/basic-notes.md @@ -0,0 +1,265 @@ +# Basic Knowledge of Linyaps Application Build Projects + +Before officially starting to build a Linyaps application project, we need to have a certain understanding of the basic knowledge regarding Linyaps application building. This will help us better decide what materials to prepare and what types of operations to perform before starting the build project. + +## Basic Steps for Linyaps Application Building + +Before officially starting to build a Linyaps application project, we need to understand the basic steps a Linyaps application goes through from resource input (source code, binary files, etc.) to application package export. This helps us determine what necessary files we need to prepare: + +1. Obtain build target source files (open source project source code, application binary files, etc.) +2. Determine the Linyaps application build type based on source files and select the appropriate build solution +3. Prepare a Linyaps build environment that meets requirements +4. Customize the build configuration file `linglong.yaml` according to the build type and source code content +5. Prepare general resources used by the application, including icons and other non-binary resources + +## Materials Required for Linyaps Application Build Projects + +Based on the above knowledge, we can understand that throughout the entire Linyaps application build process, the following files are mainly involved: + +1. Linyaps application build project configuration file `linglong.yaml` +2. Application source code/binary files and other resources to be packaged +3. General non-binary files and other resources + +## Mainstream Standards Followed by Linyaps Applications + +In order to ensure complete functionality and good experience, every Linux desktop software package management solution needs to comply with various specifications proposed by the package management solution. This maximizes the functionality of the package management solution and ensures the application ecosystem experience. + +Linyaps is not always unique and needs to meet certain specifications to ensure the steady and continuous development of the Linyaps ecosystem. + +Currently, the Linyaps solution complies with the following mainstream standards: + +1. Freedesktop XDG specification +2. Linyaps application directory structure specification +3. Linyaps application build project configuration file `linglong.yaml` specification + +### Freedesktop XDG Specification + +1. The Linyaps application solution follows the Freedesktop XDG specification. A normal graphical application should have icon files and desktop files that comply with the Freedesktop XDG specification. +2. Linyaps application icon files should be categorized into different sizes under the `$PREFIX/share/icons/hicolor/` directory +3. Linyaps applications use environment variables like `XDG_DATA_DIRS` in containers to support reading and writing user directories in the host machine + +### Linyaps Application Directory Structure Specification + +1. Linyaps applications follow the $PREFIX path rule. This variable is automatically generated, and all application-related files need to be stored under this directory. Under this directory level, there are directories like `bin` and `share`. + +2. Applications in Linyaps containers will not be allowed to read binary files and runtime libraries in the host machine's system directories + +3. During the build process, the build project directory will be mapped to the Linyaps container and mounted as `/project` + +4. The directories where runtime libraries and header files are located in Linyaps application containers will vary depending on the runtime environment type: + - foundation type: Mapped as normal system paths `/usr/bin` `/usr/include` etc. in Linyaps containers, serving as the basic runtime system environment + - runtime type: Mapped as runtime container paths `/runtime/usr/bin` `/runtime/usr/include` etc. in Linyaps containers, serving as the basic runtime system environment + +\*By default, the environment variables inside the Linyaps container have been automatically processed for path recognition, such as: + +``` +PATH=szbt@szbt-linyaps23:/project$ echo $PATH +/bin:/usr/bin:/runtime/bin:/opt/apps/com.tencent.wechat/files/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/sbin:/usr/sbin +``` + +General expression is: + +``` +PATH=szbt@szbt-linyaps23:/project$ echo $PATH +/bin:/usr/bin:/runtime/bin:$PREFIX/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/sbin:/usr/sbin +``` + +## Specifications for General Resources in Linyaps Application Build Projects + +In Linyaps application build projects, different resource files need to comply with relevant specifications to ensure that the build and experience meet requirements + +### Icons Directory Specification + +According to the `Freedesktop XDG specification` and `Linyaps application directory structure specification` followed by Linyaps, icons are placed in corresponding directories according to different sizes + +Mainstream non-vector icon sizes are: `16x16` `24x24` `32x32` `48x48` `128x128` `256x256` `512x512` +To ensure icons can achieve better experience effects in the system, at least one non-vector icon file with a size not smaller than `128x128` is required. Vector icons do not have this restriction. + +Therefore, in a Linyaps application installation directory, the icons directory should be as shown in the following example: + +``` +$PREFIX/share/icons/hicolor/16x16/apps +$PREFIX/share/icons/hicolor/24x24/apps +$PREFIX/share/icons/hicolor/32x32/apps +$PREFIX/share/icons/hicolor/48x48/apps +$PREFIX/share/icons/hicolor/128x128/apps +$PREFIX/share/icons/hicolor/256x256/apps +$PREFIX/share/icons/hicolor/512x512/apps +$PREFIX/share/icons/hicolor/scalable/apps +``` + +\* The `scalable` directory is used to place `vector icon` files, generally in `.svg` format + +Assuming your Linyaps application provides both a non-vector icon file `linyaps-app-demo.png` with size `128x128` and a vector icon file `linyaps-app-demo.svg` with size `128x128`, they should appear in the following state in the Linyaps container: + +``` +$PREFIX/share/icons/hicolor/128x128/apps/linyaps-app-demo.png +$PREFIX/share/icons/hicolor/scalable/apps/linyaps-app-demo.svg +``` + +\* To avoid icon conflicts being overwritten, please use the application's `unique English name` or `Linyaps application ID` for the icon file name + +### Desktop File Specification + +Linyaps applications are compatible with most `desktop startup files` that comply with the `Freedesktop XDG specification`. The following fields need special attention: + +| Field | Value Requirements | +| ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Exec | This value is used to set the command executed when clicking this desktop file. It needs to be consistent with the `command` value in `linglong.yaml` | +| Icon | This value is used to set the application icon displayed by this desktop file. It needs to be consistent with the icon file name in the `Icons Directory Specification`. This value does not require the file name extension | + +Therefore, a desktop file that complies with Linyaps application specifications can refer to: + +``` +org.qbittorrent.qBittorrent.desktop +[Desktop Entry] +Categories=Network;FileTransfer;P2P;Qt; +Exec=/opt/apps/org.qbittorrent.qBittorrent/files/bin/qbittorrent %U +Comment=Download and share files over BitTorrent +Icon=qbittorrent +MimeType=application/x-bittorrent;x-scheme-handler/magnet; +Name=qBittorrent +Type=Application +StartupWMClass=qbittorrent +Keywords=bittorrent;torrent;magnet;download;p2p; + +StartupNotify=true +Terminal=false +``` + +## Linyaps Application Build Project `linglong.yaml` Specification + +Like other traditional package management suites, manually creating a Linyaps application build project requires setting up a build rule file `linglong.yaml`. In the build rules, it is divided into `global fields` and `custom fields` according to usage. \* In the case, all space symbols and placeholders in the `linglong.yaml` body are valid characters. Please do not delete or change the format + +### Global Field Specification + +In `linglong.yaml`, fields that are not affected by the build type are called `global fields`. The following are the main reference specifications: + +1. A `linglong.yaml` that can normally start a build project should contain the following key parts: + | Module | Explanation | + |--------|-------------| + | version | Build project version number | + | package | Basic information of Linyaps application | + | base | Linyaps application container base environment and version setting. The base environment contains some basic runtime libraries | + | runtime | Linyaps application runtime library `runtime` and version setting. This module can be deleted when the basic runtime libraries in `base` meet the program runtime requirements | + | command | Command executed when Linyaps application container starts. It is consistent with the `Exec` field content of the `desktop` file | + | sources | Source file type of Linyaps application build project | + | build | Build rules to be executed by Linyaps application build project | + +The `package` module contains several sub-modules: +| Sub-module | Explanation | +|-------------|-------------| +| id | Linyaps application ID/package name | +| name | Linyaps application name, use English name | +| version | Linyaps application version number | +| kind | Linyaps application type, default is `app` | +| description | Linyaps application description | + +2. Linyaps applications follow the $PREFIX path rule. This variable is automatically generated, and all application-related files need to be stored under this directory. If installation file operations are needed in the build rules, they all need to be installed to the $PREFIX path. \* The $PREFIX variable name is the actual content filled in. **Please do not use `absolute path` or any content with absolute value effect as a substitute** + +3. Linyaps applications currently follow the `four-digit` version number naming rule. Applications that do not comply with the rule cannot start the build project + +4. `base` and `runtime` versions support automatic matching of the latest version `tail number`. The version number can only fill in the `first three digits` of the version number. For example: + When base `org.deepin.foundation` provides both `23.0.0.28` and `23.0.0.29`, if only the following is filled in `linglong.yaml`: + +``` +base: org.deepin.foundation/23.0.0 +``` + +Then when starting the Linyaps application build project, it will default to using the highest version number `23.0.0.29` + +5. The Linyaps application build project configuration file is currently not directly compatible with configuration files of other package build tools. It needs to be adapted and modified according to build project configuration file cases: + https://linglong.dev/guide/ll-builder/manifests.html + +### Custom Fields + +According to the Linyaps application build project source file type, Linyaps application build projects can be divided into `local file builds` and `git source repository pull builds`. Different types require filling in different `linglong.yaml` content. +The Linyaps application build project source file type `sources` mainly supports these types: `git` `local` `file` `archive` +Complete description reference: [Build Configuration File Introduction](https://linyaps.org.cn/guide/ll-builder/manifests.html) + +#### Git Pull Source Code Compilation Mode + +When the Linyaps application build project needs to pull open source project repository resources to local for building through git, the `sources` source file type `kind` should be set to `git` and fill in the `linglong.yaml` according to requirements. +At this time, you need to write the `sources` and `build` modules according to specifications. + +1. `sources` Example: + +```yaml +sources: + - kind: git + url: https://githubfast.com/qbittorrent/qBittorrent.git + version: release-4.6.7 + commit: 839bc696d066aca34ebd994ee1673c4b2d5afd7b + + - kind: git + url: https://githubfast.com/arvidn/libtorrent.git + version: v2.0.9 + commit: 4b4003d0fdc09a257a0841ad965b22533ed87a0d +``` + +| Name | Description | +| ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| kind | Source file type | +| url | Source code repository address that needs to be pulled through git. The repository needs to support git functionality. When the network condition is poor, mirror addresses can be used as alternatives | +| version | Specify the version number of the source code repository, i.e., `tag label`, or pull the main line `master` | +| commit | Pull source code based on the `commit` change history of the repository. Fill in the value corresponding to the commit here, which will apply all changes up to this commit in the repository. \*This field has higher priority than `version`. Please do not fill in any `commit` after the merge time of `version` | + +\* Supports adding multiple git repositories as `sources` pulls simultaneously + +2. `build` Example: + +```yaml +build: | + mkdir -p ${PREFIX}/bin/ ${PREFIX}/share/ + ##Apply patch for qBittorrent + cd /project/linglong/sources/qBittorrent.git + git apply -v /project/patches/linyaps-qBittorrent-4.6.7-szbt2.patch +``` + +This module is the main body of build rules, and the path follows the `Linyaps Application Directory Structure Specification` +After `sources` is pulled to local, the repository files will be stored in the `/project/linglong/sources` directory. At this time, different repository directories are named with `xxx.git` +Supports using the `git patch` function to conveniently maintain the source code + +#### Local Resource Operation Mode + +When the Linyaps application build project needs to operate on files in the build directory, the `kind` should be set to `local` type and fill in the `linglong.yaml` according to requirements. +At this time, you need to write the `sources` and `build` modules according to specifications. + +1. `sources` Example: + +```yaml +sources: +source: + - kind: local + name: "qBittorrent" +``` + +| Name | Description | +| ---- | ---------------------------------------------- | +| kind | Source file type | +| name | Source file name identifier, has no actual use | + +\* When the `kind` is set to `local` type, the build project will not perform any operations on source files + +2. `build` Example: + +```yaml +build: | + ##Build main + mkdir /project/src/qBittorrent-release-4.6.7-szbt2/build + cd /project/src/qBittorrent-release-4.6.7-szbt2/build + cmake -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=$PREFIX .. + make -j$(nproc) + make install +``` + +This module is the main body of build rules, and the path follows the `Linyaps Application Directory Structure Specification` +At this time, the `build` rules support multiple writing methods to simulate manual operations. \* You need to ensure that all steps of this build rule can be executed normally, otherwise the current build task will be interrupted + +#### Container Internal Manual Operation Mode + +If you plan to directly enter the Linyaps container for manual operations instead of through the build rule file `linglong.yaml`, you should refer to the `Local Resource Operation Mode` to fill in the `linglong.yaml`. + +1. The `sources` part is written consistently with the `Local Resource Operation Mode` +2. Since manual operations are used, complete and executable `build` rules are not required. At this time, `linglong.yaml` is used to generate a container that meets the description rather than executing all tasks. For specific operations, please refer to subsequent courses about container internal build file cases diff --git a/docs/pages/en/guide/lessons/build-git-patch.md b/docs/pages/en/guide/lessons/build-git-patch.md new file mode 100644 index 000000000..bca380d94 --- /dev/null +++ b/docs/pages/en/guide/lessons/build-git-patch.md @@ -0,0 +1,177 @@ +# Adapting Qt5-Based Open Source Application -- qBittorrent to Support Automated Linyaps Application Build Projects + +Continuing from the previous chapter, we will explore how to adapt the `linglong.yaml` to support automated build versions. +Since we have already determined the build rules that can successfully complete the compilation and build tasks in the previous section, this section mainly discusses how to use the `git` function to complete the following automated operations: + +1. Automatically pull open source project git repository resources +2. Automatically apply custom patch content + +## Modifying `linglong.yaml` + +In the previous section, we obtained a `linglong.yaml` that can successfully compile local source code. Since it's the same application project, we can directly modify it based on the existing configuration. + +For `linglong.yaml`, the two core parts are mainly the `sources` and `build` modules. This time we will explain these two parts separately. + +### `sources` Module + +According to the [Linyaps Application Build Project `linglong.yaml` Specification], when the build project's source files are git repositories (i.e., pulling source code repositories through git clone), the source file type `kind` of `sources` should be set to `git` and fill in the relevant information of the repository. + +According to the [Linyaps Application Build Project `linglong.yaml` Specification] `Git Pull Source Code Compilation Mode` specification, we need to master the following information about the source code repository: + +1. url, which is the address used for git clone, can use mirror addresses like ordinary git clone +2. version, which is the specific version number of the repository that needs to be fetched, generally the `Tags` label +3. The repository commit number that needs to be applied. Fill in the value corresponding to the commit here, which will apply all changes up to this commit in the repository. This field has higher priority than `version`. Please do not fill in any `commit` after the merge time of `version` + +Combined with the compilation notes in the second section, we collected information about the `qBittorrent.git` and `libtorrent.git` repositories. To reduce build progress blocking caused by network issues, I chose to use mirror addresses here: + +```yaml +sources: + - kind: git + url: https://githubfast.com/qbittorrent/qBittorrent.git + version: release-4.6.7 + commit: 839bc696d066aca34ebd994ee1673c4b2d5afd7b + + - kind: git + url: https://githubfast.com/arvidn/libtorrent.git + version: v2.0.9 + commit: 4b4003d0fdc09a257a0841ad965b22533ed87a0d +``` + +![commit-1](images/4-commit-1.png) + +![commit-2](images/4-commit-2.png) + +As can be seen from the figures, the filled commit values all match the commits when the corresponding tags were generated. + +### `build` Module + +After completing the source file information settings, we start modifying the build rules. +Considering that we have obtained executable build rules in the previous lesson, we only need to modify the source code path according to the relevant specifications in the [Linyaps Application Build Project `linglong.yaml` Specification] `Git Pull Source Code Compilation Mode`. + +After completing the modifications, we will get the following build rules: + +```yaml +build: | + mkdir -p ${PREFIX}/bin/ ${PREFIX}/share/ + ##Build 3rd libs + mkdir /project/linglong/sources/libtorrent.git/build + cd /project/linglong/sources/libtorrent.git/build + cmake -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=$PREFIX .. + make -j$(nproc) + make install + + ##Build main + mkdir /project/linglong/sources/qBittorrent.git/build + cd /project/linglong/sources/qBittorrent.git/build + cmake -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=$PREFIX .. + make -j$(nproc) + make install + + ##Extract common res + cp -rf /project/template_app/* ${PREFIX}/share/ +``` + +### Custom Patch Application + +In this case, we also introduce a new scenario: after pulling open source project repository resources of a specific version number, we need to modify the source code to achieve patch effects for fixing vulnerabilities and bugs. + +For this, we need to learn new knowledge: `git patch` related content. The git program has a built-in patch management system that needs to conveniently use this function to revise the source code. Generally, there are the following steps: + +1. Pull the open source project repository resources to the local directory through `git clone` +2. Manually modify based on the pulled resources. At this time, you can compare the differences and changes with the initial state through the `git diff` function. This forms the content of the patch. The specific patch division can vary according to the maintainer +3. After generating the patch document, pull the same open source project repository again. At this time, apply this patch through `git apply` to achieve automatic revision based on change records, and also facilitate recording source code maintenance records + +For example, after pulling the `qBittorrent--4.6.7` repository in this case, I need to add a merge related to security vulnerabilities: +https://github.com/qbittorrent/qBittorrent/pull/21364 +![commit-3](images/4-commit-3.png) + +It should be noted that this submission is based on the `qBittorrent--5.x` version, which means that if I want to fix this vulnerability on `qBittorrent--4.6.7`, I need to manually modify the source code. +Considering that the main version number of this application maintained in the short term will not be iterated to `5.x`, and with the possibility of other security vulnerabilities occurring and reducing the labor cost of repeatedly modifying the source code, I adopted the method of adding patches to assist me in modifying the source code. + +The following shows my process of obtaining & applying patches: + +1. First, I pulled the `qBittorrent--4.6.7` repository in `sources` to the local directory through `git clone` +2. Enter the pulled directory and check whether the current directory is a valid git directory through the git program: + +```zsh +❯ git remote -v +origin https://ghp.ci/https://github.com/qbittorrent/qBittorrent.git (fetch) +origin https://ghp.ci/https://github.com/qbittorrent/qBittorrent.git (push) +``` + +As can be seen, after executing the command, information about the remote repository can be returned, indicating that this directory meets the requirements. + +3. Then, manually modify the source code according to the file changes when the above security vulnerability was submitted. \* Here, the maintainer needs to judge which specific submissions need to be merged based on experience + +4. After the modification is completed, return to the root directory of the source code and execute `git diff` to view the existing difference comparison: + +5. After confirmation, save this difference locally to form a patch file + +```bash +ziggy@linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-local$ git diff > ./ +``` + +6. After obtaining the patch file, we will add the content of the applied patch to the existing `build` build rules: + +```yaml +build: | + mkdir -p ${PREFIX}/bin/ ${PREFIX}/share/ + ##Apply patch for qBittorrent + cd /project/linglong/sources/qBittorrent.git + git apply -v /project/patches/linyaps-qBittorrent-4.6.7-szbt2.patch + + ##Build 3rd libs + mkdir /project/linglong/sources/libtorrent.git/build + cd /project/linglong/sources/libtorrent.git/build + cmake -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=$PREFIX .. + make -j$(nproc) + make install + + ##Build main + mkdir /project/linglong/sources/qBittorrent.git/build + cd /project/linglong/sources/qBittorrent.git/build + cmake -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=$PREFIX .. + make -j$(nproc) + make install + + ##Extract common res + cp -rf /project/template_app/* ${PREFIX}/share/ +``` + +7. At this point, we can return to the build directory and start the build test. Execute: + +```bash +ziggy@linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-local$ ll-builder build -v +``` + +This build ended quickly and successfully. We execute the following command to export the container as a Linyaps application installation package `binary.layer`: + +```bash +ziggy@linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-local$ ll-builder export --layer +``` + +## Local Build Result Testing + +After obtaining the Linyaps application installation package, I tried to experience it on different mainstream distributions that support the Linyaps environment to confirm whether the binary programs built through Linyaps containers have universality. + +### deepin 23 + +![deepin 23](images/4-test-1.png) + +### openKylin 2.0 + +![openKylin 2.0](images/4-test-2.png) + +### Ubuntu 2404 + +![Ubuntu 2404](images/4-test-3.png) + +### OpenEuler 2403 + +![OpenEuler 2403](images/4-test-4.png) + +So far, it is sufficient to prove that `Qt5-based open source application--qBittorrent` can achieve one-stop pulling of project source code and compilation into executable binary files after adding custom patches and modifying build rules, and can also be used on other distributions! diff --git a/docs/pages/en/guide/lessons/build-in-env.md b/docs/pages/en/guide/lessons/build-in-env.md new file mode 100644 index 000000000..9aa85040d --- /dev/null +++ b/docs/pages/en/guide/lessons/build-in-env.md @@ -0,0 +1,139 @@ +# Compiling Qt5-Based Open Source Application -- qBittorrent in Linyaps Container + +After learning the `Basic Knowledge of Linyaps Application Build Projects` in the previous chapter, we are about to enter the practical classroom and use the knowledge we have learned to officially build a Linyaps application. + +Today, we will demonstrate how to enter the Linyaps container and compile the source code of an open source graphical application `qBittorrent` into binary files and test its operation. + +## Preliminary Preparation + +According to the requirements in `Basic Knowledge of Linyaps Application Build Projects` for the `Specifications for General Resources in Linyaps Application Build Projects`, we should provide both `icons` icon files and `desktop` startup files for graphical applications to ensure desktop user experience. + +However, this practical classroom will only perform compilation and testing operations in the Linyaps container, so general resources do not need to be prepared temporarily. + +This sharing is based on the `deepin 23` distribution, so before performing any of the following steps, you need to prepare a `deepin 23` system environment that can build Linyaps applications: + +1. Ensure that the `ll-builder` build suite has been installed in the environment. For installation methods on different distributions, please refer to: [Install Linyaps](https://linyaps.org.cn/guide/start/install.html) + +2. Since we need to connect to the network to obtain the runtime libraries of the Linyaps container and possibly needed third-party libraries during the build process, we need to ensure smooth network connection throughout the entire operation process + +3. Before compiling through the Linyaps container, you had better successfully compiled `qBittorrent` in `deepin 23` which is relatively close to this build container to ensure you have some understanding of the source code compilation + +4. Combine the [Linyaps Application Build Project `linglong.yaml` Specification] in the previous section and simply write a Linyaps build project configuration file `linglong.yaml` according to the following template to generate a container that meets the requirements + +The main points to note are: \* Since this operation directly enters the container for operation, the build rules in the `build` part do not need to be written in detail \* Since this compilation operation is involved, in order to include the required runtime libraries to the greatest extent, we add the `runtime` section. For specific writing specifications, please refer to [Basic Knowledge of Linyaps Application Build Projects] + +```yaml +# SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +version: "4.6.7.2" + +package: + id: org.qbittorrent.qBittorrent + name: "qBittorrent" + version: 4.6.7.2 + kind: app + description: | + qBittorrent binary + +base: org.deepin.foundation/23.0.0 +runtime: org.deepin.Runtime/23.0.1 + +command: + - /opt/apps/org.qbittorrent.qBittorrent/files/bin/qbittorrent + +source: + - kind: local + name: "qBittorrent" + +build: | + mkdir -p ${PREFIX}/bin/ ${PREFIX}/share/ +``` + +### Project Compilation Demonstration + +\*Here we need to review a knowledge point: According to [Linyaps Application Directory Structure Specification], the build directory at the same level as the build project configuration file `linglong.yaml` will be mapped as the `/project` directory +Everything is ready, we can start compiling + +1. For convenience of operation, we open two shell windows in the build directory at the same time, which are used for `Linyaps Container Operation` and `Normal Operation` respectively + +2. After completing the preparation of `linglong.yaml` editing, we can start generating the container. Execute limited operations to directly enter the Linyaps container: + +``` +szbt@szbt-linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-git$ ll-builder build --exec bash +``` + +When the path changes similar to the following, it means we have entered the Linyaps container: + +``` +szbt@szbt-linyaps23:/project$ +``` + +3. Extract the `qBittorrent-4.6.7` source code to the build directory through the `Normal Operation` window. I extracted it to a subdirectory here separately + +``` +szbt@szbt-linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-git$ tar -xvf qBittorrent-4.6.7-git-origin-src.tar.zst -C src/ +``` + +4. After the source code is extracted, according to [Basic Steps for Linyaps Application Building], we should correctly choose which compilation system/tools to use before compiling any source code. We observe the `qBittorrent-4.6.7` source code directory and can see that it has a `CMakeLists.txt` file, which is a `CMake` build project. + ![1](images/2-1.png) + +5. Since the [qBittorrent INSTALL](https://github.com/qbittorrent/qBittorrent/blob/release-4.6.7/INSTALL) briefly describes the runtime libraries mainly used by this project, we can compare this document to determine which runtime libraries exist in the `base` and `runtime` provided by Linyaps and which runtime libraries are not provided. For runtime libraries that are not officially provided, we may need to pre-compile the necessary third-party libraries before compiling the main program. + +Since the runtime libraries described in the document are few, we can directly perform a test compilation this time to confirm the missing runtime libraries + +6. Without delay, we enter the source code directory through the `Linyaps Container Operation` window. In order to avoid interference with the source directory as much as possible, I create a new `build` directory here for compilation. After entering the `build` directory, we enter CMake-related configuration parameters to configure the build project. + According to [Linyaps Application Directory Structure Specification], we assign the value of `DCMAKE_INSTALL_PREFIX` to `$PREFIX`. Finally, I executed the following operations locally: + +``` + cmake -DCMAKE_BUILD_TYPE=Release\ + -DCMAKE_INSTALL_PREFIX=$PREFIX .. +``` + +7. As can be seen from the figure, an error occurred here that prevented the configuration from being completed. We see that `pkg-config` has an error: the `libtorrent-rasterbar>=1.2.19` library cannot meet the conditions: + +![error-1](images/2-error-1.png) + +``` +-- Found PkgConfig: /bin/pkg-config (found version "1.8.1") +-- Checking for module 'libtorrent-rasterbar>=1.2.19' +``` + +I also cannot obtain relevant information about this library through `pkg-config` alone: + +``` +szbt@szbt-linyaps23:/project/src/qBittorrent-release-4.6.7-szbt2/build$ pkg-config --print-provides libtorrent-rasterbar +``` + +Based on this error, we can basically determine that the library is missing, so we need to compile and install this third-party library before compiling the main program + +8. We return to the `Normal Operation` window and download the source code corresponding to the `libtorrent-rasterbar>=1.2.19` library to the current build directory. Enter the `Linyaps Container Operation` window to recompile + +9. After the source code is extracted, according to [Basic Steps for Linyaps Application Building], we should correctly choose which compilation system/tools to use before compiling any source code. We observe the `libtorrent-rasterbar-2.0.9` source code directory and can see that it has a `CMakeLists.txt` file, which is a `CMake` build project. + +![2](images/2-2.png) + +10. We enter the source code directory through the `Linyaps Container Operation` window. In order to avoid interference with the source directory as much as possible, I create a new `build` directory here for compilation. After entering the `build` directory, we enter CMake-related configuration parameters to configure the build project. + According to [Linyaps Application Directory Structure Specification], we assign the value of `DCMAKE_INSTALL_PREFIX` to `$PREFIX`. Finally, I executed the following operations locally: + +``` + cmake -DCMAKE_BUILD_TYPE=Release\ + -DCMAKE_INSTALL_PREFIX=$PREFIX .. + make -j$(nproc) + make install +``` + +As can be seen, the third-party library `libtorrent-rasterbar-2.0.9` was successfully compiled and installed into the `$PREFIX` directory in the container. We can start the next operation + +11. We return to the `Linyaps Container Operation` window and enter the `qBittorrent-4.6.7` source code directory. Re-execute the configuration, compilation, and installation operations. No errors exist. + +### Compilation Result Testing + +After the process ends, we find the binary executable file of this project in the `$PREFIX` directory `/opt/apps/org.qbittorrent.qBittorrent/files/bin/qbittorrent` and run the test in the container. \* This operation needs to be performed in the terminal of the graphical desktop, otherwise the graphical interface of the program may not be invoked + +It seems that because it is not directly started through the container, there is a problem that the runtime library cannot be found. Since the reported library is also in $PREFIX, we directly use the variable `LD_LIBRARY_PATH` to specify the dynamic runtime library search path + +![test](images/2-test.png) + +So far, it is sufficient to prove that `Qt5-based open source application--qBittorrent` can be successfully compiled and run in the `Linyaps` application container! diff --git a/docs/pages/en/guide/lessons/build-offline-src.md b/docs/pages/en/guide/lessons/build-offline-src.md new file mode 100644 index 000000000..7bf32d02d --- /dev/null +++ b/docs/pages/en/guide/lessons/build-offline-src.md @@ -0,0 +1,224 @@ +# Adapting Qt5-based Open Source Application--qBittorrent to Support Automated Linyaps Application Build Project + +After learning from the previous chapter "Compiling Qt5-based Open Source Application--qBittorrent in Linyaps Container", we have roughly understood how to compile the Qt5-based open source application--qBittorrent project source code into executable binary program files in the Linyaps container. + +Today, we will complete the final step in the "Basic Steps of Linyaps Application Building" on this basis--writing a complete Linyaps application build project configuration file `linglong.yaml`, mainly achieving the following goals: + +1. Automatically pull open source project source code +2. Automatically apply patches to modify the source code +3. Automatically execute compilation, build, and installation operations + +## Preliminary Preparation + +According to the requirements in "Basic Knowledge of Linyaps Application Build Project" regarding "General Resource Specifications for Linyaps Application Build Project", we should provide both `icons` icon files and `desktop` launch files that ensure desktop user experience for a graphical application. + +Therefore, in order to write a complete `linglong.yaml` that can automatically compile `qBittorrent` today, we need to additionally prepare the following materials: + +1. Non-binary file general resources: icons, desktop files +2. Main program qBittorrent open source project repository git information, tag version, commit information +3. Third-party runtime library libtorrent open source project repository git information, tag version, commit information + +### General Resource Preparation + +Since in the previous lesson we successfully compiled and ran `qBittorrent` in the Linyaps container, and this application provided both the icons directory and desktop launch file after installation to $PREFIX, we check these two items and confirm they both comply with the "Freedesktop XDG Specification", so we only need to copy them directly from the container to local, that is, copy to the build directory `/project`. + +``` +ziggy@linyaps23:/project/src/qBittorrent-release-4.6.7-szbt2/build$ ls $PREFIX/share/applications/ +org.qbittorrent.qBittorrent.desktop +``` + +``` +ziggy@linyaps23:/project/src/qBittorrent-release-4.6.7-szbt2/build$ ls $PREFIX/share/icons/hicolor/128x128/apps/ +qbittorrent.png +``` + +Thus, we obtained the "non-binary file general resources". For convenience of being used by build components, I placed these files in the `template_app` subdirectory of the build directory. The current structure is: + +``` +template_app +├── linglong.yaml +└── template_app + ├── applications + │ └── org.qbittorrent.qBittorrent.desktop + ├── icons + │ └── hicolor + │ ├── 128x128 + │ │ ├── apps + │ │ │ └── qbittorrent.png + │ │ └── status + │ │ └── qbittorrent-tray.png + │ └── scalable + │ ├── apps + │ │ └── qbittorrent.svg + │ └── status + │ ├── qbittorrent-tray-dark.svg + │ ├── qbittorrent-tray-light.svg + │ └── qbittorrent-tray.svg +``` + +### Desktop Launch File Customization + +According to the "General Resource Specifications for Linyaps Application Build Project" in the basic knowledge course, we need to ensure the current desktop file complies with relevant specifications. +We open the desktop file exported from the container, check the Exec and Icon fields, and draw the following conclusions: + +``` +[Desktop Entry] +Categories=Network;FileTransfer;P2P;Qt; +Exec=qbittorrent %U +GenericName=BitTorrent client +Comment=Download and share files over BitTorrent +Icon=qbittorrent +``` + +Main conclusions: + +1. Icon field value is consistent with icon file, compliant with specification +2. Exec field value is not the compilation result in Linyaps container, needs to be modified to content that complies with "General Resource Specifications for Linyaps Application Build Project". Here we replace it with absolute path pointing to the specific binary file in the container, used to wake up the container and launch the application + +## Build Project Configuration File `linglong.yaml` Preparation + +After preparing the essential general resources for graphical applications, we begin writing build rules. +Since in the previous lesson we already prepared a simple version of `linglong.yaml` that doesn't have complete build functionality, we can customize it based on that. The current initial state is: + +```yaml +version: "4.6.7.2" + +package: + id: org.qbittorrent.qBittorrent + name: "qBittorrent" + version: 4.6.7.2 + kind: app + description: | + qBittorrent binary + +base: org.deepin.foundation/23.0.0 +runtime: org.deepin.Runtime/23.0.1 + +command: + - /opt/apps/org.qbittorrent.qBittorrent/files/bin/qbittorrent + +sources: + - kind: local + name: "qBittorrent" + +build: | + mkdir -p ${PREFIX}/bin/ ${PREFIX}/share/ +``` + +### Build Rule Writing & Testing + +For smooth transition, I will first import the compilation instructions into the build rules, temporarily not introducing automatic git repository pulling content, to ensure the build rules we write are accurate and usable. +Since it's not recommended to execute too many `tar` instructions in build rules, I open two shell windows in the build directory here, respectively for "Linyaps Container Operations" and "Normal Operations". +The following is the formal transformation process: + +1. Through the "Normal Operations" window, use `git` to pull or extract `qBittorrent` and `libtorrent-rasterbar` source code to the build directory. Here I extract them to subdirectories through source code compressed packages separately + +``` +ziggy@linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-local$ tar -xvf qBittorrent-4.6.7-git-origin-src.tar.zst -C src/ +ziggy@linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-local$ tar -xvf libtorrent-rasterbar-2.0.9.tar.gz -C 3rd/ + +``` + +2. From the "Linyaps Application Directory Structure Specification", we know that the build directory will be mapped as `/project`, so we need to write the manual compilation commands used in the previous lesson into the `build` module + +``` +build: | + mkdir -p ${PREFIX}/bin/ ${PREFIX}/share/ + ##Build 3rd libs Comment: Enter `libtorrent-rasterbar` source directory and compile install to container + mkdir /project/3rd/libtorrent-rasterbar-2.0.9/build + cd /project/3rd/libtorrent-rasterbar-2.0.9/build + cmake -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=$PREFIX .. + make -j$(nproc) + make install + ##Build main Comment: Enter `qBittorrent` source directory and compile install to container + mkdir /project/src/qBittorrent-release-4.6.7-szbt2/build + cd /project/src/qBittorrent-release-4.6.7-szbt2/build + cmake -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=$PREFIX .. + make -j$(nproc) + make install + ##Extract common res Comment: Copy general files to install to container corresponding directory, comply with "Linyaps Application Directory Structure Specification" + cp -rf /project/template_app/* ${PREFIX}/share/ +``` + +After completing this build rule block, we can start trying to compile local source code into binary programs through automated building and export Linyaps application installation package `binary.layer`. \* Since this version of configuration file doesn't provide extract and delete functions, these directories need to be cleared and re-extracted before each rebuild + +### Local One-Stop Build Test + +After completing the `build` module, the current `linglong.yaml` status is: + +```yaml +version: "2" + +package: + id: org.qbittorrent.qBittorrent + name: "qBittorrent" + version: 4.6.7.2 + kind: app + description: | + qBittorrent binary + +base: org.deepin.foundation/23.0.0 +runtime: org.deepin.Runtime/23.0.1 + +command: + - /opt/apps/org.qbittorrent.qBittorrent/files/bin/qbittorrent + +source: + - kind: local + name: "qBittorrent" + +build: | + ##Build 3rd libs + mkdir -p ${PREFIX}/bin/ ${PREFIX}/share/ + mkdir /project/3rd/libtorrent-rasterbar-2.0.9/build + cd /project/3rd/libtorrent-rasterbar-2.0.9/build + cmake -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=$PREFIX .. + make -j$(nproc) + make install + ##Build main + mkdir /project/src/qBittorrent-release-4.6.7-szbt2/build + cd /project/src/qBittorrent-release-4.6.7-szbt2/build + cmake -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=$PREFIX .. + make -j$(nproc) + make install + ##Extract common res + cp -rf /project/template_app/* ${PREFIX}/share/ +``` + +At this point we can return to the build directory and start the build test, execute: + +``` +ziggy@linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-local$ ll-builder build -v +``` + +Thanks to the compilation notes in the Linyaps container, this build quickly ended successfully. We execute the following command to export the container as a Linyaps application installation package `binary.layer`: + +``` +ziggy@linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-local$ ll-builder export --layer +``` + +## Local Build Result Testing + +After obtaining the Linyaps application installation package, I tried to experience it on different mainstream distributions that support the Linyaps environment to confirm whether the binary programs built through the Linyaps container have universality. + +### deepin 23 + +![deepin 23](images/3-test-1.png) + +### openKylin 2.0 + +![openKylin 2.0](images/3-test-2.png) + +### Ubuntu 2404 + +![Ubuntu 2404](images/3-test-3.png) + +### OpenEuler 2403 + +![OpenEuler 2403](images/3-test-4.png) + +So far, it is sufficient to prove that the "Qt5-based open source application--qBittorrent" can be successfully built and run in third-party distributions that support the "Linyaps" application solution! diff --git a/docs/pages/guide/lessons/image/2-1.png b/docs/pages/en/guide/lessons/images/2-1.png similarity index 100% rename from docs/pages/guide/lessons/image/2-1.png rename to docs/pages/en/guide/lessons/images/2-1.png diff --git a/docs/pages/guide/lessons/image/2-2.png b/docs/pages/en/guide/lessons/images/2-2.png similarity index 100% rename from docs/pages/guide/lessons/image/2-2.png rename to docs/pages/en/guide/lessons/images/2-2.png diff --git a/docs/pages/guide/lessons/image/2-error-1.png b/docs/pages/en/guide/lessons/images/2-error-1.png similarity index 100% rename from docs/pages/guide/lessons/image/2-error-1.png rename to docs/pages/en/guide/lessons/images/2-error-1.png diff --git a/docs/pages/guide/lessons/image/2-test.png b/docs/pages/en/guide/lessons/images/2-test.png similarity index 100% rename from docs/pages/guide/lessons/image/2-test.png rename to docs/pages/en/guide/lessons/images/2-test.png diff --git a/docs/pages/guide/lessons/image/3-test-1.png b/docs/pages/en/guide/lessons/images/3-test-1.png similarity index 100% rename from docs/pages/guide/lessons/image/3-test-1.png rename to docs/pages/en/guide/lessons/images/3-test-1.png diff --git a/docs/pages/guide/lessons/image/3-test-2.png b/docs/pages/en/guide/lessons/images/3-test-2.png similarity index 100% rename from docs/pages/guide/lessons/image/3-test-2.png rename to docs/pages/en/guide/lessons/images/3-test-2.png diff --git a/docs/pages/guide/lessons/image/3-test-3.png b/docs/pages/en/guide/lessons/images/3-test-3.png similarity index 100% rename from docs/pages/guide/lessons/image/3-test-3.png rename to docs/pages/en/guide/lessons/images/3-test-3.png diff --git a/docs/pages/guide/lessons/image/3-test-4.png b/docs/pages/en/guide/lessons/images/3-test-4.png similarity index 100% rename from docs/pages/guide/lessons/image/3-test-4.png rename to docs/pages/en/guide/lessons/images/3-test-4.png diff --git a/docs/pages/guide/lessons/image/4-commit-1.png b/docs/pages/en/guide/lessons/images/4-commit-1.png similarity index 100% rename from docs/pages/guide/lessons/image/4-commit-1.png rename to docs/pages/en/guide/lessons/images/4-commit-1.png diff --git a/docs/pages/guide/lessons/image/4-commit-2.png b/docs/pages/en/guide/lessons/images/4-commit-2.png similarity index 100% rename from docs/pages/guide/lessons/image/4-commit-2.png rename to docs/pages/en/guide/lessons/images/4-commit-2.png diff --git a/docs/pages/guide/lessons/image/4-commit-3.png b/docs/pages/en/guide/lessons/images/4-commit-3.png similarity index 100% rename from docs/pages/guide/lessons/image/4-commit-3.png rename to docs/pages/en/guide/lessons/images/4-commit-3.png diff --git a/docs/pages/guide/lessons/image/4-test-1.png b/docs/pages/en/guide/lessons/images/4-test-1.png similarity index 100% rename from docs/pages/guide/lessons/image/4-test-1.png rename to docs/pages/en/guide/lessons/images/4-test-1.png diff --git a/docs/pages/guide/lessons/image/4-test-2.png b/docs/pages/en/guide/lessons/images/4-test-2.png similarity index 100% rename from docs/pages/guide/lessons/image/4-test-2.png rename to docs/pages/en/guide/lessons/images/4-test-2.png diff --git a/docs/pages/guide/lessons/image/4-test-3.png b/docs/pages/en/guide/lessons/images/4-test-3.png similarity index 100% rename from docs/pages/guide/lessons/image/4-test-3.png rename to docs/pages/en/guide/lessons/images/4-test-3.png diff --git a/docs/pages/guide/lessons/image/4-test-4.png b/docs/pages/en/guide/lessons/images/4-test-4.png similarity index 100% rename from docs/pages/guide/lessons/image/4-test-4.png rename to docs/pages/en/guide/lessons/images/4-test-4.png diff --git a/docs/pages/guide/lessons/image/5-test-1.png b/docs/pages/en/guide/lessons/images/5-test-1.png similarity index 100% rename from docs/pages/guide/lessons/image/5-test-1.png rename to docs/pages/en/guide/lessons/images/5-test-1.png diff --git a/docs/pages/guide/lessons/image/5-test-2.png b/docs/pages/en/guide/lessons/images/5-test-2.png similarity index 100% rename from docs/pages/guide/lessons/image/5-test-2.png rename to docs/pages/en/guide/lessons/images/5-test-2.png diff --git a/docs/pages/guide/lessons/image/5-test-3.png b/docs/pages/en/guide/lessons/images/5-test-3.png similarity index 100% rename from docs/pages/guide/lessons/image/5-test-3.png rename to docs/pages/en/guide/lessons/images/5-test-3.png diff --git a/docs/pages/guide/lessons/image/5-test-4.png b/docs/pages/en/guide/lessons/images/5-test-4.png similarity index 100% rename from docs/pages/guide/lessons/image/5-test-4.png rename to docs/pages/en/guide/lessons/images/5-test-4.png diff --git a/docs/pages/guide/lessons/image/5-test-5.png b/docs/pages/en/guide/lessons/images/5-test-5.png similarity index 100% rename from docs/pages/guide/lessons/image/5-test-5.png rename to docs/pages/en/guide/lessons/images/5-test-5.png diff --git a/docs/pages/en/guide/lessons/test-with-toolchains.md b/docs/pages/en/guide/lessons/test-with-toolchains.md new file mode 100644 index 000000000..64e678a90 --- /dev/null +++ b/docs/pages/en/guide/lessons/test-with-toolchains.md @@ -0,0 +1,184 @@ +# Advanced Linyaps Application Compatibility Testing -- Linyaps Application Automated Testing Suite + +As you may have noticed, in our previous Linyaps application compilation, we manually installed packages and launched applications to test compatibility +However, this raises a question: as the number of applications that need testing continues to increase, doesn't the manual testing approach seem relatively inefficient? +To address this, I would like to introduce to you the `Linyaps Application Automated Testing Suite -- Next Linyaps Testing Toolchains` currently available to ecosystem contributors in the Linyaps community + +## Project Introduction + +`Next Linyaps Testing Toolchains` is a Linyaps application testing toolchain composed of shell scripts, designed to bring more convenient solutions for Linyaps application testing +This project is the legitimate spiritual successor of [linglong-automan](https://gitee.com/ziggy615/linglong-automan) and promises to remain open source forever + +## Implemented Features + +1. Organize scattered `*binary.layer` files in a specified directory into a standardized directory structure: `xxx/id/package` and generate two tables storing Linyaps application IDs and application version numbers + +2. After specifying the organized Linyaps file storage directory, start the streamlined installation process + +3. After specifying the resource storage directory and application information table, simulate launching applications through desktop files based on `installation status`, `desktop file existence status`, and `window generation status`, and take screenshots of test results \* The current code partially depends on `deepin 23` system components and needs to be re-adapted when used on other distributions + +4. Scan icon files for installed Linyaps applications, determine whether the current application icons directory and files comply with `Freedesktop XDG` specifications, and collect icons + +5. Batch uninstall installed Linyaps applications + +## Code Structure Analysis + +Entering the suite repository, you can see that the suite is divided into several key independent scripts according to function/role, roughly: + +1. `linyaps-auto-optimize.sh`, Linyaps application installation package `binary.layer` organization tool. Organize all `binary.layer` files in a directory into a structure suitable for the testing suite and produce two tables for recording Linyaps application IDs and version numbers, such as: + +``` +org.qbittorrent.qBittorrent/package/org.qbittorrent.qBittorrent_4.6.7.22_x86_64_binary.layer +com.poki.apple-knight-golf.linyaps/package/com.poki.apple-knight-golf.linyaps_28.3.3.2_x86_64_binary.layer +``` + +ll-pkg-name.csv + +``` +org.qbittorrent.qBittorrent +com.poki.apple-knight-golf.linyaps +``` + +ll-pkg-version.csv + +``` +4.6.7.22 +28.3.3.2 +``` + +2. `linyaps-auto-install-release.sh`, Linyaps application installation package `binary.layer` batch installation tool, used to install packages organized by `linyaps-auto-optimize.sh` + +3. `linyaps-auto-screenshot-deepin23.sh`, application automated testing suite, including running status screenshot function, only for `deepin 23` environment + +4. `linyaps-auto-screenshot-general.sh`, application automated testing suite general version, does not include running status screenshot function, for non-deepin 23 environments + +5. `linyaps-auto-uninstall-release.sh`, Linyaps application batch uninstallation tool + +## Next Linyaps Testing Toolchains Practical Application + +After introducing the overall functions and code logic, we demonstrate how to complete batch testing of Linyaps application installation packages `binary.layer` produced in previous lessons through the `Linyaps Application Automated Testing Suite` based on `deepin 23` + +### Environment Preparation + +Before starting to use the testing suite, you need to ensure that the current environment meets the following conditions + +1. Some functions of the self-service compatibility testing suite used in this practical demonstration require the use of `Linux x11` window management tools, so you need to install the following software packages before use: + +``` +wmctrl x11-utils +``` + +2. The testing suite uses x11 window management tools to determine application window startup status, so you need to ensure that your system is an `x11` environment rather than a `Wayland` environment + +3. `wmctrl` and `xwininfo` components can work normally, and window information can be queried through `xwininfo` + +4. Since `deepin 23` provides compatibility testing result screenshot function, you need to install related software packages: + +``` +deepin-screen-recorder imagesmagick-6.q16 +``` + +5. Manually start `deepin-screen-recorder` once to ensure that the system screenshot save path is in the current user's ~/Pictures/Screenshots, and the directory is empty + +### Start Testing Function + +1. In the previous practical lesson, we obtained the Linyaps installation package `org.qbittorrent.qBittorrent_4.6.7.22_x86_64_binary.layer` for `qBittorrent--4.6.7`. For convenience in demonstrating the suite's batch support capability, I separately found another installation package here + +2. Now we have two Linyaps application installation packages. First execute the `linyaps-auto-optimize.sh` script to organize the directory + This script mainly uses two parameters to point to the current directory storing Linyaps application installation packages `binary.layer` `$ll_origin_pool` and the destination directory that needs to be organized `$ll_stored_pool` + +3. I created two separate directories `ll-bins` `ll-pool` locally to point to `$ll_origin_pool` and `$ll_stored_pool` + The current directory structure of `ll-bins`: + +``` +├── ll-bins +│ ├── org.qbittorrent.qBittorrent_4.6.7.22_x86_64_binary.layer +│ └── com.poki.apple-knight-golf.linyaps_28.3.3.2_x86_64_binary.layer +``` + +4. Execute directory organization operation + +```bash +ziggy@linyaps23:/media/szbt/Data/linyaps-testing-toolchains$ ./linyaps-auto-optimize.sh ./ll-bins ./ll-pool +``` + +After the organization is completed, the directory presents this structure: + +``` +ll-pool/ +├── org.qbittorrent.qBittorrent +│ └── package +│ └── org.qbittorrent.qBittorrent_4.6.7.22_x86_64_binary.layer +└── com.poki.apple-knight-golf.linyaps + └── package + └── com.poki.apple-knight-golf.linyaps_28.3.3.2_x86_64_binary.layer + +``` + +5. After the directory organization, two tables `ll-pkg-name.csv` `ll-pkg-version.csv` are generated to record application information. We merge the two columns into a new table `ll-pkg-info.csv`: + +ll-pkg-info.csv + +``` +org.qbittorrent.qBittorrent,4.6.7.22 +com.poki.apple-knight-golf.linyaps,28.3.3.2 +``` + +6. Based on this file, we can start batch installing Linyaps applications + This script mainly uses one parameter to point to the current organized destination directory `$ll_stored_pool`: + +```bash +ziggy@linyaps23:/media/szbt/Data/linyaps-testing-toolchains$ linyaps-auto-install-release.sh ./ll-pool +``` + +7. After installing the Linyaps applications and completing all prerequisite work, we can start the testing process. Here we create a new `res` directory to store test result resources such as icons and screenshots + +8. Open a terminal in the graphical interface and execute the screenshot script. Since we are in a `deepin 23 x11` environment and have installed the necessary programs, we run `linyaps-auto-screenshot-deepin23.sh` + This script mainly uses two parameters to point to the directory for placing test result resources `$ll_res_pool` and the table recording application information `$ll_pkgname_list`. Here it refers to the new table `ll-pkg-info.csv` we obtained in the previous step: + +```bash +ziggy@linyaps23:/media/szbt/Data/linyaps-testing-toolchains$ ./linyaps-auto-screenshot-deepin23.sh ./res ./ll-pkg-info.csv +``` + +\* Remember, this script must be executed in a graphical terminal, otherwise the process cannot be properly launched + +9. After the script starts, minimize the terminal window and keep it running in the background. The testing suite will judge the application installation status and desktop file existence status to `start` and `close` application windows + +![test-1](images/5-test-1.png) +![test-2](images/5-test-2.png) + +10. After meeting the running requirements, the suite will simulate launching the program through the desktop file and judge the window after about 30s delay, checking whether the application generates a new window after running + +![test-3](images/5-test-3.png) +![test-4](images/5-test-4.png) + +11. After the application runs successfully, it will complete screenshot, icon detection & acquisition operations in sequence + +12. After the test is completed, you can see tables of different statuses and test result materials in the `res` directory. Since both applications here passed the compatibility test, they will be recorded in `all-good.csv` + Otherwise, two abnormal situations will occur: + a. Applications that timeout without generating windows will be written into the `failed.csv` file, judged as applications that cannot be launched + b. If the Linyaps application directory does not contain icon files, it will be written into the `icons-missing.csv` file, not meeting the specifications for graphical applications in the Linyaps community + +``` +res/ +├── all-good.csv +├── com.poki.apple-knight-golf.linyaps +│ ├── icons +│ │ └── com.poki.apple-knight-golf.png ##Application icon file +│ └── screenshots ##Application compatibility test screenshots +│ ├── 1.png +│ ├── 2.png +│ └── 3.png +└── org.qbittorrent.qBittorrent + ├── icons + │ ├── qbittorrent.png + │ └── qbittorrent.svg + └── screenshots + ├── 1.png + ├── 2.png + └── 3.png +``` + +![test-5](images/5-test-5.png) + +So far, we have successfully completed compatibility testing of Linyaps applications produced in previous lessons through the Linyaps Application Automated Testing Suite diff --git a/docs/pages/en/guide/linyaps-devel/README.md b/docs/pages/en/guide/linyaps-devel/README.md new file mode 100644 index 000000000..085fdb052 --- /dev/null +++ b/docs/pages/en/guide/linyaps-devel/README.md @@ -0,0 +1 @@ +This repository contains developer-related documentation. (To be supplemented) diff --git a/docs/pages/en/guide/ll-appimage-convert/convert-appimage.md b/docs/pages/en/guide/ll-appimage-convert/convert-appimage.md deleted file mode 100644 index ffed46ea1..000000000 --- a/docs/pages/en/guide/ll-appimage-convert/convert-appimage.md +++ /dev/null @@ -1,86 +0,0 @@ - - -## Conversion appimage application - -convert `appimage` format( `.appimage` or `.AppImage` ) application to linyaps format( `.layer` or `.uab` ) application - -View the help information for the `ll-appimage-convert convert --help` command: - -```bash -ll-appimage-convert convert --help -``` - -Here is the output: - -```text -Usage: - ll-appimage-convert convert [flags] -Flags: - -b, --build build linglong - -d, --description string detailed description of the package - -f, --file string app package file, it not required option, - you can ignore this option - when you set --url option and --hash option - --hash string pkg hash value, it must be used with --url option - -h, --help help for convert - -i, --id string the unique name of the package - -l, --layer export layer file - -n, --name string the description the package - -u, --url string pkg url, it not required option,you can ignore this option when you set -f option - -v, --version string the version of the package -Global Flags: - -V, --verbose verbose output -``` - -The `ll-appimage-convert convert` command will generate a directory according to specified app name( `--name` option), it will as a root directory of the linyaps project, where the `linglong.yaml` file is located. and it supports two convert methods: - -1. you can use `--file` option to convert to linyaps application according to specified appimage file; -2. you can use `--url` and `--hash` option to convert to linyaps application according to specified appimage url and hash value; -3. you can use `--layer` option to export `.layer`, or it will export `.uab` default. - -`Tips: When the linglong version is greater than 1.5.7, the default convert package format is `.uab`, if you want to export a `.layer` file, you need to add the --layer option.` - -you can use `--output` option to generate config file( `linglong.yaml` ) of linyaps project and a script of build linyaps `.layer`(`.uab`) -then you can execute script file to generate after you modify the `linglong.yaml` file. if you do not specify this option, it will export linyaps `.layer` or `.uab` directly. - -Take converting [BrainWaves](https://github.com/makebrainwaves/BrainWaves/releases/download/v0.15.1/BrainWaves-0.15.1.AppImage) into linyaps `.layer` through `--url` as an example, the main steps as follows: - -Specify the relevant parameters of the linyaps package you want to convert, you can acquire `io.github.brainwaves_0.15.1.0_x86_64_runtime.layer` or `io.github.brainwaves_0.15.1.0_x86_64_runtime.uab` wait a moment. - -```bash -ll-appimage-convert convert --url "https://github.com/makebrainwaves/BrainWaves/releases/download/v0.15.1/BrainWaves-0.15.1.AppImage" --hash "04fcfb9ccf5c0437cd3007922fdd7cd1d0a73883fd28e364b79661dbd25a4093" --name "io.github.brainwaves" --id "io.github.brainwaves" --version "0.15.1.0" --description "io.github.brainwaves" -b -``` - -Take converting BrainWaves-0.15.1.AppImage into `.uab` through `--file` as an example, the main steps as follows: - -```bash -ll-appimage-convert convert -f ~/Downloads/BrainWaves-0.15.1.AppImage --name "io.github.brainwaves" --id "io.github.brainwaves" --version "0.15.1.0" --description "io.github.brainwaves" -b -``` - -The converted directory structure is as follows: -```text -├── io.github.brainwaves_x86_64_0.15.1.0_main.uab -├── linglong -└── linglong.yaml -``` - -Take converting BrainWaves-0.15.1.AppImage into `.layer` through `--file` as an example, the main steps as follows: - -```bash -ll-appimage-convert convert -f ~/Downloads/BrainWaves-0.15.1.AppImage --name "io.github.brainwaves" --id "io.github.brainwaves" --version "0.15.1.0" --description "io.github.brainwaves" -b --layer -``` - -The converted directory structure is as follows: -```text -├── io.github.brainwaves_0.15.1.0_x86_64_binary.layer -├── io.github.brainwaves_0.15.1.0_x86_64_develop.layer -├── linglong -└── linglong.yaml -``` - -`.uab` or `.layer` file verification -The exported `.uab` or `.layer` needs to be installed and verified. install the layer file and run the application, you can refer to: [Install the application](../ll-cli/install.md) diff --git a/docs/pages/en/guide/ll-appimage-convert/introduction.md b/docs/pages/en/guide/ll-appimage-convert/introduction.md deleted file mode 100644 index 0bcbe6bb2..000000000 --- a/docs/pages/en/guide/ll-appimage-convert/introduction.md +++ /dev/null @@ -1,42 +0,0 @@ -# ll-appimage-convert introduction - -This tool is provided by the `linglong-pica` package.which provides the ability to convert appimage packages into linyaps packages, generate the linglong.yaml file required to build linyaps applications, and rely on ll-builder to implement application building and export. - -:::tip - -The conversion tool is merely an auxiliary tool and does not guarantee -that the converted application will definitely run. It's possible that -the software depends on libraries installed in paths or other -configuration paths that do not align with those inside linyaps's -internal structure, leading to the inability to execute. In such cases, -you would need to use the command `ll-builder run --exec bash` to enter the container for debugging purposes. -::: - -View the help information for the `ll-appimage-convert` command: - -```bash -ll-appimage-convert --help -``` - -Here is the output: - -```bash -Convert the appimage to uab. For example: - Simple: - ll-appimage-convert convert -f xxx.appimage -i "io.github.demo" -n "io.github.demo" -v "1.0.0.0" -d "this is a appimage convert demo" -b - ll-appimage-convert help - -Usage: - ll-appimage-convert [command] - -Available Commands: - convert Convert appimage to uab - help Help about any command - -Flags: - -h, --help help for ll-appimage-convert - -V, --verbose verbose output - -v, --version version for ll-appimage-convert - -Use "ll-appimage-convert [command] --help" for more information about a command. -``` diff --git a/docs/pages/en/guide/ll-builder/build.md b/docs/pages/en/guide/ll-builder/build.md deleted file mode 100644 index 280b3cb3d..000000000 --- a/docs/pages/en/guide/ll-builder/build.md +++ /dev/null @@ -1,69 +0,0 @@ - - -# Build App - -Use `ll-builder build` to build a linyaps application. - -View the help information for the `ll-builder build` command: - -```bash -ll-builder build --help -``` - -Here is the output: - -```text -Build a linyaps project -Usage: ll-builder build [OPTIONS] [COMMAND...] - -Positionals: - COMMAND TEXT ... Enter the container to execute command instead of building applications - -Options: - -h,--help Print this help message and exit - --help-all Expand all help - --file FILE:FILE [./linglong.yaml] - File path of the linglong.yaml - --arch ARCH Set the build arch - --offline Only use local files. This implies --skip-fetch-source and --skip-pull-depend will be set - --skip-fetch-source Skip fetch sources - --skip-pull-depend Skip pull dependency - --skip-run-container Skip run container - --skip-commit-output Skip commit build output - --skip-output-check Skip output check - --skip-strip-symbols Skip strip debug symbols -``` - -The `ll-builder build` command can be run in two ways: -1. the root directory of the project, where the `linglong.yaml` file is located. -2. specify the linglong.yaml file path with the `--file` parameter. - -Taking the linyaps project `org.deepin.demo`, as an example, the main steps to build a linyaps application would be as follows: - -Go to the `org.deepin.demo` project directory: - -```bash -cd org.deepin.demo -``` - -Execute the `ll-builder build` command to start building: - -```bash -ll-builder build -``` - -After the build is complete, the build content will be automatically committed to the local ostree cache. See `ll-builder export` for exporting build content. - -Use the `--exec` parameter to enter the linyaps container before the build script is executed: - -```bash -ll-builder build --exec /bin/bash -``` - -After entering the container, you can execute `shell` commands, such as `gdb`, `strace`, etc. - -For more debugging information of linyaps application `debug` version, please refer to: [Debug App](../debug/debug.md). diff --git a/docs/pages/en/guide/ll-builder/create.md b/docs/pages/en/guide/ll-builder/create.md deleted file mode 100644 index 724f85e07..000000000 --- a/docs/pages/en/guide/ll-builder/create.md +++ /dev/null @@ -1,144 +0,0 @@ - - -# Create linyaps project - -Use `ll-builder create` to create a linyaps project. - -View the help information for the `ll-builder create` command: - -```bash -ll-builder create --help -``` - -Here is the output: - -```text -Create linyaps build template project -Usage: ll-builder create [OPTIONS] NAME - -Positionals: - NAME TEXT REQUIRED Project name - -Options: - -h,--help Print this help message and exit - --help-all Expand all help -``` - -The `ll-builder create` command creates a folder in the current directory according to the project name, and generates the `linglong.yaml` template file required for the build. Here is an example: - -```bash -ll-builder create org.deepin.demo -``` - -Here is the output: - -```text -org.deepin.demo/ -└── linglong.yaml -``` - -## Edit linglong.yaml - -### The syntax version of the linglong.yaml file. - -```yaml -version: "1" -``` - -### App meta info - -```yaml -package: - id: org.deepin.demo - name: hello - version: 0.0.0.1 - kind: app - description: | - simple Qt demo. -``` - -### Base - -The minimum root filesystem. - -```yaml -base: org.deepin.base/23.1.0 -``` - -### Runtime - -On the basis of the rootfs, add fundamental environments such as Qt. - -```yaml -runtime: org.deepin.runtime.dtk/23.1.0 -``` - -### Command - -linyaps application startup command. - -```yaml -command: [echo, -e, hello world] -``` - -### Source - -Use git source code - -```yaml -sources: - kind: git - url: "https://github.com/linuxdeepin/linglong-builder-demo.git" - commit: a3b89c3aa34c1aff8d7f823f0f4a87d5da8d4dc0 -``` - -### Build - -The commands required to build the project. - -```yaml -build: | - cd /project/linglong/sources/linglong-builder-demo.git - qmake demo.pro - make -j${JOBS} - make install -``` - -### Completed `linglong.yaml` config - -The contents of the `linglong.yaml` file are as follows: - -```yaml -version: "1" - -package: - id: @ID@ - name: your name #set your application name - version: 0.0.0.1 #set your version - kind: app - description: | - your description #set a brief text to introduce your application. - -command: [echo, -e, hello world] #the commands that your application need to run. - -base: org.deepin.base/23.1.0 #set the base environment, this can be changed. - -#set the runtime environment if you need, a example of setting deepin runtime is as follows. -#runtime: -#runtime: org.deepin.runtime.dtk/23.1.0 - -#set the source if you need, a simple example of git is as follows. -#sources: -# - kind: git -# url: https://github.com/linuxdeepin/linglong-builder-demo.git -# version: master\n -# commit: a3b89c3aa34c1aff8d7f823f0f4a87d5da8d4dc0 - -build: | - echo 'hello' #some operation to build this project - -``` diff --git a/docs/pages/en/guide/ll-builder/demo.md b/docs/pages/en/guide/ll-builder/demo.md deleted file mode 100644 index 9d9ffb20d..000000000 --- a/docs/pages/en/guide/ll-builder/demo.md +++ /dev/null @@ -1,149 +0,0 @@ - - -## Initialize linyaps Projects - -```text -ll-builder create org.deepin.calculator -``` - -## Edit linglong.yaml - -### Fill in the meta information of packages - -```text -package: - id: org.deepin.calculator - name: deepin-calculator - version: 5.9.17 - kind: app - description: | - calculator for deepin os. -``` - -### Fill in the runtime info - -```text -runtime: - id: org.deepin.runtime.dtk - version: 23.1.0 -``` - -### Fill in the source code info - -Use git source code - -```text -source: - kind: git - url: "https://github.com/linuxdeepin/deepin-calculator.git" - commit: 7b5fdf8d133c356317636bb4b4a76fc73ef288c6 -``` - -### Fill in the dependencies - -```text -depends: - - id: "dde-qt-dbus-factory" - version: 5.5.12 - - id: googletest - version: 1.8.1 - - id: icu - version: 63.1.0 - type: runtime - - id: xcb-util - type: runtime -``` - -### Choose build template - -The source code is a cmake project, and choose the build type as cmake (see cmake.yaml for the template content). - -```text -build: - kind: cmake -``` - -### Override template content - -If the general template content does meet the build requirements, you can override the specified content in the linglong.yaml file. Variables or commands that are not re-declared in linglong.yaml will continue to be used. - -Override the variable extra_args: - -```text -variables: - extra_args: | - -DVERSION=1.1.1 \ - -DPREFIX=/usr -``` - -Override the build command “build”: - -```text -build: - kind: cmake - manual : - build: | - cd ${build_dir} && make -j8 - -``` - -### Complete linglong.yaml - -```text -package: - id: org.deepin.calculator - name: deepin-calculator - version: 5.7.21 - kind: app - description: | - calculator for deepin os -variables: - extra_args: | - -DVERSION=${VERSION} \ - -DAPP_VERSION=5.7.21 -runtime: - id: org.deepin.runtime.dtk - version: 23.1.0 -depends: - - id: "dde-qt-dbus-factory" - version: 5.5.12 - - id: googletest - version: 1.8.1 - - id: icu - version: 63.1.0 - type: runtime - - id: xcb-util - type: runtime -source: - kind: git - url: https://github.com/linuxdeepin/deepin-calculator.git - commit: 7b5fdf8d133c356317636bb4b4a76fc73ef288c6 -build: - kind: cmake -``` - -## Start building - -Execute the build subcommand in the root directory of linyaps projects: - -```text -ll-builder build -``` - -## Export build content - -Execute the export subcommand in the root directory of linyaps projects to check out the build content and generate the bundle package. - -```text -ll-builder export --layer -``` - -## Push to repositories - -```text -ll-builder push org.deepin.calculator_5.7.21_x86_64.uab -``` diff --git a/docs/pages/en/guide/ll-builder/export.md b/docs/pages/en/guide/ll-builder/export.md deleted file mode 100644 index dec84ef65..000000000 --- a/docs/pages/en/guide/ll-builder/export.md +++ /dev/null @@ -1,86 +0,0 @@ - - -# Export - -The `ll-builder export` command is used to export applications from the local build cache into a UAB (Universal Application Bundle) file. This is the recommended format. It can also export to the deprecated linglong layer file format. - -## Basic Usage - -```bash -ll-builder export [OPTIONS] -``` - -To view all available options and their detailed descriptions, run: -```bash -ll-builder export --help -``` - -## Main Options - -* `-f, --file FILE`: Specify the path to the `linglong.yaml` configuration file (default: `./linglong.yaml`). The directory containing `linglong.yaml` serves as the project's working directory. -* `-o, --output FILE`: Specify the output file path. For UAB, this is typically the full path or filename of the `.uab` file. For layers, this is the prefix for the output filenames. -* `-z, --compressor X`: Specify the compression algorithm. Supports `lz4` (UAB default), `lzma` (layer default), `zstd`. -* `--icon FILE`: Specify an icon for the exported UAB file (UAB mode only, mutually exclusive with `--layer`). -* `--loader FILE`: Specify a custom loader for the exported UAB file (UAB mode only, mutually exclusive with `--layer`). -* `--layer`: **(Deprecated)** Export as layer file format instead of UAB (mutually exclusive with `--icon`, `--loader`). -* `--no-develop`: When exporting layer files, do not include the `develop` module. - -## Exporting UAB Files (Recommended) - -A UAB (Universal Application Bundle) file is a self-contained, offline-distributable file format that includes the content required to run the application. This is the recommended export format. - -After execution, the `ll-builder export` command generates a `.uab` file in the project's working directory (or the path specified with `-o`), for example, `__.uab`. - -You can customize the UAB export using other options: - -```bash -# Export UAB file specifying icon and output path -ll-builder export --icon assets/app.png -o dist/my-app-installer.uab - -# Export UAB file using zstd compression -ll-builder export -z zstd -o my-app-zstd.uab - -# Export UAB file specifying a custom loader -ll-builder export --loader /path/to/custom/loader -o my-app-custom-loader.uab -``` - -## Exporting Layer Files (Deprecated) - -**Note: Exporting layer file format is deprecated. Using the UAB format is recommended.** - -Export layer files using the command `ll-builder export --layer`. Other examples: - -```bash -# Export layer format without the develop module -ll-builder export --layer --no-develop - -# Export layer format and specify the output file prefix -ll-builder export --layer -o my-app -# (Generates my-app_binary.layer and my-app_develop.layer) -``` - -Exporting layer files generates the following files: -* `*_binary.layer`: Contains the basic files required for the application to run. -* `*_develop.layer`: (Optional) Contains files for development and debugging. This file is not generated if the `--no-develop` option is used. - -## Advanced Notes - -A UAB is a statically linked ELF executable intended to run on any Linux distribution. By default, exporting a UAB file uses the "bundle mode". Using the `--loader` parameter exports a UAB file in "custom loader mode". - -### Bundle Mode - -Bundle mode is primarily for distribution and supports self-running capabilities as much as possible. Users typically install offline-distributed applications via `ll-cli install `, which automatically completes the required runtime environment for the application. Once installed, the UAB application is used the same way as an application installed directly from a repository. - -During export in bundle mode, the builder attempts to automatically resolve application dependencies and export necessary content (best effort). If you grant executable permissions to a bundle mode UAB file and run it, the application runs directly without being installed. In this case, the application still runs in an isolated container, but missing parts of the runtime environment will use the host system's environment directly, so the application is not guaranteed to run. - -If application developers need to rely on the self-running feature, ensure the application includes the necessary runtime dependencies. - -### Custom Loader Mode - -A UAB file exported in custom loader mode contains only the application data and the provided custom loader. After the UAB file is unpacked and mounted, control is handed over to the custom loader, which runs outside the container environment. The environment variable `LINGLONG_UAB_APPROOT` stores the application's directory. The custom loader is responsible for initializing the application's required runtime environment, such as library search paths. - -In this mode, the application needs to ensure its compatibility with the target system. The recommended practice is to build the application on the oldest supported system version and include all dependencies. diff --git a/docs/pages/en/guide/ll-builder/introduction.md b/docs/pages/en/guide/ll-builder/introduction.md deleted file mode 100644 index 8e93f2690..000000000 --- a/docs/pages/en/guide/ll-builder/introduction.md +++ /dev/null @@ -1,52 +0,0 @@ - - -# ll-builder Introduction - -`ll-builder` is a tool for developers for building linyaps applications. - -The main functions are as follows: - -- Supports building in a standalone sandbox. - - - -- Provides DTK software development kits. - - - -View the help information for the `ll-builder` command: - -```bash -ll-builder --help -``` - -Here is the output: - -```text -linyaps builder CLI -A CLI program to build linyaps application - -Usage: ll-builder [OPTIONS] [SUBCOMMAND] - -Options: - -h,--help Print this help message and exit - --help-all Expand all help - --version Show version - -Subcommands: - create Create linyaps build template project - build Build a linyaps project - run Run builded linyaps app - export Export to linyaps layer or uab - push Push linyaps app to remote repo - import Import linyaps layer to build repo - extract Extract linyaps layer to dir - repo Display and manage repositories - -If you found any problems during use -You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues -``` diff --git a/docs/pages/en/guide/ll-builder/linyaps_package_spec.md b/docs/pages/en/guide/ll-builder/linyaps_package_spec.md deleted file mode 100644 index 760dd0de5..000000000 --- a/docs/pages/en/guide/ll-builder/linyaps_package_spec.md +++ /dev/null @@ -1,760 +0,0 @@ -# Linglong Application Packaging Specification - -The explanations of the keywords **must**, **prohibited**, **necessary**, **should**, **should not**, **recommended**, **allowed**, and **optional**[^rfc2119-keywords] in this document can be found in the description in [RFC 2119][rfc-2119]. - -The correspondence between these keywords and the English words in the original text is shown in the following table: - -| Chinese | English | -|------------|-------------| -| **Must** | MUST | -| **Prohibited** | MUST NOT | -| **Necessary** | REQUIRED | -| **Should** | SHALL | -| **Should not** | SHALL NOT | -| **Recommended** | RECOMMENDED | -| **Allowed** | MAY | -| **Optional** | OPTIONAL | - -[rfc-2119]: https://datatracker.ietf.org/doc/html/rfc2119 - -This document is intended to help application developers standardize the behavior of the application build process in order to migrate to the Linglong package management system. - -## General - -This section mainly records some general specifications that almost all projects should follow. - -### Application name - -The application name **should** use [reverse domain name notation](https://zh.wikipedia.org/wiki/%E5%8F%8D%E5%90%91%E5%9F%9F%E5%90%8D%E8%A1%A8%E7%A4%BA%E6%B3%95), such as `org.deepin.demo`. - -This application name is mainly used in scenarios such as naming desktop files and DBus services. - -- Developers **should** use the reverse of the domain name they actually own as the prefix of the application name, followed by the application name - -**Note**: If the developer cannot prove that they actually own the domain name, the application package may be removed from the repository. - -- For third-party applications developed on GitHub, if the organization where the application is located has an additional domain name, it should be used first, otherwise `io.github..` should be used as the prefix. - -In particular, if the organization name and application name of the application are the same, such as , the packager should not omit the duplicate application name and organization name, and the ID of this application should be `io.github.neovim.neovim`. - -**Note**: In fact, the organization owns the domain name `neovim.io`, so the most reasonable application name **should** be `io.neovim.neovim`. - -- **Not recommended** to use application names containing `-`, if the domain name/application name does contain `-`, **recommend** to use `_` instead - -- **Not recommended** application names ending with `.desktop` - -The above specifications are from [Desktop Entry Specification][desktop-entry-specification]. - -[desktop-entry-specification]: https://specifications.freedesktop.org/desktop-entry-spec/latest - -Further reading: - -### `prefix` and `$DESTDIR` - -When writing the build process of an application, developers **should** not assume that the installation location is fixed. It is not standard to install executable files to a hard-coded path such as `/usr/bin` in Makefile/CMakeLists.txt. - -When writing the build/installation process, developers **should** respect the build system's `prefix` configuration and the value of the `$DESTDIR` environment variable so that packagers can easily configure the specific installation location of the application when packaging. - -`prefix` refers to the specific location specified to the build system during build/installation where the application will eventually be installed to the system. - -When the developer does not specify the installation location, the default value should be `/usr/local`. -When packaging through the package management system, the package management system will configure its value. When using dpkg-related tools for packaging, its value will be configured as `/usr`. However, when writing the build/installation process, the developer should consider the case where `prefix` is configured to any value. - -`$DESTDIR` refers to an environment variable agreed upon when the build system is installed to facilitate the distribution packaging process. Its general working logic is as follows: - -If the build system completes the build work and executes the installation process, it is specified with `prefix=/usr` and `$DESTDIR=./tmp`, then after the installation is completed, all product files should appear in the `./tmp/usr` directory. The packaging tool will then treat `./tmp` as the root directory and compress and package the files in it. - -Here, taking the common build system as an example, several **recommended** ways of writing common file installation processes are given. These writing methods all respect the `prefix` configuration and `$DESTDIR`: - -#### Makefile - -This section is mainly written with reference to the relevant content in and . - -Here, the default values ​​of some variables and other common parts are defined for the purpose of writing examples later. The relevant descriptions of the default values ​​of these variables can be found in the above link. - -```makefile -DESTDIR ?= - -prefix ?= /usr/local -bindir ?= $(prefix)/bin -libdir ?= $(prefix)/lib -libexecdir ?= $(prefix)/libexec -datarootdir ?= $(prefix)/share - -INSTALL ?= install -INSTALL_PROGRAM ?= $(INSTALL) -INSTALL_DATA ?= $(INSTALL) -m 644 - -# The variables with default values ​​defined above are the recommended behaviors in the above specifications, and no modification is recommended. - -PKG_CONFIG ?= pkg-config - -.PHONY: install -``` - -- Executable files - -```makefile -install: -$(INSTALL) -d "$(DESTDIR)$(bindir)" -$(INSTALL_PROGRAM) path/to/your/executable "$(DESTDIR)$(bindir)"/executable -``` - -- Internal executable files - -Refers to executable files that should not be called directly by users in the terminal. These executable files **should** not be found through `$PATH` - -```makefile -install: -$(INSTALL) -d "$(DESTDIR)$(libexecdir)" -$(INSTALL_PROGRAM) path/to/my/internal/executable "$(DESTDIR)$(libexecdir)"/executable -``` - -- Static libraries - -```makefile -install: -$(INSTALL) -d "$(DESTDIR)$(libdir)" $(INSTALL_DATA) path/to/my/library.a "$(DESTDIR)$(libdir)"/library.a ``` - pkg-config configuration file ```makefile pc_dir ?= $(libdir)/pkgconfig ifeq ($(findstring $(pc_dir), $(subst :, , $(shell \ $(PKG_CONFIG) --variable=pc_path)), ) $(warning pc_dir="$(pc_dir)" \ is not in the search path of current pkg-config installation) endif .PHONY: install-pkg-config install-pkg-config: $(INSTALL) -d "$(DESTDIR)$(pc_dir)" $(INSTALL_DATA) path/to/your.pc "$(DESTDIR)$(pc_dir)"/your.pc -``` - -If you are sure that the file is available across architectures, you can use `$(datarootdir)` instead of `$(libdir)`. - -- systemd system level unit ```makefile systemd_system_unit_dir ?= $(shell \ $(PKG_CONFIG) --define-variable=prefix=$(prefix) \ systemd --variable=systemd_system_unit_dir) ifeq ($(findstring $(systemd_system_unit_dir), $(subst :, , $(shell \ $(PKG_CONFIG) systemd --variable=systemd_system_unit_path))), ) $(warning systemd_system_unit_dir="$(systemd_system_unit_dir)" \ is not in the system unit search path of current systemd installation) endif .PHONY: install-systemd-system-unit install-systemd-system-unit: $(INSTALL) -d "$(DESTDIR)$(systemd_system_unit_dir)" $(INSTALL_DATA) path/to/your.service "$(DESTDIR)$(systemd_system_unit_dir)"/your.service ``` - systemd user-level unit ```makefile systemd_user_unit_dir ?= $(shell \ $(PKG_CONFIG) --define-variable=prefix=$(prefix) \ systemd --variable=systemd_user_unit_dir) ifeq ($(findstring $(systemd_user_unit_dir), $(subst :, , $(shell \ $(PKG_CONFIG) systemd --variable=systemd_user_unit_path))), ) $(warning systemd_user_unit_dir="$(systemd_user_unit_dir)" \ is not in the user unit search path of current systemd installation) endif .PHONY: install-systemd-user-unit install-systemd-user-unit: $(INSTALL) -d "$(DESTDIR)$(systemd_user_unit_dir)" $(INSTALL_DATA) path/to/your.service "$(DESTDIR)$(systemd_user_unit_dir)"/your.service -``` - -- desktop file - -```makefile -install: -$(INSTALL) -d "$(DESTDIR)$(datarootdir)"/applications -$(INSTALL_PROGRAM) path/to/your.desktop "$(DESTDIR)$(datarootdir)"/applications/your.desktop -``` - -- desktop file corresponding icon - -See: - -- If the installed icon is a fixed size version, it is **recommended** to use png format - -At least **need** to install a 48x48 size png to ensure the normal basic functions of icons in the desktop environment - -- If the installed icon is a vector version, it is **recommended** to use svg format - -```makefile -install: $(INSTALL) -d "$(DESTDIR)$(datarootdir)"/icons/hicolor/48x48/apps $(INSTALL_DATA) path/to/your.png "$(DESTDIR)$(datarootdir)"/icons/hicolor/48x48/apps/your.png # Add more size of .png icons here... $(INSTALL) -d "$(DESTDIR)$(datarootdir)"/icons/hicolor/scalable/apps $(INSTALL_DATA) path/to/your.svg "$(DESTDIR)$(datarootdir)"/icons/hicolor/scalable/apps/your.svg ``` #### CMake - -This section is mainly written with reference to the relevant content in and . - -Here we define the default values ​​of some variables and other common parts for writing examples later. The relevant descriptions of these variable default values ​​can be found in the link above. - -The writing logic is consistent with the relevant content in the Makefile section. - -```cmake -include(GNUInstallDirs) -``` - -- Executable files - -See: - -```cmake -install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/path/to/your/executable TYPE BIN) -``` - -- Internal executable files - -Refers to executable files that should not be called directly in the terminal. These executable files **should** not be found through `$PATH` - -See: - -```cmake -install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/path/to/your/executable DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}) -``` - -Note: TYPE is not used because TYPE does not currently support LIBEXEC - -- Target file/export file - -To be added - -- pkg-config configuration file - -To be added - -- systemd system-level unit - -```cmake -find_package(PkgConfig) -if(NOT SYSTEMD_SYSTEM_UNIT_DIR) -if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.28") -pkg_get_variable(SYSTEMD_SYSTEM_UNIT_DIR systemd systemd_system_unit_dir -DEFINE_VARIABLES prefix=${CMAKE_INSTALL_PREFIX}) -else() -pkg_get_variable(SYSTEMD_PREFIX systemd prefix) -pkg_get_variable(SYSTEMD_SYSTEM_UNIT_DIR systemd systemd_system_unit_dir) -string(REPLACE "${SYSTEMD_PREFIX}" "${CMAKE_INSTALL_PREFIX}" SYSTEMD_SYSTEM_UNIT_DIR "${SYSTEMD_SYSTEM_UNIT_DIR}") endif() endif() pkg_get_variable(SYSTEMD_SYSTEM_UNIT_PATH systemd systemd_system_unit_path) if(NOT SYSTEMD_SYSTEM_UNIT_PATH MATCHES ".*:${SYSTEMD_SYSTEM_UNIT_DIR}:.*") message(WARNING SYSTEMD_SYSTEM_UNIT_DIR="${SYSTEMD_SYSTEM_UNIT_DIR}" is not in the system unit search path of current systemd installation) endif() install(FILES path/to/your.service DESTINATION ${SYSTEMD_SYSTEM_UNIT_DIR}) ``` - systemd user-level unit ```cmake find_package(PkgConfig) if(NOT SYSTEMD_USER_UNIT_DIR) if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.28") pkg_get_variable(SYSTEMD_USER_UNIT_DIR systemd systemd_user_unit_dir DEFINE_VARIABLES prefix=${CMAKE_INSTALL_PREFIX}) else() pkg_get_variable(SYSTEMD_PREFIX systemd prefix) pkg_get_variable(SYSTEMD_USER_UNIT_DIR systemd systemd_user_unit_dir) string(REPLACE "${SYSTEMD_PREFIX}" "${CMAKE_INSTALL_PREFIX}" SYSTEMD_USER_UNIT_DIR "${SYSTEMD_USER_UNIT_DIR}") endif() endif() pkg_get_variable(SYSTEMD_USER_UNIT_PATH systemd systemd_user_unit_path) if(NOT SYSTEMD_USER_UNIT_PATH MATCHES ".*:${SYSTEMD_USER_UNIT_DIR}:.*") message(WARNING SYSTEMD_USER_UNIT_DIR="${SYSTEMD_USER_UNIT_DIR}" is not in the user unit search path of current systemd installation) endif() install(FILES path/to/your.service DESTINATION ${SYSTEMD_USER_UNIT_DIR}) ``` - desktop file ```cmake install(FILES path/to/your.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) ``` - icon corresponding to desktop file ```cmake install(FILES path/to/your.png -DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/48x48/apps) -# Add more size of .png icons here... - -install(FILES path/to/your.svg -DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps) -``` - -### Configuration file - -#### desktop file - -It is **not** recommended** to have `-` in the desktop file name. After removing the .desktop suffix, it should comply with the relevant specifications described in the application name section. - -- **Recommended** Fill in the [`TryExec` field][key-tryexec] to ensure that the desktop file is no longer valid after the application has been uninstalled -- **Recommended** Fill in the [`WMClass` field][key-startupwmclass] to ensure that basic desktop environment functions such as the taskbar based on window and application matching can work properly -- **Recommended** Use only the executable file name instead of the absolute path when filling in the [`Exec` field][key-exec] -- **Not recommended** Use the absolute path when filling in the [`Icon` field][key-icon] - -[key-tryexec]: https://specifications.freedesktop.org/desktop-entry-spec/latest/recognized-keys.html#key-tryexec - -[key-startupwmclass]: https://specifications.freedesktop.org/desktop-entry-spec/latest/recognized-keys.html#key-startupwmclass - -[key-exec]: https://specifications.freedesktop.org/desktop-entry-spec/latest/recognized-keys.html#key-exec [key-icon]: https://specifications.freedesktop.org/desktop-entry-spec/ - -latest/recognized-keys.html#key-icon - -#### DBus service - -- **Recommend** that the file name of the service file is consistent with the Name field in the file -- **Recommend** that the absolute path is used in the Exec field in the service file -- **Recommend** that the SystemdService field is filled in -- **Recommend** that the service name in the SystemdService field is consistent with the Name field -- **Recommend** that the Name field ends with a number - -#### Systemd service - -- **Recommend** that the file name of the service file with BusName is consistent with BusName -- **Recommend** that the absolute path is used in the ExecStart field - -When using absolute paths in the above configuration files, **hard-coded paths are **not recommended**. The path **should** be consistent with the final installation path. **Recommend** that the template file be written in the project first, and the placeholder is used to represent the absolute path. The final configuration file is generated by replacing the placeholder through the build system. - -Here, taking the desktop file as an example, several examples of generating the final configuration file under common build systems are given. -Assume that the final product `org.deepin.demo.desktop` has the following content: -```ini -[Desktop Entry] -Name=demo -Exec=/usr/bin/demo -Type=Application -Terminal=false -``` - -- Use Makefile as the build system. - -1. First write the template file `org.deepin.demo.desktop.in`, the content is as follows: - -```ini -[Desktop Entry] -Name=demo -Exec=@BINDIR@/demo -Type=Application -Terminal=false -``` -2. Write the corresponding makefile rules. -```makefile -DESKTOP_TEMPLATE = org.deepin.demo.desktop.in -DESKTOP_FILE = org.deepin.demo.desktop - -# Replace placeholders and generate final .desktop file -desktop: $(DESKTOP_TEMPLATE) -sed -e "s/@BINDIR@/$(bindir)/g" \ -$(DESKTOP_TEMPLATE) > $(DESKTOP_FILE) - -install: -$(INSTALL) -d "$(DESTDIR)$(datarootdir)"/applications -$(INSTALL_PROGRAM) $(DESKTOP_FILE) "$(DESTDIR)$(datarootdir)"/applications/$(DESKTOP_FILE) - -clean: -rm -f $(DESKTOP_FILE) - -all: desktop -``` - -- If using CMake as build system. -1. Write the desktop template file. -```desktop -[Desktop Entry] -Name=demo -Exec=@CMAKE_INSTALL_BINDIR@/demo -Type=Application -Terminal=false -``` -2. Write the corresponding cmake rules. -```cmake -set(DESKTOP_FILE "org.deepin.demo.desktop") -# Use configure_file to replace placeholders -configure_file( -${CMAKE_CURRENT_SOURCE_DIR}/org.deepin.demo.desktop.in -${CMAKE_CURRENT_BINARY_DIR}/${DESKTOP_FILE} -@ONLY -) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${DESKTOP_FILE} -DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) -``` -### Header files and link libraries - -Linglong's environment consists of up to three parts. Taking the compilation of `org.deepin.demo` under the `x86_64` architecture as an example, the default search path for header files and library files includes the following parts: - -| **Composition** | **Package name** | **Header file** | **Library files** | -| ----------------------------------------------- | ------------------------------------------------ | ------------------------------------------------ | ------------------------------------------------ | -| base | org.deepin.base | /usr/include | /usr/lib
/usr/lib/x86_64-linux-gnu | -| runtime (optional) | org.deepin.runtime.dtk | /runtime/include | /runtime/lib
/runtime/lib/x86_64-linux-gnu | -| app | org.deepin.demo | /opt/apps/org.deepin.demo/files/include | /opt/apps/org.deepin.demo/files/lib
/opt/apps/org.deepin.demo/files/lib/x86_64-linux-gnu | - -Priority is in order from top to bottom. If a header file exists in both `org.deepin.base` and `org.deepin.demo`, the file in `org.deepin.base` will be matched first when used. The same applies to library files. - -The default search path is applicable to standard libraries or development libraries without configuration files. In actual build scenarios, development libraries usually provide configuration files to facilitate user compilation and linking. Developers should use this file in their own build system instead of relying on the default search path. - -Common configuration files include `.pc`, `.cmake`, etc. How to use it depends on the development library and the build system. Here are some examples of using configuration files in common build systems. - -#### Makefile - -##### Use `.pc` file -```makefile -# Common variables, inherit the environment variable CXXFLAGS and append content -CXX = g++ -CXXFLAGS = $(CXXFLAGS) -Wall -Wextra -std=c++11 -# Get the content of the .pc file through the pkg-config tool -# The return value is generally -I/path -lname type content -PKG_CONFIG = pkg-config -LIBS = $(shell $(PKG_CONFIG) --cflags --libs libname) - -TARGET = demo - -SRCS = main.cpp - -all: $(TARGET) - -# Provide the information provided by .pc to the compiler during construction -$(TARGET): $(SRCS) -$(CXX) $(CXXFLAGS) $(LIBS) -o $@ $^ - -clean: -rm -f $(TARGET) -``` - -#### CMake - -##### Using `.pc` files - -```cmake -find_package(PkgConfig REQUIRED) -pkg_check_modules(PackageAliasName REQUIRED IMPORTED_TARGET PackageName) - -# Add executable files -add_executable(demo main.cpp) - -# Set the link library. The header file search path will be automatically expanded. -target_link_libraries(demo PRIVATE PkgConfig::PackageAliasName) -``` - -##### Using `.cmake` files - -```cmake -find_package( REQUIRED COMPONENTS ) - -# Add executable files -add_executable(demo main.cpp) - -# Set the link library. The header file search path will be automatically expanded. -target_link_libraries(demo PRIVATE PackageName::Component) -``` - -Note: - -It is not recommended to hardcode the above default search paths directly in the project build configuration file. - -It is not recommended to overwrite environment variables such as CFLAGS/CXXFLAGS. Additional parameters should be appended to these variables. - -### Dependency introduction - -As mentioned in the section `Header files and link libraries`, the Linglong environment consists of multiple parts. If the content in the base or even the runtime cannot meet the requirements, the developer should introduce the missing dependencies on the APP side. The introduction method is to declare it under the `sources` field in the `linglong.yaml` file and write the corresponding installation or compilation rules under the `build` field. - -`sources` supports multiple file types, **allowing** to introduce source code or compiled binary files, even a deb. However, for the introduction of compiled binary files, developers must consider whether they are compatible with the current base or runtime. - -#### Use source code to introduce - -Introducing dependencies through source code is a **recommended** practice, which can greatly ensure the stability and maintainability of the build process. The disadvantage is that this may take developers a lot of time to write yaml files, because the dependencies may also have their own dependencies. - -*If developers find that the dependencies are complex and repeatedly used by other applications, they should consider integrating the dependencies into a runtime type package. * - -When the dependency is compiled in the Linglong environment, its configuration file is usually "reliable". After compilation and installation, developers can use it directly in the project. - -```yaml -sources: -- kind: git -url: # app source url -commit: # commit hash -- kind: git -url: # dependency source url -commit: # commit hash -build: -# Compile dependency -cd /project/your_dependency_name/ -cmake -Bbuild -DCMAKE_INSTALL_PREFIX=$PREFIX -make install - -# Compile and install APP -cd /project/your_app_name -cmake -Bbuild -DCMAKE_INSTALL_PREFIX=$PREFIX -make install -``` - -#### Import using deb - -This is a "shortcut". If the developer does not consider the subsequent updates of the application, this method can be used. The developer can use auxiliary tools to analyze the dependencies and import the dependencies involved in batches in sources. - -##### Use vscode linglong extension - -1. Install the aptly command line tool -2. Search for linglong in the vscode extension store and install related plug-ins. -3. Put the sources field at the end of linglong.yaml -4. Add the gen_deb_source comment at the end of sources -5. Press Ctrl+Shift+P to search and execute the linglong: Gen deb sources command - -After execution, the yaml file will automatically write the following content: -```yaml -build: -# Unzip and import deb, install_dep file is automatically downloaded by the plugin -bash ./install_dep linglong/sources "$PREFIX" - -# Compile and install APP -sources: -# Source code -- kind: git -url: # app source url -commit: # commit hash -# The following comments are generated and used by the plugin, retrieve libical-dev from the warehouse, analyze its dependencies, and automatically generate sources below the comments -# linglong:gen_deb_source sources amd64 https://ci.deepin.com/repo/deepin/deepin-community/backup/rc2 beige main -# linglong:gen_deb_source install libical-dev -``` - -Note: -The installation prefix of the deb compilation product is `/usr`, and the `install_dep` script will automatically process the `.pc` file and replace `/usr` with `$PREFIX`. `xxx.cmake` type files cannot be processed in batches, and may not work properly if there is hard-coded path behavior. - -## Linglong - -This section mainly describes some special requirements of the Linglong package management system for applications. - -### Restrictions - -- Applications that need to be packaged through the Linglong package management system must be run as the user who starts the Linglong container (usually a normal user). Any form of privilege escalation mechanism is not available when the Linglong package management system runs applications, including but not limited to the SUID bit recorded in the file system and privilege escalation mechanisms based on file system extension attributes such as capabilities. -- Linglong currently does not support packaging applications containing system-level systemd units. -- It is **not recommended** to package desktop environment components such as launchers, file managers, resource managers, status bars, etc. - -### Specifications - -#### Application package name - -The package name of Linglong application **must** fully comply with the relevant provisions in the "Application Name" section above, except: - -- Application names are case-insensitive - -#### Application version number - -The application version number of Linglong package **must** be four groups of decimal numbers separated by `.`, for example, `1.0.0.0`. - -If the specified version number is less than four groups, 0 will be added to the back until the conditions are met, for example, `1.90` will be automatically added to `1.90.0.0`. - -The total length of the version number after automatically adding to four groups in the string sense **must** not exceed 256 bytes. - -#### Running environment - -Linglong application **must** select a base as the basic running environment. Available base: - -| **Base library** | **Package name/version** | -| ----------------------------------------------- | ------------------------------------------------ | -| glibc(2.38) | org.deepin.base/23.1.0.0 | - -If you need to use additional frameworks other than the base environment, you should use the appropriate runtime. Available runtime: - -| **Framework** | **Package name/version** | -| ----------------------------------------------- | ------------------------------------------------ | -| QT(5.15) + DTK(5.6) | org.deepin.runtime.dtk/23.1.0.0 | - -When using base or runtime, it is recommended to fill in the first three digits of the version number, such as '23.1.0', to facilitate subsequent updates. Filling in the full 4-digit version means that base or runtime updates are prohibited. - -#### Installation location - -During the build and installation process, Linglong's build tool will set the `$PREFIX` environment variable. The value of this environment variable **should** be `/opt/apps/${APPID}/files`, but it is not recommended to use its common value directly during the build and installation process. **Recommend** to always read the `$PREFIX` environment variable. - -For the application build and installation process, the only writable directories are - -1. The `/source` directory where the source code required for the build is placed - -2. The installation location, that is, the location specified by `$PREFIX` - -Installing files to other locations during the build process is **prohibited**, which usually causes write failures or the application cannot find these files at runtime. - -The following is an example of using the `$PREFIX` environment variable to control the application installation location when calling some common build systems: - -##### cmake - -```bash -cd path/to/build && cmake path/to/source -DCMAKE_INSTALL_PREFIX="$PREFIX" -``` - -##### make - -```bash -cd path/to/source && make prefix="$PREFIX" -``` - -##### meson - -```bash -cd path/to/source && meson configure --prefix="$PREFIX" path/to/build -``` - -## Build products - -This section mainly describes the product composition and related functions after the application is successfully built. - -### Directory structure - -After the application is successfully built, Linglong's build tool will submit the product to the local cache. When distributing offline, it should be exported as a `.layer` -or `.uab` type file. - -Build the product layer file by decompressing: - -```bash -ll-builder extract org.deepin.demo_0.0.0.1_x86_64_binary.layer ./tmp -``` - -You can get the following directory structure: - -```plain -./tmp -├── entries -│ └── share -> ../files/share -├── files -│ ├── bin -│ │ └── demo -│ ├── share -│ │ ├── applications -│ │ │ └── org.deepin.demo.desktop -│ │ ├── icons -│ │ │ └── hicolor -│ │ │ └── scalable -│ │ │ └── apps -│ │ │ └── org.deepin.demo.svg │ │ ├── doc │ │ │ ├── changelog.gz │ │ │ └── copyright │ │ ├── mime │ │ │ └── packages │ │ │ └── org.deepin.demo.xml │ │ ├── locale │ │ │ └── zh_CN │ │ │ └── info.json │ │ └── services │ │ └── org.deepin.demo.xml │ └── libs │ └── libdemo.so.5.2.1 ├── info.json └── org.deepin.demo.install -``` - -When the application is running, these files or directories will be mapped to the following paths in the container: - -```plain -/ -├── bin -├── ... -├── opt -│ └── apps -│ └── org.deepin.demo -│ ├── files -│ ├── entries -│ ├── info.json -│ └── org.deepin.demo.install -└── var -``` - -#### info.json文件 - -info.json is the application description file defined by Linglong. This file is automatically generated by the build tool and it **should** not be modified manually. Its content is as follows: ```json { "id": "org.deepin.demo", "arch": [ "x86_64" ], "base": "main:org.deepin.foundation/23.0.0/x86_64", "channel": "main", "command": [ "/opt/apps/org.deepin.demo/files/bin/demo" ], "description": "simple Qt demo.\n", "kind": "app", "module": "runtime", "name": "demo", "runtime": "main:org.deepin.Runtime/23.0.1/x86_64", "size": 118763, "version": "0.0.0.1" -} -``` - -The following is a description of each field in info.json: - -`id`: package identifier, i.e., application package name. - -`arch`: package support architecture, currently supports the following CPU architectures. - -- `amd64`: Applicable to `x86_64` architecture `CPU`. - -- `loongarch64`: Applicable to the new version of Loongson series `CPU`. - -- `arm64`: Applicable to `ARM64` bit `CPU`. - -`base`: The basic environment used by the package when running. - -`channel`: Package distribution channel. - -`command`: The default startup command of the package. - -`description`: Description of the package. - -`kind`: Package category. - -`module`: Package module. - -`name`: Common name of the package. - -`runtime`: The environment used when the package runs. - -`size`: Package size. - -`version`: Application version, its format should meet the requirements described in the Application Version Number section. - -#### entries directory - -This directory is used to share application configuration files with the host (desktop environment). This directory usually has the following subdirectories: - -- entries/share/applications -- entries/share/dbus-1/services -- entries/share/systemd/user -- entries/share/icons -- entries/share/mime -- entries/share/fonts - -The entries directory is automatically generated by the build tool. There is only one soft link named share in the directory. The link file points to the files/share in the upper directory. - -When the application is installed on the host, Linglong Package Manager will link all the files in it to the path added by Linglong to the `$XDG_DATA_DIRS` variable through the link file. That is, `/var/lib/linglong/entries/share/`. - -```bash $ ls /var/lib/linglong/entries/share/applications/ -l lrwxrwxrwx 1 deepin-linglong deepin-linglong 101 July 30 11:13 org.deepin.demo.desktop -> ../../../layers/main/org.deepin.demo/0.0.0.1/x86_64/runtime/entries/share/applications/org.deep -in.demo.desktop -``` - -##### applications directory - -Place the application startup configuration file, that is, the .desktop file. - -```ini -[Desktop Entry] -Exec=demo -Name=demo -TryExec=demo -Type=Application -``` - -When building, this file will be automatically modified to: - -```ini -[Desktop Entry] -Exec=/usr/bin/ll-cli run org.deepin.demo -- demo -Name=demo -TryExec=/usr/bin/ll-cli -Type=Application -``` -An application can have multiple desktop files. - -**Path correspondence:** - -| **Packaging path** | **Installation path** | -| -------------------------------------------------- | --------------------------------------------------------- | -| $PREFIX/share/applications/org.deepin.demo.desktop | $XDG_DATA_DIRS/share/applications/org.deepin.demo.desktop | - -##### dbus services directory - -The dbus service directory registered by the program, for example: - -```ini -[D-BUS Service] -Name=org.deepin.demo -Exec=/opt/apps/org.deepin.demo/files/bin/demo --dbus -``` - -When building, this file will be automatically modified to: - -```ini -[D-BUS Service] -Name=org.deepin.demo -Exec=/usr/bin/ll-cli run org.deepin.demo -- /opt/apps/org.deepin.demo/files/bin/demo --dbus -``` - -An application can be configured with multiple services, and the service name must be a subdomain. - -**Path correspondence:** - -| **Packaging path** | **Installation path** | -| ---------------------------------------------------- | ----------------------------------------------------------- | -| $PREFIX/share/services/org.deepin.demo.service | $XDG_DATA_DIRS/dbus-1/service/org.deepin.demo.service | -| $PREFIX/share/services/org.deepin.demo.hello.service | $XDG_DATA_DIRS/dbus-1/service/org.deepin.demo.hello.service | - -##### User-level systemd service - -User-level service directory registered by the program, for example: - -```ini -[Unit] -Description = demo service -After=user-session.target - -[Service] -Type = simple -ExecStart = demo - -[Install] -WantedBy=user-session.target - -``` - -This file will be automatically modified to when it is built : - -```ini -[Unit] -Description = demo service -After=user-session.target - -[Service] -Type = simple -ExecStart = ll-cli run org.deepin.demo -- demo - -[Install] -WantedBy=user-session.target -``` - -Unlike dbus service, files installed to ```$PREFIX/lib/systemd/user``` will be automatically copied to ```$PREFIX/share/systemd/user```. - -**Path correspondence:** - -| **Packaging path** | **Installation path** | -| ------------------------------------------------------------- | -------------------------------------------------------------- | -| $PREFIX/lib/systemd/user/org.deepin.demo.service | $XDG_DATA_DIRS/systemd/user/org.deepin.demo.service | - -##### icons directory - -The directory for storing application icons should be consistent with the system icons directory structure. - -**Path correspondence:** - -| **Packaging path** | **Installation path** | -| ------------------------------------------------------------- | -------------------------------------------------------------- | -| $PREFIX/share/icons/hicolor/scalable/apps/org.deepin.demo.svg | $XDG_DATA_DIRS/icons/hicolor/scalable/apps/org.deepin.demo.svg | -| $PREFIX/share/icons/hicolor/24x24/apps/org.deepin.demo.png | $XDG_DATA_DIRS/icons/hicolor/24x24/apps/org.deepin.demo.png | -| $PREFIX/share/icons/hicolor/16x16/apps/org.deepin.demo.png | $XDG_DATA_DIRS/icons/hicolor/16x16/apps/org.deepin.demo.png | - -##### mime directory - -MIME (Multipurpose Internet Mail Extensions) Multipurpose Internet Mail Extensions type. This directory is used to store mime configuration files. The files are in XML format and end with .xml. - -**Path correspondence:** - -| **Packaging path** | **Installation path** | -| ----------------------------------------------- | ------------------------------------------------ | -| $PREFIX/share/mime/packages/org.deepin.demo.xml | $XDG_DATA_DIRS/mime/packages/org.deepin.demo.xml | - -##### fonts directory - -Font storage path. - -#### files directory - -Store various files required by the application. There is no restriction on placing files in this directory, but it is recommended to place executable programs in the bin subdirectory. It is recommended that third-party libraries that applications or plug-ins depend on be placed in the /opt/apps/${id}/files/lib directory. - -#### .install file - -The org.deepin.demo.install file in the above example org.deepin.demo is a file automatically generated during the build process. This file is used to define which files should be installed in the binary module and can be used to trim the size of the final product of the software package. - -When the file is not defined in the same directory as linglong.yaml, all content is installed to the binary module according to the rules under build in linglong.yaml. - -Usage: - -After the first successful build, the .install file will be generated in the product and record all files installed to the binary module. Copy the file to the same directory as linglong.yaml, modify the content in the .install file and build again. Only the content noted in .install will be submitted to the binary module. - -## References - -[Desktop Application Packaging Specifications](https://github.com/linuxdeepin/deepin-specifications/blob/master/unstable/%E6%A1%8C%E9%9D%A2%E5%BA%94%E7%94%A8%E6%89%93%E5%8C%85%E8%A7%84%E8%8C%83.md) diff --git a/docs/pages/en/guide/ll-builder/manifests.md b/docs/pages/en/guide/ll-builder/manifests.md deleted file mode 100644 index f98670905..000000000 --- a/docs/pages/en/guide/ll-builder/manifests.md +++ /dev/null @@ -1,363 +0,0 @@ - - -# Introduction to Build Configuration Files - -`linglong.yaml` is the description file for a linyaps project, recording relevant information required for building, such as the name, version, source address, and build dependencies of the build artifact. - -## Project Directory Structure - -```bash -{project-root} -├── linglong.yaml -└── linglong - -{user-home} -└── .cache -    └── linglong-builder -      ├── repo -     └── layers -``` - -## Field Definitions - -The `linglong.yaml` file structure follows specific specifications. First, you need to declare the configuration file version at the top level: - -```yaml -version: '1' -``` - -| Name | Description | Required | -| ------- | ------------------------------------------ | -------- | -| version | The version of the build configuration file, currently '1' | Yes | - -Next are the main configuration blocks. Among them, `package`, `base`, and `build` must be defined. - -### Package Metadata Configuration (`package`) - -Defines the basic information of the build artifact. This `package` configuration block is required. - -```yaml -package: - id: org.deepin.calculator - name: deepin-calculator - version: 5.7.21.0 # Four-digit version number recommended - kind: app # or runtime - description: | - calculator for deepin os. - architecture: amd64 # Optional - channel: stable # Optional -``` - -| Name | Description | Required | -| -------------- | --------------------------------------------------------------- | -------- | -| id | Unique name of the build artifact (e.g., `org.deepin.calculator`) | Yes | -| name | Name of the build artifact (e.g., `deepin-calculator`) | Yes | -| version | Version of the build artifact, four digits recommended (e.g., `5.7.21.0`) | Yes | -| kind | Type of the build artifact: `app` (Application), `runtime` (Runtime) | Yes | -| description | Detailed description of the build artifact | Yes | -| architecture | Target architecture of the build artifact (e.g., `amd64`, `arm64`) | No | -| channel | Channel of the build artifact (e.g., `stable`, `beta`) | No | - -### Command (`command`) - -Defines how to start the application. This is a list of strings, where the first element is usually the absolute path to the executable (relative to the container's interior), and subsequent elements are arguments passed to the executable. - -```yaml -command: - - /opt/apps/org.deepin.calculator/files/bin/deepin-calculator - # - --some-argument # More arguments can be added -``` - -| Name | Description | Required | -| ------- | --------------------------------------------------------------------------- | -------- | -| command | Defines the executable path and its argument list for starting the application. Usually required for `kind: app`. | No | - -### Base Environment (`base`) - -Specifies the minimum root filesystem required for building and running. This field is required. - -```yaml -base: org.deepin.base/23.1.0 -``` - -| Name | Description | Required | -| ------- | ------------------------------------------------ | -------- | -| base | Identifier for the base, format `id/version`. Version number supports three-digit fuzzy matching. | Yes | - -### Runtime (`runtime`) - -Application runtime dependencies, which are also build dependencies. - -```yaml -runtime: org.deepin.runtime.dtk/23.1.0 -``` - -| Name | Description | -| ------- | ------------------------------------------------------ | -| id | Unique name of the runtime | -| version | Runtime version, three digits can fuzzy match the fourth | - -### Sources (`sources`) - -Describes the source information required for the project. `sources` is a list and can contain multiple source items. Fetched sources are stored by default in the `linglong/sources` directory at the same level as `linglong.yaml`. - -#### Git Type - -```yaml -sources: - - kind: git - url: https://github.com/linuxdeepin/deepin-calculator.git - version: master # or tag - commit: d7e207b4a71bbd97f7d818de5044228c1a6e2c92 # Optional, for specifying the exact commit - name: deepin-calculator.git # Optional, specifies the directory name after download -``` - -| Name | Description | Required (within a single source) | -| ------- | --------------------------------------------------------------------------- | --------------------------------- | -| kind | `git`, indicates download using the git tool. | Yes | -| url | Source repository address | Yes | -| version | Branch or tag of the source repository | No (defaults to the main branch) | -| commit | Hash value of a specific commit, used for precise checkout | No | -| name | Optional, specifies the subdirectory name under `linglong/sources` after download. | No | - -#### File Type - -```yaml -sources: - - kind: file - url: https://example.com/some-file.dat - digest: sha256:... # Recommended to provide sha256 hash - name: my-data.dat # Optional, specifies the filename after download -``` - -| Name | Description | Required (within a single source) | -| ------ | --------------------------------------------------------------------------- | --------------------------------- | -| kind | `file`, indicates direct file download. | Yes | -| url | File download address | Yes | -| digest | Optional, sha256 hash of the file, used for verification. | No | -| name | Optional, specifies the filename under `linglong/sources` after download. | No | - -#### Archive Type - -```yaml -sources: - - kind: archive - url: https://github.com/linuxdeepin/deepin-calculator/archive/refs/tags/6.5.4.tar.gz - digest: 9675e27395891da9d9ee0a6094841410e344027fd81265ab75f83704174bb3a8 # Recommended to provide sha256 hash - name: deepin-calculator-6.5.4 # Optional, specifies the directory name after extraction -``` - -| Name | Description | Required (within a single source) | -| ------ | --------------------------------------------------------------------------- | --------------------------------- | -| kind | `archive`, downloads and automatically extracts the archive. Supports common compression formats. | Yes | -| url | Archive download address | Yes | -| digest | Optional, sha256 hash of the archive file, used for verification. | No | -| name | Optional, specifies the directory name under `linglong/sources` after extraction. | No | - -#### DSC Type - -```yaml -sources: - - kind: dsc - url: https://cdn-community-packages.deepin.com/deepin/beige/pool/main/d/deepin-calculator/deepin-calculator_6.0.1.dsc - digest: ce47ed04a427a887a52e3cc098534bba53188ee0f38f59713f4f176374ea2141 # Recommended to provide sha256 hash - name: deepin-calculator-dsc # Optional, specifies the directory name after download and extraction -``` - -| Name | Description | Required (within a single source) | -| ------ | --------------------------------------------------------------------------- | --------------------------------- | -| kind | `dsc`, handles Debian source package description files and associated files. | Yes | -| url | `.dsc` file download address | Yes | -| digest | Optional, sha256 hash of the `.dsc` file, used for verification. | No | -| name | Optional, specifies the directory name under `linglong/sources` after download and extraction. | No | - -### Export Rules (`exclude`/`include`) - -When exporting the built application to a UAB package, files to be trimmed are specified as shown in the example below: - -```yaml -exclude: - - /usr/share/locale # Trim the entire folder - - /usr/lib/libavfs.a # Trim a single file - -include: - - /usr/share/locale/zh_CN.UTF-8 # Used with exclude to export only specific files under a folder -``` - -| Name | Description | -| ------- | ------------------------------------------------------------------------ | -| exclude | Absolute path within the container, can be a file or folder, used for exclusion. | -| include | Absolute path within the container, files that must be included in the UAB package (even if the parent directory is excluded). | - -### Build Rules (`build`) - -Describes how to compile and install the project in the build environment. This field is required, and its content is a multi-line string treated as a shell script. - -Describes the build rules. - -```yaml -build: | - qmake -makefile PREFIX=${PREFIX} LIB_INSTALL_DIR=${PREFIX}/lib/${TRIPLET} - make - make install -``` - -| Name | Description | Required | -| ----- | --------------------------------------------------------------------------- | -------- | -| build | Shell script executed during the build phase. Runs inside the container build environment. | Yes | - -### Build Extensions (`buildext`) - -Optional field for defining extension behaviors for specific build stages. Currently mainly supports the `apt` extension for managing Debian package dependencies required for build and runtime. - -```yaml -buildext: - apt: - build_depends: # Build-time dependencies, installed only in the build environment - - build-essential - - cmake - - qt6-base-dev - depends: # Runtime dependencies, included in the final application or runtime - - libqt6widgets6 - - libglib2.0-0 -``` - -| Name | Description | Required | -| ----------- | ------------------------------------------------------------------------- | -------- | -| buildext | Container block for build extension configurations. | No | -| apt | Extension configuration using the apt package manager. | No | -| build_depends | A list of strings listing packages needed at build time, not included in the final artifact. | No | -| depends | A list of strings listing packages needed at runtime, included in the final artifact. | No | - -### Modules (`modules`) - -Optional field for splitting files installed under the `${PREFIX}` directory into different modules. Useful for on-demand downloads or providing optional features. - -```yaml -modules: - - name: main # Main module name, usually same as or related to package.id - files: # List of files or directories included in this module (relative to ${PREFIX}) - - bin/ - - share/applications/ - - share/icons/ - - lib/ # Includes all libraries - - name: translations # Translation module - files: - - share/locale/ - - name: extra-data # Optional data module - files: - - share/my-app/optional-data/ -``` - -| Name | Description | Required | -| ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -| modules | List defining the rules for splitting the application into modules. | No | -| name | Name of the module. Each module requires a unique name. | Yes (within each module item) | -| files | A list of strings listing files or directories belonging to this module. Paths are relative to `${PREFIX}`. | Yes (within each module item) | - -**Note:** All files installed under `${PREFIX}` will be assigned to a module. When `modules` is not defined, the build system automatically generates default `binary` and `develop` modules. - -### Variables - -Describes variables that can be used during the build process. - -| Name | Description | -| ------- | ------------------------------------------------------------------------------------------------------------- | -| PREFIX | Environment variable used under the `build` field; provides the installation path during build, e.g., /opt/apps/org.deepin.calculator | -| TRIPLET | Environment variable used under the `build` field; provides a triplet containing architecture information, e.g., x86_64-linux-gnu | - -## Complete Example - -### Build Application - -#### Calculator - -```yaml -version: '1' - -package: - id: org.deepin.calculator - name: deepin-calculator - version: 5.7.21.0 - kind: app - description: | - calculator for deepin os. - -command: - - /opt/apps/org.deepin.calculator/files/bin/deepin-calculator - -base: org.deepin.base/23.1.0 -runtime: org.deepin.runtime.dtk/23.1.0 - -sources: - - kind: git - url: https://github.com/linuxdeepin/deepin-calculator.git - version: master - commit: d7e207b4a71bbd97f7d818de5044228c1a6e2c92 - - - kind: git - url: https://github.com/linuxdeepin/dde-qt-dbus-factory.git - version: master - commit: d952e1913172c5507af080f644a654f9ba5fed95 - -build: | - # build dde-qt-dbus-factory - cd /project/linglong/sources/dde-qt-dbus-factory.git - qmake -makefile \ - PREFIX=${PREFIX} \ - LIB_INSTALL_DIR=${PREFIX}/lib/${TRIPLET} \ - INSTALL_ROOT=${PREFIX} - - make - make install - - # build calculator - cd /project/linglong/sources/deepin-calculator.git - cmake -Bbuild \ - -DCMAKE_INSTALL_PREFIX=${PREFIX} \ - -DCMAKE_INSTALL_LIBDIR=${PREFIX}/lib/${TRIPLET} \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_SAFETYTEST_ARG="CMAKE_SAFETYTEST_ARG_OFF" \ - -DAPP_VERSION=5.7.21 \ - -DVERSION=5.7.21 - - cmake --build build - cmake --build build --target install - -buildext: - apt: - # Extra packages depended on during build - build_depends: [] - # Extra packages depended on during runtime - depends: [] -``` - -### Build Root Filesystem - -```bash -git clone git@github.com:linglongdev/org.deepin.foundation.git -cd org.deepin.foundation -bash build_base.sh beige amd64 -``` - -This project is used to build the root filesystem used by Linglong. `beige` refers to the distribution codename, and `amd64` refers to the architecture. - -| Distribution Version | Architecture | -| -------------------- | ------------------------- | -| eagle (UOS 20) | amd64, arm64, loongarch64 | -| beige (deepin 23) | amd64, arm64 | - -### Build Runtime - -```bash -git clone git@github.com:linglongdev/org.deepin.Runtime.git -b v23 -cd org.deepin.Runtime -./depend-deb-list.sh | ./tools/download_deb_depend.bash -ll-builder build --skip-fetch-source -``` - -Adds basic environments like Qt on top of the root filesystem. diff --git a/docs/pages/en/guide/ll-builder/push.md b/docs/pages/en/guide/ll-builder/push.md deleted file mode 100644 index 58ab9ec8a..000000000 --- a/docs/pages/en/guide/ll-builder/push.md +++ /dev/null @@ -1,37 +0,0 @@ - - -# Push UAB to Remote Repositories - -Use the `ll-builder push` command to push linyaps packages to linyaps remote repositories. - -View the help information for the `ll-builder push` command: - -```bash -ll-builder push --help -``` - -Here is the output: - -```text -Push linyaps app to remote repo -Usage: ll-builder push [OPTIONS] - -Options: - -h,--help Print this help message and exit - --help-all Expand all help - --file FILE:FILE [./linglong.yaml] - File path of the linglong.yaml - --repo-url URL Remote repo url - --repo-name NAME Remote repo name - --module TEXT Push single module -``` - -The `ll-builder push` command reads the content of the `bundle` format package according to the file path, and transfers the software data and `bundle` format package to the server. - -```bash -ll-builder push -``` diff --git a/docs/pages/en/guide/ll-builder/run.md b/docs/pages/en/guide/ll-builder/run.md deleted file mode 100644 index 3e645ab6a..000000000 --- a/docs/pages/en/guide/ll-builder/run.md +++ /dev/null @@ -1,54 +0,0 @@ - - -# Run compiled App - -Use `ll-builder run` to run the compiled executable program. - -View the help information for the `ll-builder run` command: - -```bash -ll-builder run --help -``` - -Here is the output: - -```text -Run builded linyaps app -Usage: ll-builder run [OPTIONS] [COMMAND...] - -Positionals: - COMMAND TEXT ... Enter the container to execute command instead of running application - -Options: - -h,--help Print this help message and exit - --help-all Expand all help - --file FILE:FILE [./linglong.yaml] - File path of the linglong.yaml - --offline Only use local files - --modules modules ... Run specified module. eg: --modules binary,develop - --debug Run in debug mode (enable develop module) -``` - -The `ll-builder run` command reads the operating system environment information related to the program according to the configuration file, constructs a container, and executes the program in the container without installation. - -```bash -ll-builder run -``` - -If `ll-builder run` runs successfully, the output is as follows: - -```bash -hello world -``` - -To facilitate debugging, use an additional `--exec /bin/bash` parameter to replace the default execution program after entering the container, such as: - -```bash -ll-builder run --exec /bin/bash -``` - -With this option, `ll-builder` will enter the `bash` terminal after creating the container, and can perform other operations inside the container. diff --git a/docs/pages/en/guide/ll-cli/content.md b/docs/pages/en/guide/ll-cli/content.md deleted file mode 100644 index c669b56d7..000000000 --- a/docs/pages/en/guide/ll-cli/content.md +++ /dev/null @@ -1,43 +0,0 @@ - - -# Display App exported files - -Use `ll-cli content` to display the exported files. - -View the help information for the `ll-cli content` command: - -```bash -ll-cli content --help -``` - -Here is the output: - -```text -Display the exported files of installed application -Usage: ll-cli content [OPTIONS] APP - -Positionals: - APP TEXT REQUIRED Specify the installed application ID - -Options: - -h,--help Print this help message and exit - --help-all Expand all help - -If you found any problems during use, -You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -Use `ll-cli content org.dde.calendar` to display the exported files of org.dde.calendar. - -Here is the output: - -```text -/var/lib/linglong/entries/share/applications -/var/lib/linglong/entries/share/applications/dde-calendar.desktop -/var/lib/linglong/entries/share/metainfo -/var/lib/linglong/entries/share/metainfo/org.deepin.calendar.metainfo.xml -``` diff --git a/docs/pages/en/guide/ll-cli/exec.md b/docs/pages/en/guide/ll-cli/exec.md deleted file mode 100644 index 2fda1a2e8..000000000 --- a/docs/pages/en/guide/ll-cli/exec.md +++ /dev/null @@ -1,73 +0,0 @@ - - -# Attach To Container - -Use `ll-cli exec` to enter the inside of the running linyaps container. - -View the help information for the `ll-cli exec` command: - -```bash -ll-cli exec --help -``` - -Here is the output: - -```text -Execute commands in the currently running sandbox -Usage: ll-cli [OPTIONS] [SUBCOMMAND] - -Positionals: - INSTANCE TEXT REQUIRED Specify the application running instance(you can get it by ps command) - COMMAND TEXT ... Run commands in a running sandbox - -Options: - -h,--help Print this help message and exit - --help-all Expand all help - --working-directory PATH:DIR - Specify working directory - -If you found any problems during use, -You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -Open a new terminal window and run these commands: - -Example of using `ll-cli exec` to get inside org.dde.calendar container: - -1. using `ll-cli ps` to get container id: - -```bash -App ContainerID Pid -main:org.dde.calendar/5.14.5.0/x86_64 c3b5ce363172 539537 -``` - -2. enter the org.dde.calendar container -```bash -ll-cli exec main:org.dde.calendar/5.14.5.0/x86_64 /bin/bash -``` - -Use `ls -l /` to view the root directory structure. The output is as follows: - -```text -lrwxrwxrwx 1 root root 8 July 27 20:58 bin -> /usr/bin -drwxr-xr-x 7 root root 420 July 27 20:58 dev -drwxr-xr-x 119 nobody nogroup 12288 July 27 20:37 etc -drwxr-xr-x 3 root root 60 July 27 20:58 home -lrwxrwxrwx 1 root root 8 July 27 20:58 lib -> /usr/lib -lrwxrwxrwx 1 root root 10 July 27 20:58 lib32 -> /usr/lib32 -lrwxrwxrwx 1 root root 10 July 27 20:58 lib64 -> /usr/lib64 -lrwxrwxrwx 1 root root 11 July 27 20:58 libx32 -> /usr/libx32 -drwxr-xr-x 2 root root 40 July 27 20:58 ll-host -drwxr-xr-x 3 root root 60 July 27 20:58 opt -dr-xr-xr-x 365 nobody nogroup 0 July 27 20:58 proc -drwxr-xr-x 6 root root 120 July 27 20:58 run -drwxr-xr-x 7 nobody nogroup 4096 January 1 1970 runtime -dr-xr-xr-x 13 nobody nogroup 0 July 21 16:43 sys -drwxr-xr-x 3 root root 4096 July 27 20:58 tmp -drwxr-xr-x 15 nobody nogroup 4096 June 30 16:22 usr -drwxr-xr-x 13 nobody nogroup 4096 June 30 16:23 var -``` diff --git a/docs/pages/en/guide/ll-cli/info.md b/docs/pages/en/guide/ll-cli/info.md deleted file mode 100644 index f764926bb..000000000 --- a/docs/pages/en/guide/ll-cli/info.md +++ /dev/null @@ -1,58 +0,0 @@ - - -# Display app information - -Use `ll-cli info` to display information about installed apps or runtimes. - -View the help information for the `ll-cli info` command: - -```bash -ll-cli info --help -``` - -Here is the output: - -```text -Display information about installed apps or runtimes -Usage: ll-cli info [OPTIONS] APP - -Positionals: - APP TEXT REQUIRED Specify the application ID, and it can also be a .layer file - -Options: - -h,--help Print this help message and exit - --help-all Expand all help - -If you found any problems during use, -You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -Use `ll-cli info org.dde.calendar` to display information about org.dde.calendar. - -Here is the output: - -```text -{ - "arch": [ - "x86_64" - ], - "base": "main:org.deepin.base/23.1.0/x86_64", - "channel": "main", - "command": [ - "dde-calendar" - ], - "description": "calendar for deepin os.\n", - "id": "org.dde.calendar", - "kind": "app", - "module": "binary", - "name": "dde-calendar", - "runtime": "main:org.deepin.runtime.dtk/23.1.0/x86_64", - "schema_version": "1.0", - "size": 13483249, - "version": "5.14.5.1" -} -``` diff --git a/docs/pages/en/guide/ll-cli/install.md b/docs/pages/en/guide/ll-cli/install.md deleted file mode 100644 index 927e25d49..000000000 --- a/docs/pages/en/guide/ll-cli/install.md +++ /dev/null @@ -1,99 +0,0 @@ - - -# Install linyaps Apps - -Use `ll-cli install` to install linyaps apps. - -View the help information for the `ll-cli install` command: - -```bash -ll-cli install --help -``` - -Here is the output: - -```text -Installing an application or runtime -Usage: ll-cli install [OPTIONS] APP - -Example: -# install application by appid -ll-cli install org.deepin.demo -# install application by linyaps layer -ll-cli install demo_0.0.0.1_x86_64_binary.layer -# install application by linyaps uab -ll-cli install demo_x86_64_0.0.0.1_main.uab -# install specified module of the appid -ll-cli install org.deepin.demo --module=binary -# install specified version of the appid -ll-cli install org.deepin.demo/0.0.0.1 -# install application by detailed reference -ll-cli install stable:org.deepin.demo/0.0.0.1/x86_64 - - -Positionals: - APP TEXT REQUIRED Specify the application ID, and it can also be a .uab or .layer file - -Options: - -h,--help Print this help message and exit - --help-all Expand all help - --module MODULE Install a specify module - --force Force install the application - -y Automatically answer yes to all questions - -If you found any problems during use, -You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -Example of the `ll-cli install` command to install a linyaps app: - -```bash -ll-cli install -``` - -Enter the complete `appid` after `ll-cli install`. If the repository has multiple versions, the highest version will be installed by default. - -To install a specified version, append the corresponding version number after `appid`: - -```bash -ll-cli install -``` - -Here is the output of `ll-cli install org.deepin.calculator`: - -```text -Install main:org.deepin.calculator/5.7.21.4/x86_64 success:100% -``` - -After the application is installed, the installation result will be displayed. - -The layer or uab files we export using the `ll-builder export` command can be installed using the `ll-cli install` command. - -`.layer` -```bash -ll-cli install ./com.baidu.baidunetdisk_4.17.7.0_x86_64_runtime.layer -``` - -`.uab` -There are two ways to install uab files -- use `ll-cli install` to install -```bash -ll-cli install com.baidu.baidunetdisk_x86_64_4.17.7.0_main.uab -``` - -- Execute `uab` on a machine with linyaps environment to install the application. -```bash -./com.baidu.baidunetdisk_x86_64_4.17.7.0_main.uab -``` - -You can use the command `ll-cli list | grep com.baidu.baidunetdisk` to check if it has been installed successfully. - -Run the application using the following command. - -```bash -ll-cli run com.baidu.baidunetdisk -``` diff --git a/docs/pages/en/guide/ll-cli/introduction.md b/docs/pages/en/guide/ll-cli/introduction.md deleted file mode 100644 index 125aa85ca..000000000 --- a/docs/pages/en/guide/ll-cli/introduction.md +++ /dev/null @@ -1,43 +0,0 @@ - - -# ll-cli Introduction - -`ll-cli` is the command line tool of linyaps, used to install, uninstall, check, run, close, debug, and update linyaps applications. - -View the help information for the `ll-cli` command: - -```bash -ll-cli --help -``` - -Here is the output: - -```text -Run an application -Usage: ll-cli run [OPTIONS] APP [COMMAND...] - -Example: -# run application by appid -ll-cli run org.deepin.demo -# execute commands in the container rather than running the application -ll-cli run org.deepin.demo bash -ll-cli run org.deepin.demo -- bash -ll-cli run org.deepin.demo -- bash -x /path/to/bash/script - -Positionals: - APP TEXT REQUIRED Specify the application ID - COMMAND TEXT ... Run commands in a running sandbox - -Options: - -h,--help Print this help message and exit - --help-all Expand all help - --file FILE:FILE Pass file to applications running in a sandbox - --url URL Pass url to applications running in a sandbox - -If you found any problems during use, -You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues -``` diff --git a/docs/pages/en/guide/ll-cli/kill.md b/docs/pages/en/guide/ll-cli/kill.md deleted file mode 100644 index d9588172e..000000000 --- a/docs/pages/en/guide/ll-cli/kill.md +++ /dev/null @@ -1,38 +0,0 @@ - - -# Force Quit Running App - -Use `ll-cli kill` to force quit running linyaps apps. - -View the help information for the `ll-cli kill` command: - -```bash -ll-cli kill --help -``` - -Here is the output: - -```text -Stop running applications -Usage: ll-cli kill [OPTIONS] APP - -Positionals: - APP TEXT REQUIRED Specify the running application - -Options: - -h,--help Print this help message and exit - --help-all Expand all help - -If you found any problems during use, -You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -Example of the `ll-cli kill` command to force quit running linyaps apps: - -```bash -ll-cli kill org.deepin.calculator -``` diff --git a/docs/pages/en/guide/ll-cli/prune.md b/docs/pages/en/guide/ll-cli/prune.md deleted file mode 100644 index aebf11096..000000000 --- a/docs/pages/en/guide/ll-cli/prune.md +++ /dev/null @@ -1,43 +0,0 @@ - - -# Remove the unused base or runtime - -Use `ll-cli prune` to remove the unused base or runtime. - -View the help information for the `ll-cli prune` command: - -```bash -ll-cli prune --help -``` - -Here is the output: - -```text -Remove the unused base or runtime -Usage: ll-cli prune [OPTIONS] - -Options: - -h,--help Print this help message and exit - --help-all Expand all help - -If you found any problems during use, -You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -Use `ll-cli prune` to remove the unused base or runtime - -Here is the output: - -```text -Unused base or runtime: -main:org.deepin.Runtime/23.0.1.2/x86_64 -main:org.deepin.foundation/20.0.0.27/x86_64 -main:org.deepin.Runtime/23.0.1.0/x86_64 -main:org.deepin.foundation/23.0.0.27/x86_64 -main:org.deepin.Runtime/20.0.0.8/x86_64 -5 unused base or runtime have been removed. -``` diff --git a/docs/pages/en/guide/ll-cli/ps.md b/docs/pages/en/guide/ll-cli/ps.md deleted file mode 100644 index 2f520c43d..000000000 --- a/docs/pages/en/guide/ll-cli/ps.md +++ /dev/null @@ -1,42 +0,0 @@ - - -# View Running Apps - -Use `ll-cli ps` to view running linyaps Apps. - -View the help information for the `ll-cli ps` command: - -```bash -ll-cli ps --help -``` - -Here is the output: - -```text -List running applications -Usage: ll-cli ps [OPTIONS] - -Options: - -h,--help Print this help message and exit - --help-all Expand all help - -If you found any problems during use, -You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -Use `ll-cli ps` to view running linyaps Apps: - -```bash -ll-cli ps -``` - -Here is the output of `ll-cli ps`: - -```text -App ContainerID Pid -main:org.dde.calendar/5.14.5.0/x86_64 c3b5ce363172 539537 -``` diff --git a/docs/pages/en/guide/ll-cli/query.md b/docs/pages/en/guide/ll-cli/query.md deleted file mode 100644 index dcd90d69a..000000000 --- a/docs/pages/en/guide/ll-cli/query.md +++ /dev/null @@ -1,73 +0,0 @@ - - -# Search Apps From Remote - -Use `ll-cli search` to search app meta info from remote repository. - -View the help information for the `ll-cli search` command: - -```bash -ll-cli search --help -``` - -Here is the output: - -```text -Search the applications/runtimes containing the specified text from the remote repository -Usage: ll-cli search [OPTIONS] KEYWORDS - -Example: -# find remotely app by name ll-cli search org.deepin.demo -# find remotely runtime by name -ll-cli search org.deepin.base --type=runtime -# find all off app of remote -ll-cli search . -# find all off runtime of remote -ll-cli search . --type=runtime - -Positionals: - KEYWORDS TEXT REQUIRED Specify the Keywords - -Options: - -h,--help Print this help message and exit --help-all Expand all help - --type TYPE [app] Filter result with specify type. One of "runtime", "app" or "all" - --dev include develop application in result - -If you found any problems during use, -You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -Use `ll-cli search` to search app meta info from remote repository and local cache: - -```bash -ll-cli search calculator -``` - -This command returns the info of all apps whose `appid` (appid is the app's unique identifier) contains the keyword "calculator", including the complete `appid`, application name, version, CPU architecture and descriptions. - -Here is the output: - -```text -id name version arch channel module description -com.github.matrix-calculator.linyaps com.github.matrix-calculator 3.3.0.0 x86_64 main runtime convert from 3.3 build uos https://chinauos.com \Pyth... -io.github.Calculator Calculator 0.0.1.0 x86_64 main runtime C++ GUI Calculator app. -io.github.Calculator Calculator 0.0.1.1 x86_64 main runtime C++ GUI Calculator app. -io.github.cupcalculator cupcalculator 1.1.2.0 x86_64 main runtime A program which calculates scorings from orienteering... -io.github.cyber-calculator cyber-calculator 1.0.0.0 x86_64 main runtime CyberOS Calculator. -io.github.galaxy-calculator galaxy-calculator 0.0.2.0 x86_64 main runtime Galaxy Calculator: Given the size of the Galaxy you c... -io.github.Huawei_modem_calculator_v2 Huawei_modem_calculator_v2 1.0.0.0 x86_64 main runtime Is it Huawei modem unlock code calculator from forth3... -io.github.QT_GraphingCalculator QT_GraphingCalculator 0.0.1.0 x86_64 main runtime Graphing calculator using QT and QTcustomplot -io.github.Qt-calculator Qt-calculator 1.0.0.0 x86_64 main runtime A simple GUI calculator🧮 built using C++. -io.github.SolarCalculator SolarCalculator 1.0.0.0 x86_64 main runtime Small app to calculate sunrise and sunset based on da... -io.github.StringCalculator StringCalculator 0.0.1.0 x86_64 main runtime Full-featured calculator written in C++ with Qt frame... -``` - -If you need to look up Base and Runtime, you can use the following command: - -```bash -ll-cli search . --type=runtime -``` diff --git a/docs/pages/en/guide/ll-cli/run.md b/docs/pages/en/guide/ll-cli/run.md deleted file mode 100644 index 7cad014d2..000000000 --- a/docs/pages/en/guide/ll-cli/run.md +++ /dev/null @@ -1,65 +0,0 @@ - - -# Run App - -Use `ll-cli run` command to start a linyaps application. - -See help for the `ll-cli run` command: - -```bash -ll-cli run --help -``` - -View the help information for the `ll-cli run` command: - -```text -Run an application -Usage: ll-cli run [OPTIONS] APP [COMMAND...] - -Example: -# run application by appid ll-cli run org.deepin.demo -# execute commands in the container rather than running the application -ll-cli run org.deepin.demo bash -ll-cli run org.deepin.demo -- bash -ll-cli run org.deepin.demo -- bash -x /path/to/bash/script - -Positionals: - APP TEXT REQUIRED Specify the application ID - COMMAND TEXT ... Run commands in a running sandbox - -Options: - -h,--help Print this help message and exit - --help-all Expand all help --file FILE:FILE Pass file to applications running in a sandbox - --url URL Pass url to applications running in a sandbox - -If you found any problems during use, -You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -When the application is installed normally, use the `ll-cli run` command to start it: - -```bash -ll-cli run org.deepin.calculator -``` - -Use the `ll-cli run` command to enter the specified program container: - -```bash -ll-cli run org.deepin.calculator --exec /bin/bash -``` - -After entering, execute `shell` commands, such as `gdb`, `strace`, `ls`, `find`, etc. - -Since linyaps applications run in the container, they cannot be directly debugged in the conventional way. You need to run debugging tools in the container, such as `gdb`: - -```bash -gdb /opt/apps/org.deepin.calculator/files/bin/deepin-calculator -``` - -The path is the absolute path of the application in the container. - -For more debugging information on linyaps application `release` version, please refer to: [Run FAQ](../debug/faq.md). diff --git a/docs/pages/en/guide/ll-cli/uninstall.md b/docs/pages/en/guide/ll-cli/uninstall.md deleted file mode 100644 index 357842df8..000000000 --- a/docs/pages/en/guide/ll-cli/uninstall.md +++ /dev/null @@ -1,47 +0,0 @@ - - -# Uninstall App - -Use `ll-cli uninstall` to uninstall linyaps apps. - -View the help information for the `ll-cli uninstall` command: - -```bash -ll-cli uninstall --help -``` - -Here is the output: - -```text -Uninstall the application or runtimes -Usage: ll-cli uninstall [OPTIONS] APP - -Positionals: - APP TEXT REQUIRED Specify the applications ID - -Options: - -h,--help Print this help message and exit - --help-all Expand all help - --module MODULE Uninstall a specify module - -If you found any problems during use, -You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -The command below gives an example of how to uninstall a linyaps app: - -```bash -ll-cli uninstall -``` - -Here is the output of `ll-cli uninstall org.deepin.calculator`: - -```text -Uninstall main:org.deepin.calculator/5.7.21.4/x86_64 success:100% -``` - -After the command is executed successfully, the org.deepin.calculator will be uninstalled. diff --git a/docs/pages/en/guide/ll-cli/update.md b/docs/pages/en/guide/ll-cli/update.md deleted file mode 100644 index 9036df4fb..000000000 --- a/docs/pages/en/guide/ll-cli/update.md +++ /dev/null @@ -1,56 +0,0 @@ - - -# Update linyaps App - -Use `ll-cli upgrade` to upgrade linyaps apps. - -View the help information for the `ll-cli upgrade` command: - -```bash -ll-cli upgrade --help -``` - -Here is the output: - -```text -Upgrade the application or runtimes -Usage: ll-cli upgrade [OPTIONS] [APP] - -Positionals: - APP TEXT Specify the application ID.If it not be specified, all applications will be upgraded - -Options: - -h,--help Print this help message and exit - --help-all Expand all help - -If you found any problems during use, You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -Use `ll-cli upgrade ` to upgrade all installed apps to the latest version - -Here is the output: - -```text -Upgrade main:org.dde.calendar/5.14.5.0/x86_64 to main:org.dde.calendar/5.14.5.1/x86_64 success:100% -Upgrade main:org.deepin.mail/6.4.10.0/x86_64 to main:org.deepin.mail/6.4.10.1/x86_64 success:100% -Please restart the application after saving the data to experience the new version. -``` - -Use `ll-cli upgrade org.deepin.calculator` to upgrade org.deepin.calculator to the latest version in the remote repository, such as: - -```bash -ll-cli upgrade org.deepin.calculator -``` - -Here is the output: - -```text -Upgrade main:org.deepin.calculator/5.7.21.3/x86_64 to main:org.deepin.calculator/5.7.21.4/x86_64 success:100% -Please restart the application after saving the data to experience the new version. -``` - - diff --git a/docs/pages/en/guide/ll-flatpak-convert/convert-flatpak.md b/docs/pages/en/guide/ll-flatpak-convert/convert-flatpak.md deleted file mode 100644 index 5bb17812a..000000000 --- a/docs/pages/en/guide/ll-flatpak-convert/convert-flatpak.md +++ /dev/null @@ -1,75 +0,0 @@ -## Conversion Flatpak application - -The `ll-pica-flatpak convert` command is used to convert Flatpak applications into linyaps applications. - -View the help information for the `ll-pica-flatpak convert` command: - -```bash -ll-pica-flatpak --help -``` - -Here is the output: - -```bash -Convert the flatpak to uab. For example: -Simple: - ll-pica-flatpak convert [flatpak name] --build - -Usage: - ll-pica-flatpak [command] - -Available Commands: - convert Convert flatpak to uab - help Help about any command - -Flags: - -h, --help help for ll-pica-flatpak -``` - -Convert Flatpak application - -```bash -ll-pica-flatpak convert org.videolan.VLC --build -``` - -:::tip - -The package name for Flatpak is org.videolan.VLC. It can be found by visiting [https://flathub.org/](https://flathub.org/) => clicking on the app => selecting the Install drop-down menu => viewing the package name. - -ll-pica-flatpak uses ostree commands to retrieve the application data of org.videolan.VLC, and generates the corresponding linyaps base environment based on the runtime defined in the metadata - -::: - -The application defaults to generating a uab file. To export a layer file, you need to add the --layer parameter. - -```bash -ll-pica-flatpak convert org.videolan.VLC --build --layer -``` - -To specify the version of the linyaps application to be generated, you need to add the --version parameter. - -```bash -ll-pica-flatpak convert org.videolan.VLC --version "1.0.0.0" --build --layer -``` - -To specify the base environment and version of the linyaps application, you need to add the --base and --base-version parameters. - -```bash -ll-pica-flatpak convert org.videolan.VLC --base "org.deepin.base.flatpak.kde" --base-version "6.7.0.2" --build --layer -``` - -The constructed products are as follows: - -```bash -├── org.videolan.VLC -│ ├── org.videolan.VLC_1.0.0.0_x86_64_develop.layer -│ ├── org.videolan.VLC_1.0.0.0_x86_64_binary.layer - or -│ ├── org.videolan.VLC_x86_64_1.0.0.0_main.uab -``` - -Layer files are divided into two categories: `binary` and `develop`. The `binary` includes the application's execution environment, while the `develop` layer, built upon the `binary`, retains the debugging environment. - -The uab file is an offline distribution format used by the linyaps software package, which is not suitable for systems that can normally connect to the linyaps repository. Instead, one should utilize the delta transfer scheme provided by the linyaps software repository to reduce the network transmission size. - -Installing Layer Files and Running the Application Reference:[Install linyaps Apps](../ll-cli/install.md) diff --git a/docs/pages/en/guide/ll-flatpak-convert/introduction.md b/docs/pages/en/guide/ll-flatpak-convert/introduction.md deleted file mode 100644 index 1d1f0bff2..000000000 --- a/docs/pages/en/guide/ll-flatpak-convert/introduction.md +++ /dev/null @@ -1,37 +0,0 @@ -# ll-flatpak-convert introduction - -This tool is provided by the `linglong-pica` package.which provides the ability to convert flatpak packages into linyaps packages, generate the linglong.yaml file required to build linyaps applications, and rely on ll-builder to implement application building and export. - -:::tip - -The conversion tool is merely an auxiliary tool and does not guarantee -that the converted application will definitely run. It's possible that -the software depends on libraries installed in paths or other -configuration paths that do not align with those inside linyaps's -internal structure, leading to the inability to execute. In such cases, -you would need to use the command `ll-builder run --exec bash` to enter the container for debugging purposes. -::: - -View the help information for the `ll-flatpak-convert` command: - -```bash -ll-flatpak-convert --help -``` - -Here is the output: - -```bash -Convert the flatpak to uab. For example: -Simple: - ll-pica-flatpak convert [flatpak name] --build - -Usage: - ll-pica [command] - -Available Commands: - convert Convert flatpak to uab - help Help about any command - -Flags: - -h, --help help for ll-pica-flatpak -``` diff --git a/docs/pages/en/guide/ll-pica/adep.md b/docs/pages/en/guide/ll-pica/adep.md deleted file mode 100644 index 3315efddb..000000000 --- a/docs/pages/en/guide/ll-pica/adep.md +++ /dev/null @@ -1,35 +0,0 @@ -## Add dependency - -linyaps applications may lack package dependencies, which can currently - be addressed by adding the corresponding package dependencies in the `linglong.yaml` file. - -The `ll-pica adep` command is used to add package dependencies to the `linglong.yaml` file. - -View the help information for the `ll-cli adep` command: - -```bash -ll-pica adep --help -``` - -Here is the output: - -```bash -Add dependency packages to linglong.yaml - -Usage: - ll-pica adep [flags] - -Flags: - -d, --deps string dependencies to be added, separator is ',' - -h, --help help for adep - -p, --path string path to linglong.yaml (default "linglong.yaml") - -Global Flags: - -V, --verbose verbose output -``` - -```bash -ll-pica adep -d "dep1,dep2" -p /path/to/linglong.yaml -``` - -If executing within the same path where the `linglong.yaml` file resides, there is no need to include the `-p` parameter. diff --git a/docs/pages/en/guide/ll-pica/convert.md b/docs/pages/en/guide/ll-pica/convert.md deleted file mode 100644 index cf1e2d13e..000000000 --- a/docs/pages/en/guide/ll-pica/convert.md +++ /dev/null @@ -1,76 +0,0 @@ -## Conversion application - -The `ll-pica convert` command is used to generate the `linglong.yaml` file required by linyaps. - -View the help information for the `ll-cli convert` command: - -```bash -ll-pica convert --help -``` - -Here is the output: - -```bash -Convert deb to uab - -Usage: - ll-pica convert [flags] - -Flags: - -b, --build build linglong - -c, --config string config file - --exportFile string export uab or layer (default "uab") - -h, --help help for convert - --pi string package id - --pn string package name - -t, --type string get app type (default "local") - --withDep Add dependency tree - -w, --workdir string work directory - -Global Flags: - -V, --verbose verbose output -``` - -Translation: After executing the `ll-pica init -w w --pi com.baidu.baidunetdisk --pn com.baidu.baidunetdisk -t repo` command - -We only need to execute the command `ll-pica convert -w w -b` to convert the linyaps application. Here, we will use the `apt download` command to download the deb package named `com.baidu.baidunetdisk`. - -```bash -ll-pica convert -c com.baidu.baidunetdisk_4.17.7_amd64.deb -w work -b -``` - -:::tip -Here, the `apt download` command is used to download the deb package; however, the process may fail due to -the deb package being excessively large or issues with obtaining the link. It is recommended to use the following command instead. If you use the following command directly, there is no need to execute the command `ll-pica init -w w --pi com.baidu.baidunetdisk --pn com.baidu.baidunetdisk -t repo`. -::: - -```bash -apt download com.baidu.baidunetdisk -``` - -```bash -ll-pica convert -c com.baidu.baidunetdisk_4.17.7_amd64.deb -w w -b --exportFile layer -``` - -- -w working directory。 -- -c The configuration method employed here utilizes deb files. -- -b It indicates that a build is required; without adding this parameter, neither building nor exporting the layer file will take place. -- --exportFile layer exports the output as a layer file. If you want to export a uab file, use --exportFile uab. - -The constructed products are as follows: - -```bash -├── package -│ └── com.baidu.baidunetdisk -│ ├── com.baidu.baidunetdisk_4.17.7.0_x86_64_develop.layer -│ ├── com.baidu.baidunetdisk_4.17.7.0_x86_64_binary.layer - or -│ ├── com.baidu.baidunetdisk_x86_64_4.17.7.0_main.uab -└── package.yaml -``` - -Layer files are divided into two categories: `binary` and `develop`. The `binary` includes the application's execution environment, while the `develop` layer, built upon the `binary`, retains the debugging environment. - -The uab file is an offline distribution format used by the linyaps software package, which is not suitable for systems that can normally connect to the linyaps repository. Instead, one should utilize the delta transfer scheme provided by the linyaps software repository to reduce the network transmission size. - -Installing Layer Files and Running the Application Reference:[Install linyaps Apps](../ll-cli/install.md) diff --git a/docs/pages/en/guide/ll-pica/init.md b/docs/pages/en/guide/ll-pica/init.md deleted file mode 100644 index bfd8a2242..000000000 --- a/docs/pages/en/guide/ll-pica/init.md +++ /dev/null @@ -1,79 +0,0 @@ -# Initialization configuration - -The `ll-pica init` command is used to initialize the configuration information for the conversion package. - -View the help information for the `ll-cli init` command: - -```bash -ll-pica init --help -``` - -Here is the output: - -```bash -init config template - -Usage: - ll-pica init [flags] - -Flags: - -a, --arch string runtime arch - -c, --config string config file - --dv string distribution Version - -h, --help help for init - --pi string package id - --pn string package name - -s, --source string runtime source - -t, --type string get type - -v, --version string runtime version - -w, --workdir string work directory - -Global Flags: - -V, --verbose verbose output -``` - -The specific command as follows: - -```bash -ll-pica init -w w --pi com.baidu.baidunetdisk --pn com.baidu.baidunetdisk -t repo -``` - -- -w working directory -- --pi specifies the appid used by the linyaps application. -- --pn specifies the correct package name that apt can search for. -- -t specifies the type to retrieve, `repo` fetches from the apt repository. - -The specific configuration is as follows: - -```bash -runtime: - version: 23.0.1 - base_version: 23.0.0 - source: https://community-packages.deepin.com/beige/ - distro_version: beige - arch: amd64 -file: - deb: - - type: repo - id: com.baidu.baidunetdisk - name: com.baidu.baidunetdisk -``` - -Detailed Field Reference: [Manifests](../manifests.md) - -:::tip -The default configuration file `~/.pica/config.json` - is set to use Deepin v23. If you need to specify UOS 20 as the BASE and - RUNTIME, modify the default configuration using the following command. -Please update the link below, [https://professional-packages.chinauos.com/desktop-professional](https://professional-packages.chinauos.com/desktop-professional), to a version that does not require authentication. -::: - -```bash -ll-pica init --rv "20.0.0" --bv "20.0.0" -s "https://professional-packages.chinauos.com/desktop-professional" --dv "eagle/1070" -``` - -If it needs to be used on arm64, the default architecture needs to be modified. - -```bash -ll-pica init -a "arm64" -``` diff --git a/docs/pages/en/guide/ll-pica/install.md b/docs/pages/en/guide/ll-pica/install.md deleted file mode 100644 index 56d53563a..000000000 --- a/docs/pages/en/guide/ll-pica/install.md +++ /dev/null @@ -1,17 +0,0 @@ -# Linglong conversion tool (pica) installation - -This tool provides the ability to convert deb, appimage, and flatpak packages to linyaps packages, generates the linglong.yaml file required to build linyaps applications, and relies on ll-builder to implement application building and export. - -## deepin v23 - -```bash -sudo apt install linglong-pica -``` - -## UOS 1070 - -```bash -echo "deb [trusted=yes] https://ci.deepin.com/repo/deepin/deepin-community/linglong-repo/ unstable main" | sudo tee -a /etc/apt/sources.list -sudo apt update -sudo apt install linglong-pica -``` diff --git a/docs/pages/en/guide/ll-pica/introduction.md b/docs/pages/en/guide/ll-pica/introduction.md deleted file mode 100644 index a8905bc3a..000000000 --- a/docs/pages/en/guide/ll-pica/introduction.md +++ /dev/null @@ -1,52 +0,0 @@ -# ll-pica Introduction - -This tool currently provides the capability to convert DEB packages into linyaps packages. Generate the required `linglong.yaml` file for building linyaps applications and rely on `ll-builder` to implement application build and export. Only software packages that comply with the [app store packaging standards](https://doc.chinauos.com/content/M7kCi3QB_uwzIp6HyF5J) are supported for conversion. - -:::tip - -The conversion tool is merely an auxiliary tool and does not guarantee -that the converted application will definitely run. It's possible that -the software depends on libraries installed in paths or other -configuration paths that do not align with those inside linyaps's -internal structure, leading to the inability to execute. In such cases, -you would need to use the command `ll-builder run --exec bash` to enter the container for debugging purposes. -::: - -The following situations are likely to result in unsuccessful execution: - -1. Packages related to Wine, Android emulators, input methods, and security software cannot be converted. -2. The package utilizes preinst, postinst, prerm, and postrm scripts. -3. It is necessary to read configuration files from a fixed path. -4. Need to obtain root permissions. - -View the help information for the `ll-pica` command: - -```bash -ll-pica --help -``` - -Here is the output: - -```bash -Convert the deb to uab. For example: -Simple: - ll-pica init -c package -w work-dir - ll-pica convert -c package.yaml -w work-dir - ll-pica help - -Usage: - ll-pica [command] - -Available Commands: - adep Add dependency packages to linglong.yaml - convert Convert deb to uab - help Help about any command - init init config template - -Flags: - -h, --help help for ll-pica - -V, --verbose verbose output - -v, --version version for ll-pica - -Use "ll-pica [command] --help" for more information about a command. -``` diff --git a/docs/pages/en/guide/ll-pica/manifests.md b/docs/pages/en/guide/ll-pica/manifests.md deleted file mode 100644 index bbff4bb8e..000000000 --- a/docs/pages/en/guide/ll-pica/manifests.md +++ /dev/null @@ -1,56 +0,0 @@ -# Manifests - -The `package.yaml` file serves as the foundation for ll-pica to convert packages into DEB format. It encompasses essential information such as the base and runtime versions used in the build process, as well as the DEB package that is to be converted. - -## Project directory structure - -```bash -{workdir} -├── package -│ └── {appid} -│ ├── linglong -│ ├── linglong.yaml -│ └── start.sh -└── package.yaml -``` - -## Field definitions - -### Build environment - -Conversion build environment for DEB packages to linyaps packages. - -```bash -runtime: - version: 23.0.1 - base_version: 23.0.0 - source: https://community-packages.deepin.com/beige/ - distro_version: beige - arch: amd64 -``` - -| name | description | -| -------------- | ------------------------------------------------------------------------------------------- | -| version | Runtime version, A three-digit number can be loosely matched with a potential fourth digit | -| base_version | Base version, A three-digit number can be loosely matched with a potential fourth digit | -| source | Obtain the sources used by the dependencies of a deb package. | -| distro_version | The codename of a distribution." | -| arch | The architecture required by a deb package. | - -### Deb package informationeb - -```bash -file: - deb: - - type: local - id: com.baidu.baidunetdisk - name: com.baidu.baidunetdisk - ref: /tmp/com.baidu.baidunetdisk_4.17.7_amd64.deb -``` - -| name | description | -| ---- | -------------------------------------------------------------------------------------------------------------------------- | -| type | The method of acquisition: 'local' requires specifying a reference, while 'repo' does not require specifying a reference." | -| id | Unique name of the build product | -| name | Specify the correct package name that apt can search for. | -| ref | The path of the deb package on the host machine. | diff --git a/docs/pages/en/guide/publishing/mirrors.md b/docs/pages/en/guide/publishing/mirrors.md new file mode 100644 index 000000000..b49f6d361 --- /dev/null +++ b/docs/pages/en/guide/publishing/mirrors.md @@ -0,0 +1,69 @@ +# Linyaps Repository Mirror Function Design + +The `enable-mirror` and `disable-mirror` commands have been added to ll-cli and ll-builder to enable and disable mirror functionality. + +When mirror functionality is enabled for a repository, the ostree config file is updated to add the contenturl configuration item: + +```diff +url=$repo_url/repos/$repo_name +gpg-verify=false +http2=false ++ contenturl=mirrorlist=$repo_url/api/v2/mirrors/$repo_name +``` + +After adding the contenturl configuration item, ostree will prioritize using contenturl to download static files such as files, while url is only used to obtain metadata like summary. The contenturl supports three protocols: file://, http://, and https://. + +If `mirrorlist=` is added before the url, ostree will first obtain a line-separated mirror list from the url, then select mirrors from the mirror list for downloading files. See the [ostree_pull](#ostree-pull-steps) section for specific logic. + +/api/v2/mirrors/$repo_name is an API interface of the Linyaps server that obtains the client's country through the client IP, gets the corresponding country's mirror list from the configuration file, and then returns it to ostree. This implements the function of automatically diverting repository file downloads based on the user's country. + +## Mirror Site Configuration + +Linyaps mirror sites only need to provide https access to repository static files. Linyaps repositories support both rsync and ostree synchronization protocols. + +### Using rsync Synchronization Configuration + +The advantage is fast synchronization speed, the disadvantage is that it needs to synchronize from mirror sites or official repositories that support the rsync protocol. + +```bash +rsync rsync://rsync.linyaps.org.cn/repos/stable $www_root/repos/stable +``` + +### Using ostree Synchronization Configuration + +The advantage is that no protocol support is needed, and repositories can be synchronized from any mirror site. The disadvantage is slower synchronization speed. + +Save the following script and name it sync.sh, then execute `sh sync.sh https://mirror-repo-linglong.deepin.com/repos/stable/ $www_root/repos/stable` + +```bash +#!/bin/bash +set -e +url=$1 +dir=$2 +echo sync $url to $dir +sleep 3 +ostree init --repo=$dir --mode archive +ostree --repo=$dir remote add --if-not-exists --no-sign-verify remote $url +for ref in $(ostree --repo=$dir remote refs remote); do + echo pull $ref; + ostree --repo=$dir pull --mirror $ref; +done +``` + +## ostree pull Steps + +### Determine Mirror Availability + +When pulling, ostree first obtains the mirror list from contenturl, then gets the /config file from each url. If the /config file cannot be obtained, the mirror is considered unavailable. If the /config file is obtained, the mirror is considered available. If no mirrors are available, the pull fails. + +### Get summary File + +ostree gets the summary file from url. If the summary file cannot be obtained, or the summary file does not contain the ref, the pull fails. + +### delta-indexes File Acquisition + +ostree gets delta-indexes from each available mirror. If the mirror server returns 4xx or 5xx, it gets delta-indexes from the next mirror. If the last mirror returns 5xx, the pull fails. If the last mirror returns 4xx, it skips the delta step and directly pulls files. + +### files File Acquisition + +ostree gets files from available mirrors in order. If the mirror server returns 403, 404, or 410, the error is considered unrecoverable and the pull fails. If the mirror server returns other error codes, it uses the next mirror to get files. If all mirrors cannot get files, the pull fails. diff --git a/docs/pages/en/guide/publishing/repositories.md b/docs/pages/en/guide/publishing/repositories.md new file mode 100644 index 000000000..1daa9c742 --- /dev/null +++ b/docs/pages/en/guide/publishing/repositories.md @@ -0,0 +1,13 @@ +# Repository + +The official Linyaps repository is the primary mechanism for publishing applications so that users can install applications more conveniently. Currently, after installing the Linyaps components, this repository is used by default. + +- Some basic concepts of repositories have been introduced in [Repository Basic Concepts](../reference/basic-concepts.md); +- Adding, updating, and deleting repositories can be done using the `ll-cli repo` command. For specific usage, please refer to [ll-cli-repo(1)](../reference/commands/ll-cli/repo.md); +- Using self-hosted repositories: To be supplemented; + +## Publishing Updates + +Linyaps repositories are similar to Git repositories in that they store each version of an application by recording the differences between each version. This makes updates efficient because when performing an update, only the differences (or "deltas") between the two versions need to be downloaded. + +When a new version of an application is added to the repository, it immediately becomes available to users. The app store can automatically check for and install new versions. Using the command line requires manually running `ll-cli list --upgradable` to check and use `ll-cli update` to update installed applications to the new version. diff --git a/docs/pages/en/guide/publishing/uab.md b/docs/pages/en/guide/publishing/uab.md new file mode 100644 index 000000000..4a4eaaed2 --- /dev/null +++ b/docs/pages/en/guide/publishing/uab.md @@ -0,0 +1,142 @@ +# UAB Application Publishing + +This document supplements the relevant content for application publishing using UAB (Universal Application Bundle). + +## What is UAB + +UAB (Universal Application Bundle) is a cross-distribution application packaging format designed to solve the compatibility issues of Linux applications across different distributions. It packages applications and all their dependencies into a single file, enabling one-click installation and operation. + +## UAB Publishing Advantages + +- **Cross-distribution compatibility**: Applications packaged in UAB format can run on different Linux distributions +- **One-click installation**: Users only need to download one file to complete the installation +- **Dependency self-contained**: All dependencies are included in the package, avoiding dependency conflicts +- **Easy to distribute**: A single file is easy to transmit and share + +## Creating UAB Packages + +### Prerequisites + +Before creating a UAB package, you need to: + +1. Complete the development and testing of the application +2. Ensure the application can run normally in the Linyaps environment +3. Prepare the application's metadata information (name, version, description, etc.) + +### Build Process + +1. Use `ll-builder` to build the application: + +```bash +ll-builder build +``` + +2. Export as UAB format: + +```bash +ll-builder export --type=uab +``` + +3. The generated UAB file will be saved in the current directory, with the file name format: `{app-id}_{version}_{arch}.uab` + +## UAB File Structure + +The UAB file is essentially a compressed package containing: + +- Application executable files and resource files +- All dependent libraries and runtime environments +- Application metadata and configuration files +- Installation scripts and desktop entry files + +## Publishing UAB Applications + +### Method 1: Direct Distribution + +You can directly distribute the generated UAB file to users through the following methods: + +- Official website download +- GitHub Releases +- Third-party software download sites +- USB flash drive or other storage media + +### Method 2: Repository Publishing + +Upload the UAB file to the Linyaps repository: + +```bash +ll-builder push --repo=your-repo +``` + +### Method 3: App Store Publishing + +Submit the application to the app store through the official channel, and the app store will automatically handle the UAB package and provide it to users for download. + +## User Installation + +Users can install UAB applications in the following ways: + +### Command Line Installation + +```bash +ll-cli install ./your-app.uab +``` + +### Graphical Interface Installation + +Double-click the UAB file, and the system will automatically call the Linyaps installer to complete the installation. + +## UAB Application Management + +### View Installed Applications + +```bash +ll-cli list +``` + +### Update Applications + +```bash +ll-cli update your-app-id +``` + +### Uninstall Applications + +```bash +ll-cli uninstall your-app-id +``` + +## Best Practices + +1. **Version Management**: Use semantic versioning (Semantic Versioning) to manage application versions +2. **Testing**: Test on multiple distributions to ensure compatibility +3. **Documentation**: Provide detailed installation and usage instructions +4. **Updates**: Regularly update applications and dependencies +5. **Security**: Ensure that applications and dependencies do not contain security vulnerabilities + +## Common Issues + +### Installation Failure + +- Check if the UAB file is complete +- Confirm that the system has Linyaps installed +- View error logs to locate the problem + +### Runtime Errors + +- Check if dependencies are complete +- Confirm system compatibility +- View application logs + +### Update Issues + +- Check network connection +- Confirm repository configuration +- View update logs + +## Technical Support + +If you encounter problems during the UAB application publishing process, you can: + +1. View the official documentation: [Linyaps Documentation](https://linglong.dev) +2. Submit an Issue: [GitHub Issues](https://github.com/OpenAtom-Linyaps/linyaps/issues) +3. Community Support: Join the Linyaps community for discussion diff --git a/docs/pages/en/guide/reference/basic-concepts.md b/docs/pages/en/guide/reference/basic-concepts.md new file mode 100644 index 000000000..fe8aa26c2 --- /dev/null +++ b/docs/pages/en/guide/reference/basic-concepts.md @@ -0,0 +1,24 @@ +# Linyaps Basic Concepts Introduction + +## Base + +Base can be understood as a lightweight "minimal system image" that contains core operating system components (such as glibc, bash, and other basic toolchains), providing a consistent underlying dependency environment for applications across different distributions. It ensures that applications running on different Linux distributions (such as Debian, Ubuntu, etc.) do not need to rely on the host system's libraries, avoiding compatibility issues caused by environmental differences. + +For detailed information, see: [Base Component](./runtime.md). + +## Runtime + +Runtime is the environment that applications depend on during execution, containing specific framework libraries required for application operation. For example, some applications may depend on specific graphical interface frameworks (such as DTK), browser engines (such as QT WebEngine), etc. Runtime provides the corresponding runtime environment support for these applications, ensuring they can start and run properly. It works together with the Base environment to ensure applications can run stably and efficiently across different Linux distributions. Runtime and Base use a hierarchical dependency relationship - applications must first select an appropriate Base, then choose a compatible Runtime. This design ensures cross-distribution compatibility for applications. + +For detailed information, see: [Runtime Component](./runtime.md). + +## Sandbox + +When using Linyaps, each application is built and runs in an isolated environment called a "sandbox". Each sandbox contains Base, Runtime, and the application itself. +Out of necessity, some resources within the sandbox need to be exported to the host system for use. These exported resources include the application's desktop files and icons. + +## Repository + +Linyaps applications and runtimes are typically stored and distributed using repositories, which behave very similarly to Git repositories: a Linyaps repository can contain multiple objects, each of which is versioned, allowing for upgrades or even downgrades. +Each system using Linyaps can be configured to access any number of remote repositories. Once a system is configured to access a 'remote', it can inspect, search the contents of the remote repository, and use it as a source for applications and runtimes. +When performing updates, new versions of applications and runtimes are downloaded from the relevant remote repositories. Similar to Git, only the parts that have changed between versions are downloaded, making the process very efficient. diff --git a/docs/pages/en/guide/reference/commands/ll-appimage-convert/ll-appimage-convert-convert.md b/docs/pages/en/guide/reference/commands/ll-appimage-convert/ll-appimage-convert-convert.md new file mode 100644 index 000000000..724aeb569 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-appimage-convert/ll-appimage-convert-convert.md @@ -0,0 +1,75 @@ +% ll-appimage-convert-convert 1 + +## NAME + +ll\-appimage\-convert\-convert - Convert AppImage packages to Linyaps package format + +## SYNOPSIS + +**ll-appimage-convert convert** [*flags*] + +## DESCRIPTION + +The ll-appimage-convert convert command generates a directory based on the specified application name, which serves as the root directory of the Linyaps project, i.e., the location of the linglong.yaml file. It supports two conversion methods: + +1. Use the `--file` option to convert the specified appimage file to a Linyaps package file +2. Use the `--url` and `--hash` options to convert the specified appimage URL and hash value to a Linyaps package file +3. Use the `--layer` option to export .layer format files, otherwise it will export .uab format files by default + +When the Linyaps version is greater than 1.5.7, convert exports uab packages by default. If you want to export layer files, you need to add the --layer parameter. + +You can use the `--output` option to generate Linyaps project configuration files (linglong.yaml) and build scripts for Linyaps .layer (.uab) files, and then execute the script to generate the corresponding Linyaps package when the linglong.yaml configuration file is modified. If this option is not specified, the corresponding Linyaps package will be exported directly. + +## OPTIONS + +**-b, --build** +: Build Linyaps package + +**-d, --description** _string_ +: Detailed description of the package + +**-f, --file** _string_ +: App package file, this option is not required when --url option and --hash option are set + +**--hash** _string_ +: Package hash value, must be used together with --url option + +**-i, --id** _string_ +: Unique name of the package + +**-l, --layer** +: Export layer file + +**-n, --name** _string_ +: Descriptive name of the package + +**-u, --url** _string_ +: Package URL, this option is not required when -f option is set + +**-v, --version** _string_ +: Version of the package + +**-V, --verbose** +: Verbose output + +## EXAMPLES + +Convert BrainWaves appimage file to Linyaps .layer file via --url option: + +```bash +ll-appimage-convert convert --url "https://github.com/makebrainwaves/BrainWaves/releases/download/v0.15.1/BrainWaves-0.15.1.AppImage" --hash "04fcfb9ccf5c0437cd3007922fdd7cd1d0a73883fd28e364b79661dbd25a4093" --name "io.github.brainwaves" --id "io.github.brainwaves" --version "0.15.1.0" --description "io.github.brainwaves" -b +``` + +Convert BrainWaves-0.15.1.AppImage to Linyaps .uab via --file option: + +```bash +ll-appimage-convert convert -f ~/Downloads/BrainWaves-0.15.1.AppImage --name "io.github.brainwaves" --id "io.github.brainwaves" --version "0.15.1.0" --description "io.github.brainwaves" -b +``` + +## SEE ALSO + +**[ll-appimage-convert(1)](ll-appimage-convert.md)**, **[ll-builder(1)](../ll-builder/ll-builder.md)** + +## HISTORY + +Developed in 2024 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-appimage-convert/ll-appimage-convert.md b/docs/pages/en/guide/reference/commands/ll-appimage-convert/ll-appimage-convert.md new file mode 100644 index 000000000..89b51f903 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-appimage-convert/ll-appimage-convert.md @@ -0,0 +1,29 @@ +% ll-appimage-convert 1 + +## NAME + +ll\-appimage\-convert - Convert AppImage packages to Linyaps package format + +## SYNOPSIS + +**ll-appimage-convert** _subcommand_ + +## DESCRIPTION + +The ll-appimage-convert command is used to convert AppImage package formats (.appimage or .AppImage) to Linyaps package formats (.layer or .uab). This tool generates the linglong.yaml file needed to build Linyaps applications and relies on ll-builder to implement application building and export. + +Note: The conversion tool is only an auxiliary tool and cannot guarantee that the converted application will run. The software itself may have dependency library installation paths or other configuration paths that are inconsistent with Linyaps internal paths, causing it to fail to run. You need to use the `ll-builder run --exec bash` command to enter the container for debugging. + +## COMMANDS + +| Command | Man Page | Description | +| ------- | ---------------------------------------------------------------- | --------------------------------------------------- | +| convert | [ll-appimage-convert-convert(1)](ll-appimage-convert-convert.md) | Convert AppImage packages to Linyaps package format | + +## SEE ALSO + +**[ll-appimage-convert-convert](ll-appimage-convert-convert.md)** + +## HISTORY + +Developed in 2024 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-builder/build.md b/docs/pages/en/guide/reference/commands/ll-builder/build.md new file mode 100644 index 000000000..014f35c95 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-builder/build.md @@ -0,0 +1,81 @@ +% ll-builder-build 1 + +## NAME + +ll-builder-build - Build Linyaps project + +## SYNOPSIS + +**ll-builder build** [*options*] [*command*...] + +## DESCRIPTION + +The `ll-builder build` command is used to build Linyaps applications. After the build is complete, the build content will be automatically committed to the local `ostree` cache. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help + +**-f, --file** _file_ [./linglong.yaml] +: Path to the linglong.yaml file + +**--offline** +: Use only local files. This implies --skip-fetch-source and --skip-pull-depend + +**--skip-fetch-source** +: Skip fetching source code + +**--skip-pull-depend** +: Skip pulling dependencies + +**--skip-run-container** +: Skip running container + +**--skip-commit-output** +: Skip committing build output + +**--skip-output-check** +: Skip output checking + +**--skip-strip-symbols** +: Skip stripping debug symbols + +**--isolate-network** +: Build in isolated network environment + +**command** -- _COMMAND_ ... +: Enter container to execute commands instead of building application + +## EXAMPLES + +### Basic Usage + +Build application in project root directory (where linglong.yaml file is located): + +```bash +ll-builder build +``` + +Or use the `--file` parameter to specify the configuration file path: + +```bash +ll-builder build --file /path/to/linglong.yaml +``` + +Enter container to execute commands instead of building application: + +```bash +ll-builder build -- bash +``` + +## SEE ALSO + +**[ll-builder(1)](./ll-builder.md)**, **[ll-builder-export(1)](export.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-builder/create.md b/docs/pages/en/guide/reference/commands/ll-builder/create.md new file mode 100644 index 000000000..209e5ed8b --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-builder/create.md @@ -0,0 +1,81 @@ +% ll-builder-create 1 + +## NAME + +ll-builder-create - Create Linyaps build template + +## SYNOPSIS + +**ll-builder create** [*options*] _name_ + +## DESCRIPTION + +The `ll-builder create` command creates a corresponding folder in the current directory based on the input project name, and generates the required `linglong.yaml` template file for building. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help + +**name** (required) +: Project name + +## EXAMPLES + +Create a project named `org.deepin.demo`: + +```bash +ll-builder create org.deepin.demo +``` + +Command output as follows: + +```text +org.deepin.demo/ +└── linglong.yaml +``` + +### Complete linglong.yaml configuration + +The `linglong.yaml` file content is as follows: + +```yaml +version: "1" + +package: + id: org.deepin.demo + name: your name #set your application name + version: 0.0.0.1 #set your version + kind: app + description: | + your description #set a brief text to introduce your application. + +command: [echo, -e, hello world] #the commands that your application need to run. + +base: org.deepin.base/23.1.0 #set the base environment, this can be changed. + +#set the runtime environment if you need, a example of setting deepin runtime is as follows. +#runtime: +#org.deepin.runtime.dtk/23.1.0 + +#set the source if you need, a simple example of git is as follows. +#sources: +# - kind: git +# url: https://github.com/linuxdeepin/linglong-builder-demo.git +# version: master\n +# commit: a3b89c3aa34c1aff8d7f823f0f4a87d5da8d4dc0 + +build: | + echo 'hello' #some operation to build this project +``` + +## SEE ALSO + +**[ll-builder(1)](./ll-builder.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-builder/export.md b/docs/pages/en/guide/reference/commands/ll-builder/export.md new file mode 100644 index 000000000..bb40216ef --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-builder/export.md @@ -0,0 +1,99 @@ +% ll-builder-export 1 + +## NAME + +ll-builder-export - Export Linyaps layer or UAB file + +## SYNOPSIS + +**ll-builder export** [*options*] + +## DESCRIPTION + +The `ll-builder export` command is used to export applications from the local build cache as UAB (Universal Application Bundle) files. This is the recommended format. It can also export to the deprecated linglong layer file format. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help + +**-f, --file** _file_ [./linglong.yaml] +: Specify the path to the `linglong.yaml` configuration file. The directory where the `linglong.yaml` file is located is the project's working directory + +**-o, --output** _file_ +: Specify the path for the output file. For UAB, this is usually the full path or filename of the `.uab` file. For layer, this is the prefix for the output filename + +**-z, --compressor** _x_ +: Specify the compression algorithm. Supports `lz4` (UAB default), `lzma` (layer default), `zstd` + +**--icon** _file_ +: Specify an icon for the exported UAB file (UAB mode only, mutually exclusive with `--layer`) + +**--loader** _file_ +: Specify a custom loader for the exported UAB file (UAB mode only, mutually exclusive with `--layer`) + +**--layer** +: **(Deprecated)** Export as layer file format instead of UAB (mutually exclusive with `--icon`, `--loader`) + +**--no-develop** +: Do not export the `develop` module when exporting layer files + +**--ref** _ref_ +: Specify package reference + +**--modules** _modules_ +: Specify modules to export + +## EXAMPLES + +### Export UAB File (Recommended) + +UAB (Universal Application Bundle) file is a self-contained, offline-distributable file format that includes all content required for application runtime. This is the recommended export format. + +```bash +# Basic export +ll-builder export + +# Export UAB file and specify icon and output path +ll-builder export --icon assets/app.png -o dist/my-app-installer.uab + +# Export UAB file using zstd compression +ll-builder export -z zstd -o my-app-zstd.uab + +# Export UAB file and specify custom loader +ll-builder export --loader /path/to/custom/loader -o my-app-custom-loader.uab +``` + +### Export Layer File + +```bash +# Export layer format without develop module +ll-builder export --layer --no-develop + +# Export layer format and specify output file prefix +ll-builder export --layer -o my-app +# (Will generate my-app_binary.layer and my-app_develop.layer) +``` + +## Advanced Notes + +UAB is a statically linked ELF executable file whose goal is to run on any Linux distribution. By default, exported UAB files belong to bundle mode, while UAB files exported using the `--loader` parameter belong to custom loader mode. + +### Bundle Mode + +Bundle mode is mainly used for distribution and supports self-running functionality as much as possible. Users typically install offline-distributed applications through `ll-cli install `, and the application runtime environment is automatically completed. + +### Custom Loader Mode + +UAB files exported in custom loader mode contain only application data and the passed custom loader. After the UAB file is extracted and mounted, control is handed over to the custom loader, which is no longer in the container environment. + +## SEE ALSO + +**[ll-builder(1)](./ll-builder.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-builder/extract.md b/docs/pages/en/guide/reference/commands/ll-builder/extract.md new file mode 100644 index 000000000..e87571a71 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-builder/extract.md @@ -0,0 +1,43 @@ +% ll-builder-extract 1 + +## NAME + +ll-builder-extract - Extract Linyaps layer file to directory + +## SYNOPSIS + +**ll-builder extract** [*options*] _file_ _directory_ + +## DESCRIPTION + +The `ll-builder extract` command is used to extract Linyaps layer files to a specified directory. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help + +**file** (required) +: Path to the layer file to be extracted + +**directory** (required) +: Target directory for extraction + +## EXAMPLES + +Extract layer file to specified directory: + +```bash +ll-builder extract org.deepin.demo_binary.layer /tmp/extracted +``` + +## SEE ALSO + +**[ll-builder(1)](./ll-builder.md)**, **[ll-builder-export(1)](export.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/ll-builder/images/org.deepin.demo.png b/docs/pages/en/guide/reference/commands/ll-builder/images/org.deepin.demo.png similarity index 100% rename from docs/pages/en/guide/ll-builder/images/org.deepin.demo.png rename to docs/pages/en/guide/reference/commands/ll-builder/images/org.deepin.demo.png diff --git a/docs/pages/en/guide/ll-builder/images/org.deepin.demo.png.license b/docs/pages/en/guide/reference/commands/ll-builder/images/org.deepin.demo.png.license similarity index 100% rename from docs/pages/en/guide/ll-builder/images/org.deepin.demo.png.license rename to docs/pages/en/guide/reference/commands/ll-builder/images/org.deepin.demo.png.license diff --git a/docs/pages/en/guide/reference/commands/ll-builder/import.md b/docs/pages/en/guide/reference/commands/ll-builder/import.md new file mode 100644 index 000000000..0a2ed1d79 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-builder/import.md @@ -0,0 +1,40 @@ +% ll-builder-import 1 + +## NAME + +ll-builder-import - Import Linyaps layer file to build repository + +## SYNOPSIS + +**ll-builder import** [*options*] _file_ + +## DESCRIPTION + +The `ll-builder import` command is used to import Linyaps layer files to the build repository. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help + +**file** (required) +: Path to the layer file to be imported + +## EXAMPLES + +Import layer file to build repository: + +```bash +ll-builder import org.deepin.demo_binary.layer +``` + +## SEE ALSO + +**[ll-builder(1)](./ll-builder.md)**, **[ll-builder-export(1)](export.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-builder/list.md b/docs/pages/en/guide/reference/commands/ll-builder/list.md new file mode 100644 index 000000000..cf38ff75a --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-builder/list.md @@ -0,0 +1,37 @@ +% ll-builder-list 1 + +## NAME + +ll-builder-list - List built applications + +## SYNOPSIS + +**ll-builder list** [*options*] + +## DESCRIPTION + +The `ll-builder list` command is used to list built applications. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help + +## EXAMPLES + +List all built applications: + +```bash +ll-builder list +``` + +## SEE ALSO + +**[ll-builder(1)](./ll-builder.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-builder/ll-builder.md b/docs/pages/en/guide/reference/commands/ll-builder/ll-builder.md new file mode 100644 index 000000000..3075e6ff0 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-builder/ll-builder.md @@ -0,0 +1,41 @@ +% ll-builder 1 + +## NAME + +ll-builder - Linyaps application build tool + +## SYNOPSIS + +**ll-builder** _subcommand_ + +## DESCRIPTION + +ll-builder is a tool provided for application developers to build Linyaps applications. It supports building applications in isolated containers and includes a complete push and publish workflow. + +Main features include: + +- Building applications in isolated containers +- Complete application build, test, export, and publish workflow + +## COMMANDS + +| Command | Man Page | Description | +| ------- | ------------------------------------- | --------------------------------------------- | +| create | [ll-builder-create(1)](./create.md) | Create Linyaps build template | +| build | [ll-builder-build(1)](./build.md) | Build Linyaps project | +| run | [ll-builder-run(1)](./run.md) | Run the built application | +| list | [ll-builder-list(1)](./list.md) | List built applications | +| remove | [ll-builder-remove(1)](./remove.md) | Remove built applications | +| export | [ll-builder-export(1)](./export.md) | Export Linyaps layer or UAB file | +| push | [ll-builder-push(1)](./push.md) | Push Linyaps application to remote repository | +| import | [ll-builder-import(1)](./import.md) | Import Linyaps layer file to build repository | +| extract | [ll-builder-extract(1)](./extract.md) | Extract Linyaps layer file to directory | +| repo | [ll-builder-repo(1)](./repo.md) | Display and manage repository | + +## SEE ALSO + +**[ll-builder-create(1)](./create.md)**, **[ll-builder-build(1)](./build.md)**, **[ll-builder-run(1)](./run.md)**, **[ll-builder-export(1)](./export.md)**, **[ll-builder-push(1)](./push.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-builder/push.md b/docs/pages/en/guide/reference/commands/ll-builder/push.md new file mode 100644 index 000000000..aaae747fa --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-builder/push.md @@ -0,0 +1,71 @@ +% ll-builder-push 1 + +## NAME + +ll-builder-push - Push Linyaps applications to remote repository + +## SYNOPSIS + +**ll-builder push** [*options*] + +## DESCRIPTION + +The `ll-builder push` command is used to push Linyaps packages to the Linyaps remote repository. The command automatically pushes all modules or specified modules from the project to the remote repository based on the project configuration. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help + +**-f, --file** _file_ [./linglong.yaml] +: Path to the linglong.yaml file + +**--repo-url** _url_ +: Remote repository URL + +**--repo-name** _name_ +: Remote repository name + +**--module** _module_ +: Push a single module + +## Module Push Description + +When the `--module` parameter is not specified, the command automatically pushes all modules in the project, including: + +- `binary` - Binary module +- `develop` - Development module +- Other custom modules defined in the project + +When the `--module` parameter is specified, only the specified single module is pushed. + +## EXAMPLES + +Push all modules in the project to the remote repository: + +```bash +ll-builder push +``` + +Push a specified module to the remote repository: + +```bash +ll-builder push --module binary +``` + +Push modules to a specified remote repository: + +```bash +ll-builder push --repo-url https://repo.example.com --repo-name myrepo +``` + +## SEE ALSO + +**[ll-builder(1)](./ll-builder.md)**, **[ll-builder-export(1)](export.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-builder/remove.md b/docs/pages/en/guide/reference/commands/ll-builder/remove.md new file mode 100644 index 000000000..69bd572a2 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-builder/remove.md @@ -0,0 +1,43 @@ +% ll-builder-remove 1 + +## NAME + +ll-builder-remove - Remove built applications + +## SYNOPSIS + +**ll-builder remove** [*options*] _package_ + +## DESCRIPTION + +The `ll-builder remove` command is used to remove built applications. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help + +**--no-clean-objects** +: Do not clean object files before removing application + +**package** (required) +: Application package name to be removed + +## EXAMPLES + +Remove specified application: + +```bash +ll-builder remove org.deepin.demo +``` + +## SEE ALSO + +**[ll-builder(1)](./ll-builder.md)**, **[ll-builder-list(1)](list.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-builder/repo.md b/docs/pages/en/guide/reference/commands/ll-builder/repo.md new file mode 100644 index 000000000..972f05412 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-builder/repo.md @@ -0,0 +1,102 @@ +% ll-builder-repo 1 + +## NAME + +ll-builder-repo - Display and manage repositories + +## SYNOPSIS + +**ll-builder repo** [*options*] _subcommand_ + +## DESCRIPTION + +The `ll-builder repo` command is used to display and manage Linyaps repositories. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help + +## SUBCOMMANDS + +**show** +: Display repository information + +**add** _name_ _url_ [*options*] +: Add new repository configuration + +**remove** _alias_ +: Remove repository configuration + +**update** _alias_ _url_ +: Update repository URL + +**set-default** _alias_ +: Set default repository name + +**enable-mirror** _alias_ +: Enable repository mirror + +**disable-mirror** _alias_ +: Disable repository mirror + +## EXAMPLES + +Display repository information: + +```bash +ll-builder repo show +``` + +Add a new repository: + +```bash +ll-builder repo add myrepo https://repo.example.com +``` + +Add repository with alias: + +```bash +ll-builder repo add myrepo https://repo.example.com --alias myalias +``` + +Remove repository: + +```bash +ll-builder repo remove myalias +``` + +Update repository URL: + +```bash +ll-builder repo update myalias https://new-repo.example.com +``` + +Set default repository: + +```bash +ll-builder repo set-default myalias +``` + +Enable repository mirror: + +```bash +ll-builder repo enable-mirror myalias +``` + +Disable repository mirror: + +```bash +ll-builder repo disable-mirror myalias +``` + +## SEE ALSO + +**[ll-builder(1)](./ll-builder.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-builder/run.md b/docs/pages/en/guide/reference/commands/ll-builder/run.md new file mode 100644 index 000000000..5a313c903 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-builder/run.md @@ -0,0 +1,80 @@ +% ll-builder-run 1 + +## NAME + +ll-builder-run - Run the built application + +## SYNOPSIS + +**ll-builder run** [*options*] [*command*...] + +## DESCRIPTION + +The `ll-builder run` command reads the runtime environment information related to the program based on the configuration file, constructs a container environment, and executes the program in the container without installation. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help + +**-f, --file** _file_ [./linglong.yaml] +: Path to the linglong.yaml file + +**--modules** _modules_... +: Run specified modules. For example: --modules binary,develop + +**--debug** +: Run in debug mode (enable development modules) + +**--extensions** _extensions_ +: Specify extensions used by the application at runtime + +**COMMAND** _TEXT_... +: Enter container to execute commands instead of running application + +## EXAMPLES + +### Basic Usage + +Run the built application, enter the project directory: + +```bash +ll-builder run +``` + +### Debug Mode + +For debugging purposes, you can enter the container to execute shell commands instead of running the application: + +```bash +ll-builder run /bin/bash +``` + +Using this command, `ll-builder` will create a container and then enter the `bash` terminal, allowing you to execute other operations within the container. + +### Run Specific Modules + +Run specified modules instead of the default binary module: + +```bash +ll-builder run --modules binary,develop +``` + +### Run Application with Extensions + +Run the application using specified extensions: + +```bash +ll-builder run --extensions org.deepin.extension1,org.deepin.extension2 +``` + +## SEE ALSO + +**[ll-builder(1)](./ll-builder.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-cli/content.md b/docs/pages/en/guide/reference/commands/ll-cli/content.md new file mode 100644 index 000000000..458298b07 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-cli/content.md @@ -0,0 +1,51 @@ +% ll-cli-content 1 + +## NAME + +ll\-cli\-content - Display application exported files + +## SYNOPSIS + +**ll-cli content** [*options*] _app_ + +## DESCRIPTION + +Use `ll-cli content` to display application exported files. This command is used to display the file paths exported by installed applications, including desktop files, metadata files, etc. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help + +## POSITIONAL ARGUMENTS + +**APP** _TEXT_ _REQUIRED_ +: Specify installed application name + +## EXAMPLES + +Use `ll-cli content org.dde.calendar` to display the exported files of the calendar application: + +```bash +ll-cli content org.dde.calendar +``` + +`ll-cli content org.dde.calendar` output as follows: + +```text +/var/lib/linglong/entries/share/applications +/var/lib/linglong/entries/share/applications/dde-calendar.desktop +/var/lib/linglong/entries/share/metainfo +/var/lib/linglong/entries/share/metainfo/org.deepin.calendar.metainfo.xml +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-info(1)](info.md)**, **[ll-cli-list(1)](list.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-cli/enter.md b/docs/pages/en/guide/reference/commands/ll-cli/enter.md new file mode 100644 index 000000000..1c2de70a5 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-cli/enter.md @@ -0,0 +1,79 @@ +% ll-cli-exec 1 + +## NAME + +ll\-cli\-exec - Execute commands in the currently running sandbox + +## SYNOPSIS + +**ll-cli enter** [*options*] _instance_ _command_... + +## DESCRIPTION + +The `ll-cli enter` command can enter the interior of a running container. This command allows users to execute specified commands in the running application container. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help information + +**--working-directory** _PATH:DIR_ +: Specify the working directory + +## POSITIONAL ARGUMENTS + +**INSTANCE** _TEXT_ _REQUIRED_ +: Specify the running application instance (can be obtained through the ps command) + +**COMMAND** _TEXT_... +: Run commands in the running sandbox + +## EXAMPLES + +Using `ll-cli enter` to enter the interior of a running container: + +1. Use `ll-cli ps` to get the running container ID: + +```bash +App ContainerID Pid +main:org.dde.calendar/5.14.5.0/x86_64 c3b5ce363172 539537 +``` + +2. Enter the `org.dde.calendar` container interior: + +```bash +ll-cli enter main:org.dde.calendar/5.14.5.0/x86_64 /bin/bash +``` + +`ls -l /` to view the root directory structure, output as follows: + +```text +lrwxrwxrwx 1 root root 8 Jul 27 20:58 bin -> /usr/bin +drwxr-xr-x 7 root root 420 Jul 27 20:58 dev +drwxr-xr-x 119 nobody nogroup 12288 Jul 27 20:37 etc +drwxr-xr-x 3 root root 60 Jul 27 20:58 home +lrwxrwxrwx 1 root root 8 Jul 27 20:58 lib -> /usr/lib +lrwxrwxrwx 1 root root 10 Jul 27 20:58 lib32 -> /usr/lib32 +lrwxrwxrwx 1 root root 10 Jul 27 20:58 lib64 -> /usr/lib64 +lrwxrwxrwx 1 root root 11 Jul 27 20:58 libx32 -> /usr/libx32 +drwxr-xr-x 2 root root 40 Jul 27 20:58 ll-host +drwxr-xr-x 3 root root 60 Jul 27 20:58 opt +dr-xr-xr-x 365 nobody nogroup 0 Jul 27 20:58 proc +drwxr-xr-x 6 root root 120 Jul 27 20:58 run +drwxr-xr-x 7 nobody nogroup 4096 Jan 1 1970 runtime +dr-xr-xr-x 13 nobody nogroup 0 Jul 21 16:43 sys +drwxr-xr-x 3 root root 4096 Jul 27 20:58 tmp +drwxr-xr-x 15 nobody nogroup 4096 Jun 30 16:22 usr +drwxr-xr-x 13 nobody nogroup 4096 Jun 30 16:23 var +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-ps(1)](ps.md)**, **[ll-cli-run(1)](run.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-cli/info.md b/docs/pages/en/guide/reference/commands/ll-cli/info.md new file mode 100644 index 000000000..049a399ed --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-cli/info.md @@ -0,0 +1,66 @@ +% ll-cli-info 1 + +## NAME + +ll\-cli\-info - Display information about installed applications or runtimes + +## SYNOPSIS + +**ll-cli info** [*options*] _app_ + +## DESCRIPTION + +Use `ll-cli info` to display information about installed applications or runtimes. This command shows detailed information about applications or runtimes in JSON format, including architecture, base environment, runtime, description, etc. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help + +## POSITIONAL ARGUMENTS + +**APP** _TEXT_ _REQUIRED_ +: Specify application name, can also be a Linyaps.layer file + +## EXAMPLES + +Use `ll-cli info` to display information about installed applications or runtimes: + +```bash +ll-cli info org.dde.calendar +``` + +`ll-cli info org.dde.calendar` output as follows: + +```text +{ + "arch": [ + "x86_64" + ], + "base": "main:org.deepin.base/23.1.0/x86_64", + "channel": "main", + "command": [ + "dde-calendar" + ], + "description": "calendar for deepin os.\n", + "id": "org.dde.calendar", + "kind": "app", + "module": "binary", + "name": "dde-calendar", + "runtime": "main:org.deepin.runtime.dtk/23.1.0/x86_64", + "schema_version": "1.0", + "size": 13483249, + "version": "5.14.5.1" +} +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-list(1)](list.md)**, **[ll-cli-content(1)](content.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-cli/install.md b/docs/pages/en/guide/reference/commands/ll-cli/install.md new file mode 100644 index 000000000..f8bb2b688 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-cli/install.md @@ -0,0 +1,84 @@ +% ll-cli-install 1 + +## NAME + +ll\-cli\-install - Install applications or runtimes + +## SYNOPSIS + +**ll-cli install** [*options*] _app_ + +## DESCRIPTION + +The `ll-cli install` command is used to install Linyaps applications. This command supports installing applications or runtimes through application names, .layer files, or .uab files. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help + +**--module** _MODULE_ +: Install specified module + +**--repo** _REPO_ +: Install from specified repository + +**--force** +: Force installation of specified application version + +**-y** +: Automatically answer yes to all questions + +## POSITIONAL ARGUMENTS + +**APP** _TEXT_ _REQUIRED_ +: Specify application name, can also be .uab or .layer file + +## EXAMPLES + +Install application through application name: + +```bash +ll-cli install org.deepin.demo +``` + +Install application through Linyaps .layer file: + +```bash +ll-cli install demo_0.0.0.1_x86_64_binary.layer +``` + +Install application through Linyaps .uab file: + +```bash +ll-cli install demo_x86_64_0.0.0.1_main.uab +``` + +Install specified module of application: + +```bash +ll-cli install org.deepin.demo --module=binary +``` + +Install specified version of application: + +```bash +ll-cli install org.deepin.demo/0.0.0.1 +``` + +Install application through specific identifier: + +```bash +ll-cli install stable:org.deepin.demo/0.0.0.1/x86_64 +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-uninstall(1)](uninstall.md)**, **[ll-cli-upgrade(1)](upgrade.md)**, **[ll-cli-list(1)](list.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-cli/kill.md b/docs/pages/en/guide/reference/commands/ll-cli/kill.md new file mode 100644 index 000000000..45520f912 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-cli/kill.md @@ -0,0 +1,45 @@ +% ll-cli-kill 1 + +## NAME + +ll\-cli\-kill - Stop running applications + +## SYNOPSIS + +**ll-cli kill** [*options*] _app_ + +## DESCRIPTION + +The `ll-cli kill` command can forcefully exit running Linyaps applications. This command is used to terminate running application processes. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help + +**-s, --signal** _SIGNAL_ [*SIGTERM*] +: Specify the signal to send to the application + +## POSITIONAL ARGUMENTS + +**APP** _TEXT_ _REQUIRED_ +: Specify the name of the running application + +## EXAMPLES + +Use the `ll-cli kill` command to forcefully exit running Linyaps applications: + +```bash +ll-cli kill org.deepin.calculator +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-ps(1)](ps.md)**, **[ll-cli-run(1)](run.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/ll-cli/list.md b/docs/pages/en/guide/reference/commands/ll-cli/list.md similarity index 53% rename from docs/pages/en/guide/ll-cli/list.md rename to docs/pages/en/guide/reference/commands/ll-cli/list.md index 248638c86..5e9f118cd 100644 --- a/docs/pages/en/guide/ll-cli/list.md +++ b/docs/pages/en/guide/reference/commands/ll-cli/list.md @@ -1,63 +1,54 @@ - +## NAME -# List Installed Apps +ll\-cli\-list - List installed applications or runtimes -Use `ll-cli list` to view the installed linyaps apps. +## SYNOPSIS -View the help information for the `ll-cli list` command: +**ll-cli list** [*options*] -```bash -ll-cli list --help -``` +## DESCRIPTION -Here is the output: +The `ll-cli list` command can view installed Linyaps applications. This command is used to display detailed information about installed applications, runtimes, and base environments in the system. -```text -List installed applications or runtimes -Usage: ll-cli list [OPTIONS] +## OPTIONS -Example: -# show installed application(s) -ll-cli list -# show installed runtime(s) -ll-cli list --type=runtime -# show the latest version list of the currently installed application(s) -ll-cli list --upgradable +**-h, --help** +: Print help information and exit -Options: - -h,--help Print this help message and exit - --help-all Expand all help - --type TYPE [app] Filter result with specify type. One of "runtime", "app" or "all" - --upgradable Show the list of latest version of the currently installed applications, it only works for app +**--help-all** +: Expand all help -If you found any problems during use, -You can report bugs to the linyaps team under this project: https://github.com/OpenAtom-Linyaps/linyaps/issues -``` +**--type** _TYPE_ [*all*] +: Filter results using specified type. One of "runtime", "base", "app", or "all" + +**--upgradable** +: Display the latest version list of currently installed applications, applicable only to applications + +## EXAMPLES -To view the installed apps, run `ll-cli list`: +View installed applications, run the `ll-cli list` command: ```bash ll-cli list ``` -Here is the output: +`ll-cli list` output as follows: ```text id name version arch channel module description org.dde.calendar dde-calendar 5.14.5.0 x86_64 main binary calendar for deepin os. org.deepin.browser deepin-browser 6.5.5.4 x86_64 main binary browser for deepin os. ``` -To view the installed runtime, run `ll-cli list --type=runtime`: + +View installed runtime environments, run the `ll-cli list --type=runtime` command: ```bash ll-cli list --type=runtime ``` -Here is the output: +Output as follows: ```text id name version arch channel module description @@ -67,12 +58,24 @@ org.deepin.Runtime deepin runtime 23.0.1.2 org.deepin.foundation deepin-foundation 23.0.0.27 x86_64 main runtime deepin base environment. ``` -To view the list of latest version of the currently installed applications, run `ll-cli list --upgradable`: +Display the latest version list of currently installed applications, applicable only to applications. Run `ll-cli list --upgradable`: + +```bash +ll-cli list --upgradable +``` -Here is the output: +`ll-cli list --upgradable` output as follows: ```text id installed new com.qq.wemeet.linyaps 3.19.2.402 3.19.2.403 org.dde.calendar 5.14.5.0 5.14.5.1 ``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-info(1)](info.md)**, **[ll-cli-search(1)](search.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-cli/ll-cli.md b/docs/pages/en/guide/reference/commands/ll-cli/ll-cli.md new file mode 100644 index 000000000..5e98e7c4f --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-cli/ll-cli.md @@ -0,0 +1,59 @@ +% ll-cli 1 + +## NAME + +ll\-cli - Linyaps command-line tool for managing applications and runtimes + +## SYNOPSIS + +**ll-cli** [*global-options*] _subcommand_ [*subcommand-options*] + +## DESCRIPTION + +ll-cli is a package manager frontend for managing Linyaps application installation, uninstallation, viewing, launching, termination, debugging, updating, and other operations. It provides complete application lifecycle management functionality. + +## GLOBAL OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help information + +**--version** +: Display version information + +**-v, --verbose** +: Show debug information (detailed logs) + +**--json** +: Output results in JSON format + +**--no-dbus** +: Use peer-to-peer D-Bus, only used when D-Bus daemon is unavailable (internal use) + +## COMMANDS + +| Command | Man Page | Description | +| --------- | ------------------------------------- | --------------------------------------------------------------------------------------- | +| run | [ll-cli-run(1)](./run.md) | Run applications | +| ps | [ll-cli-ps(1)](./ps.md) | List running applications | +| enter | [ll-cli-exec(1)](./enter.md) | Enter the namespace of a running application | +| kill | [ll-cli-kill(1)](./kill.md) | Stop running applications | +| prune | [ll-cli-prune(1)](./prune.md) | Remove unused base systems or runtimes | +| install | [ll-cli-install(1)](./install.md) | Install applications or runtimes | +| uninstall | [ll-cli-uninstall(1)](./uninstall.md) | Uninstall applications or runtimes | +| upgrade | [ll-cli-upgrade(1)](./upgrade.md) | Upgrade applications or runtimes | +| list | [ll-cli-list(1)](./list.md) | List installed applications or runtimes | +| info | [ll-cli-info(1)](./info.md) | Display information about installed applications or runtimes | +| content | [ll-cli-content(1)](./content.md) | Display exported files of installed applications | +| search | [ll-cli-search(1)](./search.md) | Search for applications/runtimes containing specified keywords from remote repositories | +| repo | [ll-cli-repo(1)](./repo.md) | Display or modify current repository information | + +## SEE ALSO + +**[ll-cli-run(1)](./run.md)**, **[ll-cli-ps(1)](./ps.md)**, **[ll-cli-exec(1)](./enter.md)**, **[ll-cli-kill(1)](./kill.md)**, **[ll-cli-prune(1)](./prune.md)**, **[ll-cli-install(1)](./install.md)**, **[ll-cli-uninstall(1)](./uninstall.md)**, **[ll-cli-upgrade(1)](./upgrade.md)**, **[ll-cli-list(1)](./list.md)**, **[ll-cli-info(1)](./info.md)**, **[ll-cli-content(1)](./content.md)**, **[ll-cli-search(1)](./search.md)**, **[ll-cli-repo(1)](./repo.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-cli/prune.md b/docs/pages/en/guide/reference/commands/ll-cli/prune.md new file mode 100644 index 000000000..383ae0dd9 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-cli/prune.md @@ -0,0 +1,49 @@ +% ll-cli-prune 1 + +## NAME + +ll\-cli\-prune - Remove unused minimal system or runtime + +## SYNOPSIS + +**ll-cli prune** [*options*] + +## DESCRIPTION + +Use `ll-cli prune` to remove unused minimal systems or runtimes. This command is used to clean up base environments or runtime components in the system that are no longer used by any applications, freeing up disk space. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help + +## EXAMPLES + +Use `ll-cli prune` to remove unused minimal systems or runtimes: + +```bash +ll-cli prune +``` + +`ll-cli prune` output as follows: + +```text +Unused base or runtime: +main:org.deepin.Runtime/23.0.1.2/x86_64 +main:org.deepin.foundation/20.0.0.27/x86_64 +main:org.deepin.Runtime/23.0.1.0/x86_64 +main:org.deepin.foundation/23.0.0.27/x86_64 +main:org.deepin.Runtime/20.0.0.8/x86_64 +5 unused base or runtime have been removed. +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-list(1)](./list.md)**, **[ll-cli-uninstall(1)](./uninstall.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-cli/ps.md b/docs/pages/en/guide/reference/commands/ll-cli/ps.md new file mode 100644 index 000000000..208cd1121 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-cli/ps.md @@ -0,0 +1,44 @@ +% ll-cli-ps 1 + +## NAME + +ll\-cli\-ps - List running applications + +## SYNOPSIS + +**ll-cli ps** [*options*] + +## DESCRIPTION + +The `ll-cli ps` command can view running Linyaps applications. This command displays all currently running Linyaps applications in the system and their related information. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help information + +## EXAMPLES + +To view running applications, run the `ll-cli ps` command: + +```bash +ll-cli ps +``` + +The `ll-cli ps` command output is as follows: + +```text +Application ContainerID ProcessID +org.dde.calendar 4e3407a8a052 1279610 +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-run(1)](run.md)**, **[ll-cli-kill(1)](kill.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-cli/repo.md b/docs/pages/en/guide/reference/commands/ll-cli/repo.md new file mode 100644 index 000000000..55b11eb9d --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-cli/repo.md @@ -0,0 +1,191 @@ +% ll-cli-repo 1 + +## NAME + +ll\-cli\-repo - Display or modify current repository information + +## SYNOPSIS + +**ll-cli repo** _subcommand_ [*options*] + +## DESCRIPTION + +The `ll-cli repo` command is used to manage remote repositories. This command provides a series of subcommands to add, modify, delete, display, and configure repository information. + +## SUBCOMMANDS + +### add + +Add a new repository. + +**Usage**: `ll-cli repo add [OPTIONS] NAME URL` + +**Parameters**: + +- **NAME** _TEXT_ _REQUIRED_: Specify repository name +- **URL** _TEXT_ _REQUIRED_: Repository URL address +- **--alias** _ALIAS_: Repository name alias + +**Examples**: + +```bash +ll-cli repo add myrepo https://repo.example.com +``` + +### remove + +Remove a repository. + +**Usage**: `ll-cli repo remove [OPTIONS] NAME` + +**Parameters**: + +- **ALIAS** _TEXT_ _REQUIRED_: Repository name alias + +**Examples**: + +```bash +ll-cli repo remove myrepo +``` + +### update + +Update repository URL. + +**Usage**: `ll-cli repo update [OPTIONS] NAME URL` + +**Parameters**: + +- **ALIAS** _TEXT_ _REQUIRED_: Repository name alias +- **URL** _TEXT_ _REQUIRED_: New repository URL address + +**Examples**: + +```bash +ll-cli repo update myrepo https://updated-repo.example.com +``` + +### set-default + +Set default repository name. + +**Usage**: `ll-cli repo set-default [OPTIONS] NAME` + +**Parameters**: + +- **Alias** _TEXT_ _REQUIRED_: Repository name alias + +**Examples**: + +```bash +ll-cli repo set-default myrepo +``` + +### show + +Display repository information. + +**Usage**: `ll-cli repo show [OPTIONS]` + +**Examples**: + +```bash +ll-cli repo show +``` + +### set-priority + +Set repository priority. + +**Usage**: `ll-cli repo set-priority ALIAS PRIORITY` + +**Parameters**: + +- **ALIAS** _TEXT_ _REQUIRED_: Repository name alias +- **PRIORITY** _TEXT_ _REQUIRED_: Repository priority + +**Examples**: + +```bash +ll-cli repo set-priority myrepo 100 +``` + +### enable-mirror + +Enable mirror for repository. + +**Usage**: `ll-cli repo enable-mirror [OPTIONS] ALIAS` + +**Parameters**: + +- **ALIAS** _TEXT_ _REQUIRED_: Repository name alias + +**Examples**: + +```bash +ll-cli repo enable-mirror myrepo +``` + +### disable-mirror + +Disable mirror for repository. + +**Usage**: `ll-cli repo disable-mirror [OPTIONS] ALIAS` + +**Parameters**: + +- **ALIAS** _TEXT_ _REQUIRED_: Repository name alias + +**Examples**: + +```bash +ll-cli repo disable-mirror myrepo +``` + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help + +## EXAMPLES + +Display all repository information: + +```bash +ll-cli repo show +``` + +Add a new repository: + +```bash +ll-cli repo add deepin https://repo.deepin.com +``` + +Update repository URL: + +```bash +ll-cli repo update deepin https://new-repo.deepin.com +``` + +Set repository priority: + +```bash +ll-cli repo set-priority deepin 50 +``` + +Remove a repository: + +```bash +ll-cli repo remove deepin +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-search(1)](./search.md)**, **[ll-cli-install(1)](./install.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-cli/run.md b/docs/pages/en/guide/reference/commands/ll-cli/run.md new file mode 100644 index 000000000..f662941f6 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-cli/run.md @@ -0,0 +1,71 @@ +% ll-cli-run 1 + +## NAME + +ll\-cli\-run - Run applications + +## SYNOPSIS + +**ll-cli run** [*options*] _app_ [*command*...] + +## DESCRIPTION + +The `ll-cli run` command can start a Linyaps application. This command supports running applications by name, or executing commands in the container instead of running the application. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help information + +**--file** _FILES:FILE_... +: Pass files to the application running in the sandbox + +**--url** _URLS_... +: Pass URLs to the application running in the sandbox + +**--env** _ENV_... +: Set environment variables for the application (format: KEY=VALUE) + +**--base** _REF_ +: Specify the base environment used for application execution + +**--runtime** _REF_ +: Specify the runtime used for application execution + +**--extensions** _REF_... +: Specify extensions used for application execution (multiple extensions separated by commas) + +## POSITIONAL ARGUMENTS + +**APP** _TEXT_ _REQUIRED_ +: Specify the application name + +**COMMAND** _TEXT_... +: Run commands in the running sandbox + +## EXAMPLES + +Run application by name: + +```bash +ll-cli run org.deepin.demo +``` + +Execute commands in the container instead of running the application: + +```bash +ll-cli run org.deepin.demo bash +ll-cli run org.deepin.demo -- bash +ll-cli run org.deepin.demo -- bash -x /path/to/bash/script +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-ps(1)](./ps.md)**, **[ll-cli-exec(1)](./enter.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-cli/search.md b/docs/pages/en/guide/reference/commands/ll-cli/search.md new file mode 100644 index 000000000..497f96977 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-cli/search.md @@ -0,0 +1,117 @@ +% ll-cli-search 1 + +## NAME + +ll\-cli\-search - Search for applications/runtimes containing specified keywords from remote repositories + +## SYNOPSIS + +**ll-cli search** [*options*] _keywords_ + +## DESCRIPTION + +The `ll-cli search` command can query application information from Linyaps remote repositories. This command is used to search for applications, runtimes, or base environments containing specified keywords from remote repositories. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help + +**--type** _TYPE_ [*all*] +: Filter results by specified type. Available types: "runtime", "base", "app", or "all". + +**--repo** _REPO_ +: Specify repository + +**--dev** +: Include application debug packages in results + +**--show-all-version** +: Show all versions of applications, base, or runtime + +## POSITIONAL ARGUMENTS + +**KEYWORDS** _TEXT_ _REQUIRED_ +: Specify search keywords + +## EXAMPLES + +Use the `ll-cli search` command to find application information from remote repositories: + +```bash +ll-cli search calculator +``` + +This command will return all application information containing the calculator keyword, including complete `appid`, application name, version, platform, and application description information. + +`ll-cli search calculator` output as follows: + +```text +ID Name Version Channel Module Repository Description +com.bixense.passwordcalculator com.bixense.passwordcalculator 1.1.0.0 main binary nightly flatpak runtime environment on linglong +com.expidusos.calculator com.expidusos.calculator 0.1.1.0 main binary nightly flatpak runtime environment on linglong +dev.edfloreshz.calculator dev.edfloreshz.calculator 0.1.1.0 main binary nightly flatpak runtime environment on linglong +io.github.deaen.awesomecalculator io.github.deaen.awesomecalculator 2.2.0.0 main binary nightly flatpak runtime environment on linglong +org.deepin.calculator deepin-calculator 6.5.26.1 main binary nightly Calculator for UOS +org.gnome.calculator org.gnome.calculator 48.1.0.0 main binary nightly flatpak runtime environment on linglong +uno.platform.uno-calculator uno.platform.uno-calculator 1.2.9.0 main binary nightly flatpak runtime environment on linglong +com.github.matrix-calculator.linyaps com.github.matrix-calculator 3.3.0.0 main runtime stable convert from 3.3 build uos https://chinauos.com \Pyth... +com.github.thatonecalculator.discordrpcmaker discordrpcmaker 2.1.1.0 main binary stable The best way to create and manage custom Discord rich presence with buttons! +com.poki.true-love-calculator True Love Calculator 34.4.1.20250423 main binary stable True Love Calculator is an online mini-game provided ... +com.poki.your-love-calculator Your Love Calculator 34.4.1.20250423 main binary stable Your Love Calculator is an online mini-game provided ... +dev.edfloreshz.calculator dev.edfloreshz.calculator 0.1.1.0 main binary stable flatpak runtime environment on linglong +io.github.Calculator Calculator 0.0.1.1 main runtime stable C++ GUI Calculator app. +io.github.Huawei_modem_calculator_v2 Huawei_modem_calculator_v2 1.0.0.0 main runtime stable Is it Huawei modem unlock code calculator from forth3... +io.github.QT_GraphingCalculator QT_GraphingCalculator 0.0.1.0 main runtime stable Graphing calculator using QT and QTcustomplot +io.github.Qt-calculator Qt-calculator 1.0.0.0 main runtime stable A simple GUI calculator🧮 built using C++. +io.github.SolarCalculator SolarCalculator 1.0.0.0 main runtime stable Small app to calculate sunrise and sunset based on da... +io.github.StringCalculator StringCalculator 0.0.1.0 main runtime stable Full-featured calculator written in C++ with Qt frame... +io.github.cupcalculator cupcalculator 1.1.2.0 main runtime stable A program which calculates scorings from orienteering... +io.github.cyber-calculator cyber-calculator 1.0.0.0 main runtime stable CyberOS Calculator. +io.github.euduardop.faultcalculator-app io.github.euduardop.faultcalc... 31.7.24.0 main binary stable appimage convert +io.github.galaxy-calculator galaxy-calculator 0.0.2.0 main runtime stable Galaxy Calculator: Given the size of the Galaxy you c... +io.github.johannesboehler2.BmiCalculator io.github.johannesboehler2.Bm... 1.3.1.0 main binary stable Calculate your body mass index from weight, height an... +org.deepin.calculator deepin-calculator 6.5.26.1 main binary stable Calculator for UOS +uno.platform.uno-calculator uno.platform.uno-calculator 1.2.9.0 main binary stable flatpak runtime environment on linglong +``` + +If you need to find all remote base environments, you can use the following command: + +```bash +ll-cli search . --type=base +``` + +If you need to find all remote runtimes, you can use the following command: + +```bash +ll-cli search . --type=runtime +``` + +Search for remote base by name: + +```bash +ll-cli search org.deepin.base --type=base +``` + +Search for remote runtime by name: + +```bash +ll-cli search org.deepin.runtime.dtk --type=runtime +``` + +Search for all remote packages: + +```bash +ll-cli search . +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-list(1)](./list.md)**, **[ll-cli-install(1)](./install.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-cli/uninstall.md b/docs/pages/en/guide/reference/commands/ll-cli/uninstall.md new file mode 100644 index 000000000..2624e85a3 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-cli/uninstall.md @@ -0,0 +1,53 @@ +% ll-cli-uninstall 1 + +## NAME + +ll\-cli\-uninstall - Uninstall applications or runtimes + +## SYNOPSIS + +**ll-cli uninstall** [*options*] _app_ + +## DESCRIPTION + +The `ll-cli uninstall` command can uninstall Linyaps applications. This command is used to remove installed applications from the system. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help + +**--module** _MODULE_ +: Uninstall specified module + +## POSITIONAL ARGUMENTS + +**APP** _TEXT_ _REQUIRED_ +: Specify application name + +## EXAMPLES + +Use the `ll-cli uninstall` command to uninstall Linyaps applications: + +```bash +ll-cli uninstall org.deepin.calculator +``` + +Output as follows: + +```text +Uninstall main:org.deepin.calculator/5.7.21.4/x86_64 success:100% +``` + +After the command executes successfully, the Linyaps application will be removed from the system. + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-install(1)](./install.md)**, **[ll-cli-list(1)](./list.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-cli/upgrade.md b/docs/pages/en/guide/reference/commands/ll-cli/upgrade.md new file mode 100644 index 000000000..a8536e797 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-cli/upgrade.md @@ -0,0 +1,63 @@ +% ll-cli-upgrade 1 + +## NAME + +ll\-cli\-upgrade - Upgrade applications or runtimes + +## SYNOPSIS + +**ll-cli upgrade** [*options*] [*app*] + +## DESCRIPTION + +The `ll-cli upgrade` command can update Linyaps applications. This command is used to upgrade installed applications or runtimes to the latest version in the remote repository. + +## OPTIONS + +**-h, --help** +: Print help information and exit + +**--help-all** +: Expand all help + +## POSITIONAL ARGUMENTS + +**APP** _TEXT_ +: Specify application name. If not specified, all upgradeable applications will be upgraded + +## EXAMPLES + +Use `ll-cli upgrade` to upgrade all installed applications to the latest version: + +```bash +ll-cli upgrade +``` + +Output as follows: + +```text +Upgrade main:org.dde.calendar/5.14.5.0/x86_64 to main:org.dde.calendar/5.14.5.1/x86_64 success:100% +Upgrade main:org.deepin.mail/6.4.10.0/x86_64 to main:org.deepin.mail/6.4.10.1/x86_64 success:100% +Please restart the application after saving the data to experience the new version. +``` + +Use `ll-cli upgrade org.deepin.calculator` to upgrade the org.deepin.calculator application to the latest version in the remote repository: + +```bash +ll-cli upgrade org.deepin.calculator +``` + +Output as follows: + +```text +Upgrade main:org.deepin.calculator/5.7.21.3/x86_64 to main:org.deepin.calculator/5.7.21.4/x86_64 success:100% +Please restart the application after saving the data to experience the new version. +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-install(1)](./install.md)**, **[ll-cli-list(1)](./list.md)** + +## HISTORY + +Developed in 2023 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-pica-flatpak/ll-pica-flatpak-convert.md b/docs/pages/en/guide/reference/commands/ll-pica-flatpak/ll-pica-flatpak-convert.md new file mode 100644 index 000000000..30523f605 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-pica-flatpak/ll-pica-flatpak-convert.md @@ -0,0 +1,66 @@ +% ll-pica-flatpak-convert 1 + +## NAME + +ll\-pica\-flatpak\-convert - Convert Flatpak applications to Linyaps applications + +## SYNOPSIS + +**ll-pica-flatpak convert** [*flags*] + +## DESCRIPTION + +The ll-pica-flatpak convert command is used to convert Flatpak applications to Linyaps applications. This command uses the ostree command to pull Flatpak application data and generates the corresponding Linyaps base environment based on the runtime defined in the metadata. + +By default, the converted application generates a uab file. To convert to a layer file, you need to add the --layer parameter. + +## OPTIONS + +**--build** +: Build Linyaps package + +**--layer** +: Export layer file + +**--version** _string_ +: Specify the version of the generated Linyaps application + +**--base** _string_ +: Specify the base environment of the Linyaps application + +**--base-version** _string_ +: Specify the base version of the Linyaps application + +## EXAMPLES + +Convert Flatpak application org.videolan.VLC: + +```bash +ll-pica-flatpak convert org.videolan.VLC --build +``` + +Convert application and generate layer file: + +```bash +ll-pica-flatpak convert org.videolan.VLC --build --layer +``` + +Specify the version of the generated Linyaps application: + +```bash +ll-pica-flatpak convert org.videolan.VLC --version "1.0.0.0" --build --layer +``` + +Specify the base environment and version of the Linyaps application: + +```bash +ll-pica-flatpak convert org.videolan.VLC --base "org.deepin.base.flatpak.kde" --base-version "6.7.0.2" --build --layer +``` + +## SEE ALSO + +**[ll-pica-flatpak(1)](ll-pica-flatpak.md)**, **[ll-builder(1)](../ll-builder/ll-builder.md)** + +## HISTORY + +Developed in 2024 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-pica-flatpak/ll-pica-flatpak.md b/docs/pages/en/guide/reference/commands/ll-pica-flatpak/ll-pica-flatpak.md new file mode 100644 index 000000000..7b2d5cf00 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-pica-flatpak/ll-pica-flatpak.md @@ -0,0 +1,29 @@ +% ll-pica-flatpak 1 + +## NAME + +ll\-pica\-flatpak - Convert Flatpak applications to Linyaps applications + +## SYNOPSIS + +**ll-pica-flatpak** _subcommand_ + +## DESCRIPTION + +The ll-pica-flatpak command is used to convert Flatpak applications to Linyaps applications. This tool uses the ostree command to pull Flatpak application data, generates the corresponding Linyaps base environment based on the runtime defined in the metadata, and generates the linglong.yaml file needed to build Linyaps applications. + +Note: The conversion tool is only an auxiliary tool and cannot guarantee that the converted application will definitely run. The installation path of the software's dependent libraries or other configuration paths may not be consistent with the internal paths of Linyaps, resulting in the inability to run. You need to use the `ll-builder run --exec bash` command to enter the container for debugging. + +## COMMANDS + +| Command | Man Page | Description | +| ------- | -------------------------------------------------------- | ---------------------------------------------------- | +| convert | [ll-pica-flatpak-convert(1)](ll-pica-flatpak-convert.md) | Convert Flatpak applications to Linyaps applications | + +## SEE ALSO + +**[ll-builder(1)](../ll-builder/ll-builder.md)**, **[ll-pica-flatpak-convert(1)](ll-pica-flatpak-convert.md)** + +## HISTORY + +Developed in 2024 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-pica/ll-pica-adep.md b/docs/pages/en/guide/reference/commands/ll-pica/ll-pica-adep.md new file mode 100644 index 000000000..f226b143e --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-pica/ll-pica-adep.md @@ -0,0 +1,46 @@ +% ll-pica-adep 1 + +## NAME + +ll\-pica\-adep - Add package dependencies to linglong.yaml file + +## SYNOPSIS + +**ll-pica adep** [*flags*] + +## DESCRIPTION + +The ll-pica adep command is used to add package dependencies to the linglong.yaml file. Linyaps applications may lack package dependencies, and this command can be used to add corresponding package dependencies to the linglong.yaml file. + +## OPTIONS + +**-d, --deps** _string_ +: Dependencies to be added, separated by ',' + +**-p, --path** _string_ +: Path to linglong.yaml (defaults to "linglong.yaml") + +**-V, --verbose** +: Verbose output + +## EXAMPLES + +Add multiple dependencies: + +```bash +ll-pica adep -d "dep1,dep2" -p /path/to/linglong.yaml +``` + +Execute in the path where linglong.yaml is located (no need to add -p parameter): + +```bash +ll-pica adep -d "dep1,dep2" +``` + +## SEE ALSO + +**[ll-pica(1)](ll-pica.md)** + +## HISTORY + +Developed in 2024 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-pica/ll-pica-convert.md b/docs/pages/en/guide/reference/commands/ll-pica/ll-pica-convert.md new file mode 100644 index 000000000..a01c66998 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-pica/ll-pica-convert.md @@ -0,0 +1,68 @@ +% ll-pica-convert 1 + +## NAME + +ll\-pica\-convert - Convert deb packages to Linyaps packages + +## SYNOPSIS + +**ll-pica convert** [*flags*] + +## DESCRIPTION + +The ll-pica convert command is used to generate the linglong.yaml file needed by Linyaps and convert deb packages to Linyaps packages. This command supports converting from local deb files or downloading deb packages from repositories through the apt download command. + +## OPTIONS + +**-b, --build** +: Build Linyaps package + +**-c, --config** _string_ +: Configuration file + +**--exportFile** _string_ +: Export uab or layer (defaults to "uab") + +**--pi** _string_ +: Package ID + +**--pn** _string_ +: Package name + +**-t, --type** _string_ +: Get application type (defaults to "local") + +**--withDep** +: Add dependency tree + +**-w, --workdir** _string_ +: Working directory + +**-V, --verbose** +: Verbose output + +## EXAMPLES + +Download deb package from repository and convert: + +```bash +ll-pica init -w w --pi com.baidu.baidunetdisk --pn com.baidu.baidunetdisk -t repo +``` + +```bash +ll-pica convert -w w -b --exportFile +``` + +Convert from local deb file: + +```bash +ll-pica convert -c com.baidu.baidunetdisk_4.17.7_amd64.deb -w w -b --exportFile layer +``` + +## SEE ALSO + +**[ll-pica(1)](ll-pica.md)**, **[ll-cli(1)](ll-pica-init.md)** + +## HISTORY + +Developed in 2024 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-pica/ll-pica-init.md b/docs/pages/en/guide/reference/commands/ll-pica/ll-pica-init.md new file mode 100644 index 000000000..88e92e8f2 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-pica/ll-pica-init.md @@ -0,0 +1,77 @@ +% ll-pica-init 1 + +## NAME + +ll\-pica\-init - Initialize conversion package configuration information + +## SYNOPSIS + +**ll-pica init** [*flags*] + +## DESCRIPTION + +The ll-pica init command is used to initialize conversion package configuration information. This command reads the ~/.pica/config.json file to generate the package.yaml configuration file, which contains basic information for ll-pica to convert deb packages, including the base and runtime versions for building, as well as the deb package information to be converted. + +## OPTIONS + +**-a, --arch** _string_ +: Runtime architecture + +**-c, --config** _string_ +: Configuration file + +**--dv** _string_ +: Distribution version + +**--pi** _string_ +: Package ID + +**--pn** _string_ +: Package name + +**-s, --source** _string_ +: Runtime source + +**-t, --type** _string_ +: Acquisition type + +**-v, --version** _string_ +: Runtime version + +**-w, --workdir** _string_ +: Working directory + +**-V, --verbose** +: Verbose output + +## EXAMPLES + +Get package information from repository: + +```bash +ll-pica init -w w --pi com.baidu.baidunetdisk --pn com.baidu.baidunetdisk -t repo +``` + +Specify UOS 20 version as BASE and RUNTIME: + +```bash +ll-pica init --rv "20.0.0" --bv "20.0.0" -s "https://professional-packages.chinauos.com/desktop-professional" --dv "eagle/1070" +``` + +Use on arm64 architecture: + +```bash +ll-pica init -a "arm64" +``` + +## NOTES + +After the package.yaml file is generated, users can modify it as needed. For detailed fields, refer to: [Conversion Configuration File Introduction](./ll-pica-manifests.md). + +## SEE ALSO + +**[ll-pica(1)](ll-pica.md)**, **[ll-builder(1)](ll-pica-convert.md)** + +## HISTORY + +Developed in 2024 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/commands/ll-pica/ll-pica-manifests.md b/docs/pages/en/guide/reference/commands/ll-pica/ll-pica-manifests.md new file mode 100644 index 000000000..7d83fcde1 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-pica/ll-pica-manifests.md @@ -0,0 +1,57 @@ +# Conversion Configuration File Introduction + +`package.yaml` is the basic information file for `ll-pica` to convert deb packages. It contains information such as the base and runtime versions to be built, and the deb packages that need to be converted. + +## Project Directory Structure + +```bash +{workdir} +├── package +│ └── {appid} +│ ├── linglong +│ ├── linglong.yaml +│ └── start.sh +└── package.yaml +``` + +## Field Definitions + +### Build Environment + +The build environment for converting deb packages to Linglong packages. + +```bash +runtime: + version: 23.0.1 + base_version: 23.0.0 + source: https://community-packages.deepin.com/beige/ + distro_version: beige + arch: amd64 +``` + +| Name | Description | +| -------------- | ------------------------------------------------------------------------- | +| runtime | Runtime environment | +| version | Runtime version, three-digit version can fuzzy match the fourth digit | +| base_version | Base version number, three-digit version can fuzzy match the fourth digit | +| source | Source used when obtaining deb package dependencies | +| distro_version | Distribution code name | +| arch | Architecture required for obtaining deb packages | + +### Deb Package Information + +```bash +file: + deb: + - type: local + id: com.baidu.baidunetdisk + name: com.baidu.baidunetdisk + ref: /tmp/com.baidu.baidunetdisk_4.17.7_amd64.deb +``` + +| Name | Description | +| ---- | ---------------------------------------------------------------------------------------- | +| type | Acquisition method, local requires specifying ref, repo does not require specifying ref. | +| id | Unique name of the build product | +| name | Specify the correct package name that apt can search for | +| ref | Path of the deb package on the host machine | diff --git a/docs/pages/en/guide/reference/commands/ll-pica/ll-pica.md b/docs/pages/en/guide/reference/commands/ll-pica/ll-pica.md new file mode 100644 index 000000000..0cd3f3f68 --- /dev/null +++ b/docs/pages/en/guide/reference/commands/ll-pica/ll-pica.md @@ -0,0 +1,38 @@ +% ll-pica 1 + +## NAME + +ll\-pica - Tool for converting deb packages to Linyaps packages + +## SYNOPSIS + +**ll-pica** _subcommand_ + +## DESCRIPTION + +The ll-pica command provides the ability to convert deb packages to Linyaps packages, generating the linglong.yaml file needed to build Linyaps applications, and relies on ll-builder to implement application building and export. Currently, it only supports converting software packages that comply with application store packaging specifications. + +Note: The conversion tool is only an auxiliary tool and cannot guarantee that the converted application will definitely run. The installation path of the software's dependent libraries or other configuration paths may not be consistent with the internal paths of Linyaps, resulting in the inability to run. You need to use the `ll-builder run --exec bash` command to enter the container for debugging. + +The following situations are likely to fail to run successfully: + +- Android, input method, and security software cannot be converted +- Software packages use preinst, postinst, prerm, postrm scripts +- Need to read configuration files with fixed paths +- Need to obtain root privileges + +## COMMANDS + +| Command | Man Page | Description | +| ------- | ---------------------------------------- | ------------------------------------------------------- | +| adep | [ll-pica-adep(1)](ll-pica-adep.md) | Add package dependencies to linglong.yaml file | +| convert | [ll-pica-convert(1)](ll-pica-convert.md) | Convert deb packages to Linyaps packages | +| init | [ll-pica-init(1)](ll-pica-init.md) | Initialize conversion package configuration information | + +## SEE ALSO + +**[ll-builder(1)](../ll-builder/ll-builder.md)**, **[ll-pica-adep(1)](ll-pica-adep.md)**, **[ll-pica-convert(1)](ll-pica-convert.md)**, **[ll-pica-init(1)](ll-pica-init.md)** + +## HISTORY + +Developed in 2024 by UnionTech Software Technology Co., Ltd. diff --git a/docs/pages/en/guide/reference/driver.md b/docs/pages/en/guide/reference/driver.md new file mode 100644 index 000000000..c58dc3675 --- /dev/null +++ b/docs/pages/en/guide/reference/driver.md @@ -0,0 +1,25 @@ +# Linyaps Graphics Driver Guide + +The Linyaps runtime environment is isolated from the host system environment. When running Linyaps applications that require graphics hardware acceleration, two conditions must be met: + +1. The host system must have the graphics drivers properly installed and configured. +2. The corresponding driver packages must be installed in the Linyaps environment. + +## Supported Graphics Drivers List + +### Mesa Open Source Drivers + +The base that applications depend on already includes the appropriate version of Mesa, so no additional installation is required. Mesa open source drivers include: + +- amdgpu: The new AMD graphics driver. +- intel: Intel graphics driver. +- nouveau: The open source NVIDIA graphics driver. +- radeon: The legacy AMD/ATI graphics driver. + +### Other Drivers + +Drivers not included in the base that require additional installation: + +- NVIDIA proprietary drivers: Install via `sudo ll-cli install org.deepin.driver.display.nvidia.570-124-04`. The `570-124-04` is the driver version number, which must match the driver version installed on the host system. Check the host driver version through the `/sys/module/nvidia/version` file. If the extension is not installed, linyaps will attempt to link NVIDIA driver files from the host at runtime. +- Glenfly graphics drivers: Install via `sudo ll-cli install com.glenfly.driver.display.arise`. +- Intel video codec drivers (VAAPI): Install via `sudo ll-cli install org.deepin.driver.media.intel`, which includes support for both new and legacy Intel graphics cards. diff --git a/docs/pages/en/guide/reference/runtime.md b/docs/pages/en/guide/reference/runtime.md new file mode 100644 index 000000000..c0fc92592 --- /dev/null +++ b/docs/pages/en/guide/reference/runtime.md @@ -0,0 +1,172 @@ +# Base and Runtime Introduction + +In the Linyaps application packaging system, base provides the fundamental runtime environment, while runtime provides application framework support. Both use a hierarchical dependency relationship. Proper selection ensures cross-distribution compatibility for applications. The following selection principles are recommended: + + **Base Priority Principle**: First select the base corresponding to the distribution that the application has been adapted for + **Runtime Inheritance Principle**: Runtime must remain compatible with base + +This document will provide detailed information about base and runtime to help developers choose appropriate base and runtime components. + +_Base and runtime version numbers follow the "major.minor.patch.build" specification. Only the first three version numbers need to be specified when using._ + +## Base Introduction + +Linyaps base provides the most fundamental runtime environment, containing core operating system components (such as glibc, bash, and other basic toolchains). +As a containerized "minimal system image", it ensures applications maintain consistent underlying dependencies across different distributions. Base is typically maintained by the Linyaps official team, and developers can directly reference it without worrying about compatibility issues when applications run on different distributions. + +The following stable versions are recommended. Bases not listed in the documentation are generally experimental versions and are not recommended for use. For more detailed information, see [Base List](#base-list) + + + + + + + + + + + + + + + + + + + + + + + + +
baserepositorystatus
org.deepin.base/25.2.0deepin 25testing phase
org.deepin.base/23.1.0deepin 23maintenance phase
org.deepin.foundation/20.0.0uos 20end of support
+ +## Runtime Introduction + +Linyaps runtime provides the specific runtime environment required by applications (such as DTK/Wine/GNOME framework libraries). Developers can choose appropriate runtime based on application requirements, and Linyaps official team also provides various pre-compiled runtime images for developers to choose from. Currently, applications can only use one runtime, so runtime may contain multiple environments. For example, DTK runtime includes the QT framework, and Wine runtime includes the DTK framework. _Applications can also choose not to use runtime_ + +The following stable runtimes are officially maintained. Runtimes not listed in the documentation are generally experimental versions and are not recommended for use. For more detailed information, see [Runtime List](#runtime-list) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
runtimebasedescription
org.deepin.runtime.dtk/25.2.0org.deepin.base/25.2.0includes QT6 and DTK6
org.deepin.runtime.webengine/25.2.0org.deepin.base/25.2.0includes QT6, QT6 webengine, and DTK6
org.deepin.Runtime/23.1.0org.deepin.base/23.1.0includes QT5 and DTK5
org.deepin.Runtime/20.0.0org.deepin.foundation/20.0.0includes QT5 and DTK5
+ +## base 列表 + +### org.deepin.foundation/20.0.0 + +使用 uos 1070 仓库制作的 base,支持 x86, arm64, loongarch64 三个架构。 + +_在容器中执行 `cat /var/lib/dpkg/status|grep "^Package: "|sort|awk '{print $2}'` 查看包列表_ + +``` +adduser adwaita-icon-theme apt base-files base-passwd bash bsdutils ca-certificates coreutils dash dbus dbus-user-session dconf-gsettings-backend dconf-service debconf debianutils deepin-desktop-base deepin-elf-verify deepin-keyring diffutils distro-info-data dlnfs dmsetup dpkg e2fsprogs eject fdisk findutils fontconfig fontconfig-config fonts-dejavu-core fonts-noto fonts-noto-core fonts-symbola fuse3 gcc-8-base glib-networking glib-networking-common glib-networking-services gpgv grep gsettings-desktop-schemas gtk-update-icon-cache gzip hicolor-icon-theme hostname init-system-helpers libacl1 libapparmor1 libapt-pkg5.0 libargon2-1 libasound2 libasound2-data libatk1.0-0 libatk1.0-data libatk-bridge2.0-0 libatomic1 libatspi2.0-0 libattr1 libaudit1 libaudit-common libavahi-client3 libavahi-common3 libavahi-common-data libblkid1 libbsd0 libbz2-1.0 libc6 libc6-dev libcairo2 libcairo-gobject2 libcap2 libcap-ng0 libc-bin libc-dev-bin libcolord2 libcom-err2 libcroco3 libcryptsetup12 libcups2 libcupsimage2 libdatrie1 libdb5.3 libdbus-1-3 libdconf1 libdebconfclient0 libdevmapper1.02.1 libdrm2 libdrm-amdgpu1 libdrm-common libdrm-intel1 libdrm-nouveau2 libdrm-radeon1 libedit2 libegl1 libegl1-mesa libegl-mesa0 libelf1 libepoxy0 libexpat1 libext2fs2 libfdisk1 libffi6 libfontconfig1 libfreetype6 libfribidi0 libfuse3-3 libgbm1 libgcc1 libgcrypt20 libgdk-pixbuf2.0-0 libgdk-pixbuf2.0-common libgl1 libgl1-mesa-dri libglapi-mesa libglib2.0-0 libglu1-mesa libglvnd0 libglx0 libglx-mesa0 libgmp10 libgnutls30 libgomp1 libgpg-error0 libgraphite2-3 libgssapi-krb5-2 libgtk2.0-0 libgtk2.0-common libgtk-3-0 libgtk-3-common libharfbuzz0b libhogweed4 libice6 libicu63 libidn11 libidn2-0 libip4tc0 libjbig0 libjpeg62-turbo libjson-c3 libjson-glib-1.0-0 libjson-glib-1.0-common libk5crypto3 libkeyutils1 libkmod2 libkrb5-3 libkrb5support0 liblcms2-2 libllvm7 liblocale-gettext-perl liblz4-1 liblzma5 libmagic1 libmagic-mgc libmount1 libncursesw6 libnettle6 libnspr4 libnss3 libopengl0 libp11-kit0 libpam0g libpam-deepin-security libpam-modules libpam-modules-bin libpam-runtime libpam-systemd libpango-1.0-0 libpango1.0-0 libpangocairo-1.0-0 libpangoft2-1.0-0 libpangox-1.0-0 libpangoxft-1.0-0 libpciaccess0 libpcre16-3 libpcre3 libpcre32-3 libpcsclite1 libpixman-1-0 libpng16-16 libproxy1v5 libpsl5 librest-0.7-0 librsvg2-2 librsvg2-common libseccomp2 libselinux1 libsemanage1 libsemanage-common libsensors5 libsensors-config libsepol1 libsm6 libsmartcols1 libsoup2.4-1 libsoup-gnome2.4-1 libsqlite3-0 libss2 libssl1.1 libstdc++6 libsystemd0 libtasn1-6 libtext-charwidth-perl libtext-iconv-perl libtext-wrapi18n-perl libthai0 libthai-data libtiff5 libtinfo6 libudev1 libunistring2 libuuid1 libwayland-client0 libwayland-cursor0 libwayland-egl1 libwayland-egl1-mesa libwayland-server0 libwebp6 libx11-6 libx11-data libx11-xcb1 libxau6 libxcb1 libxcb-composite0 libxcb-damage0 libxcb-doc libxcb-dpms0 libxcb-dri2-0 libxcb-dri3-0 libxcb-glx0 libxcb-present0 libxcb-randr0 libxcb-record0 libxcb-render0 libxcb-res0 libxcb-screensaver0 libxcb-shape0 libxcb-shm0 libxcb-sync1 libxcb-xf86dri0 libxcb-xfixes0 libxcb-xinerama0 libxcb-xinput0 libxcb-xkb1 libxcb-xtest0 libxcb-xv0 libxcb-xvmc0 libxcomposite1 libxcursor1 libxdamage1 libxdmcp6 libxext6 libxfixes3 libxft2 libxi6 libxinerama1 libxkbcommon0 libxml2 libxrandr2 libxrender1 libxshmfence1 libxss1 libxtst6 libxxf86vm1 libzstd1 linux-libc-dev login lsb-base mawk mime-support mount ncurses-base ncurses-bin openssl passwd perl-base sed sensible-utils shared-mime-info sudo systemd systemd-sysv sysvinit-utils tar tzdata ucf util-linux uuid-runtime x11-common xkb-data zlib1g +``` + +### org.deepin.foundation/23.0.0 + +使用 deepin 23 beta 仓库制作的 base,支持 x86 架构。 + +_在容器中执行 `cat /var/lib/dpkg/status|grep "^Package: "|sort|awk '{print $2}'` 查看包列表_ + +```txt +adduser adwaita-icon-theme apt at-spi2-common base-files base-passwd bash binutils-common bsdutils ca-certificates coreutils dash dbus dbus-bin dbus-daemon dbus-session-bus-common dbus-system-bus-common dbus-user-session dconf-gsettings-backend dconf-service debconf debianutils deepin-desktop-base deepin-keyring diffutils distro-info-data dmsetup dpkg e2fsprogs eject findutils fontconfig fontconfig-config fonts-noto fonts-noto-core fonts-symbola gcc-13-base glib-networking glib-networking-common glib-networking-services gpgv grep gsettings-desktop-schemas gtk-update-icon-cache gzip hicolor-icon-theme hostname init-system-helpers libacl1 libapparmor1 libapt-pkg6.0 libarchive13 libargon2-1 libasan8 libasm1 libasound2 libasound2-data libatk1.0-0 libatk-bridge2.0-0 libatomic1 libatspi2.0-0 libattr1 libaudit1 libaudit-common libavahi-client3 libavahi-common3 libavahi-common-data libbabeltrace1 libbinutils libblkid1 libboost-regex1.74.0 libbrotli1 libbsd0 libbz2-1.0 libc6 libc6-dev libcairo2 libcairo-gobject2 libcairo-script-interpreter2 libcap2 libcap-ng0 libc-bin libcc1-0 libc-dev-bin libcolord2 libcom-err2 libcrypt1 libcrypt-dev libcryptsetup12 libctf0 libctf-nobfd0 libcups2 libcupsimage2 libcurl3-gnutls libcurl4 libdatrie1 libdb5.3 libdbus-1-3 libdconf1 libdebconfclient0 libdebuginfod1 libdebuginfod-common libdeflate0 libdevmapper1.02.1 libdpkg-perl libdrm2 libdrm-amdgpu1 libdrm-common libdrm-intel1 libdrm-nouveau2 libdrm-radeon1 libdw1 libedit2 libegl1 libegl-mesa0 libelf1 libepoxy0 libevent-2.1-7 libexpat1 libext2fs2 libfdisk1 libffi8 libfontconfig1 libfreetype6 libfribidi0 libgbm1 libgcc-s1 libgcrypt20 libgdbm6 libgdbm-compat4 libgdk-pixbuf-2.0-0 libgdk-pixbuf2.0-0 libgdk-pixbuf2.0-common libgdk-pixbuf-xlib-2.0-0 libgirepository-1.0-1 libgl1 libgl1-mesa-dri libglapi-mesa libgles1 libgles2 libglib2.0-0 libglib2.0-data libglu1-mesa libglvnd0 libglx0 libglx-mesa0 libgmp10 libgmpxx4ldbl libgnutls30 libgnutls-dane0 libgnutls-openssl27 libgnutlsxx30 libgomp1 libgpg-error0 libgprofng0 libgraphite2-3 libgssapi-krb5-2 libgtk2.0-0 libgtk2.0-common libgtk-3-0 libgtk-3-common libharfbuzz0b libharfbuzz-cairo0 libharfbuzz-gobject0 libharfbuzz-icu0 libharfbuzz-subset0 libhogweed6 libhwasan0 libice6 libicu73 libidn2-0 libip4tc2 libipt2 libisl23 libitm1 libjansson4 libjbig0 libjpeg62-turbo libjson-c5 libjsoncpp24 libk5crypto3 libkeyutils1 libkmod2 libkrb5-3 libkrb5support0 liblcms2-2 libldap-2.5-0 liblerc4 libllvm16 liblocale-gettext-perl liblsan0 liblz4-1 liblzma5 liblzo2-2 libmagic1 libmagic-mgc libmd0 libmount1 libmpc3 libmpfr6 libncursesw6 libnettle8 libnghttp2-14 libnsl2 libnsl-dev libnspr4 libnss3 libopengl0 libp11-kit0 libpam0g libpam-modules libpam-modules-bin libpam-runtime libpam-systemd libpango-1.0-0 libpango1.0-0 libpangocairo-1.0-0 libpangoft2-1.0-0 libpangoxft-1.0-0 libpciaccess0 libpcre16-3 libpcre2-16-0 libpcre2-32-0 libpcre2-8-0 libpcre2-posix3 libpcre3 libpcre32-3 libpcrecpp0v5 libperl5.36 libpixman-1-0 libpkgconf3 libpng16-16 libproc2-0 libproxy1v5 libpsl5 libpython3.11 libpython3.11-minimal libpython3.11-stdlib libpython3-stdlib libquadmath0 libreadline8 librhash0 librsvg2-2 librsvg2-common librtmp1 libsasl2-2 libsasl2-modules-db libseccomp2 libselinux1 libsemanage2 libsemanage-common libsensors5 libsensors-config libsepol2 libsframe1 libsharpyuv0 libsm6 libsmartcols1 libsource-highlight4v5 libsource-highlight-common libsqlite3-0 libss2 libssh2-1 libssl3 libstdc++6 libsystemd0 libsystemd-shared libtasn1-6 libtext-charwidth-perl libtext-iconv-perl libtext-wrapi18n-perl libthai0 libthai-data libtiff6 libtiffxx6 libtinfo6 libtirpc3 libtirpc-common libtirpc-dev libtsan2 libubsan1 libudev1 libunbound8 libunistring2 libuuid1 libuv1 libvulkan1 libwayland-client0 libwayland-cursor0 libwayland-egl1 libwayland-server0 libwebp7 libwebpdecoder3 libwebpdemux2 libwebpmux3 libx11-6 libx11-data libx11-xcb1 libxau6 libxcb1 libxcb-composite0 libxcb-damage0 libxcb-doc libxcb-dpms0 libxcb-dri2-0 libxcb-dri3-0 libxcb-glx0 libxcb-present0 libxcb-randr0 libxcb-record0 libxcb-render0 libxcb-res0 libxcb-screensaver0 libxcb-shape0 libxcb-shm0 libxcb-sync1 libxcb-xf86dri0 libxcb-xfixes0 libxcb-xinerama0 libxcb-xinput0 libxcb-xkb1 libxcb-xtest0 libxcb-xv0 libxcb-xvmc0 libxcomposite1 libxcursor1 libxdamage1 libxdmcp6 libxext6 libxfixes3 libxft2 libxi6 libxinerama1 libxkbcommon0 libxml2 libxrandr2 libxrender1 libxshmfence1 libxss1 libxtst6 libxxf86vm1 libxxhash0 libz3-4 libzstd1 linux-libc-dev login logsave mailcap mawk media-types mime-support mount ncurses-base ncurses-bin openssl passwd perl perl-base perl-modules-5.36 readline-common rpcsvc-proto sed sensible-utils shared-mime-info systemd systemd-dev systemd-sysv sysvinit-utils tar tzdata ucf usr-is-merged util-linux uuid-runtime x11-common xkb-data zlib1g +``` + +### org.deepin.base/23.1.0 + +基于 deepin v23 release 仓库制作的 base,支持 x86 架构。 + +_在容器中执行 `cat /var/lib/dpkg/status|grep "^Package: "|sort|awk '{print $2}'` 查看包列表_ + +```txt +acl adduser adwaita-icon-theme apt at-spi2-common base-files base-passwd bash bc binutils binutils-common binutils-x86-64-linux-gnu bluez bluez-obexd bsdextrautils bsdutils busybox bzip2 ca-certificates coreutils cpio cryptsetup cryptsetup-bin cryptsetup-initramfs cups cups-bsd cups-client cups-common cups-core-drivers cups-daemon cups-filters cups-filters-core-drivers cups-ipp-utils cups-ppdc cups-server-common curl dash dbus dbus-bin dbus-daemon dbus-session-bus-common dbus-system-bus-common dbus-x11 dconf-gsettings-backend dconf-service debconf debianutils deepin-keyring dictionaries-common diffutils dirmngr dmeventd dmsetup dpkg e2fsprogs eject emacsen-common fcitx5-frontend-gtk2 fcitx5-frontend-gtk3 fdisk file findutils fontconfig fontconfig-config fonts-dejavu-core fonts-urw-base35 gawk gcc-13-base gettext-base ghostscript gir1.2-atk-1.0 gir1.2-freedesktop gir1.2-gdkpixbuf-2.0 gir1.2-glib-2.0 gir1.2-harfbuzz-0.0 gir1.2-pango-1.0 glib-networking glib-networking-common glib-networking-services gnupg gnupg-l10n gnupg-utils gnutls-bin gpg gpg-agent gpgconf gpgsm gpgv gpg-wks-client grep gsettings-desktop-schemas gtk-update-icon-cache gzip hicolor-icon-theme hostname initramfs-tools initramfs-tools-core init-system-helpers iso-codes kbd klibc-utils kmod libacl1 libaio1 libaom3 libapparmor1 libapt-pkg6.0 libarchive13 libargon2-1 libasound2 libasound2-data libasound2-plugins libassuan0 libasyncns0 libatk1.0-0 libatk-bridge2.0-0 libatspi2.0-0 libattr1 libaudit1 libaudit-common libavahi-client3 libavahi-common3 libavahi-common-data libavcodec60 libavutil58 libbinutils libblkid1 libbluetooth3 libbrotli1 libbsd0 libbz2-1.0 libc6 libc6-dev libcairo2 libcairo-gobject2 libcap2 libcap2-bin libcap-ng0 libc-bin libcbor0.8 libc-dev-bin libc-l10n libcloudproviders0 libcodec2-0.9 libcolord2 libcom-err2 libconfig++9v5 libcrypt1 libcrypt-dev libcryptsetup12 libctf0 libctf-nobfd0 libcups2 libcupsfilters1 libcupsimage2 libcurl3-gnutls libcurl4 libdaemon0 libdatrie1 libdav1d6 libdb5.3 libdbus-1-3 libdconf1 libdebconfclient0 libdecor-0-0 libdeflate0 libdevmapper1.02.1 libdevmapper-event1.02.1 libdrm2 libdrm-amdgpu1 libdrm-common libdrm-intel1 libdrm-nouveau2 libdrm-radeon1 libdw1 libedit2 libegl1 libegl-mesa0 libelf1 libencode-locale-perl libepoxy0 libevent-2.1-7 libexif12 libexpat1 libext2fs2 libfcitx5gclient2 libfdisk1 libffado2 libffi8 libfftw3-single3 libfido2-1 libfile-listing-perl libflac8 libfontconfig1 libfontembed1 libfontenc1 libfreeaptx0 libfreetype6 libfribidi0 libgbm1 libgcc-s1 libgcrypt20 libgdbm6 libgdbm-compat4 libgdk-pixbuf-2.0-0 libgdk-pixbuf2.0-common libgdk-pixbuf-xlib-2.0-0 libgl1 libgl1-mesa-dri libglapi-mesa libgle3 libgles2 libglib2.0-0 libglib2.0-bin libglib2.0-data libglibmm-2.4-1v5 libglu1-mesa libglvnd0 libglx0 libglx-mesa0 libgmp10 libgnutls30 libgnutls-dane0 libgomp1 libgpg-error0 libgprofng0 libgraphite2-3 libgs9 libgs9-common libgsm1 libgssapi-krb5-2 libgstreamer1.0-0 libgstreamer-plugins-base1.0-0 libgtk2.0-0 libgtk2.0-common libgtk-3-0 libgtk-3-common libharfbuzz0b libharfbuzz-gobject0 libharfbuzz-icu0 libharfbuzz-subset0 libhogweed6 libhtml-parser-perl libhtml-tagset-perl libhtml-tree-perl libhttp-cookies-perl libhttp-date-perl libhttp-message-perl libhttp-negotiate-perl libhwy1 libical3 libice6 libicu74 libidn12 libidn2-0 libiec61883-0 libijs-0.35 libio-html-perl libio-socket-ssl-perl libjack-jackd2-0 libjansson4 libjbig0 libjbig2dec0 libjpeg62-turbo libjpeg-turbo-progs libjson-c5 libjxl0.7 libk5crypto3 libkeyutils1 libklibc libkmod2 libkrb5-3 libkrb5support0 libksba8 liblc3-1 liblcms2-2 libldacbt-abr2 libldacbt-enc2 libldap-2.5-0 liblerc4 liblilv-0-0 libllvm17 libltdl7 liblvm2cmd2.03 liblwp-mediatypes-perl liblwp-protocol-https-perl liblz4-1 liblzma5 libmagic1 libmagic-mgc libmd0 libminizip1 libmnl0 libmount1 libmp3lame0 libmpfr6 libmysofa1 libnatspec0 libncurses6 libncursesw6 libnet-http-perl libnetpbm10 libnet-ssleay-perl libnettle8 libnghttp2-14 libnpth0 libnsl2 libnsl-dev libnspr4 libnss3 libnss-myhostname libnuma1 libogg0 libopengl0 libopenjp2-7 libopus0 liborc-0.4-0 libp11-kit0 libpam0g libpam-modules libpam-modules-bin libpam-runtime libpango-1.0-0 libpangocairo-1.0-0 libpangoft2-1.0-0 libpangoxft-1.0-0 libpaper1 libpciaccess0 libpcre2-16-0 libpcre2-8-0 libperl5.36 libpipewire-0.3-0 libpipewire-0.3-modules libpixman-1-0 libpng16-16 libpoppler118 libpoppler-cpp0v5 libpopt0 libproc2-0 libproxy1v5 libpsl5 libpulse0 libpulsedsp libpulse-mainloop-glib0 libpython3.11-minimal libpython3.11-stdlib libpython3.12 libpython3.12-minimal libpython3.12-stdlib libpython3-stdlib libqpdf29 librav1e0 libraw1394-11 libreadline8 libroc0.3 librsvg2-2 librtmp1 libsamplerate0 libsasl2-2 libsasl2-modules-db libsbc1 libseccomp2 libselinux1 libsemanage2 libsemanage-common libsensors5 libsensors-config libsepol2 libserd-0-0 libsframe1 libsharpyuv0 libshine3 libsigc++-2.0-0v5 libsigsegv2 libsm6 libsmartcols1 libsnappy1v5 libsndfile1 libsord-0-0 libsoxr0 libspa-0.2-bluetooth libspa-0.2-modules libspeex1 libspeexdsp1 libsqlite3-0 libsratom-0-0 libss2 libssh2-1 libssl3 libstdc++6 libsvtav1enc1d1 libswresample4 libsystemd0 libsystemd-shared libtasn1-6 libtdb1 libtext-iconv-perl libthai0 libthai-data libtheora0 libtiff6 libtimedate-perl libtinfo6 libtirpc3 libtirpc-common libtirpc-dev libtry-tiny-perl libtss2-esys-3.0.2-0 libtss2-mu0 libtss2-sys1 libtss2-tcti-cmd0 libtss2-tcti-device0 libtss2-tctildr0 libtss2-tcti-libtpms0 libtss2-tcti-mssim0 libtss2-tcti-spi-helper0 libtss2-tcti-swtpm0 libturbojpeg0 libtwolame0 libudev1 libunbound8 libunistring2 libunwind8 liburi-perl libusb-1.0-0 libuuid1 libuv1 libv4l-0 libv4lconvert0 libva2 libva-drm2 libva-x11-2 libvdpau1 libvorbis0a libvorbisenc2 libvpl2 libvpx7 libvulkan1 libwayland-client0 libwayland-cursor0 libwayland-egl1 libwayland-server0 libwebp7 libwebpdemux2 libwebpmux3 libwebrtc-audio-processing1 libwrap0 libwww-perl libwww-robotrules-perl libx11-6 libx11-data libx11-xcb1 libx264-160 libx265-199 libxau6 libxaw7 libxcb1 libxcb-composite0 libxcb-cursor0 libxcb-damage0 libxcb-dri2-0 libxcb-dri3-0 libxcb-ewmh2 libxcb-glx0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-present0 libxcb-randr0 libxcb-record0 libxcb-render0 libxcb-render-util0 libxcb-res0 libxcb-shape0 libxcb-shm0 libxcb-sync1 libxcb-util1 libxcb-xfixes0 libxcb-xinerama0 libxcb-xinput0 libxcb-xkb1 libxcb-xtest0 libxcomposite1 libxcursor1 libxdamage1 libxdmcp6 libxext6 libxfixes3 libxft2 libxi6 libxinerama1 libxkbcommon0 libxkbcommon-x11-0 libxkbfile1 libxml2 libxml++2.6-2v5 libxmu6 libxpm4 libxrandr2 libxrender1 libxshmfence1 libxt6 libxtst6 libxv1 libxvidcore4 libxxf86vm1 libxxhash0 libz3-4 libzstd1 libzvbi0 libzvbi-common linux-base linux-libc-dev locales login logsave lvm2 mawk media-types mesa-vdpau-drivers mesa-vulkan-drivers ncurses-base ncurses-bin netbase netpbm ocl-icd-libopencl1 openssl p11-kit p11-kit-modules passwd perl perl-base perl-modules-5.36 perl-openssl-defaults pinentry-curses pipewire pipewire-bin pipewire-pulse poppler-data poppler-utils procps pulseaudio pulseaudio-module-bluetooth pulseaudio-utils python3 python3.11 python3.11-minimal python3.12 python3.12-minimal python3-minimal readline-common rfkill rpcsvc-proto sed sensible-utils shared-mime-info sqlite3 ssl-cert systemd-dev systemd-standalone-sysusers sysvinit-utils tar tpm-udev tzdata tzdata-legacy ucf udev unzip usr-is-merged util-linux x11-common x11-xkb-utils xdg-user-dirs xfonts-encodings xfonts-utils xkb-data xscreensaver-data xscreensaver-data-extra xscreensaver-gl xscreensaver-gl-extra xz-utils zlib1g zstd +``` + +### org.deepin.base/25.2.0 + +基于 deepin 25 beta 仓库制作的 base,支持 x86, arm64, loong64 架构。 + +_在容器中执行 `cat /var/lib/dpkg/status|grep "^Package: "|sort|awk '{print $2}'` 查看包列表_ + +```txt +acl adduser at-spi2-common base-files base-passwd bash bc binutils binutils-common binutils-x86-64-linux-gnu bluez bluez-obexd bsdextrautils bsdutils busybox bzip2 ca-certificates coreutils cpio cryptsetup cryptsetup-bin cryptsetup-initramfs cups cups-bsd cups-client cups-common cups-core-drivers cups-daemon cups-filters cups-filters-core-drivers cups-ipp-utils cups-ppdc cups-server-common curl dash dbus dbus-bin dbus-daemon dbus-session-bus-common dbus-system-bus-common dbus-user-session dbus-x11 dconf-gsettings-backend dconf-service debconf debianutils deepin-desktop-base deepin-keyring dictionaries-common diffutils dirmngr distro-info-data dmeventd dmsetup dpkg dracut-install e2fsprogs eject emacsen-common fdisk file findutils fontconfig fontconfig-config fonts-dejavu-core fonts-noto fonts-noto-core fonts-symbola fonts-urw-base35 gawk gcc-13-base gdbserver gettext-base ghostscript gir1.2-atk-1.0 gir1.2-freedesktop gir1.2-gdkpixbuf-2.0 gir1.2-glib-2.0 gir1.2-harfbuzz-0.0 gir1.2-pango-1.0 glib-networking glib-networking-common glib-networking-services gnupg gnupg-l10n gnutls-bin gpg gpg-agent gpgconf gpgsm gpgv grep gsettings-desktop-schemas gzip hicolor-icon-theme hostname initramfs-tools initramfs-tools-core init-system-helpers iso-codes klibc-utils kmod libabsl20220623 libacl1 libaio1 libaom3 libapparmor1 libarchive13 libasound2 libasound2-data libasound2-plugins libassuan0 libasyncns0 libatk1.0-0 libatk-bridge2.0-0 libatspi2.0-0 libattr1 libaudit1 libaudit-common libavahi-client3 libavahi-common3 libavahi-common-data libavcodec60 libavutil58 libbinutils libblkid1 libbluetooth3 libbrotli1 libbsd0 libbz2-1.0 libc6 libc6-dev libcairo2 libcairo-gobject2 libcap2 libcap2-bin libcap-ng0 libc-bin libcbor0.8 libc-dev-bin libc-l10n libcodec2-0.9 libcom-err2 libconfig++9v5 libcrypt1 libcrypt-dev libcryptsetup12 libctf0 libctf-nobfd0 libcups2 libcupsfilters1 libcupsimage2 libcurl3-gnutls libcurl4 libdaemon0 libdatrie1 libdav1d6 libdb5.3 libdbus-1-3 libdconf1 libdebconfclient0 libdecor-0-0 libdeflate0 libdevmapper1.02.1 libdevmapper-event1.02.1 libdrm2 libdrm-amdgpu1 libdrm-common libdrm-intel1 libdrm-nouveau2 libdrm-radeon1 libdw1 libedit2 libegl1 libegl-mesa0 libelf1 libencode-locale-perl libepoxy0 libevent-2.1-7 libexif12 libexpat1 libext2fs2 libfdisk1 libffado2 libffi8 libfftw3-single3 libfido2-1 libfile-listing-perl libflac8 libfontconfig1 libfontembed1 libfontenc1 libfreeaptx0 libfreetype6 libfribidi0 libgbm1 libgcc-s1 libgcrypt20 libgdbm6 libgdbm-compat4 libgdk-pixbuf-2.0-0 libgdk-pixbuf2.0-common libgdk-pixbuf-xlib-2.0-0 libgl1 libgl1-mesa-dri libglapi-mesa libgle3 libgles2 libglib2.0-0 libglib2.0-bin libglib2.0-data libglibmm-2.4-1v5 libglu1-mesa libglvnd0 libglx0 libglx-mesa0 libgmp10 libgnutls30 libgnutls-dane0 libgomp1 libgpg-error0 libgprofng0 libgraphite2-3 libgs10 libgs10-common libgs-common libgsm1 libgssapi-krb5-2 libgstreamer1.0-0 libgstreamer-plugins-base1.0-0 libharfbuzz0b libharfbuzz-gobject0 libharfbuzz-icu0 libharfbuzz-subset0 libhogweed6 libhtml-parser-perl libhtml-tagset-perl libhtml-tree-perl libhttp-cookies-perl libhttp-date-perl libhttp-message-perl libhttp-negotiate-perl libhwy1 libical3 libice6 libicu74 libidn12 libidn2-0 libiec61883-0 libijs-0.35 libio-html-perl libio-socket-ssl-perl libjack-jackd2-0 libjansson4 libjbig0 libjbig2dec0 libjpeg62-turbo libjpeg-turbo-progs libjson-c5 libjxl0.7 libk5crypto3 libkeyutils1 libklibc libkmod2 libkrb5-3 libkrb5support0 libksba8 liblc3-1 liblcms2-2 libldacbt-abr2 libldacbt-enc2 libldap-2.5-0 liblerc4 liblilv-0-0 libllvm19 libltdl7 liblvm2cmd2.03 liblwp-mediatypes-perl liblwp-protocol-https-perl liblz4-1 liblzma5 libmagic1 libmagic-mgc libmd0 libminizip1 libmnl0 libmount1 libmp3lame0 libmpfr6 libmysofa1 libnatspec0 libncurses6 libncursesw6 libnet-http-perl libnetpbm11 libnet-ssleay-perl libnettle8 libnghttp2-14 libnghttp3-9 libngtcp2-16 libngtcp2-crypto-gnutls8 libnpth0 libnsl2 libnsl-dev libnspr4 libnss3 libnss-myhostname libnuma1 libogg0 libopengl0 libopenjp2-7 libopus0 liborc-0.4-0 libp11-kit0 libpam0g libpam-modules libpam-modules-bin libpam-runtime libpam-systemd libpango-1.0-0 libpangocairo-1.0-0 libpangoft2-1.0-0 libpangoxft-1.0-0 libpaper1 libpciaccess0 libpcre2-16-0 libpcre2-8-0 libperl5.36 libpipewire-0.3-0 libpipewire-0.3-modules libpixman-1-0 libpng16-16 libpoppler126 libpoppler-cpp0v5 libpopt0 libproc2-0 libproc2-1 libproxy1v5 libpsl5 libpulse0 libpulsedsp libpulse-mainloop-glib0 libpython3.12 libpython3.12-minimal libpython3.12-stdlib libpython3-stdlib libqpdf29 librav1e0 libraw1394-11 libreadline8 libroc0.3 librsvg2-2 librtmp1 libsamplerate0 libsasl2-2 libsasl2-modules-db libsbc1 libseccomp2 libselinux1 libsemanage2 libsemanage-common libsensors5 libsensors-config libsepol2 libserd-0-0 libsframe1 libsharpyuv0 libshine3 libsigc++-2.0-0v5 libsigsegv2 libsm6 libsmartcols1 libsnappy1v5 libsndfile1 libsord-0-0 libsoxr0 libspa-0.2-bluetooth libspa-0.2-modules libspeex1 libspeexdsp1 libsqlite3-0 libsratom-0-0 libss2 libssh2-1 libssl3 libstdc++6 libsvtav1enc1d1 libswresample4 libsystemd0 libsystemd-shared libtasn1-6 libtdb1 libtext-iconv-perl libthai0 libthai-data libtheora0 libtiff6 libtimedate-perl libtinfo6 libtirpc3 libtirpc-common libtirpc-dev libtry-tiny-perl libtss2-esys-3.0.2-0 libtss2-mu0 libtss2-sys1 libtss2-tcti-cmd0 libtss2-tcti-device0 libtss2-tctildr0 libtss2-tcti-libtpms0 libtss2-tcti-mssim0 libtss2-tcti-spi-helper0 libtss2-tcti-swtpm0 libturbojpeg0 libtwolame0 libudev1 libunbound8 libunistring2 libunwind8 liburi-perl libusb-1.0-0 libuuid1 libuv1 libv4l-0 libv4lconvert0 libva2 libva-drm2 libva-x11-2 libvdpau1 libvorbis0a libvorbisenc2 libvpl2 libvpx7 libvulkan1 libwayland-client0 libwayland-cursor0 libwayland-egl1 libwayland-server0 libwebp7 libwebpdemux2 libwebpmux3 libwebrtc-audio-processing1 libwebrtc-audio-processing-1-3 libwrap0 libwww-perl libwww-robotrules-perl libx11-6 libx11-data libx11-xcb1 libx264-160 libx265-199 libxau6 libxaw7 libxcb1 libxcb-composite0 libxcb-cursor0 libxcb-damage0 libxcb-dri2-0 libxcb-dri3-0 libxcb-ewmh2 libxcb-glx0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-present0 libxcb-randr0 libxcb-record0 libxcb-render0 libxcb-render-util0 libxcb-res0 libxcb-shape0 libxcb-shm0 libxcb-sync1 libxcb-util1 libxcb-xfixes0 libxcb-xinerama0 libxcb-xinput0 libxcb-xkb1 libxcb-xtest0 libxcomposite1 libxcursor1 libxdamage1 libxdmcp6 libxext6 libxfixes3 libxft2 libxi6 libxinerama1 libxkbcommon0 libxkbcommon-x11-0 libxkbfile1 libxml2 libxml++2.6-2v5 libxmu6 libxpm4 libxrandr2 libxrender1 libxshmfence1 libxt6 libxtst6 libxv1 libxvidcore4 libxxf86vm1 libxxhash0 libz3-4 libzstd1 libzvbi0 libzvbi-common linux-base linux-libc-dev locales login login.defs logsave lvm2 mawk media-types mesa-libgallium mesa-vdpau-drivers mesa-vulkan-drivers mount ncurses-base ncurses-bin netbase netpbm ocl-icd-libopencl1 openssl p11-kit p11-kit-modules passwd perl perl-base perl-modules-5.36 perl-openssl-defaults pinentry-curses pipewire pipewire-bin pipewire-pulse poppler-data poppler-utils procps pulseaudio pulseaudio-module-bluetooth pulseaudio-utils python3 python3.12 python3.12-minimal python3-minimal readline-common rfkill rpcsvc-proto sed sensible-utils shared-mime-info sqlite3 ssl-cert systemd systemd-dev systemd-sysv systemd-timesyncd sysvinit-utils tar tpm-udev tzdata tzdata-legacy ucf udev unzip usr-is-merged util-linux x11-common x11-xkb-utils xdg-user-dirs xfonts-encodings xfonts-utils xkb-data xscreensaver-data xscreensaver-data-extra xscreensaver-gl xscreensaver-gl-extra xz-utils zlib1g zstd +``` + +## runtime 列表 + +### org.deepin.Runtime/20.0.0 + +使用 uos 1070 仓库制作的 runtime,支持 x86, arm64, loongarch64 三个架构。 + +_在容器中执行 `cat /runtime/packages.list|awk '{print $2}'` 查看包列表_ + +```txt +libqt5core5a libqt5gui5 qt5-gtk-platformtheme qt5-flatpak-platformtheme libqt5network5 libqt5opengl5 libqt5sql5 libqt5sql5-mysql libqt5sql5-odbc libqt5sql5-psql libqt5sql5-sqlite libqt5sql5-tds libqt5sql5-ibase libqt5xml5 libqt5dbus5 libqt5test5 libqt5concurrent5 libqt5widgets5 libqt5printsupport5 qtbase5-dev qtbase5-private-dev libqt5opengl5-dev qtbase5-dev-tools qt5-qmake-bin qt5-qmake qtbase5-examples qt5-default qtbase5-doc qtbase5-doc-html libqt5svg5 libqt5svg5-dev qtsvg5-examples qtsvg5-doc qtsvg5-doc-html libqt5qml5 libqt5quick5 libqt5quickparticles5 libqt5quicktest5 libqt5quickwidgets5 qml-module-qtquick-layouts qt5-qmltooling-plugins qml-module-qt-labs-folderlistmodel qml-module-qtquick-localstorage qml-module-qt-labs-sharedimage qml-module-qtqml-models2 qml-module-qtqml-statemachine qml-module-qtquick-particles2 qml-module-qtquick2 qml-module-qtquick-shapes qml-module-qt-labs-handlers qml-module-qt-labs-settings qml-module-qttest qml-module-qtquick-window2 qml-module-qtquick-xmllistmodel qtdeclarative5-dev qtdeclarative5-private-dev qtdeclarative5-dev-tools qmlscene qml qtdeclarative5-examples qtdeclarative5-doc qtdeclarative5-doc-html qml-module-qtgraphicaleffects qtgraphicaleffects5-doc qtgraphicaleffects5-doc-html qml-module-qtquick-controls qml-module-qtquick-extras qml-module-qtquick-dialogs qml-module-qtquick-privatewidgets qtquickcontrols5-examples qtquickcontrols5-doc qtquickcontrols5-doc-html libqt5quickcontrols2-5 libqt5quicktemplates2-5 qml-module-qt-labs-calendar qml-module-qt-labs-platform qml-module-qtquick-controls2 qml-module-qtquick-templates2 qtquickcontrols2-5-dev qtquickcontrols2-5-doc qtquickcontrols2-5-doc-html qtquickcontrols2-5-examples libqt5script5 libqt5scripttools5 qtscript5-dev qtscript5-examples qtscript5-doc qtscript5-doc-html libqt5xmlpatterns5 libqt5xmlpatterns5-dev qtxmlpatterns5-dev-tools qtxmlpatterns5-examples qtxmlpatterns5-doc qtxmlpatterns5-doc-html qt5-image-formats-plugins libqt5location5 libqt5positioningquick5 libqt5positioning5 libqt5location5-plugins libqt5positioning5-plugins qml-module-qtlocation qml-module-qtpositioning qml-module-qt-labs-location qtlocation5-dev qtpositioning5-dev qtlocation5-examples qtlocation5-doc qtlocation5-doc-html libqt5multimedia5 libqt5multimedia5-plugins libqt5multimediaquick5 libqt5multimediawidgets5 qml-module-qtmultimedia qml-module-qtaudioengine libqt5multimediagsttools5 qtmultimedia5-examples qtmultimedia5-dev qtmultimedia5-doc qtmultimedia5-doc-html libqt53dcore5 libqt53dquick5 libqt53dquickrender5 libqt53dinput5 libqt53drender5 libqt53dlogic5 libqt53dquickinput5 libqt53dquickextras5 libqt53dextras5 libqt53dquickscene2d5 libqt53danimation5 libqt53dquickanimation5 qt3d5-dev-tools qt3d-gltfsceneio-plugin qt3d-assimpsceneimport-plugin qt3d-defaultgeometryloader-plugin qt3d-scene2d-plugin qml-module-qt3d qml-module-qtquick-scene3d qml-module-qtquick-scene2d qt3d5-dev qt3d5-examples qt3d5-doc qt3d5-doc-html libqt5charts5 libqt5charts5-dev qml-module-qtcharts qtcharts5-examples qtcharts5-doc qtcharts5-doc-html libqt5bluetooth5 libqt5bluetooth5-bin qml-module-qtbluetooth libqt5nfc5 qml-module-qtnfc qtconnectivity5-dev qtconnectivity5-examples qtconnectivity5-doc qtconnectivity5-doc-html libqt5gamepad5-dev libqt5gamepad5 qtgamepad5-examples libqt5sensors5 qml-module-qtsensors libqt5sensors5-dev qtsensors5-examples qtsensors5-doc qtsensors5-doc-html libqt5texttospeech5-dev libqt5texttospeech5 qtspeech5-flite-plugin qtspeech5-speechd-plugin qtspeech5-examples qtspeech5-doc qtspeech5-doc-html qml-module-qtquick-virtualkeyboard qtvirtualkeyboard-plugin qtvirtualkeyboard5-examples qtvirtualkeyboard5-doc qtvirtualkeyboard5-doc-html libqt5serialport5 libqt5serialport5-dev qt5serialport-examples qtserialport5-doc qtserialport5-doc-html qtnetworkauth5-doc qtnetworkauth5-doc-html libqt5networkauth5-dev qtnetworkauth5-examples libqt5networkauth5 libqt5designer5 libqt5designercomponents5 qdbus-qt5 qdoc-qt5 libqt5help5 qttools5-dev qttools5-private-dev qttools5-dev-tools qt5-assistant qttools5-examples qttools5-doc qttools5-doc-html libqt5x11extras5 libqt5x11extras5-dev qtx11extras5-doc qtx11extras5-doc-html qtwayland5-examples libqt5waylandclient5 libqt5waylandcompositor5 qml-module-qtwayland-compositor qml-module-qtwayland-client-texturesharing libqt5waylandcompositor5-dev libqt5waylandclient5-dev qtwayland5-private-dev qtwayland5-dev-tools qtwayland5 qtwayland5-doc qtwayland5-doc-html lxqt-build-tools libqt5xdg3 libqt5xdgiconloader3 libqt5xdg-dev libqt5xdgiconloader-dev qtxdg-dev-tools libdtkcommon libdtkcommon-dev libdtkcore5 libdtkcore5-bin libdtkcore-dev libdtkcore-doc libdtkgui5 libdtkgui5-bin libdtkgui-dev libdtkgui-doc libdtkwidget5 libdtkwidget5-bin libdtkwidget-dev dtkwidget5-examples dtkwidget-doc googletest googletest-tools libgtest-dev libgmock-dev google-mock dde-qt5integration dde-qt5xcb-plugin dde-qt5wayland-plugin +``` + +### org.deepin.Runtime/23.0.1 + +使用 deepin 23 beta 仓库制作的 runtime,支持 x86 架构。 + +_在容器中执行 `cat /runtime/packages.list|awk '{print $2}'` 查看包列表_ + +```txt +libqt5core5a libqt5gui5 qt5-gtk-platformtheme qt5-flatpak-platformtheme qt5-xdgdesktopportal-platformtheme libqt5network5 libqt5opengl5 libqt5sql5 libqt5sql5-mysql libqt5sql5-odbc libqt5sql5-psql libqt5sql5-sqlite libqt5sql5-tds libqt5sql5-ibase libqt5xml5 libqt5dbus5 libqt5test5 libqt5concurrent5 libqt5widgets5 libqt5printsupport5 qtbase5-dev qtbase5-private-dev libqt5opengl5-dev qtbase5-dev-tools qt5-qmake-bin qt5-qmake qtbase5-examples qt5-default qtbase5-doc qtbase5-doc-html qtbase5-doc-dev libqt5svg5 libqt5svg5-dev qtsvg5-examples qtsvg5-doc qtsvg5-doc-html libqt5qml5 libqt5qmlmodels5 libqt5qmlworkerscript5 libqt5quick5 libqt5quickparticles5 libqt5quickshapes5 libqt5quicktest5 libqt5quickwidgets5 qml-module-qtquick-layouts qt5-qmltooling-plugins qml-module-qt-labs-animation qml-module-qt-labs-folderlistmodel qml-module-qtquick-localstorage qml-module-qt-labs-sharedimage qml-module-qt-labs-qmlmodels qml-module-qt-labs-wavefrontmesh qml-module-qtqml qml-module-qtqml-models2 qml-module-qtqml-statemachine qml-module-qtqml-workerscript2 qml-module-qtquick-particles2 qml-module-qtquick2 qml-module-qtquick-shapes qml-module-qt-labs-settings qml-module-qttest qml-module-qtquick-window2 qtdeclarative5-dev qtdeclarative5-private-dev qtdeclarative5-dev-tools qmlscene qml qtdeclarative5-examples qtdeclarative5-doc qtdeclarative5-doc-html qtdeclarative5-doc-dev qml-module-qtgraphicaleffects qtgraphicaleffects5-doc qtgraphicaleffects5-doc-html qml-module-qtquick-controls qml-module-qtquick-extras qml-module-qtquick-dialogs qml-module-qtquick-privatewidgets qtquickcontrols5-examples qtquickcontrols5-doc qtquickcontrols5-doc-html libqt5quickcontrols2-5 libqt5quicktemplates2-5 qml-module-qt-labs-calendar qml-module-qt-labs-platform qml-module-qtquick-controls2 qml-module-qtquick-templates2 qtquickcontrols2-5-dev qtquickcontrols2-5-private-dev qtquickcontrols2-5-doc qtquickcontrols2-5-doc-html qtquickcontrols2-5-examples libqt5script5 libqt5scripttools5 qtscript5-dev qtscript5-examples qtscript5-doc qtscript5-doc-html libqt5xmlpatterns5 libqt5xmlpatterns5-dev qtxmlpatterns5-dev-tools qml-module-qtquick-xmllistmodel qtxmlpatterns5-examples qtxmlpatterns5-doc qtxmlpatterns5-doc-html qt5-image-formats-plugins libqt5location5 libqt5positioningquick5 libqt5positioning5 libqt5location5-plugins libqt5location5-plugin-mapboxgl libqt5positioning5-plugins qml-module-qtlocation qml-module-qtpositioning qml-module-qt-labs-location qtlocation5-dev qtpositioning5-dev qtlocation5-examples qtlocation5-doc qtlocation5-doc-html qtlocation5-doc-dev libqt5multimedia5 libqt5multimedia5-plugins libqt5multimediaquick5 libqt5multimediawidgets5 qml-module-qtmultimedia qml-module-qtaudioengine libqt5multimediagsttools5 qtmultimedia5-examples qtmultimedia5-dev qtmultimedia5-doc qtmultimedia5-doc-html libqt53dcore5 libqt53dquick5 libqt53dquickrender5 libqt53dinput5 libqt53drender5 libqt53dlogic5 libqt53dquickinput5 libqt53dquickextras5 libqt53dextras5 libqt53dquickscene2d5 libqt53danimation5 libqt53dquickanimation5 qt3d5-dev-tools qt3d-gltfsceneio-plugin qt3d-assimpsceneimport-plugin qt3d-defaultgeometryloader-plugin qt3d-scene2d-plugin qml-module-qt3d qml-module-qtquick-scene3d qml-module-qtquick-scene2d qt3d5-dev qt3d5-examples qt3d5-doc qt3d5-doc-html libqt5charts5 libqt5charts5-dev qml-module-qtcharts qtcharts5-examples qtcharts5-doc qtcharts5-doc-html libqt5bluetooth5 libqt5bluetooth5-bin qml-module-qtbluetooth libqt5nfc5 qml-module-qtnfc qtconnectivity5-dev qtconnectivity5-examples qtconnectivity5-doc qtconnectivity5-doc-html libqt5gamepad5-dev libqt5gamepad5 qtgamepad5-examples qml-module-qtgamepad qtgamepad5-doc qtgamepad5-doc-html libqt5sensors5 qml-module-qtsensors libqt5sensors5-dev qtsensors5-examples qtsensors5-doc qtsensors5-doc-html libqt5texttospeech5-dev libqt5texttospeech5 qtspeech5-flite-plugin qtspeech5-speechd-plugin qtspeech5-examples qtspeech5-doc qtspeech5-doc-html libqt5hunspellinputmethod5 libqt5virtualkeyboard5 libqt5virtualkeyboard5-dev qml-module-qtquick-virtualkeyboard qtvirtualkeyboard-plugin qtvirtualkeyboard5-examples qtvirtualkeyboard5-doc qtvirtualkeyboard5-doc-html libqt5serialport5 libqt5serialport5-dev qt5serialport-examples qtserialport5-doc qtserialport5-doc-html qtnetworkauth5-doc qtnetworkauth5-doc-html libqt5networkauth5-dev qtnetworkauth5-examples libqt5networkauth5 libqt5designer5 libqt5designercomponents5 qdbus-qt5 qdbus qdoc-qt5 qhelpgenerator-qt5 qtattributionsscanner-qt5 libqt5help5 qttools5-dev qttools5-private-dev qttools5-dev-tools qt5-assistant qttools5-examples qttools5-doc qttools5-doc-html libqt5x11extras5 libqt5x11extras5-dev qtx11extras5-doc qtx11extras5-doc-html qtwayland5-examples libqt5waylandclient5 libqt5waylandcompositor5 qml-module-qtwayland-compositor qml-module-qtwayland-client-texturesharing libqt5waylandcompositor5-dev libqt5waylandclient5-dev qtwayland5-private-dev qtwayland5-dev-tools qtwayland5 qtwayland5-doc qtwayland5-doc-html qtwebchannel5-doc qtwebchannel5-doc-html libqt5webchannel5-dev qtwebchannel5-examples libqt5webchannel5 qml-module-qtwebchannel libqt5websockets5 libqt5websockets5-dev qml-module-qtwebsockets qml-module-qt-websockets qtwebsockets5-examples qtwebsockets5-doc qtwebsockets5-doc-html qttranslations5-l10n lxqt-build-tools libqt5xdg3 libqt5xdgiconloader3 libqt5xdg-dev libqt5xdgiconloader-dev qtxdg-dev-tools libdtkdata libdtkcommon-dev libdtkcore5 libdtkcore5-bin libdtkcore-dev libdtkcore-doc libdtkgui5 libdtkgui5-bin libdtkgui-dev libdtkgui-doc libdtkwidget5 libdtkwidget5-bin libdtkwidget-dev dtkwidget5-examples dtkwidget-doc qml-module-qtquick-controls2-styles-chameleon libdtkdeclarative5 libdtkdeclarative-dev libdtkdeclarative-doc dtk-exhibition googletest libgtest-dev libgmock-dev google-mock dde-qt5integration dde-qt5xcb-plugin dde-qt5wayland-plugin qtchooser +``` + +### org.deepin.runtime.dtk/23.1.0 + +使用 deepin 23 release 仓库制作的 runtime,支持 x86 架构。 + +_在容器中执行 `cat /runtime/packages.list|awk '{print $2}'` 查看包列表_ + +```txt +libqt5core5a libqt5gui5 qt5-gtk-platformtheme qt5-flatpak-platformtheme qt5-xdgdesktopportal-platformtheme libqt5network5 libqt5opengl5 libqt5sql5 libqt5sql5-mysql libqt5sql5-odbc libqt5sql5-psql libqt5sql5-sqlite libqt5sql5-tds libqt5sql5-ibase libqt5xml5 libqt5dbus5 libqt5test5 libqt5concurrent5 libqt5widgets5 libqt5printsupport5 qtbase5-dev qtbase5-private-dev libqt5opengl5-dev qtbase5-dev-tools qt5-qmake-bin qt5-qmake qtbase5-examples qt5-default qtbase5-doc qtbase5-doc-html qtbase5-doc-dev libqt5core5a libqt5gui5 qt5-gtk-platformtheme qt5-flatpak-platformtheme qt5-xdgdesktopportal-platformtheme libqt5network5 libqt5opengl5 libqt5sql5 libqt5sql5-mysql libqt5sql5-odbc libqt5sql5-psql libqt5sql5-sqlite libqt5sql5-tds libqt5sql5-ibase libqt5xml5 libqt5dbus5 libqt5test5 libqt5concurrent5 libqt5widgets5 libqt5printsupport5 qtbase5-dev qtbase5-private-dev libqt5opengl5-dev qtbase5-dev-tools qt5-qmake-bin qt5-qmake qtbase5-examples qt5-default qtbase5-doc qtbase5-doc-html qtbase5-doc-dev libqt5svg5 libqt5svg5-dev qtsvg5-examples qtsvg5-doc qtsvg5-doc-html libqt5qml5 libqt5qmlmodels5 libqt5qmlworkerscript5 libqt5quick5 libqt5quickparticles5 libqt5quickshapes5 libqt5quicktest5 libqt5quickwidgets5 qml-module-qtquick-layouts qt5-qmltooling-plugins qml-module-qt-labs-animation qml-module-qt-labs-folderlistmodel qml-module-qtquick-localstorage qml-module-qt-labs-sharedimage qml-module-qt-labs-qmlmodels qml-module-qt-labs-wavefrontmesh qml-module-qtqml qml-module-qtqml-models2 qml-module-qtqml-statemachine qml-module-qtqml-workerscript2 qml-module-qtquick-particles2 qml-module-qtquick2 qml-module-qtquick-shapes qml-module-qt-labs-settings qml-module-qttest qml-module-qtquick-window2 qtdeclarative5-dev qtdeclarative5-private-dev qtdeclarative5-dev-tools qmlscene qml qtdeclarative5-examples qtdeclarative5-doc qtdeclarative5-doc-html qtdeclarative5-doc-dev qml-module-qtgraphicaleffects qtgraphicaleffects5-doc qtgraphicaleffects5-doc-html qml-module-qtquick-controls qml-module-qtquick-extras qml-module-qtquick-dialogs qml-module-qtquick-privatewidgets qtquickcontrols5-examples qtquickcontrols5-doc qtquickcontrols5-doc-html libqt5quickcontrols2-5 libqt5quicktemplates2-5 qml-module-qt-labs-calendar qml-module-qt-labs-platform qml-module-qtquick-controls2 qml-module-qtquick-templates2 qtquickcontrols2-5-dev qtquickcontrols2-5-private-dev qtquickcontrols2-5-doc qtquickcontrols2-5-doc-html qtquickcontrols2-5-examples qt5-image-formats-plugins libqt5multimedia5 libqt5multimedia5-plugins libqt5multimediaquick5 libqt5multimediawidgets5 qml-module-qtmultimedia qml-module-qtaudioengine libqt5multimediagsttools5 qtmultimedia5-examples qtmultimedia5-dev qtmultimedia5-doc qtmultimedia5-doc-html libqt5texttospeech5-dev libqt5texttospeech5 qtspeech5-flite-plugin qtspeech5-speechd-plugin qtspeech5-examples qtspeech5-doc qtspeech5-doc-html libqt5designer5 libqt5designercomponents5 qdbus-qt5 qdbus qdoc-qt5 qhelpgenerator-qt5 qtattributionsscanner-qt5 libqt5help5 qttools5-dev qttools5-private-dev qttools5-dev-tools qt5-assistant qttools5-examples qttools5-doc qttools5-doc-html libqt5x11extras5 libqt5x11extras5-dev qtx11extras5-doc qtx11extras5-doc-html qtwayland5-examples libqt5waylandclient5 libqt5waylandcompositor5 qml-module-qtwayland-compositor qml-module-qtwayland-client-texturesharing libqt5waylandcompositor5-dev libqt5waylandclient5-dev qtwayland5-private-dev qtwayland5-dev-tools qtwayland5 qtwayland5-doc qtwayland5-doc-html qttranslations5-l10n lxqt-build-tools libqt5xdg3 libqt5xdgiconloader3 libqt5xdg-dev libqt5xdgiconloader-dev qtxdg-dev-tools libdtkdata libdtkcommon-dev libdtkcore5 libdtkcore5-bin libdtkcore-dev libdtkcore-doc libdtkgui5 libdtkgui5-bin libdtkgui-dev libdtkgui-doc libdtkwidget5 libdtkwidget5-bin libdtkwidget-dev dtkwidget5-examples dtkwidget-doc qml-module-qtquick-controls2-styles-chameleon libdtkdeclarative5 libdtkdeclarative-dev libdtkdeclarative-doc dtk-exhibition googletest libgtest-dev libgmock-dev google-mock dde-qt5integration dde-qt5xcb-plugin dde-qt5wayland-plugin +``` + +### org.deepin.runtime.dtk/25.2.0 + +使用 deepin 25 beta 仓库制作的 runtime,支持 x86, arm64, loong64 架构。 + +_在容器中执行 `cat /runtime/packages.list|awk '{print $2}'` 查看包列表_ + +```txt +libmtdev1 libqt6core6 libvulkan-dev libinput10 qt6-wayland-private-dev libqt6quick6 libnorm1 libqt6opengl6 qml6-module-qt-labs-qmlmodels libqt6spatialaudio6 libqt6waylandcompositor6 qml6-module-qtquick-dialogs mailcap libqt6sql6-sqlite linguist-qt6 libqt6sql6-psql libsodium23 mime-support libbrotli-dev librist4 libdtk6widget gtk-update-icon-cache libqt6sql6 libjpeg-dev uuid-dev qmake6-bin libqt6xml6 libswscale7 qml6-module-qtwayland-compositor qml6-module-qtqml-base librabbitmq4 libdtk6core libqt6help6 xorg-sgml-doctools libxau-dev qt6-l10n-tools libopenmpt0 qml6-module-qttest libdeflate-dev qml6-module-qtquick3d-spatialaudio firebird3.0-common libqt6quicktemplates2-6 qt6-declarative-dev-tools libqt6sql6-ibase libsrt1.4-gnutls qt6-declarative-private-dev adwaita-icon-theme qml6-module-qtquick-controls2-styles-chameleon qml6-module-qtquick-window libglx-dev libjpeg62-turbo-dev qt6-5compat-dev qt6-wayland-dev-tools xtrans-dev qt6-tools-private-dev qt6-svg-private-dev libqt6qml6 qt6-qmltooling-plugins libcupsimage2-dev libcapstone4 pkg-config libqt6multimedia6 libwebp-dev libqt6qmlmodels6 libpciaccess-dev firebird3.0-common-doc libts0 libevdev2 libqt6quick3druntimerender6 icu-devtools libqt6svg6 qt6-speech-dev libdtk6log-dev qml-qt6 libdtk6widget-bin fonts-texgyre libdpkg-perl qml6-module-qtquick-shapes qml6-module-qmltime libmd4c0 libcolord2 libfontconfig-dev qml6-module-qtqml-workerscript libgstreamer-gl1.0-0 qt6-multimedia-dev qml6-module-qtmultimedia libavformat60 qml6-module-qtquick-effects libicu73 libodbc1 libqt6qmlcompiler6 libx11-dev libqt6quick3dutils6 libqt6svgwidgets6 qt6-tools-dev-tools libdtkcommon-dev libmariadb3 libb2-1 qml6-module-qt-labs-wavefrontmesh libexpat1-dev libsharpyuv-dev libtommath1 libstartup-notification0 libcups2-dev libspdlog1.12 dpkg-dev libcloudproviders0 libqt6printsupport6 libmbedcrypto3 qml6-module-qtquick-tooling liblerc-dev qml6-module-qtquick patch libgirepository-2.0-0 qml6-module-qtquick-particles libqt6shadertools6 qml6-module-qtquick-layouts libbluray2 libxcb-util-dev qt6-declarative-dev libwacom-common libmng1 libgl-dev libfile-find-rule-perl fonts-liberation libselinux1-dev libllvm17 libgtk-3-0 libudfread0 libzstd-dev libdtkdata qt6-speech-flite-plugin libsysprof-capture-4-dev qt6-documentation-tools qt6-gtk-platformtheme libdtk6core-dev qml6-module-qtqml-models libqt6network6 libwayland-bin libqt6test6 libwacom2 libwebpdecoder3 libdtk6log qml6-module-qtquick-localstorage qml6-module-qt5compat-graphicaleffects qml6-module-qt-labs-folderlistmodel qt6-base-private-dev libqt6designer6 libgtk-3-common qml6-module-qtquick-nativestyle libpq5 libicu-dev qt6-speech-speechd-plugin libwacom-dev qt6-image-formats-plugins fcitx5-frontend-qt6 qml6-module-qt-labs-animation dbus-broker libffi-dev libmount-dev libqt6gui6 qml6-module-qtquick-controls libpgm-5.3-0 libdtk6declarative libqt6dbus6 mysql-common libxcb1-dev pkgconf libpkgconf3 libfcitx5-qt-data qml6-module-qtcore libfcitx5-qt6-dev libspeechd2 qml6-module-qt-labs-platform qt6-translations-l10n qmlscene-qt6 dtk6-exhibition libqt6sql6-odbc libqt6designercomponents6 libpcre2-posix3 libdtk6widget-dev dde-qt6xcb-plugin libinput-bin libzmq5 liblzma-dev libjbig-dev libpcre2-dev libdtk6gui-dev libqt6waylandclient6 qml6-module-qt-labs-sharedimage qt6-base-dev libdtk6core-bin python3-packaging libssh-gcrypt-4 libxkbcommon-dev libqt6quickvectorimagegenerator6 libbz2-dev mariadb-common qml6-module-qttexttospeech libdtk6gui-bin libflite1 libgme0 libinput-dev lshw x11proto-dev libqt6quicktest6 libgumbo2 libqt6multimediawidgets6 libpng-dev libqt6wlshellintegration6 liblitehtml0 libpcre2-32-0 libqt6quickwidgets6 libxcb-util0-dev libchromaprint1 qml6-module-qtquick-templates libnumber-compare-perl gir1.2-gudev-1.0 qt6-qmllint-plugins qt6-svg-dev libudev-dev libmpg123-0 libqt6quickcontrols2-6 libqt6openglwidgets6 libwayland-dev libqt6concurrent6 fonts-freefont-otf usrmerge libclang1-17 libopengl-dev libtext-glob-perl libevdev-dev qt6-tools-dev libsepol-dev qml6-module-qtqml qt6-qpa-plugins libfcitx5-qt6-1 qt6-wayland designer-qt6 libvorbisfile3 libgudev-1.0-dev libdtk6declarative-dev qdbus-qt6 libfreetype-dev dde-qt6integration qt6-base-dev-tools libgudev-1.0-0 libqt6widgets6 x11proto-core-dev libcjson1 qml6-module-qt-labs-settings qml6-module-qtwayland-client-texturesharing libqt6texttospeech6 libdtk6gui libblkid-dev fonts-freefont-ttf make libmtdev-dev libglib2.0-dev libtiffxx6 assistant-qt6 libfcitx5utils2 libtiff-dev libclang-cpp17 qml6-module-qtqml-xmllistmodel libfmt10 libqt6core5compat6 libfbclient2 fonts-croscore libqt6quick3d6 libqt6uitools6 libdouble-conversion3 zlib1g-dev libxdmcp-dev libqt6sql6-mysql pkgconf-bin qt6-xdgdesktopportal-platformtheme libglib2.0-dev-bin libpthread-stubs0-dev qt6-wayland-dev qmake6 +``` + +### org.deepin.runtime.webengine/25.2.0 + +使用 deepin 25 beta 仓库制作的 runtime,支持 x86, arm64, loong64 架构。 + +_在容器中执行 `cat /runtime/packages.list|awk '{print $2}'` 查看包列表_ + +```txt +libmtdev1 libqt6core6 libxslt1.1 libvulkan-dev libinput10 qt6-wayland-private-dev libqt6quick6 libnorm1 libqt6opengl6 qml6-module-qt-labs-qmlmodels libqt6spatialaudio6 libqt6waylandcompositor6 qml6-module-qtquick-dialogs mailcap libqt6sql6-sqlite linguist-qt6 libqt6sql6-psql libsodium23 mime-support libbrotli-dev librist4 libdtk6widget gtk-update-icon-cache libqt6sql6 libjpeg-dev uuid-dev qmake6-bin libqt6xml6 libswscale7 qml6-module-qtwayland-compositor qml6-module-qtqml-base librabbitmq4 libdtk6core libqt6help6 libqt6positioningquick6 xorg-sgml-doctools libxau-dev qt6-l10n-tools libopenmpt0 qml6-module-qtwebengine-controlsdelegates qml6-module-qttest libdeflate-dev qml6-module-qtquick3d-spatialaudio firebird3.0-common libqt6quicktemplates2-6 qt6-declarative-dev-tools libqt6sql6-ibase libsrt1.4-gnutls qt6-declarative-private-dev adwaita-icon-theme qml6-module-qtquick-controls2-styles-chameleon qml6-module-qtquick-window libglx-dev libjpeg62-turbo-dev qt6-5compat-dev qt6-wayland-dev-tools xtrans-dev qt6-tools-private-dev qt6-svg-private-dev libqt6pdf6 libqt6qml6 qt6-qmltooling-plugins libcupsimage2-dev libcapstone4 pkg-config libqt6multimedia6 libqt6webenginewidgets6 libwebp-dev libqt6qmlmodels6 libpciaccess-dev firebird3.0-common-doc libts0 libevdev2 libqt6quick3druntimerender6 icu-devtools libqt6svg6 qt6-speech-dev libdtk6log-dev qml-qt6 libdtk6widget-bin fonts-texgyre libdpkg-perl qml6-module-qtquick-shapes qml6-module-qmltime libmd4c0 libcolord2 libfontconfig-dev qml6-module-qtqml-workerscript libgstreamer-gl1.0-0 qt6-multimedia-dev qml6-module-qtmultimedia libavformat60 qml6-module-qtquick-effects libicu73 libodbc1 libqt6pdfquick6 libqt6qmlcompiler6 libx11-dev qt6-webengine-dev libqt6quick3dutils6 libqt6svgwidgets6 qt6-tools-dev-tools libdtkcommon-dev libmariadb3 libb2-1 qml6-module-qt-labs-wavefrontmesh libexpat1-dev libsharpyuv-dev libtommath1 sse3-support libstartup-notification0 libcups2-dev libspdlog1.12 dpkg-dev libcloudproviders0 libqt6printsupport6 libmbedcrypto3 qml6-module-qtquick-tooling liblerc-dev qml6-module-qtquick patch libgirepository-2.0-0 qml6-module-qtquick-particles libqt6shadertools6 qml6-module-qtquick-layouts qt6-webengine-private-dev libbluray2 qt6-webengine-dev-tools libxcb-util-dev qt6-declarative-dev libwacom-common libmng1 libgl-dev libfile-find-rule-perl fonts-liberation libselinux1-dev libllvm17 libgtk-3-0 libudfread0 libzstd-dev libdtkdata qt6-speech-flite-plugin libsysprof-capture-4-dev qt6-documentation-tools qt6-gtk-platformtheme libdtk6core-dev qml6-module-qtqml-models libqt6network6 libwayland-bin qt6-pdf-dev libqt6test6 libwacom2 libwebpdecoder3 libdtk6log qml6-module-qtquick-localstorage qml6-module-qt5compat-graphicaleffects qml6-module-qt-labs-folderlistmodel isa-support qt6-base-private-dev libqt6designer6 libgtk-3-common qml6-module-qtquick-nativestyle libpq5 libicu-dev qt6-image-formats-plugin-pdf qt6-speech-speechd-plugin libwacom-dev qt6-image-formats-plugins fcitx5-frontend-qt6 qml6-module-qt-labs-animation dbus-broker libffi-dev libmount-dev libqt6gui6 qml6-module-qtquick-controls libqt6positioning6-plugins libpgm-5.3-0 libdtk6declarative libqt6dbus6 mysql-common libxcb1-dev pkgconf libqt6webenginecore6 libpkgconf3 libfcitx5-qt-data qml6-module-qtcore libfcitx5-qt6-dev libspeechd2 qml6-module-qt-labs-platform qt6-translations-l10n qmlscene-qt6 dtk6-exhibition libqt6sql6-odbc libqt6designercomponents6 libpcre2-posix3 libdtk6widget-dev dde-qt6xcb-plugin libinput-bin libqt6webenginecore6-bin libzmq5 liblzma-dev libjbig-dev libpcre2-dev libdtk6gui-dev libqt6waylandclient6 qml6-module-qt-labs-sharedimage qt6-base-dev libdtk6core-bin python3-packaging libssh-gcrypt-4 libxkbcommon-dev libqt6quickvectorimagegenerator6 qml6-module-qtwebchannel qml6-module-qtwebengine libbz2-dev mariadb-common qml6-module-qttexttospeech libdtk6gui-bin libflite1 libgme0 libinput-dev libqt6webengine6-data lshw x11proto-dev libqt6quicktest6 libgumbo2 libqt6multimediawidgets6 libqt6webenginequick6 libpng-dev libqt6wlshellintegration6 libqt6webchannel6 liblitehtml0 libpcre2-32-0 libqt6quickwidgets6 libxcb-util0-dev libchromaprint1 qt6-positioning-dev qml6-module-qtquick-templates libnumber-compare-perl gir1.2-gudev-1.0 qt6-qmllint-plugins qt6-svg-dev libudev-dev libmpg123-0 libqt6quickcontrols2-6 libqt6openglwidgets6 libwayland-dev libqt6serialport6 libqt6concurrent6 fonts-freefont-otf usrmerge qt6-webchannel-dev libclang1-17 libopengl-dev libtext-glob-perl libevdev-dev qt6-tools-dev libsepol-dev libqt6pdfwidgets6 qml6-module-qtqml qml6-module-qtquick-pdf qt6-qpa-plugins libfcitx5-qt6-1 qt6-wayland designer-qt6 libvorbisfile3 libqt6webchannelquick6 libgudev-1.0-dev libdtk6declarative-dev qdbus-qt6 libfreetype-dev dde-qt6integration qt6-base-dev-tools libgudev-1.0-0 libqt6widgets6 x11proto-core-dev libcjson1 qml6-module-qt-labs-settings qml6-module-qtwayland-client-texturesharing libqt6texttospeech6 libdtk6gui libblkid-dev fonts-freefont-ttf make libmtdev-dev libglib2.0-dev libtiffxx6 assistant-qt6 libfcitx5utils2 libtiff-dev libqt6positioning6 libclang-cpp17 qml6-module-qtqml-xmllistmodel libfmt10 libqt6core5compat6 libfbclient2 fonts-croscore libqt6quick3d6 libqt6uitools6 libdouble-conversion3 zlib1g-dev libxdmcp-dev libqt6sql6-mysql pkgconf-bin qt6-xdgdesktopportal-platformtheme libglib2.0-dev-bin libpthread-stubs0-dev qt6-wayland-dev qmake6 +``` diff --git a/docs/pages/en/guide/start/how_to_use.md b/docs/pages/en/guide/start/build_your_first_app.md similarity index 56% rename from docs/pages/en/guide/start/how_to_use.md rename to docs/pages/en/guide/start/build_your_first_app.md index 232a783e6..b4cb2c8fc 100644 --- a/docs/pages/en/guide/start/how_to_use.md +++ b/docs/pages/en/guide/start/build_your_first_app.md @@ -4,17 +4,19 @@ SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. SPDX-License-Identifier: LGPL-3.0-or-later --> -# Build linyaps applications +# Build Your First Linyaps Application -Taking [deepin-calculator](https://github.com/linuxdeepin/deepin-calculator.git) as an example, introduce the process of building a linyaps package from source code. +Using [deepin-calculator](https://github.com/linuxdeepin/deepin-calculator.git) as an example, this guide introduces the process of building a Linyaps package from source code. -## Create linyaps project +Linyaps applications need to use reverse domain name notation for their appid. + +## Create Project ```bash mkdir org.deepin.calculator ``` -Create a file named `linglong.yaml` in the directory. +Create a linglong.yaml file in the directory ```bash touch org.deepin.calculator/linglong.yaml @@ -26,7 +28,7 @@ Enter the directory cd org.deepin.calculator ``` -Edit the linglong.yaml file using a text editor. +Edit linglong.yaml using a text editor ```bash version: '1' @@ -42,8 +44,8 @@ package: command: - /opt/apps/org.deepin.calculator/files/bin/deepin-calculator -base: org.deepin.foundation/23.0.0 -runtime: org.deepin.Runtime/23.0.1 +base: org.deepin.base/23.1.0 +runtime: org.deepin.runtime.dtk/23.1.0 sources: - kind: git @@ -81,9 +83,9 @@ build: | cmake --build build --target install ``` -The file "linglong.yaml" is written following the YAML syntax specifications. +The linglong.yaml file follows YAML syntax specifications. -Detailed explanation of fields in linglong.yaml for reference: [Manifests](../ll-builder/manifests.md) +For detailed explanation of fields in linglong.yaml, refer to: [Build Configuration File Introduction](../building/manifests.md) ## Build @@ -91,37 +93,40 @@ Detailed explanation of fields in linglong.yaml for reference: [Manifests](../ll ll-builder build ``` -## Run +Wait for the Linyaps application to finish building. + +## Run Linyaps Application ```bash ll-builder run ``` -the successful output of `ll-builder run` is as follows: +Successful output from `ll-builder run` is as follows: ![org.deepin.calculator.png](./images/org.deepin.calculator.png) -For debugging purposes, use the additional `--exec /bin/bash` parameter to replace the default program executed upon entering the container, for example: +For debugging convenience, you can use the additional `--exec /bin/bash` parameter to replace the default program executed after entering the container ```bash ll-builder run --exec /bin/bash ``` -# Conversion application +
+
+ +# Convert deb Application -Here, we use baidunetdisk as an example. We will introduce the process of converting DEB packages into linyaps packages +Using Baidu Netdisk as an example, this introduces the process of converting a deb package to a Linyaps package. -## Obtain software package +## Get Software Package -First, obtain the deb package file. -Currently, only software following the application store packaging -specifications is supported for conversion. +First obtain the deb package file. Currently only supports converting software that follows application store packaging specifications. ```bash apt download com.baidu.baidunetdisk ``` -## Conversion +## Convert Application ```bash ll-pica convert -c com.baidu.baidunetdisk_4.17.7_amd64.deb -w work -b --exportFile layer @@ -133,12 +138,22 @@ Enter the directory cd work/package/com.baidu.baidunetdisk/amd64 ``` -Installed using the `ll-cli install` command. +## Install layer file ```bash ll-cli install ./com.baidu.baidunetdisk_4.17.7.0_x86_64_runtime.layer ``` -Successful execution output as follows: +## Run Application + +``` +ll-cli run com.baidu.baidunetdisk +``` + +Successful run output is as follows: ![img](images/com.baidu.baidunetdisk.png) + +# Video Links + +[Tongxin Alliance "Development Empowerment to Build Linyaps Ecosystem" Sharing Live Conference Replay Video](https://www.bilibili.com/video/BV1ff421R7aY) diff --git a/docs/pages/en/guide/start/install.md b/docs/pages/en/guide/start/install.md index f328f5f88..c15ff2e96 100644 --- a/docs/pages/en/guide/start/install.md +++ b/docs/pages/en/guide/start/install.md @@ -4,46 +4,59 @@ SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. SPDX-License-Identifier: LGPL-3.0-or-later --> -# Install linyaps +# Install Linyaps -linyaps is composed of three parts. +linyaps is composed of three parts: -- ll-builder is used to build and debug linyaps applications, provided by linglong-builder. -- ll-box is a sandbox container, provided by linglong-box. -- ll-cli manages and runs linyaps applications, provided by linglong-bin. +- ll-builder is used to build and debug Linyaps applications, provided by linglong-builder. +- ll-box sandbox container, provided by linglong-box. +- ll-cli manages and runs Linyaps applications, provided by linglong-bin. ## Repository Usage Instructions -### Release Repository +### release repository -Automatically built based on the latest tag. +Automatically built based on the latest tag -Repository URL: +1. Repository address +2. Build address -Build URL: +### latest repository -### Latest Repository +Automatically built based on the latest commit -Automatically built based on the latest commits. - -Repository URL: - -Build URL: +1. Repository address +2. Build address :::tip -The installation steps below are based on the release repository. If you'd like to experience unreleased features, you can replace release in the repository URL with latest to install the preview version built from the master branch. +The following installation steps all use the release repository. If you want to experience features that have not yet been released, change "release" to "latest" in the repository address to install the preview version built based on the master branch ::: -## Installation Instructions +## Linyaps Installation Instructions + +### Arch / Manjaro / Parabola Linux + +```sh +sudo pacman -Syu linyaps +``` + +Linyaps web store installer needs to be installed through [AUR repository](https://aur.archlinux.org/packages/linyaps-web-store-installer) or [self-built repository](https://github.com/taotieren/aur-repo). + +```bash +# AUR +yay -Syu linyaps-web-store-installer +# or self-built source +sudo pacman -Syu linyaps-web-store-installer +``` ### deepin 25 ```sh echo "deb [trusted=yes] https://ci.deepin.com/repo/obs/linglong:/CI:/release/Deepin_25/ ./" | sudo tee /etc/apt/sources.list.d/linglong.list sudo apt update -sudo apt install linglong-builder linglong-box linglong-bin +sudo apt install linglong-bin linglong-installer ``` ### deepin 23 @@ -51,7 +64,7 @@ sudo apt install linglong-builder linglong-box linglong-bin ```sh echo "deb [trusted=yes] https://ci.deepin.com/repo/obs/linglong:/CI:/release/Deepin_23/ ./" | sudo tee /etc/apt/sources.list.d/linglong.list sudo apt update -sudo apt install linglong-builder linglong-box linglong-bin +sudo apt install linglong-bin linglong-installer ``` ### Fedora 41 @@ -59,7 +72,15 @@ sudo apt install linglong-builder linglong-box linglong-bin ```sh sudo dnf config-manager addrepo --from-repofile "https://ci.deepin.com/repo/obs/linglong:/CI:/release/Fedora_41/linglong%3ACI%3Arelease.repo" sudo dnf update -sudo dnf install linglong-builder linglong-box linglong-bin +sudo dnf install linglong-bin linyaps-web-store-installer +``` + +### Fedora 42 + +```sh +sudo dnf config-manager addrepo --from-repofile "https://ci.deepin.com/repo/obs/linglong:/CI:/release/Fedora_42/linglong%3ACI%3Arelease.repo" +sudo dnf update +sudo dnf install linglong-bin linyaps-web-store-installer ``` ### Ubuntu 24.04 @@ -67,7 +88,7 @@ sudo dnf install linglong-builder linglong-box linglong-bin ```sh echo "deb [trusted=yes] https://ci.deepin.com/repo/obs/linglong:/CI:/release/xUbuntu_24.04/ ./" | sudo tee /etc/apt/sources.list.d/linglong.list sudo apt update -sudo apt install linglong-builder linglong-box linglong-bin +sudo apt install linglong-bin linglong-installer ``` ### Debian 12 @@ -75,7 +96,15 @@ sudo apt install linglong-builder linglong-box linglong-bin ```sh echo "deb [trusted=yes] https://ci.deepin.com/repo/obs/linglong:/CI:/release/Debian_12/ ./" | sudo tee /etc/apt/sources.list.d/linglong.list sudo apt update -sudo apt install linglong-builder linglong-box linglong-bin +sudo apt install linglong-bin linglong-installer +``` + +### Debian 13 + +```sh +echo "deb [trusted=yes] https://ci.deepin.com/repo/obs/linglong:/CI:/release/Debian_13/ ./" | sudo tee /etc/apt/sources.list.d/linglong.list +sudo apt update +sudo apt install linglong-bin linglong-installer ``` ### openEuler 23.09 @@ -84,7 +113,16 @@ sudo apt install linglong-builder linglong-box linglong-bin sudo dnf config-manager --add-repo "https://ci.deepin.com/repo/obs/linglong:/CI:/release/openEuler_23.09/linglong%3ACI%3Arelease.repo" sudo sh -c "echo gpgcheck=0 >> /etc/yum.repos.d/linglong%3ACI%3Arelease.repo" sudo dnf update -sudo dnf install linglong-builder linglong-box linglong-bin +sudo dnf install linglong-bin linyaps-web-store-installer +``` + +### openEuler 24.03 + +```sh +sudo dnf config-manager --add-repo "https://ci.deepin.com/repo/obs/linglong:/CI:/release/openEuler_24.03/linglong%3ACI%3Arelease.repo" +sudo sh -c "echo gpgcheck=0 >> /etc/yum.repos.d/linglong%3ACI%3Arelease.repo" +sudo dnf update +sudo dnf install linglong-bin linyaps-web-store-installer ``` ### UOS 1070 @@ -92,7 +130,7 @@ sudo dnf install linglong-builder linglong-box linglong-bin ```sh echo "deb [trusted=yes] https://ci.deepin.com/repo/obs/linglong:/CI:/release/uos_1070/ ./" | sudo tee /etc/apt/sources.list.d/linglong.list sudo apt update -sudo apt install linglong-builder linglong-box linglong-bin +sudo apt install linglong-bin linglong-installer ``` ### AnolisOS 8 @@ -100,7 +138,7 @@ sudo apt install linglong-builder linglong-box linglong-bin ```sh sudo dnf config-manager addrepo --from-repofile "https://ci.deepin.com/repo/obs/linglong:/CI:/release/AnolisOS_8/linglong%3ACI%3Arelease.repo" sudo dnf update -sudo dnf install linglong-builder linglong-box linglong-bin +sudo dnf install linglong-bin linyaps-web-store-installer ``` ### openkylin 2.0 @@ -108,5 +146,51 @@ sudo dnf install linglong-builder linglong-box linglong-bin ```sh echo "deb [trusted=yes] https://ci.deepin.com/repo/obs/linglong:/CI:/release/openkylin_2.0/ ./" | sudo tee /etc/apt/sources.list.d/linglong.list sudo apt update -sudo apt install linglong-builder linglong-box linglong-bin +sudo apt install linglong-bin linglong-installer +``` + +### NixOS + +In NixOS 25.11 or later versions, modify the configuration file (usually `/etc/nixos/configuration.nix`), and add: + +```nix + services.linyaps.enable = true; +``` + +## Linyaps Build Tool Installation Instructions + +### Debian-based + +```bash +sudo apt install linglong-builder +``` + +### RPM-based + +```bash +sudo dnf install linglong-builder +``` + +## Linyaps Conversion Tool Installation Instructions + +### Deepin 23/25 + +```bash +sudo apt install linglong-pica + +``` + +### Arch Linux + +Install via [AUR repository](https://aur.archlinux.org/packages/linglong-pica) or [self-hosted repository](https://github.com/taotieren/aur-repo). + +```bash + +# AUR +yay -Syu linglong-pica + +# or self-hosted repository + +sudo pacman -Syu linglong-pica + ``` diff --git a/docs/pages/en/guide/start/release_note.md b/docs/pages/en/guide/start/release_note.md new file mode 100644 index 000000000..0e385f253 --- /dev/null +++ b/docs/pages/en/guide/start/release_note.md @@ -0,0 +1,104 @@ +# Linyaps Release Notes + +--- + +## Version 1.10 + +### 🚀 **New Features** + +* **GPU Support:** The application runtime now supports graphics processing unit (GPU) capabilities to improve computing performance and rendering efficiency. + +* **Container Process Management:** Containerized runtimes have been enhanced to support waiting for child processes to terminate, ensuring resource management and system stability. + +* **Repository Mirror Control:** Repository configuration now includes the ability to enable and disable mirroring, allowing users to flexibly control and optimize dependency pull speed. + +* **Startup Environment Variables:** The application startup command now supports using the `--env` parameter to set runtime environment variables, facilitating dynamic configuration and debugging. + +* **Build Tool Export:** The build tool now includes a `--ref` option, supporting the export of UAB packages by specific references, optimizing the distribution and deployment process. + +### 🐞 **Bug Fixes** + +* **Desktop Integration:** Fixed a logical error that could cause application icons to disappear from the taskbar after updating the Linglong component. + +* **File I/O:** Resolved encoding and parsing issues that caused operations to fail when opening file paths containing special characters. + +* **Build File Inclusion:** Fixed an issue where the build tools failed to correctly include and export hidden files when exporting packages. + +--- + +## Version 1.9 + +### 🚀 **New Features** + +* **Container Process Management Optimization:** Introduced **`dumb-init`** as the container `init` process, responsible for signal forwarding and zombie process cleanup, significantly optimizing container internal process management efficiency. +* **UAB File Generation Refactoring:** Completely refactored the UAB file generation logic, encapsulating all related dependencies into the **`ll-builder-utils`** toolchain, resolving compatibility issues during export on some distributions. +* **Qt Version Compatibility:** The project now supports both **Qt5 and Qt6**, automatically selecting the appropriate Qt version when compiling applications, improving flexibility. +* **Command Line Tool Multi-language Support:** Command line tools now support more languages from different countries and regions, enhancing internationalization capabilities. +* **Architecture-specific Configuration Loading:** Supports loading architecture-specific configuration files (e.g., `linglong.arm64.yaml`) through **`ll-builder`**, enabling automatic adaptation for different hardware architectures. +* **Build Product Compression Algorithm Selection:** Linyaps build tools now allow users to specify compression algorithms when exporting target products. +* **Local Multi-repository Support:** Added support for local multi-repository management, which can be used for installing and searching applications. + +### 🐞 **Bug Fixes** + +* Fixed the issue where error messages were too vague, now the prompts are clearer and more explicit. +* Fixed anomalies in application cache loading and update logic. +* Fixed defects where update tasks would abnormally terminate during application runtime. +* Fixed potential abnormal error reporting issues when uninstalling applications. + +--- + +## Version 1.8 + +### 🚀 **New Features** + +* **Enhanced Build Capabilities:** + * **Dependency Management Optimization:** Improved dependency management mechanism, supporting installation of build toolchain dependencies through **APT package manager**. + * **Compression Algorithm Extension:** When exporting applications, now supports more compression algorithms, including **LZ4, LZMA, and ZSTD**. + * **Build Environment Upgrade:** Linyaps client now supports building in **Qt6 environment**. +* **Internationalization Support:** Command line tools added support for multiple languages, including English (en_US/en_GB), Spanish (es), Simplified Chinese (zh_CN), Catalan (ca), Finnish (fi), Polish (pl), Brazilian Portuguese (pt_BR), Albanian (sq), and Ukrainian (uk). + +### 🐞 **Bug Fixes** + +* **Stability Improvements:** + * Fixed the issue where mounted directories were not completely cleaned up after installing layers. + * Resolved defects in upgrading base environment and runtime components. + * Optimized application uninstall logic to ensure residual directories can be thoroughly cleaned. +* **Symbolic Link Processing Mechanism Improvement:** Fixed the anomaly where relative path symbolic links were incorrectly converted to empty directories; also corrected the issue where invalid symbolic links were not properly copied. + +--- + +## Version 1.7 + +### 🚀 **New Features** + +* **Repository Storage Layer Structure Optimization:** Optimized the repository's storage layer structure, making application management no longer forcibly dependent on the file system, improving flexibility. +* **Linyaps Data File Export Optimization:** Linyaps data file export function no longer exports all files under the `share` directory, reducing export volume. +* **Loongson New World Architecture Support:** Linyaps now supports application packaging and running on **Loongson New World architecture**. +* **Installation, Uninstallation, and Update Behavior Adjustment and Optimization:** + * The new version no longer supports installing multiple versions of the same application locally. For multiple old versions retained after client upgrade, all package management operations will only take effect on the highest version except for uninstall operations. + * When upgrading or downgrading while the application is running, the uninstall action of the old version will be delayed to ensure smooth transition. +* **Linyaps Command Line Tool Help Information Internationalization:** Command line tool help information has begun internationalization, currently supporting Chinese, English, and Spanish, with professional internationalization translation platforms to be integrated later. +* **Linyaps Command Line Parameter Parsing Optimization:** Adopted a new command line parameter parsing framework, making parameter information display clearer and more readable. +* **Linyaps Application Packaging Build Optimization:** When using the new build tool to package applications, application debug symbols will be stripped to effectively reduce the final application package size. +* **`runtime/base` Management Command Adjustment:** `runtime/base` no longer supports uninstallation using the `uninstall` command, instead providing the `prune` command for cleaning up unused `runtime` and `base` components. +* **New `ll-cli list --upgradable` Command:** This command is used to display all upgradeable version lists of currently installed applications. + +### 🐞 **Bug Fixes** + +* Solved the problem of Linyaps application debugging failure. +* Fixed the defect that could cause application crashes when using the `ll-cli search` command to find applications after enabling system proxy. + +--- + +## Version 1.6 + +### 🚀 **New Features** + +* **USB Drive Directory File Reading:** Linyaps applications now support direct reading of directories and files in USB drives. +* **New `ll-pica-flatpak` Tool:** Added the **`ll-pica-flatpak`** tool, supporting conversion of `Flatpak` format applications to Linyaps format. + +### 🐞 **Bug Fixes** + +* Fixed the issue where script execution failed when upgrading Linyaps packages. +* Fixed the defect where executing other commands might be blocked when installing Linyaps applications. +* Fixed the problem where application names were too long and displayed incompletely when viewing the application list. diff --git a/docs/pages/en/guide/start/whatis.md b/docs/pages/en/guide/start/whatis.md index d3c0d62eb..01aa2c0c8 100644 --- a/docs/pages/en/guide/start/whatis.md +++ b/docs/pages/en/guide/start/whatis.md @@ -4,53 +4,51 @@ SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. SPDX-License-Identifier: LGPL-3.0-or-later --> -# Summary +# Overview -linyaps, an open source package format developed by UnionTech Software, is designed to manage, distribute, create a sandbox for packages, and integrate development tools, instead of using package management tools such as `deb` or `rpm`. +linyaps, an open source package format developed by UnionTech Software, is designed to manage, distribute, create sandboxes for packages, and integrate development tools, instead of using package management tools such as `deb` or `rpm`. -## Problems with current package management +## Current Issues with Package Managers -1. Both `deb` and `rpm` are strongly-dependent package management systems and allow complex cross dependencies (or circular dependencies) between components, which makes maintenance a matter of great expertise. A little carelessness will lead to a complete system failure that cannot be repaired. +1. Both `deb` and `rpm` are strongly-dependent package management systems that allow complex cross dependencies (or circular dependencies) between components, which makes maintenance a matter of great expertise. A little carelessness will lead to a complete system failure that cannot be repaired. 2. Installation dependencies and running dependencies are coupled so that multiple versions can hardly coexist. Although `deb` and `rpm` have provided several solutions to solve the multi-version coexistence problem, these solutions require changes in source code and are infeasible. 3. The `Hook` system is complex and has no restrictions, through which many operations can damage the system. 4. They have insufficient reliability, no redundant recovery design, and a lack of verification mechanisms. Once the package management system fails, the system can hardly be repaired. -5. The permissions of `deb` and `rpm` are loosely controlled with big security risks. +5. The permissions of `deb` and `rpm` are loosely controlled with significant security risks. 6. The current package updates do not support incremental updates, which is a great waste of resources. -## linyaps advantages +## Advantages of Linyaps 1. Improve usability and solve the dependency conflict problem of `deb` and `rpm`. -2. Perform the application permission management mechanism to strengthen security. +2. Implement the application permission management mechanism to strengthen security. 3. Support incremental updates of applications. ## Comparison -| Features | Linglong | Flatpak | Snap | AppImage | -| ------------------------------------------- | ----------------------------------------------- | --------------------------- | --------------------------- | --------------------------------------------------------- | -| Package desktop apps | ✔ | ✔ | ✔ | ✔ | -| Package terminal apps | ✔ | ✔ | ✔ | ✔ | -| Deal with server apps | ✔ | ✘ | ✔ | ✘ | -| Package system services (root access) | ✘ | ✘ | ✔ | ✘ | -| Normal themes | ✔ | ✔ | ✔ | ✔ | -| Library hosting services | ✔ | ✘ | ✘ | ✘ | -| Source of libraries/dependencies | In packages | | | | -| Host system | In packages | | | | -| SDK | In packages | | | | -| snap base | | | | | -| Commercial support | ✔ | ✘ | ✔ | ✘ | -| Apps quantity | About 3000+ | 1400+ | 6600+ | 1300+ | -| Development tools | | GNOME Builder | electron-builder | | -| GNOME Builder | electron-builder | | | | -| Sandbox | ✔ | ✔ | ✔ | ◐ (Not officially available, but technically feasible) | -| Rootless sandbox | ✔ | ✘ | ✘ | ✘ | -| Run without installation | ✔ (Offer Bundle packages) | ✘ | ✘ | ✔ | -| Run without decompression | ✔ (Offer Bundle packages) | ✘ | ✔ | ✔ | -| Self-distribution/Green-format distribution | ◐ (Technically feasible, but system limits it) | ✘ | ✘ | ✔ | -| Run Wine apps | ◐ (Adapting now) | ◐ (Theoretically possible) | ◐ (Theoretically possible) | ◐ (Use LD to modify open calls, with poor compatibility) | -| Support offline environment | ✔ | ✔ | ✔ | ✔ | -| Permission management | ✔ | ✔ | ✔ | ✘ | -| Center repository | mirror-repo-linglong.deepin.com | FlatHub | Snap Store | AppImageHub | -| | | | | | -| Multi-version coexistence | ✔ | ✔ | ✔ | ✔ | -| Peer-to-peer distribution | ✔ | ✔ | ✔ | ✔ | -| App upgrades | By repository | By repository | By repository | By official tool | +| Feature | Linyaps | Flatpak | Snap | AppImage | +| ------------------------------------------- | ------------------------------- | ------------------------- | -------------------------- | ---------------------------------------------------- | +| Desktop Application Packaging | ✔ | ✔ | ✔ | ✔ | +| Terminal Application Packaging | ✔ | ✔ | ✔ | ✔ | +| Server Application Handling | ✔ | ✘ | ✔ | ✘ | +| System Service Packaging (root privileges) | ✘ | ✘ | ✔ | ✘ | +| Theme Functionality Normal | ✔ | ✔ | ✔ | ✔ | +| Library Hosting Service Provided | ✔ | ✘ | ✘ | ✘ | +| Library/Dependency Source | Package carries its own | | | | +| Host System | Package carries its own | | | | +| SDK | Package carries its own | | | | +| Snap Base | | | | | +| Commercial Support | ✔ | ✘ | ✔ | ✘ | +| Number of App Stores | Estimated 4700+ | 1400+ | 6600+ | 1300+ | +| Development Tool Support | linglong-builder | GNOME Builder | electron-builder | | +| Container Support | ✔ | ✔ | ✔ | ◐ (Not officially provided, technically feasible) | +| Rootless Container | ✔ | ✘ | ✘ | ✘ | +| Run Without Installation | ✔ (Provides Bundle Mode) | ✘ | ✘ | ✔ | +| Run Without Extraction | ✔ (Provides Bundle Mode) | ✘ | ✔ | ✔ | +| Self-distribution/Green Format Distribution | ✔ | ✘ | ✘ | ✔ | +| Wine Application Support | ✔  | ◐ (Theoretically feasible | ◐ (Theoretically feasible) | ◐ (Uses LD to modify open calls, poor compatibility) | +| Offline Environment Support | ✔ | ✔ | ✔ | ✔ | +| Permission Management | ✔ | ✔ | ✔ | ✘ | +| Central Repository | mirror-repo-linglong.deepin.com | FlatHub | Snap Store | AppImageHub | +| Multi-version Coexistence | ✔ | ✔ | ✔ | ✔ | +| Peer-to-peer Distribution | ✔ | ✔ | ✔ | ✔ | +| Application Upgrade | Repository upgrade | Repository upgrade | Repository upgrade | Official tool upgrade | diff --git a/docs/pages/en/guide/tips-and-faq/faq.md b/docs/pages/en/guide/tips-and-faq/faq.md new file mode 100644 index 000000000..914c92920 --- /dev/null +++ b/docs/pages/en/guide/tips-and-faq/faq.md @@ -0,0 +1,91 @@ + + +# Common Runtime Issues + +1. Why does the application fail to read resource files under `/usr/share` during runtime? + + Linyaps applications run in a container environment where application data is mounted under `/opt/apps//`. The `/usr/share` directory only contains system data, not application-related data. Therefore, directly reading from `/usr/share` will fail. Recommended solution: Use the `XDG_DATA_DIRS` environment variable to read resources, as `/opt/apps//files/share` will be included in this environment variable's search path. + +2. Why can't the application find font library files at runtime? Why could it read the corresponding font libraries when installed as a `deb` package? + + When installing a `deb` package, the corresponding font library files are brought in as dependencies. However, the Linyaps package format uses a self-sufficient packaging approach. Except for basic system libraries and the `Qt` and `DTK` libraries provided in the `runtime`, all other dependency data files must be provided by the application itself. It is recommended to place the corresponding data files under `files/share` and use the `XDG_DATA_DIRS` environment variable to read the path. + +3. What's in the Linyaps application `runtime`? Can I add some library files to it? + + Currently, the `runtime` that Linyaps applications depend on provides `Qt` libraries and `DTK` libraries. Due to strict size limitations on the `runtime`, adding additional library files to the `runtime` is currently not allowed. + +4. Can the application create configuration files in any path within the container during runtime? + + Configuration files can be created under `XDG_CONFIG_HOME`. + +5. Where is application data saved? Where can it be found outside the container? + + As Linyaps applications follow the principle of non-interference, the `XDG_DATA_HOME`, `XDG_CONFIG_HOME`, and `XDG_CACHE_HOME` environment variables are defined to correspond to paths under the host's `~/.linglong//`. Therefore, user application data will be saved in this path, and applications should read the corresponding environment variables when writing data during runtime. Reading and writing configurations of other applications is prohibited. + +6. The application provides a `dbus service` file, how should it be placed? What should be written in the `Exec` field? + + When the application provides a `dbus service` file, it needs to be placed in the `entries/dbus-1/services` directory. If `Exec` executes a binary within the Linyaps package, use the `--exec` option parameter to execute the corresponding binary. + +7. The launcher cannot find the application after installation? + + TryExec=xxx, when xxx does not exist in the $PATH, the application will be considered non-existent and will not be displayed. + +8. Why is the icon displayed as a small black dot? + + The desktop file has an Icon field, but the Icon field name is incorrect or an absolute path is used. + +9. Why is the icon displayed as a gear? + + The desktop file does not provide an Icon field. + +10. Where should icons be stored? + + svg → $PREFIX/share/icons/hicolor/scalable/apps/ + + Other formats are stored by resolution, such as 16x16 + + png/xpm → $PREFIX/share/icons/hicolor/16X16/apps/ + +11. Why do the application's built-in `xdg-open` and `xdg-email` fail? + + Linyaps specially handles `xdg-open` and `xdg-email` in the `runtime`, so applications are prohibited from executing their own xdg-open and xdg-email executables or scripts. + +12. Why doesn't the system environment variable used by the application take effect? + + When using environment variables, you need to confirm whether the corresponding environment variable exists in the container. If not, you need to contact the Linyaps team for handling. + +13. The library files needed for application runtime are not found, how to provide them? + + Resource files and library files that the application needs to use must be provided by the application itself. Library files should be placed under the `$PREFIX/lib` path. + +14. Why does the `Qt WebEngine` rendering process crash during application runtime? + + Due to system upgrades of `glibc`, applications fail when using the built-in browser and need to be re-adapted. A temporary solution is to set the environment variable: `export QTWEBENGINE_DISABLE_SANDBOX=1`. + +15. The application cannot find the `libqxcb.so` library or reports qtwebengine errors at runtime? + + When a `qt.conf` file exists, configure the correct path in the file, or use environment variables `QTWEBENGINEPROCESS_PATH`, `QTWEBENGINE_RESOURCES_PATH`, `QT_QPA_PLATFORM_PLUGIN_PATH`, `QT_PLUGIN_PATH` to configure the search path. + +16. Can the application carry its own database files and write data to the database during runtime? + + The file system inside the container is a read-only file system, and writing data to application resource files is not allowed. + +17. Why does executing binaries with `suid`, `guid` permissions fail? + + To ensure system security, Linyaps containers prohibit the execution of such privileged binaries. + +18. UAB offline package format cannot use input method under Debian and Ubuntu? + + It is recommended to install the `fictx` input method for better experience. + +19. How to know which packages are installed in the container environment? + + Use `ll-builder run --exec bash` to enter the container environment, and use the command `cat /var/lib/dpkg/status | grep "^Package: "` to view pre-installed packages. Additionally, libraries compiled from source can be viewed using `cat /runtime/packages.list`. + +20. Why doesn't the application tray display after the application starts? + + This may be because the application registered the tray using the same service name. According to the KDE/freedesktop StatusNotifierItem specification, applications should register service names as org.kde.StatusNotifierItem-``-``. In Linyaps applications, the pid during application runtime is 19. You can check whether a service has been registered using the following command: `dbus-send --session --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.NameHasOwner string:org.kde.StatusNotifierItem-19-1`. If `boolean true` exists, it means the service has been registered. diff --git a/docs/pages/en/guide/debug/images/ll-box-start-failed.png b/docs/pages/en/guide/tips-and-faq/images/ll-box-start-failed.png similarity index 100% rename from docs/pages/en/guide/debug/images/ll-box-start-failed.png rename to docs/pages/en/guide/tips-and-faq/images/ll-box-start-failed.png diff --git a/docs/pages/en/guide/debug/images/ll-box-start-failed.png.license b/docs/pages/en/guide/tips-and-faq/images/ll-box-start-failed.png.license similarity index 100% rename from docs/pages/en/guide/debug/images/ll-box-start-failed.png.license rename to docs/pages/en/guide/tips-and-faq/images/ll-box-start-failed.png.license diff --git a/docs/pages/en/guide/tips-and-faq/ll-builder-faq.md b/docs/pages/en/guide/tips-and-faq/ll-builder-faq.md new file mode 100644 index 000000000..2674801f2 --- /dev/null +++ b/docs/pages/en/guide/tips-and-faq/ll-builder-faq.md @@ -0,0 +1,31 @@ + + +# Common Build Issues + +1. For `cmake` type builds, `-lxxx` fails but both `ldconfig` and `pkg-config` can query the library information. + + The link library path is not in the conventional path, the new path is `/runtime/lib`. + + Add environment variable `LIBRARY_PATH=`, the build environment currently includes this environment variable by default. + +2. Static library linking fails during build, requiring rebuild with `fPIC`. + + Use the `-fPIC` parameter when building static libraries. + +3. Failed to start `box` during build, as shown below: + + ![ll-box startup failure](images/ll-box-start-failed.png) + + The kernel does not support `unprivilege namespace`, enable `unprivilege namespace` to resolve. + + ```bash + sudo sysctl -w kernel.unprivileged_userns_clone=1 + ``` + +4. `qtbase` builds successfully, but cannot build `qt` applications, showing `module,mkspec` related errors. + + Low version `fuse-overlay mount` has issues, causing file content corruption during `qtbase commit`, making it unusable. Use `fuse-overlayfs >= 1.7` version. diff --git a/docs/pages/en/guide/tips-and-faq/ll-pica-faq.md b/docs/pages/en/guide/tips-and-faq/ll-pica-faq.md new file mode 100644 index 000000000..d1443a920 --- /dev/null +++ b/docs/pages/en/guide/tips-and-faq/ll-pica-faq.md @@ -0,0 +1,19 @@ +# Common Issues + +1. Where is the default configuration for the linglong.yaml file generated by ll-pica? + + The ll-pica configuration file is located at `~/.pica/config.json`. + +2. Can ll-pica convert Wine, Android, input method, or security software? + + Linyaps applications currently do not support these types of applications, and ll-pica cannot convert them either. + +3. Why does software that needs audio have no sound? + + If you get a "not found libpulsecommon-12.2.so" error, you can add a line in the build field of the linglong.yaml file: `mv $PREFIX/lib/$TRIPLET/pulseaudio/* $PREFIX/lib/$TRIPLET`. + +4. Why is the command field empty in the generated linglong.yaml file? + + ll-pica obtains the Exec field by reading the desktop file in the deb package. If the command is empty, please check if the desktop file path in the deb package is in one of the following paths: + - /opt/apps/$appid/entries/applications + - /usr/share/applications diff --git a/docs/pages/en/index.md b/docs/pages/en/index.md deleted file mode 100644 index 571bb5396..000000000 --- a/docs/pages/en/index.md +++ /dev/null @@ -1,9 +0,0 @@ - - ---- -title: Home ---- \ No newline at end of file diff --git a/docs/pages/guide/building/demo.md b/docs/pages/guide/building/demo.md new file mode 100644 index 000000000..7b52c8880 --- /dev/null +++ b/docs/pages/guide/building/demo.md @@ -0,0 +1,156 @@ + + +# 构建示例演示 + +## 初始化如意玲珑应用项目 + +```bash +ll-builder create org.deepin.demo +``` + +## 配置 linglong.yaml 配置文件 + +### 配置软件包元数据信息 + +```yaml +package: + id: org.deepin.demo + name: demo + kind: app + version: 1.0.0.0 + description: | + A simple demo app. +``` + +### 配置应用程序启动命令 + +```yaml +command: + - demo +``` + +### 配置基础系统和运行时环境 + +```yaml +base: org.deepin.base/23.1.0 +runtime: org.deepin.runtime.dtk/23.1.0 +``` + +### 配置源代码信息 + +使用 Git 拉取源码 + +```yaml +sources: + - kind: git + url: "https://github.com/linuxdeepin/linglong-builder-demo.git" + commit: master + name: linglong-builder-demo +``` + +### 配置构建规则 + +```yaml +build: | + cd /project/linglong/sources/linglong-builder-demo + rm -rf build || true + mkdir build + cd build + qmake .. + make + make install +``` + +### 完整的 linglong.yaml 配置文件 + +```yaml +version: "1" + +package: + id: org.deepin.demo + name: demo + kind: app + version: 1.0.0.0 + description: | + A simple demo app. + +command: + - demo + +base: org.deepin.base/23.1.0 +runtime: org.deepin.runtime.dtk/23.1.0 + +sources: + - kind: git + url: "https://github.com/linuxdeepin/linglong-builder-demo.git" + commit: master + name: linglong-builder-demo + +build: | + cd /project/linglong/sources/linglong-builder-demo + rm -rf build || true + mkdir build + cd build + qmake .. + make + make install +``` + +更多配置文件字段定义请参考[配置文件说明文档](./manifests.md) + +## 执行构建流程 + +在玲珑项目根目录下执行构建命令: + +```bash +ll-builder build +``` + +## 运行应用程序 + +构建成功后,在玲珑项目目录下执行运行命令,无需安装即可直接运行应用程序。 + +```bash +ll-builder run +``` + +## 导出构建产物 + +在玲珑项目根目录下执行导出命令,检出构建内容。 + +```bash +ll-builder export --layer +``` + +导出后的目录结构如下: + +```text +├── linglong +├── linglong.yaml +├── org.deepin.demo_1.0.0.0_x86_64_binary.layer +└── org.deepin.demo_1.0.0.0_x86_64_develop.layer +``` + +## 更多参考示例 + +[qt5](https://github.com/linglongdev/cn.org.linyaps.demo.qt5) - qt5 程序 + +[dtk5](https://github.com/linglongdev/cn.org.linyaps.demo.dtk5.qmake) - dtk5 + qmake + +[dtk5](https://github.com/linglongdev/cn.org.linyaps.demo.dtk5.cmake) - dtk5 + cmake + +[dtkdeclarative5](https://github.com/linglongdev/cn.org.linyaps.demo.dtkdeclarative5) - dtk5 + qml + +[electron](https://github.com/myml/electron-vue-linyaps-app) - electron + vue 例子 + +[plantuml](https://github.com/linglongdev/com.plantuml.gpl) - 一个 java 应用,使用编程的方式绘制流程图 + +[org.sumatrapdfreader](https://github.com/linglongdev/org.sumatrapdfreader) - 一个 wine 应用,pdf 阅读器 + +## 更完整的示例 + +[完整示例](../start/build_your_first_app.md) - 包含了如何构建应用、导出构建内容、安装、运行等完整流程的示例。 diff --git a/docs/pages/guide/ll-builder/linyaps_package_spec.md b/docs/pages/guide/building/linyaps_package_spec.md similarity index 91% rename from docs/pages/guide/ll-builder/linyaps_package_spec.md rename to docs/pages/guide/building/linyaps_package_spec.md index 6944c6d58..a0feac4a2 100644 --- a/docs/pages/guide/ll-builder/linyaps_package_spec.md +++ b/docs/pages/guide/building/linyaps_package_spec.md @@ -2,10 +2,10 @@ 本文中的关键词**必须**、**禁止**、**必要的**、**应当**、**不应**、**推荐的**、**允许**以及**可选的**[^rfc2119-keywords]的解释见于[RFC 2119][rfc-2119]中的描述。 -这些关键词与原文中的英语词汇的对应关系如下表所示: +这些关键词与原文中的英文词汇的对应关系如下表所示: | 中文 | 英语 | -|------------|-------------| +| ---------- | ----------- | | **必须** | MUST | | **禁止** | MUST NOT | | **必要的** | REQUIRED | @@ -17,7 +17,7 @@ [rfc-2119]: https://datatracker.ietf.org/doc/html/rfc2119 -本文档旨在帮助应用开发者规范应用程序的构建过程中的行为,以迁移到玲珑包管理系统中。 +本文档旨在帮助应用开发者规范应用程序的构建过程中的行为,以便迁移到玲珑包管理系统中。 ## 通用 @@ -31,17 +31,17 @@ - 开发者**应当**使用自己确实拥有的域名的倒置作为应用名称的前缀,并在之后跟上应用程序名称 - **注意**:若开发者无法证明其确实拥有该域名,有可能导致应用包从仓库中移除。 +**注意**:如果开发者无法证明其确实拥有该域名,有可能导致应用包从仓库中移除。 -- 对于github上开发的第三方应用而言,如果该应用程序所在的组织有额外的域名,则应当优先使用,否则应当采用`io.github..`作为前缀。 +- 对于GitHub上开发的第三方应用而言,如果该应用程序所在的组织有额外的域名,则应当优先使用,否则应当采用`io.github..`作为前缀。 - 特别的,如果该应用的组织名和应用名称一致,例如,打包者**不应当**省略重复的应用名称与组织名,这个应用的ID**应当**为`io.github.neovim.neovim`。 + 特别的,如果该应用的组织名和应用名称一致,例如,打包者**不应当**省略重复的应用名称和组织名,这个应用的ID**应当**为`io.github.neovim.neovim`。 - **注意**:实际上该组织拥有域名`neovim.io`,故最合理的的应用名称**应当**为`io.neovim.neovim`。 + **注意**:实际上该组织拥有域名`neovim.io`,故最合理的应用名称**应当**为`io.neovim.neovim`。 -- **不推荐**使用含有`-`的应用名称,如果域名/应用名称确实含有`-`,**推荐**使用`_`代替 +- **不推荐**使用包含`-`的应用名称,如果域名/应用名称确实包含`-`,**推荐**使用`_`代替 -- **不推荐**应用名称以`.desktop`结尾 +- **不推荐**应用名称以`.desktop`结束 以上规范来自[Desktop Entry Specification][desktop-entry-specification]。 @@ -49,7 +49,7 @@ 拓展阅读: -### `prefix`与`$DESTDIR` +### `prefix`和`$DESTDIR` 在编写应用程序的构建过程时,开发者**不应当**假设自己安装的位置是固定的。在Makefile/CMakeLists.txt中将可执行文件安装到硬编码的路径,例如`/usr/bin`是不规范的行为。 @@ -57,10 +57,10 @@ `prefix`指的是构建/安装时指定给构建系统的、应用最终会被安装到系统中的具体位置。 -当开发者没有指定安装位置时,其默认值**应当**为`/usr/local`, +当开发者没有指定安装位置时,默认值**应当**为`/usr/local`, 通过包管理系统打包时,包管理系统会配置其值。当使用dpkg相关工具进行打包时,其值会被配置为`/usr`。但编写构建/安装过程时,开发者应当考虑`prefix`被配置成任意值的情况。 -`$DESTDIR`是指构建系统进行安装时,为了方便发行版打包等过程,约定的一个环境变量。其大致工作逻辑如下: +`$DESTDIR`是构建系统进行安装时,为了方便发行版打包等过程,约定的一个环境变量。其大致工作逻辑如下: 若构建系统完成了构建工作后,执行安装过程时,被指定了`prefix=/usr`,且`$DESTDIR=./tmp`,则其完成安装后,所有的产物文件都应当出现在`./tmp/usr`目录中。打包工具随后会将`./tmp`视为根目录将其中的文件进行压缩打包等工作。 @@ -102,7 +102,7 @@ PKG_CONFIG ?= pkg-config - 内部可执行文件 - 指不应当由用户在终端中直接调用的可执行文件,这些可执行文件**不应当**可以通过`$PATH`找到 + 指的是不应当由用户在终端中直接调用的可执行文件,这些可执行文件**不应当**可以通过`$PATH`找到 ```makefile install: @@ -183,10 +183,9 @@ PKG_CONFIG ?= pkg-config - desktop文件对应图标 参见: - - 如果安装的图标为固定大小的版本,那么**推荐**使用png格式 - 至少**需要**安装一个48x48大小的png才能保证桌面环境中图标相关的基础功能正常 + 至少**需要**安装一个48x48大小的PNG才能保证桌面环境中图标相关的基础功能正常 - 如果安装的图标为矢量版本,那么**推荐**使用svg格式 @@ -202,9 +201,9 @@ PKG_CONFIG ?= pkg-config #### CMake -本节主要参考以及中的相关内容编写。 +本节主要参考中的相关内容编写。 -这里定义一些变量的默认值以及其他公共部分以便后文编写示例,这些变量默认值的相关说明可以在上方链接中查找。 +这里定义一些变量的默认值以及其它公共部分以便后文编写示例,这些变量默认值的相关说明可以在上方链接中查找。 编写逻辑与Makefile一节中的相关内容一致。 @@ -322,11 +321,8 @@ desktop文件的文件名中**不推荐**带有`-`,去掉.desktop后缀后, - **不推荐**填写[`Icon`字段][key-icon]时使用绝对路径 [key-tryexec]: https://specifications.freedesktop.org/desktop-entry-spec/latest/recognized-keys.html#key-tryexec - [key-startupwmclass]: https://specifications.freedesktop.org/desktop-entry-spec/latest/recognized-keys.html#key-startupwmclass - [key-exec]: https://specifications.freedesktop.org/desktop-entry-spec/latest/recognized-keys.html#key-exec - [key-icon]: https://specifications.freedesktop.org/desktop-entry-spec/latest/recognized-keys.html#key-icon #### DBus服务 @@ -417,11 +413,11 @@ Terminal=false 玲珑的环境最多有三部分组成,以在`x86_64`架构下编译`org.deepin.demo`为例,其头文件以及库文件默认搜索路径包含以下部分: -| **组成** | **包名** | **头文件** | **库文件** | -| ----------------------------------------------- | ------------------------------------------------ | ------------------------------------------------ | ------------------------------------------------ | -| base | org.deepin.base | /usr/include | /usr/lib
/usr/lib/x86_64-linux-gnu | -| runtime (可选) | org.deepin.runtime.dtk | /runtime/include | /runtime/lib
/runtime/lib/x86_64-linux-gnu | -| app | org.deepin.demo | /opt/apps/org.deepin.demo/files/include | /opt/apps/org.deepin.demo/files/lib
/opt/apps/org.deepin.demo/files/lib/x86_64-linux-gnu | +| **组成** | **包名** | **头文件** | **库文件** | +| -------------- | ---------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------- | +| base | org.deepin.base | /usr/include | /usr/lib
/usr/lib/x86_64-linux-gnu | +| runtime (可选) | org.deepin.runtime.dtk | /runtime/include | /runtime/lib
/runtime/lib/x86_64-linux-gnu | +| app | org.deepin.demo | /opt/apps/org.deepin.demo/files/include | /opt/apps/org.deepin.demo/files/lib
/opt/apps/org.deepin.demo/files/lib/x86_64-linux-gnu | 优先级按从上往下的顺序排列。如果一份头文件同时在`org.deepin.base`和`org.deepin.demo`中存在,使用时会优先匹配到`org.deepin.base`中的文件。库文件同理。 @@ -498,7 +494,7 @@ target_link_libraries(demo PRIVATE PackageName::Component) 通过源码引入依赖是一个**推荐的**做法,它能极大的保证构建流程的稳定以及可维护性。缺点是这可能会花费开发者不少时间编写yaml文件,因为依赖也许也会有自身的依赖。 -*如果开发者发现依赖复杂且重复被其他应用使用,那么应当考虑将依赖整合做成一个runtime类型的包。* +_如果开发者发现依赖复杂且重复被其他应用使用,那么应当考虑将依赖整合做成一个runtime类型的包。_ 当依赖是在玲珑环境下编译产生时,其配置文件通常是“可靠的”。编译安装后开发者可以直接在项目中使用。 @@ -585,14 +581,14 @@ deb的编译产物,安装前缀是`/usr`,`install_dep`脚本会自动处理其 玲珑应用**必须**选择一个base作为基础运行环境。可使用的base: -| **基础库** | **包名/版本** | -| ----------------------------------------------- | ------------------------------------------------ | +| **基础库** | **包名/版本** | +| ----------- | ------------------------ | | glibc(2.38) | org.deepin.base/23.1.0.0 | 如果需要额外使用基础环境以外的框架,**应当**使用合适的runtime。可使用的runtime: -| **框架** | **包名/版本** | -| ----------------------------------------------- | ------------------------------------------------ | +| **框架** | **包名/版本** | +| ------------------- | ------------------------------- | | QT(5.15) + DTK(5.6) | org.deepin.runtime.dtk/23.1.0.0 | 在使用base或runtime时,版本号**推荐**填写前三位,如 '23.1.0',便于后续接收更新。全量填写4位版本表示**禁止**base或runtime更新。 @@ -700,14 +696,10 @@ info.json是玲珑定义的应用描述文件。该文件由构建工具自动 ```json { "id": "org.deepin.demo", - "arch": [ - "x86_64" - ], + "arch": ["x86_64"], "base": "main:org.deepin.foundation/23.0.0/x86_64", "channel": "main", - "command": [ - "/opt/apps/org.deepin.demo/files/bin/demo" - ], + "command": ["/opt/apps/org.deepin.demo/files/bin/demo"], "description": "simple Qt demo.\n", "kind": "app", "module": "runtime", @@ -857,12 +849,12 @@ ExecStart = ll-cli run org.deepin.demo -- demo WantedBy=user-session.target ``` -与dbus service不同的是,安装到```$PREFIX/lib/systemd/user```下的文件会被自动拷贝到```$PREFIX/share/systemd/user```。 +与dbus service不同的是,安装到`$PREFIX/lib/systemd/user`下的文件会被自动拷贝到`$PREFIX/share/systemd/user`。 **路径对应关系:** -| **打包路径** | **安装路径** | -| ------------------------------------------------------------- | -------------------------------------------------------------- | +| **打包路径** | **安装路径** | +| ------------------------------------------------ | --------------------------------------------------- | | $PREFIX/lib/systemd/user/org.deepin.demo.service | $XDG_DATA_DIRS/systemd/user/org.deepin.demo.service | ##### icons 目录 diff --git a/docs/pages/guide/ll-builder/manifests.md b/docs/pages/guide/building/manifests.md similarity index 65% rename from docs/pages/guide/ll-builder/manifests.md rename to docs/pages/guide/building/manifests.md index 911d023ba..5f256f319 100644 --- a/docs/pages/guide/ll-builder/manifests.md +++ b/docs/pages/guide/building/manifests.md @@ -6,7 +6,7 @@ SPDX-License-Identifier: LGPL-3.0-or-later # 构建配置文件简介 -`linglong.yaml` 是如意玲珑项目工程的描述文件,记录构建所需的相关信息。如构建产物的名称、版本、源码地址、构建依赖等。 +`linglong.yaml` 是如意玲珑项目的描述文件,记录构建所需信息。如构建产物的名称、版本、源码地址、构建依赖等。 ## 工程目录结构 @@ -24,14 +24,14 @@ SPDX-License-Identifier: LGPL-3.0-or-later ## 字段定义 -`linglong.yaml` 文件结构遵循特定的规范。首先,需要在文件顶层声明配置文件的版本: +`linglong.yaml` 文件结构遵循特定规范。首先,需要在文件顶部声明配置文件的版本: ```yaml -version: '1' +version: "1" ``` -| 名称 | 描述 | 必填 | -| ------- | ------------------------ | ---- | +| 名称 | 描述 | 必填 | +| ------- | ------------------------------ | ---- | | version | 构建配置文件的版本,当前为 '1' | 是 | 接下来是主要的配置块。其中 `package`, `base`, `build` 是必须定义的。 @@ -48,19 +48,19 @@ package: kind: app description: | calculator for deepin os. - architecture: amd64 # 可选 - channel: stable # 可选 + architecture: x86_64 # 可选 + channel: main # 可选 ``` -| 名称 | 描述 | 必填 | -| -------------- | -------------------------------------------------------- | ---- | -| id | 构建产物的唯一名称 (例如:`org.deepin.calculator`) | 是 | -| name | 构建产物的名称 (例如:`deepin-calculator`) | 是 | -| version | 构建产物的版本,建议四位数字 (例如:`5.7.21.0`) | 是 | -| kind | 构建产物的类型:`app` (应用)、`runtime` (运行时) | 是 | -| description | 构建产物的详细描述 | 是 | -| architecture | 构建产物的目标架构 (例如:`amd64`, `arm64`) | 否 | -| channel | 构建产物的通道 (例如:`stable`, `beta`) | 否 | +| 名称 | 描述 | 必填 | +| ------------ | -------------------------------------------------- | ---- | +| id | 构建产物的唯一名称 (例如:`org.deepin.calculator`) | 是 | +| name | 构建产物的名称 (例如:`deepin-calculator`) | 是 | +| version | 构建产物的版本,建议四位数字 (例如:`5.7.21.0`) | 是 | +| kind | 构建产物的类型:`app` (应用)、`runtime` (运行时) | 是 | +| description | 构建产物的详细描述 | 是 | +| architecture | 构建产物的目标架构 (例如:`x86_64`, `arm64`) | 否 | +| channel | 构建产物的通道 (例如:`main`, `dev`) | 否 | ### 启动命令 (`command`) @@ -72,8 +72,8 @@ command: # - --some-argument # 可以添加更多参数 ``` -| 名称 | 描述 | 必填 | -| ------- | -------------------------------------------------------------------- | ---- | +| 名称 | 描述 | 必填 | +| ------- | --------------------------------------------------------------------- | ---- | | command | 定义启动应用的可执行文件路径及其参数列表。对于 `kind: app` 通常需要。 | 否 | ### 基础环境 (`base`) @@ -84,9 +84,9 @@ command: base: org.deepin.base/23.1.0 ``` -| 名称 | 描述 | 必填 | -| ------- | ----------------------------------------- | ---- | -| base | base 的标识符,格式为 `id/version`。版本号支持三位模糊匹配。 | 是 | +| 名称 | 描述 | 必填 | +| ---- | ------------------------------------------------------------ | ---- | +| base | base 的标识符,格式为 `id/version`。版本号支持三位模糊匹配。 | 是 | ### 运行时(runtime) @@ -111,18 +111,16 @@ runtime: org.deepin.runtime.dtk/23.1.0 sources: - kind: git url: https://github.com/linuxdeepin/deepin-calculator.git - version: master # 或 tag - commit: d7e207b4a71bbd97f7d818de5044228c1a6e2c92 # 可选,用于精确指定提交 + commit: d7e207b4a71bbd97f7d818de5044228c1a6e2c92 # 分支、tag或commit,用于精确指定提交 name: deepin-calculator.git # 可选,指定下载后的目录名 ``` -| 名称 | 描述 | 必填 (单个source内) | -| ------- | -------------------------------------------------------------------- | ------------------- | -| kind | `git`,表示使用 git 工具下载。 | 是 | -| url | 源码仓库地址 | 是 | -| version | 源码仓库的分支或标签 | 否 (默认为主分支) | -| commit | 源码某次提交的 hash 值,用于精确检出 | 否 | -| name | 可选,指定源码下载后在 `linglong/sources` 目录下的子目录名。 | 否 | +| 名称 | 描述 | 必填 (单个source内) | +| ------ | ------------------------------------------------------------ | ------------------- | +| kind | `git`,表示使用 git 工具下载。 | 是 | +| url | 源码仓库地址 | 是 | +| commit | 源码仓库分支、标签或者某次提交的hash值,用于精确检出 | 是 | +| name | 可选,指定源码下载后在 `linglong/sources` 目录下的子目录名。 | 否 | #### file 类型 @@ -134,12 +132,12 @@ sources: name: my-data.dat # 可选,指定下载后的文件名 ``` -| 名称 | 描述 | 必填 (单个source内) | -| ------ | -------------------------------------------------------------------- | ------------------- | -| kind | `file`,表示直接下载文件。 | 是 | -| url | 文件下载地址 | 是 | -| digest | 可选,文件的 sha256 哈希值,用于校验。 | 否 | -| name | 可选,指定下载后在 `linglong/sources` 目录下的文件名。 | 否 | +| 名称 | 描述 | 必填 (单个source内) | +| ------ | ------------------------------------------------------ | ------------------- | +| kind | `file`,表示直接下载文件。 | 是 | +| url | 文件下载地址 | 是 | +| digest | 可选,文件的 sha256 哈希值,用于校验。 | 否 | +| name | 可选,指定下载后在 `linglong/sources` 目录下的文件名。 | 否 | #### archive 类型 @@ -151,12 +149,12 @@ sources: name: deepin-calculator-6.5.4 # 可选,指定解压后的目录名 ``` -| 名称 | 描述 | 必填 (单个source内) | -| ------ | -------------------------------------------------------------------- | ------------------- | -| kind | `archive`,下载压缩包并自动解压。支持常见的压缩格式。 | 是 | -| url | 压缩包下载地址 | 是 | -| digest | 可选,压缩包文件的 sha256 哈希值,用于校验。 | 否 | -| name | 可选,指定解压后在 `linglong/sources` 目录下的目录名。 | 否 | +| 名称 | 描述 | 必填 (单个source内) | +| ------ | ------------------------------------------------------ | ------------------- | +| kind | `archive`,下载压缩包并自动解压。支持常见的压缩格式。 | 是 | +| url | 压缩包下载地址 | 是 | +| digest | 可选,压缩包文件的 sha256 哈希值,用于校验。 | 否 | +| name | 可选,指定解压后在 `linglong/sources` 目录下的目录名。 | 否 | #### dsc 类型 @@ -168,12 +166,12 @@ sources: name: deepin-calculator-dsc # 可选,指定下载和解压后的目录名 ``` -| 名称 | 描述 | 必填 (单个source内) | -| ------ | -------------------------------------------------------------------- | ------------------- | -| kind | `dsc`,处理 Debian 源码包描述文件及其关联文件。 | 是 | -| url | `.dsc` 文件下载地址 | 是 | -| digest | 可选,`.dsc` 文件的 sha256 哈希值,用于校验。 | 否 | -| name | 可选,指定下载和解压后在 `linglong/sources` 目录下的目录名。 | 否 | +| 名称 | 描述 | 必填 (单个source内) | +| ------ | ------------------------------------------------------------ | ------------------- | +| kind | `dsc`,处理 Debian 源码包描述文件及其关联文件。 | 是 | +| url | `.dsc` 文件下载地址 | 是 | +| digest | 可选,`.dsc` 文件的 sha256 哈希值,用于校验。 | 否 | +| name | 可选,指定下载和解压后在 `linglong/sources` 目录下的目录名。 | 否 | ### 导出裁剪规则 (`exclude`/`include`) @@ -188,9 +186,9 @@ include: - /usr/share/locale/zh_CN.UTF-8 # 配合exclude实现仅导出一个文件夹下的某些文件 ``` -| 名称 | 描述 | -| ------- | ----------------------------------------------------------------- | -| exclude | 容器内的绝对路径,可以为文件或文件夹,用于排除。 | +| 名称 | 描述 | +| ------- | ------------------------------------------------------------------- | +| exclude | 容器内的绝对路径,可以为文件或文件夹,用于排除。 | | include | 容器内的绝对路径,需要强制包含进 UAB 包的文件(即使父目录被排除)。 | ### 构建规则 (`build`) @@ -206,9 +204,9 @@ build: | make install ``` -| 名称 | 描述 | 必填 | -| ----- | -------------------------------------------------------------------- | ---- | -| build | 构建阶段执行的 shell 脚本。脚本在容器构建环境内执行。 | 是 | +| 名称 | 描述 | 必填 | +| ----- | ----------------------------------------------------- | ---- | +| build | 构建阶段执行的 shell 脚本。脚本在容器构建环境内执行。 | 是 | ### 构建扩展 (`buildext`) @@ -226,12 +224,12 @@ buildext: - libglib2.0-0 ``` -| 名称 | 描述 | 必填 | -| ----------- | ------------------------------------------------------------------ | ---- | -| buildext | 构建扩展配置的容器块。 | 否 | -| apt | 使用 apt 包管理器的扩展配置。 | 否 | +| 名称 | 描述 | 必填 | +| ------------- | ------------------------------------------------------------------ | ---- | +| buildext | 构建扩展配置的容器块。 | 否 | +| apt | 使用 apt 包管理器的扩展配置。 | 否 | | build_depends | 一个字符串列表,列出了构建时需要的包,这些包不会进入最终产物。 | 否 | -| depends | 一个字符串列表,列出了运行时需要的包,这些包会被包含在最终产物中。 | 否 | +| depends | 一个字符串列表,列出了运行时需要的包,这些包会被包含在最终产物中。 | 否 | ### 模块 (`modules`) @@ -253,11 +251,11 @@ modules: - share/my-app/optional-data/ ``` -| 名称 | 描述 | 必填 | -| ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- | -| modules | 定义应用模块拆分的规则列表。 | 否 | -| name | 模块的名称。每个模块都需要一个唯一的名称。 | 是 (在每个模块项内) | -| files | 一个字符串列表,列出了属于该模块的文件或目录。路径是相对于 `${PREFIX}` 的路径。 | 是 (在每个模块项内) | +| 名称 | 描述 | 必填 | +| ------- | ------------------------------------------------------------------------------- | ------------------- | +| modules | 定义应用模块拆分的规则列表。 | 否 | +| name | 模块的名称。每个模块都需要一个唯一的名称。 | 是 (在每个模块项内) | +| files | 一个字符串列表,列出了属于该模块的文件或目录。路径是相对于 `${PREFIX}` 的路径。 | 是 (在每个模块项内) | **注意:** 所有安装到 `${PREFIX}` 下的文件都会被分配到一个模块中。未定义 `modules` 时,构建系统会自动生成默认的 `binary` 和 `develop` 模块。 @@ -265,10 +263,10 @@ modules: 描述构建过程走可以使用的变量。 -| 名称 | 描述 | -| ------- | ------------------------------------------------------------------------------------------------------ | +| 名称 | 描述 | +| ------- | ------------------------------------------------------------------------------------ | | PREFIX | build 字段下使用的环境变量;提供构建时的安装路径,如 /opt/apps/org.deepin.calculator | -| TRIPLET | build 字段下使用的环境变量;提供包含架构信息的三元组,如 x86_64-linux-gnu | +| TRIPLET | build 字段下使用的环境变量;提供包含架构信息的三元组,如 x86_64-linux-gnu | ## 完整示例 @@ -277,7 +275,7 @@ modules: #### 计算器 ```yaml -version: '1' +version: "1" package: id: org.deepin.calculator @@ -361,4 +359,3 @@ ll-builder build --skip-fetch-source ``` 在根文件系统基础上添加 Qt 等基础环境。 - diff --git a/docs/pages/guide/ll-builder/modules.md b/docs/pages/guide/building/modules.md similarity index 86% rename from docs/pages/guide/ll-builder/modules.md rename to docs/pages/guide/building/modules.md index 5582d876e..761346916 100644 --- a/docs/pages/guide/ll-builder/modules.md +++ b/docs/pages/guide/building/modules.md @@ -6,7 +6,7 @@ SPDX-License-Identifier: LGPL-3.0-or-later # 模块拆分 -在如意玲珑构建时,一个应用可以拆分为多个模块,每个模块包含部分构建产物,例如调试符号放到 `develop` 模块,翻译文件放到 `lang-*` 模块等。这样用户可以按需安装,缩减应用体积。 +在如意玲珑构建时,一个应用可以拆分成多个模块,每个模块包含部分构建产物,例如调试符号放到 `develop` 模块,翻译文件放到 `lang-*` 模块等。这样用户可以按需安装,缩减应用体积。 ## 模块文件 @@ -28,15 +28,15 @@ modules: files 是一个字符串数组,每列写一个文件路径,支持正则表达式。文件路径会自动添加应用安装路径 `$PREFIX` 作为前缀,所以如果模块要包含 `$PREFIX/bin/demo` 文件,仅需写 /bin/demo,如意玲珑会自动转换成 /opt/apps/org.deepin.demo/files/bin/demo 这种路径。 -如果同一个文件路径被多个模块包含,仅会移动文件到第一个模块中(按 modules 的顺序),在 files 中写正则表达式需要以^开头,否则会被认为是普通文件路径,正则表达式会自动在^后添加 `$PREFIX` 作为前缀,打包者无需重复添加。 +如果同一个文件路径被多个模块包含,仅会移动文件到第一个模块中(按 modules 的顺序),在 files 中编写正则表达式需要以^开头,否则会被认为是普通文件路径,正则表达式会自动在^后添加 `$PREFIX` 作为前缀,打包者无需重复添加。 ## 保留模块名 ### binary 模块 -_这是默认模块,无需在 modules 中声明_,binary 会保存其他模块不使用的构建产物。当 modules 字段不存在时,binary 就保存所有构建产物。 +_这是默认模块,不需要在 modules 中声明_,binary 会保存其他模块不使用的构建产物。当 modules 字段不存在时,binary 就保存所有构建产物。 -用户在使用 ll-cli 安装应用时默认安装该模块,其他模块需要在安装 binary 模块后再能安装,写在 binary 模块会同时卸载其他模块。 +用户在使用 ll-cli 安装应用时默认安装该模块,其他模块需要在安装 binary 模块后再能安装,卸载 binary 模块会同时卸载其他模块。 ### develop 模块 @@ -62,7 +62,7 @@ modules: 加载多个语言模块:`ll-builder run --modules lang-zh_CN,lang-ru_RU` -加载 develop 模块:`ll-builder run --modules develop`,仅作示例,不建议这样使用,因为应用的 develop 只有调试符号没有调试工具,如果需要调试应用应该使用 --debug 参数,见[IDE 中调试应用](../debug/debug.html)。 +加载 develop 模块:`ll-builder run --modules develop`,仅作示例,不建议这样使用,因为应用的 develop 只有调试符号没有调试工具,如果需要调试应用应该使用 --debug 参数,见[IDE 中调试应用](../debug/debug.md)。 ### 用户安装模块 diff --git a/docs/pages/guide/building/multiarch.md b/docs/pages/guide/building/multiarch.md new file mode 100644 index 000000000..192abdd0b --- /dev/null +++ b/docs/pages/guide/building/multiarch.md @@ -0,0 +1,73 @@ +# 玲珑多架构构建指南 + +## 支持的架构 + +当前玲珑打包工具支持以下 CPU 架构: + +- x86_64 + +- arm64(aarch64) + +- loong64 + +- loongarch64(龙芯旧世界) + +- sw64(申威) + +- mips64 + +## 构建限制说明 + +不支持跨架构交叉编译:目前只能在对应架构的机器上构建该架构的包 + +## 多架构项目结构建议 + +推荐采用以下目录结构管理多架构构建: + +```txt +项目根目录/ +├── arm64 +│   └── linglong.yaml # arm64 架构配置文件 +├── linglong.yaml # x86_64 架构配置文件 +├── loong64 +│   └── linglong.yaml # loong64 架构配置文件 +├── resources # 共享的资源文件 +└── src # 共享的源代码 +``` + +将源代码、资源文件等放在项目根目录,不同架构的构建由对应架构的配置文件决定。 + +## 构建命令示例 + +ll-builder 会优先查找当前架构的项目配置文件,因此在不同架构的机器上执行 ll-builder 会自动使用当前架构对应的配置文件。如果架构配置文件不在默认位置,可以使用下面的方法指定配置文件的位置: + +```bash +# 构建 arm64 架构包 +ll-builder -f arm64/linglong.yaml + +# 构建 loong64 架构包 +ll-builder -f loong64/linglong.yaml +``` + +需要注意项目配置文件(即由 -f 指定的 linglong.yaml 文件),需要在项目目录(运行 ll-builder 的当前目录)或其子目录下。 + +## 龙芯 + +龙芯新旧世界的差异可查看 [咱龙了吗](https://areweloongyet.com/docs/old-and-new-worlds/) + +> 可以使用 file 工具方便地检查一个二进制程序属于哪个世界。 假设你想检查 someprogram 这个文件,就执行 file someprogram,如果输出的行含有这些字样: +> interpreter /lib64/ld.so.1, for GNU/Linux 4.15.0 +> 就表明这是一个旧世界程序。 +> 相应地,如果输出的行含有这些字样: +> interpreter /lib64/ld-linux-loongarch-lp64d.so.1, for GNU/Linux 5.19.0 + +介于新旧世界差异不小,在玲珑中新旧世界被分为两个架构,新世界使用更简洁的 loong64 作为架构代号。 + +考虑到市面上还有部分支持龙芯的应用未适配新世界,玲珑制作了可在新世界架构运行的旧世界的 base(org.deepin.foundation/20.0.0) 和 runtime(org.deepin.Runtime/20.0.0.12),用来将支持旧世界的应用迁移到新世界。 + +迁移步骤: + +1. 准备一个新世界架构的机器并安装 deepin 或 uos 系统。 +2. 在宿主机安装 `liblol-dkms` 内核模块 `apt install liblol-dkms`。 +3. 编写一个 linglong.yaml 文件,base 和 runtime 填写上文所属的版本号。 +4. 在 linglong.yaml 里解压旧世界应用的软件包,复制到 `$PREFIX` 目录。 diff --git a/docs/pages/guide/debug/debug.md b/docs/pages/guide/debug/debug.md index 4df730888..9def36bf3 100644 --- a/docs/pages/guide/debug/debug.md +++ b/docs/pages/guide/debug/debug.md @@ -14,7 +14,7 @@ SPDX-License-Identifier: LGPL-3.0-or-later ### 在调试环境运行应用 -在 [运行编译后的应用](../ll-builder/run.md) 一节中,我们已经知道使用`ll-builder run --exec /bin/bash`可以运行编译后的应用并进入容器的终端。只需要再 run 后面加上 `--debug` 参数即可以调试环境运行容器并进入容器。调试环境和非调试环境的区别主要有以下几点: +在 [运行编译后的应用](../reference/commands/ll-builder/run.md) 一节中,我们已经知道使用`ll-builder run --exec /bin/bash`可以运行编译后的应用并进入容器的终端。只需要再 run 后面加上 `--debug` 参数即可以调试环境运行容器并进入容器。调试环境和非调试环境的区别主要有以下几点: 1. 调试环境会使用 base 和 runtime 的 binary+develop 模块,而非调试环境会使用 binary 模块,gdb 工具就在 base 的 develop 模块中。 2. 调试环境会使用 app 的 binary+develop 模块,而非调试环境默认使用 binary 模块(一般会将应用的调试符号保存到 develop 模块)。 @@ -126,3 +126,51 @@ CONFIG += debug ``` cmake 会自动使用 cflags 和 cxxflags 环境变量,所以不需要额外配置。其他构建工具可自定查询文档。 + +## 从debian仓库下载调试符号 + +由于base镜像中没有包含调试符号,如果需要调试应用的系统依赖库,需要从base对应的debian仓库手动下载调试符号包。具体步骤如下: + +1. 使用以下命令之一进入容器命令行环境: + + ```bash + ll-builder run --bash + # 或 + ll-cli run $appid --bash + ``` + +2. 查看base镜像使用的仓库地址: + + ```bash + cat /etc/apt/sources.list + ``` + +3. 在宿主机浏览器中打开仓库地址,定位依赖库的deb包所在目录: + - 使用命令 `apt-cache show | grep Filename` 查看deb包在仓库中的路径 + - 完整的下载地址为: 仓库地址 + deb包路径 + + 例如,要下载libgtk-3-0的调试符号包: + + ```bash + apt-cache show libgtk-3-0 | grep Filename + # 输出: pool/main/g/gtk+3.0/libgtk-3-0_3.24.41-1deepin3_amd64.deb + # 完整目录: /pool/main/g/gtk+3.0/ + ``` + +4. 在该目录下寻找对应的调试符号包,通常有两种命名格式: + - `-dbgsym.deb` + - `-dbg.deb` + +5. 下载并解压调试符号包: + + ```bash + dpkg-deb -R -dbgsym.deb /tmp/ + ``` + +6. 配置调试器查找调试符号: + 在上面的场景设置debug-file-directory时,追加解压的目录,用冒号分隔: + ``` + ${workspaceFolder}/linglong/output/develop/files/lib/debug:/tmp//usr/lib/debug + ``` + +这样调试器就能在解压的目录中找到系统依赖库的调试符号了。 diff --git a/docs/pages/guide/debug/images/build_parameter_list.png b/docs/pages/guide/debug/images/build_parameter_list.png deleted file mode 100644 index 42d1f6940..000000000 Binary files a/docs/pages/guide/debug/images/build_parameter_list.png and /dev/null differ diff --git a/docs/pages/guide/debug/images/build_parameter_list.png.license b/docs/pages/guide/debug/images/build_parameter_list.png.license deleted file mode 100644 index 773bc0e03..000000000 --- a/docs/pages/guide/debug/images/build_parameter_list.png.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. - -SPDX-License-Identifier: LGPL-3.0-or-later diff --git a/docs/pages/guide/debug/images/node.png b/docs/pages/guide/debug/images/node.png deleted file mode 100644 index 5e78176a3..000000000 Binary files a/docs/pages/guide/debug/images/node.png and /dev/null differ diff --git a/docs/pages/guide/debug/images/node.png.license b/docs/pages/guide/debug/images/node.png.license deleted file mode 100644 index 773bc0e03..000000000 --- a/docs/pages/guide/debug/images/node.png.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. - -SPDX-License-Identifier: LGPL-3.0-or-later diff --git a/docs/pages/guide/debug/ll-builder-faq.md b/docs/pages/guide/debug/ll-builder-faq.md deleted file mode 100644 index 7e845c091..000000000 --- a/docs/pages/guide/debug/ll-builder-faq.md +++ /dev/null @@ -1,31 +0,0 @@ - - -# 常见构建问题 - -1. `cmake`类型构建,出现`-lxxx`失败,但`ldconfig`与`pkg-config`均能查询到该库信息。 - - 链接库路径不在常规路径,新路径为`/runtime/lib`。 - - 添加环境变量 `LIBRARY_PATH=`,目前构建环境已默认包含该环境变量。 - -2. 构建时`link`静态库失败,要求重新使用`fPIC`构建。 - - 构建静态库时使用`-fPIC`参数。 - -3. 构建时启动`box`失败,如下图: - - ![ll-box启动失败](images/ll-box-start-failed.png) - - 内核不支持`unprivilege namespace`,开启`unprivilege namespace`解决。 - - ```bash - sudo sysctl -w kernel.unprivileged_userns_clone=1 - ``` - -4. `qtbase`构建成功,但无法构建`qt`应用,提示`module,mkspec` 相关错误。 - - 低版本`fuse-overlay mount`存在问题,导致`qtbase commit`时文件内容被污染 ,无法正常使用。使用`fuse-overlayfs >= 1.7`版本。 diff --git a/docs/pages/guide/desktop-integration/README.md b/docs/pages/guide/desktop-integration/README.md new file mode 100644 index 000000000..67e27ba0c --- /dev/null +++ b/docs/pages/guide/desktop-integration/README.md @@ -0,0 +1 @@ +此目录放置如意玲珑如何与桌面环境进行集成相关文档。(待补充)- portals:介绍如何为如意玲珑创建桌面门户(Portals)以实现与桌面环境的无缝集成。 diff --git a/docs/pages/guide/docs-index.md b/docs/pages/guide/docs-index.md new file mode 100644 index 000000000..a2af4b787 --- /dev/null +++ b/docs/pages/guide/docs-index.md @@ -0,0 +1,185 @@ +# 如意玲珑文档索引 + +本文档记录所有文档的索引信息。 + +## 目录结构概览 + +```txt +docs/pages/guide/ +├── building/ # 构建相关文档 +├── debug/ # 调试相关文档 +├── desktop-integration/ # 桌面集成文档 +├── extra/ # 额外文档 +├── lessons/ # 教程和示例 +├── linyaps-devel/ # 开发者文档 +├── publishing/ # 发布相关文档 +├── reference/ # 参考文档 +├── start/ # 入门指南 +└── tips-and-faq/ # 提示和常见问题 +``` + +## 详细文档索引 + +### 入门指南 (start/) + +| 文档名称 | 文件路径 | 描述 | +| ---------------------- | ------------------------------- | --------------------------------------------------------- | +| 概述 | `start/whatis.md` | 介绍如意玲珑的基本概念、优势以及与其他包管理工具的对比 | +| 安装如意玲珑 | `start/install.md` | 详细说明在不同Linux发行版上安装如意玲珑的步骤 | +| 构建第一个如意玲珑应用 | `start/build_your_first_app.md` | 从源码构建如意玲珑包的完整教程,包含计算器示例和deb包转换 | +| 发布说明 | `start/release_note.md` | 版本发布说明 | + +### 构建相关 (building/) + +| 文档名称 | 文件路径 | 描述 | +| ---------------- | ---------------------------------- | ---------------------------------------------------------- | +| 玲珑应用打包规范 | `building/linyaps_package_spec.md` | 详细的应用程序打包规范,包含命名规范、构建配置、目录结构等 | +| 构建配置文件简介 | `building/manifests.md` | `linglong.yaml` 配置文件的详细说明和字段定义 | +| 模块管理 | `building/modules.md` | 模块拆分和管理说明 | +| 多架构支持 | `building/multiarch.md` | 多架构构建支持说明 | +| 演示示例 | `building/demo.md` | 构建演示示例 | + +### 调试相关 (debug/) + +| 文档名称 | 文件路径 | 描述 | +| ---------------- | ---------------- | ----------------------------------------------------------- | +| 调试如意玲珑应用 | `debug/debug.md` | 使用gdb、vscode、Qt Creator等工具调试如意玲珑应用的详细指南 | + +### 桌面集成 (desktop-integration/) + +| 文档名称 | 路径 | 描述 | +| ------------ | ------------------------------- | ------------------------------ | +| 桌面集成说明 | `desktop-integration/README.md` | 如意玲珑与桌面环境集成相关文档 | + +### 教程和示例 (lessons/) + +| 文档名称 | 文件路径 | 描述 | +| -------------- | --------------------------------- | ---------------------------- | +| 基础笔记 | `lessons/basic-notes.md` | 基础使用笔记 | +| 构建Git补丁 | `lessons/build-git-patch.md` | Git补丁构建教程 | +| 环境内构建 | `lessons/build-in-env.md` | 在特定环境中构建的教程 | +| 离线源码构建 | `lessons/build-offline-src.md` | 离线环境下的源码构建教程 | +| 使用工具链测试 | `lessons/test-with-toolchains.md` | 使用不同工具链进行测试的教程 | + +### 开发者文档 (linyaps-devel/) + +| 文档名称 | 文件路径 | 描述 | +| ---------- | ------------------------- | ------------------------ | +| 开发者文档 | `linyaps-devel/README.md` | 开发者相关文档(待补充) | + +### 发布相关 (publishing/) + +| 文档名称 | 文件路径 | 描述 | +| ----------- | ---------------------------- | ------------------------------------------ | +| 仓库管理 | `publishing/repositories.md` | 如意玲珑仓库的基本概念、管理和发布更新说明 | +| UAB格式发布 | `publishing/uab.md` | UAB格式发布说明 | +| 镜像站点 | `publishing/mirrors.md` | 镜像站点配置和管理 | + +### 额外文档 (extra/) + +| 文档名称 | 文件路径 | 描述 | +| ---------- | ------------------------ | -------------- | +| 单元测试 | `extra/unit-testing.md` | 单元测试文档 | +| 包格式 | `extra/bundle-format.md` | 包格式文档 | +| 系统助手 | `extra/system-helper.md` | 系统助手文档 | +| 应用配置 | `extra/app-conf.md` | 应用配置文档 | +| 根文件系统 | `extra/rootfs.md` | 根文件系统文档 | +| 参考文档 | `extra/ref.md` | 参考文档 | +| UAB构建 | `extra/uab-build.md` | UAB构建文档 | + +### 参考文档 (reference/) + +#### 基础概念 + +| 文档名称 | 文件路径 | 描述 | +| ------------ | ----------------------------- | --------------------------------------- | +| 基础概念介绍 | `reference/basic-concepts.md` | Base、Runtime、沙箱、仓库等核心概念介绍 | +| 运行时组件 | `reference/runtime.md` | 运行时组件的详细介绍 | +| 驱动程序 | `reference/driver.md` | 驱动程序相关文档 | + +#### 命令参考 + +**ll-appimage-convert 命令** + +- `reference/commands/ll-appimage-convert/ll-appimage-convert.md` - 主命令说明 +- `reference/commands/ll-appimage-convert/ll-appimage-convert-convert.md` - convert子命令 + +**ll-builder 命令** + +- `reference/commands/ll-builder/ll-builder.md` - 主命令说明 +- `reference/commands/ll-builder/build.md` - build子命令 +- `reference/commands/ll-builder/create.md` - create子命令 +- `reference/commands/ll-builder/export.md` - export子命令 +- `reference/commands/ll-builder/extract.md` - extract子命令 +- `reference/commands/ll-builder/import.md` - import子命令 +- `reference/commands/ll-builder/list.md` - list子命令 +- `reference/commands/ll-builder/push.md` - push子命令 +- `reference/commands/ll-builder/remove.md` - remove子命令 +- `reference/commands/ll-builder/repo.md` - repo子命令 +- `reference/commands/ll-builder/run.md` - run子命令 + +**ll-cli 命令** + +- `reference/commands/ll-cli/ll-cli.md` - 主命令说明 +- `reference/commands/ll-cli/content.md` - content子命令 +- `reference/commands/ll-cli/enter.md` - enter子命令 +- `reference/commands/ll-cli/info.md` - info子命令 +- `reference/commands/ll-cli/install.md` - install子命令 +- `reference/commands/ll-cli/kill.md` - kill子命令 +- `reference/commands/ll-cli/list.md` - list子命令 +- `reference/commands/ll-cli/prune.md` - prune子命令 +- `reference/commands/ll-cli/ps.md` - ps子命令 +- `reference/commands/ll-cli/repo.md` - repo子命令 +- `reference/commands/ll-cli/run.md` - run子命令 +- `reference/commands/ll-cli/search.md` - search子命令 +- `reference/commands/ll-cli/uninstall.md` - uninstall子命令 +- `reference/commands/ll-cli/upgrade.md` - upgrade子命令 + +**ll-pica 命令** + +- `reference/commands/ll-pica/ll-pica.md` - 主命令说明 +- `reference/commands/ll-pica/install.md` - install子命令 +- `reference/commands/ll-pica/ll-pica-adep.md` - adep子命令 +- `reference/commands/ll-pica/ll-pica-convert.md` - convert子命令 +- `reference/commands/ll-pica/ll-pica-init.md` - init子命令 + +**ll-pica-flatpak 命令** + +- `reference/commands/ll-pica-flatpak/ll-pica-flatpak.md` - 主命令说明 +- `reference/commands/ll-pica-flatpak/ll-pica-flatpak-convert.md` - convert子命令 + +### 提示和常见问题 (tips-and-faq/) + +| 文档名称 | 文件路径 | 描述 | +| ------------------- | -------------------------------- | ------------------------ | +| 常见问题 | `tips-and-faq/faq.md` | 常见运行时问题及解决方案 | +| ll-builder 常见问题 | `tips-and-faq/ll-builder-faq.md` | 构建工具常见问题 | +| ll-pica 常见问题 | `tips-and-faq/ll-pica-faq.md` | 包转换工具常见问题 | + +## 快速导航 + +### 新手入门 + +1. 阅读 [`start/whatis.md`](start/whatis.md) 了解基本概念 +2. 按照 [`start/install.md`](start/install.md) 安装如意玲珑 +3. 跟随 [`start/build_your_first_app.md`](start/build_your_first_app.md) 构建第一个应用 + +### 开发者参考 + +- 打包规范: [`building/linyaps_package_spec.md`](building/linyaps_package_spec.md) +- 配置文件: [`building/manifests.md`](building/manifests.md) +- 调试指南: [`debug/debug.md`](debug/debug.md) + +### 命令参考 + +- 构建工具: [`reference/commands/ll-builder/`](reference/commands/ll-builder/ll-builder.md) 目录 +- 命令行工具: [`reference/commands/ll-cli/`](reference/commands/ll-cli/ll-cli.md) 目录 +- deb包转换工具: [`reference/commands/ll-pica/`](reference/commands/ll-pica/ll-pica.md) 目录 +- AppImage转换工具: [`reference/commands/ll-appimage-convert/`](reference/commands/ll-appimage-convert/ll-appimage-convert.md) 目录 +- Flatpak转换工具: [`reference/commands/ll-pica-flatpak/`](reference/commands/ll-pica-flatpak/ll-pica-flatpak.md) 目录 + +### 常见问题 + +- 运行时问题: [`tips-and-faq/faq.md`](tips-and-faq/faq.md) +- 构建问题: [`tips-and-faq/ll-builder-faq.md`](tips-and-faq/ll-builder-faq.md) +- 转换问题: [`tips-and-faq/ll-pica-faq.md`](tips-and-faq/ll-pica-faq.md) diff --git a/docs/app-conf.md b/docs/pages/guide/extra/app-conf.md similarity index 100% rename from docs/app-conf.md rename to docs/pages/guide/extra/app-conf.md diff --git a/docs/pages/guide/extra/bundle-format.md b/docs/pages/guide/extra/bundle-format.md new file mode 100644 index 000000000..77412bf70 --- /dev/null +++ b/docs/pages/guide/extra/bundle-format.md @@ -0,0 +1,50 @@ +# 捆绑包格式 + +## 介绍 + +绿色软件,指的是一些不向系统安装任何文件的二进制程序。 + +绿色软件的基本约束是: + +- 路径无关,意味着与本地文件无关。 + +- 高度兼容性,因此软件应包含系统所没有的所有依赖项。 + +在 Linux 上构建绿色软件的著名技术是 AppImage。 + +然而,该技术存在许多问题,最大的问题是主机系统 ABI 无法保持稳定,并且彼此不同。玲珑也无法解决这个问题。我们应该保持对支持系统或 ABI 的基线。 + +在统信操作系统或深度操作系统上的一个技巧是仅支持统信操作系统 1020 之后的系统,这减少了针对不同基础系统的测试工作。 + +## 目标 + +绿色捆绑包不仅仅是简单支持应用程序运行路径独立。它还被设计为办公系统服务包支持的离线维护包格式,支持自运行和安装。因此在设计时保持捆绑包格式的可变性。 + +当用户有互联网时,我们主要使用在线差异更新或通过仓库安装。如果我们可以在分发应用程序时访问仓库,则不会使用捆绑包。 + +## 规范 + +导出捆绑包的规范: + +- 必须是 ELF,可以是 FlatELF +- 必须是静态链接的 +- 必须包含一个可以使用 fuse 挂载的数据段 +- 必须包含一个在 fuse 挂载文件系统根目录下的加载器可执行文件 + +## 实现 + +**实现会随时间变化,如果您更改了实现,请尽快更新此部分!!!** + +### 原型 + +- 捆绑包是一个简单的 ELF 加载器,通过 cat 连接只读文件系统。 +- 加载器简单地调用 read_elf64 来计算只读文件系统的偏移量。 +- 加载器使用 `squashfuse -o ro,offset=xxx` 挂载只读文件系统 +- 文件系统现在是只读文件系统 + - 文件系统的根目录应该包含一个名为 loader 的文件(顺便说一下,现在是 .loader) + - 目录结构应该是:/{id}/{version}/{arch}/ +- 只读文件系统应该支持 erofs,并且可能支持 squashfs + +文件系统的完整示例是: + +```bash diff --git a/docs/ref.md b/docs/pages/guide/extra/ref.md similarity index 92% rename from docs/ref.md rename to docs/pages/guide/extra/ref.md index de29702b3..4c4a2f79c 100644 --- a/docs/ref.md +++ b/docs/pages/guide/extra/ref.md @@ -1,8 +1,8 @@ -# Ref +# 引用(Ref) ## 定义 -组件:组件一般等价于其他系统中的 artifacts/component/module/package 等,在玲珑中,我们使用 layer 来表示一个组件。 +组件:组件通常等同于其他系统中的 artifacts/component/module/package 等,在玲珑中,我们使用 layer 来表示一个组件。 ## 格式 @@ -30,8 +30,8 @@ org.deepin.calculator 为 ID,1.2.2 为版本,x86_64 为架构。 | 标识 | 取值范围 | | ------- | ------------------------------------------------------------------------------------------ | -| repo | 小写字母 + 下划线 | -| channel | 小写字母 + 下划线 | +| repo | 小写字母 + 下划线 | +| channel | 小写字母 + 下划线 | | id | 英文倒置域名 | | version | 4 位数字,使用`.`分隔。不足 4 位的补 0,超过 4 位的将后续的数字字符串拼接到第 4 位数字中。 | | arch | 架构描述字符串,目前支持 x86_64/arm/loongarch | @@ -40,7 +40,7 @@ org.deepin.calculator 为 ID,1.2.2 为版本,x86_64 为架构。 Ref 包含两个部分,远程地址标识和本地标识。其中`:`前用分割远程标识和本地标识。 -运程标识主要用于定义这个 layer 是如何获取的。其中 channel 暂时没有用到,可以为空。repo 表示远程仓库(URL)在本地的映射的别名。 +远程标识主要用于定义这个 layer 是如何获取的。其中 channel 暂时没有用到,可以为空。repo 表示远程仓库(URL)在本地的映射的别名。 在安装过程中,使用完整的 ref 可以唯一标识一个 layer。例如: diff --git a/docs/rootfs.md b/docs/pages/guide/extra/rootfs.md similarity index 83% rename from docs/rootfs.md rename to docs/pages/guide/extra/rootfs.md index 7638e927d..de05fd025 100644 --- a/docs/rootfs.md +++ b/docs/pages/guide/extra/rootfs.md @@ -1,8 +1,8 @@ # Rootfs -As oci runtime specification, the runtime start from an rootfs, but in linglong, it prepare rootfs in ll-box. so we put the information of construction rootfs in annotations to ll-box. +根据 OCI 运行时规范,运行时从 rootfs 开始,但在玲珑中,它在 ll-box 中准备 rootfs。因此我们将构建 rootfs 的信息放在 ll-box 的注释中。 -The example of annotations is: +注释的示例是: ```json "annotations": { @@ -77,6 +77,6 @@ The example of annotations is: } ``` -The ll-box support two method to build rootfs, use native ro bind mount or with overlayfs. +ll-box 支持两种构建 rootfs 的方法,使用原生只读绑定挂载或使用 overlayfs。 -`container_root_path` is the work directory of ll-box. +`container_root_path` 是 ll-box 的工作目录。 diff --git a/docs/system-helper.md b/docs/pages/guide/extra/system-helper.md similarity index 79% rename from docs/system-helper.md rename to docs/pages/guide/extra/system-helper.md index aa82a08a4..dcb904644 100644 --- a/docs/system-helper.md +++ b/docs/pages/guide/extra/system-helper.md @@ -1,6 +1,6 @@ -# System Helper +# 系统助手 -User with no privilege can mount erofs to dir with: +无特权的用户可以通过以下方式将 erofs 挂载到目录: ```bash busctl --system call org.deepin.linglong.SystemHelper \ @@ -12,4 +12,3 @@ busctl --system call org.deepin.linglong.SystemHelper \ '/run/user/1000/linglong/vfs/layers/com.qq.music/1.1.3/x86_64/' \ 'erofs' \ 0 -``` diff --git a/docs/uab-build.md b/docs/pages/guide/extra/uab-build.md similarity index 99% rename from docs/uab-build.md rename to docs/pages/guide/extra/uab-build.md index 9e64ddbb3..0e7042236 100644 --- a/docs/uab-build.md +++ b/docs/pages/guide/extra/uab-build.md @@ -13,7 +13,7 @@ loader和extra-files.txt loader的编写参考: -``` bash +```bash #!/bin/env sh APPID=org.deepin.demo ./ll-box $APPID $PWD /opt/apps/$APPID/files/bin/demo diff --git a/docs/pages/guide/extra/unit-testing.md b/docs/pages/guide/extra/unit-testing.md new file mode 100644 index 000000000..450c178e3 --- /dev/null +++ b/docs/pages/guide/extra/unit-testing.md @@ -0,0 +1,11 @@ +# 单元测试 + +如意玲珑使用 gtest 进行单元测试,测试代码和测试数据位于项目根目录的 test/ 目录中。 + +由于某些测试在 CI 环境中难以运行,我们默认禁用了这些测试。 + +以下是控制测试运行的环境变量,默认情况下它们都是空的: + +| 名称 | 值 | 说明 | +| ----------------- | ---------------------------------- | ---------------- | +| LINGLONG_TEST_ALL | 如果设置此变量,将运行所有单元测试 | 启用所有测试用例 | diff --git a/docs/pages/guide/lessons/basic-notes.md b/docs/pages/guide/lessons/basic-notes.md index f72be69bd..6ee4658c6 100755 --- a/docs/pages/guide/lessons/basic-notes.md +++ b/docs/pages/guide/lessons/basic-notes.md @@ -1,49 +1,53 @@ # 玲珑应用构建工程基础知识 -在正式开始构建一个玲珑应用工程前, 我们需要对关于玲珑应用构建的基础知识有一定的认知, 以此协助我们更好地决策我们在启动构建工程前决定要准备哪些材料、进行哪一类型的操作 + +在正式开始构建一个玲珑应用工程前,我们需要对玲珑应用构建的基础知识有一定的认知,以此协助我们更好地决定在启动构建工程前需要准备哪些材料、进行哪一类型的操作。 ## 玲珑应用构建基本步骤 -在正式开始构建一个玲珑应用工程前, 我们需要了解一个玲珑应用从资源(源代码、二进制文件等)输入到应用安装包导出所经过的基本步骤, 来确定我们需要准备哪些必要文件 -1. 获取构建目标源文件(开源项目源代码、应用二进制文件等) -2. 根据源文件判断玲珑应用构建类型, 选择合适的构建方案 +在正式开始构建一个玲珑应用工程前,我们需要了解一个玲珑应用从资源(源代码、二进制文件等)输入到应用安装包导出所经过的基本步骤,来确定我们需要准备哪些必要文件。 + +1. 获取构建目标源文件(开源项目源代码、应用二进制文件等) +2. 根据源文件判断玲珑应用构建类型,选择合适的构建方案 3. 准备符合要求的玲珑构建环境 -4. 按照构建类型及源代码内容定制构建配置文件 `linglong.yaml` -5. 准备应用所使用的通用类资源, 图标以及其他非二进制资源 +4. 按照构建类型及源代码内容定制构建配置文件 `linglong.yaml` +5. 准备应用所使用的通用类资源、图标以及其他非二进制资源 ## 玲珑应用构建工程所需材料 -结合上述的知识, 我们可以了解到一个玲珑应用在构建的全过程中, 主要涉及到以下的文件: + +结合上述知识,我们可以了解到一个玲珑应用在构建的全过程中,主要涉及到以下文件: 1. 玲珑应用构建工程配置文件 `linglong.yaml` 2. 应用源代码/需要封装的二进制文件等资源 3. 非二进制文件等通用资源 ## 玲珑应用遵循的主流规范 -每一款Linux桌面软件包管理方案为了能够保障完整的功能和良好的体验, 均需要遵守软件包管理方案提出的各类规范要求以最大限度发挥软件包管理方案的功能并保障应用生态体验. -如意玲珑也并不总是特立独行, 需要满足一定的规范来保障如意玲珑生态得以持续稳步发展. -目前如意玲珑生方案遵守以下主流的规范: +每一款 Linux 桌面软件包管理方案为了能够保障完整的功能和良好的体验,均需要遵守软件包管理方案提出的各类规范要求,以最大限度发挥软件包管理方案的功能并保障应用生态体验。 +如意玲珑也并不总是特立独行,需要满足一定的规范来保障如意玲珑生态得以持续稳步发展。 + +目前如意玲珑方案遵守以下主流的规范: -1. Freedesktop XDG规范 +1. Freedesktop XDG 规范 2. 玲珑应用目录结构规范 -3. 玲珑应用构建工程配置文件 `linglong.yaml` 规范 +3. 玲珑应用构建工程配置文件 `linglong.yaml` 规范 ### Freedesktop XDG规范 -1. 玲珑应用解决方案遵循Freedesktop XDG规范,一款正常的图形化应用应具备图标文件、desktop文件并符合Freedesktop XDG规范 -2. 玲珑应用图标文件应该根据不同尺寸归类到`$PREFIX/share/icons/hicolor/目录下 -3. 玲珑应用容器中使用 `XDG_DATA_DIRS` 等变量, 支持读写宿主机中的用户目录 +1. 玲珑应用解决方案遵循 Freedesktop XDG 规范,一款正常的图形化应用应具备图标文件、desktop 文件并符合 Freedesktop XDG 规范。 +2. 玲珑应用图标文件应该根据不同尺寸归类到 `$PREFIX/share/icons/hicolor/` 目录下。 +3. 玲珑应用容器中使用 `XDG_DATA_DIRS` 等变量,支持读写宿主机中的用户目录。 ### 玲珑应用目录结构规范 -1. 玲珑应用遵循$PREFIX路径规则,该变量自动生成, 应用所有相关文件需存放于此目录下, 该目录层级下存在 `bin` `share` 等目录 +1. 玲珑应用遵循 $PREFIX 路径规则,该变量自动生成,应用所有相关文件需存放于此目录下,该目录层级下存在 `bin`、`share` 等目录。 -2. 玲珑应用容器中的应用将不被允许读取宿主机中系统目录中的二进制文件、运行库 +2. 玲珑应用容器中的应用将不被允许读取宿主机中系统目录中的二进制文件、运行库。 -3. 在构建工程中, 构建工程目录将会被映射到玲珑容器中, 挂载为 `/project` +3. 在构建工程中,构建工程目录将会被映射到玲珑容器中,挂载为 `/project`。 -4. 玲珑应用容器中运行库、头文件所在目录将根据运行环境类型而异 -foundation类: 在玲珑容器中映射为普通系统路径 `/usr/bin` `/usr/include` 等, 作为基础运行系统环境存在 -runtime类: 在玲珑容器中映射为runtime容器路径 `/runtime/usr/bin` `/runtime/usr/include` 等, 作为基础运行系统环境存在 +4. 玲珑应用容器中运行库、头文件所在目录将根据运行环境类型而异。 + foundation 类:在玲珑容器中映射为普通系统路径 `/usr/bin`、`/usr/include` 等,作为基础运行系统环境存在。 + runtime 类:在玲珑容器中映射为 runtime 容器路径 `/runtime/usr/bin`、`/runtime/usr/include` 等,作为基础运行系统环境存在。 \*默认情况下, 玲珑容器内部的环境变量已自动处理好路径识别问题, 如: @@ -53,19 +57,22 @@ PATH=szbt@szbt-linyaps23:/project$ echo $PATH ``` 通用表达为: + ``` PATH=szbt@szbt-linyaps23:/project$ echo $PATH /bin:/usr/bin:/runtime/bin:$PREFIX/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/sbin:/usr/sbin ``` ## 玲珑应用构建工程通用资源的规范 -在玲珑应用构建工程中, 不同的资源文件均需要遵循相关规范以确保构建、体验能够满足要求 + +在玲珑应用构建工程中,不同的资源文件均需要遵循相关规范以确保构建、体验能够满足要求 ### icons 图标目录规范 -依据玲珑遵循的 `Freedesktop XDG规范` 及 `玲珑应用目录结构规范`, 图标根据不同尺寸放置在对应的目录中 + +依据玲珑遵循的 `Freedesktop XDG规范` 及 `玲珑应用目录结构规范`,图标根据不同尺寸放置在对应的目录中 主流的非矢量图标尺寸有: `16x16` `24x24` `32x32` `48x48` `128x128` `256x256` `512x512` -为保障图标在系统中能够获得较佳的体验效果, 因此需要至少一个尺寸不小于 `128x128` 的非矢量图标文件, 矢量图标则不存在该限制 +为保障图标在系统中能够获得较佳的体验效果,因此需要至少一个尺寸不小于 `128x128` 的非矢量图标文件,矢量图标则不存在该限制 因此, 一款玲珑应用安装目录中, icons图标目录应为以下示例: @@ -79,24 +86,28 @@ $PREFIX/share/icons/hicolor/256x256/apps $PREFIX/share/icons/hicolor/512x512/apps $PREFIX/share/icons/hicolor/scalable/apps ``` -\* `scalable` 目录用于放置 `矢量图标` 文件, 一般为 `.svg` 格式 + +\* `scalable` 目录用于放置 `矢量图标` 文件,一般为 `.svg` 格式 假设你的玲珑应用同时提供尺寸为 `128x128` 的非矢量图标文件 `linyaps-app-demo.png` 和 `128x128` 的矢量图标文件 `linyaps-app-demo.svg`, 在玲珑容器中应当表现为以下状态 + ``` $PREFIX/share/icons/hicolor/128x128/apps/linyaps-app-demo.png $PREFIX/share/icons/hicolor/scalable/apps/linyaps-app-demo.svg ``` -\* 为了避免图标冲突被覆盖, 图标文件名请使用应用 `唯一英文名称` 或 `玲珑应用id` + +\* 为了避免图标冲突被覆盖,图标文件名请使用应用 `唯一英文名称` 或 `玲珑应用id` ### desktop 文件规范 -玲珑应用兼容大部分符合 `Freedesktop XDG规范` 的 `desktop启动文件`, 其中有以下字段需要额外注意: -| 字段 | 值要求 | -|-------|---------| -| Exec | 该值用于设置点击此desktop文件时执行的指令, 需要与 `linglong.yaml` 中的 `command` 值保持一致 | -| Icon | 该值用于设置该desktop文件显示的应用图标, 需要与 `icons 图标目录规范` 中的图标文件名一致, 此值不需要文件名后缀 | +玲珑应用兼容大部分符合 `Freedesktop XDG规范` 的 `desktop启动文件`,其中有以下字段需要额外注意: + +| 字段 | 值要求 | +| ---- | ------------------------------------------------------------------------------------------------------------- | +| Exec | 该值用于设置点击此desktop文件时执行的指令,需要与 `linglong.yaml` 中的 `command` 值保持一致 | +| Icon | 该值用于设置该desktop文件显示的应用图标,需要与 `icons 图标目录规范` 中的图标文件名一致,此值不需要文件名后缀 | -因此, 一个符合玲珑应用规范的desktop文件可以参考: +因此,一个符合玲珑应用规范的desktop文件可以参考: ``` org.qbittorrent.qBittorrent.desktop @@ -116,22 +127,23 @@ Terminal=false ``` ## 玲珑应用构建工程 `linglong.yaml` 规范 -正如其他传统包管理套件一样, 手动创建一个玲珑应用构建工程需要设置构建规则文件 `linglong.yaml`, 在构建规则中, 则根据用途划分为 `全局字段` 及 `定制化字段`. -\* 案例中 `linglong.yaml` 正文内所有空格符号、占位符均为有效字符, 请勿删除或变更格式 + +正如其他传统包管理套件一样,手动创建一个玲珑应用构建工程需要设置构建规则文件 `linglong.yaml`,在构建规则中,则根据用途划分为 `全局字段` 及 `定制化字段`。\* 案例中 `linglong.yaml` 正文内所有空格符号、占位符均为有效字符,请勿删除或变更格式 ### 全局字段规范 -在 `linglong.yaml` 中, 对于不受构建类型影响的字段我们称为 `全局字段`, 主要有以下参考的规范: -1. 一个可以正常开始构建工程的 `linglong.yaml` 应包含以下的关键部分: -| 模块 | 解释 | -|-------|-------| -| version | 构建工程版本号 | -| package | 玲珑应用基本信息 | -| base | 玲珑应用容器基础环境及版本设置, 基础环境中包含了部分基础运行库 | -| runtime | 玲珑应用运行库 `runtime` 及版本设置, 当 `base` 中的基础运行库满足程序运行要求时, 此模块可删除 | -| command | 玲珑应用容器启动时执行的命令, 与 `desktop` 文件的 `Exec` 字段内容一致 | -| sources | 玲珑应用构建工程源文件类型 | -| build | 玲珑应用构建工程将要执行的构建规则 | +在 `linglong.yaml` 中,对于不受构建类型影响的字段我们称为 `全局字段`,主要有以下参考的规范: + +1. 一个可以正常开始构建工程的 `linglong.yaml` 应包含以下的关键部分: + | 模块 | 解释 | + |-------|-------| + | version | 构建工程版本号 | + | package | 玲珑应用基本信息 | + | base | 玲珑应用容器基础环境及版本设置, 基础环境中包含了部分基础运行库 | + | runtime | 玲珑应用运行库 `runtime` 及版本设置, 当 `base` 中的基础运行库满足程序运行要求时, 此模块可删除 | + | command | 玲珑应用容器启动时执行的命令, 与 `desktop` 文件的 `Exec` 字段内容一致 | + | sources | 玲珑应用构建工程源文件类型 | + | build | 玲珑应用构建工程将要执行的构建规则 | `package` 模块中存在数个子模块: | 子模块 | 解释 | @@ -142,32 +154,35 @@ Terminal=false | kind | 玲珑应用类型, 默认为 `app` | | description | 玲珑应用描述 | -2. 玲珑应用遵循 `$PREFIX` 路径规则,该变量自动生成,应用所有相关文件需存放于此目录下. 构建规则中若有需要涉及安装文件的操作, 均需要安装到 `$PREFIX` 路径下 -\* `$PREFIX` 变量名即为填写的实际内容, **请勿使用 `绝对路径` 或任何具有绝对值作用的内容代替 ** +2. 玲珑应用遵循 `$PREFIX` 路径规则,该变量自动生成,应用所有相关文件需存放于此目录下。构建规则中若有需要涉及安装文件的操作,均需要安装到 `$PREFIX` 路径下 \* `$PREFIX` 变量名即为填写的实际内容,**请勿使用 `绝对路径` 或任何具有绝对值作用的内容代替 ** 3. 玲珑应用目前遵循 `四位数字` 的版本号命名规则,不符合规则无法启动构建工程 -4. `base`、`runtime` 版本支持自动匹配最新版本 `尾号`,版本号可以仅填写版本号的`前三位数字`.如: -当base `org.deepin.foundation`同时提供 `23.0.0.28` `23.0.0.29`, 若 `linglong.yaml` 中仅填写 +4. `base`、`runtime` 版本支持自动匹配最新版本 `尾号`,版本号可以仅填写版本号的`前三位数字`。如: + 当base `org.deepin.foundation`同时提供 `23.0.0.28` `23.0.0.29`,若 `linglong.yaml` 中仅填写 + ``` base: org.deepin.foundation/23.0.0 ``` -那么在启动玲珑应用构建工程时, 将会默认采用最高版本号的 `23.0.0.29` -5 玲珑应用构建工程配置文件目前不直接兼容其他包构建工具的配置文件,需要根据构建工程配置文件案例来进行适配修改: -https://linglong.dev/guide/ll-builder/manifests.html +那么在启动玲珑应用构建工程时, 将会默认采用最高版本号的 `23.0.0.29` +5. 玲珑应用构建工程配置文件目前不直接兼容其他包构建工具的配置文件,需要根据构建工程配置文件案例来进行适配修改: + https://linglong.dev/guide/ll-builder/manifests.html ### 定制化字段 -根据玲珑应用构建工程源文件类型, 又可将玲珑应用构建工程划分为 `本地文件文件构建` `git 源码仓库拉取构建`, 不同类型则需要填写不同的 `linglong.yaml` -玲珑应用构建工程源文件类型 `sources` 主要支持这几种类型: `git` `local` `file` `archive` + +根据玲珑应用构建工程源文件类型,又可将玲珑应用构建工程划分为 `本地文件构建` `git 源码仓库拉取构建`,不同类型则需要填写不同的 `linglong.yaml` +玲珑应用构建工程源文件类型 `sources` 主要支持这几种类型:`git` `local` `file` `archive` 完整说明参考: [构建配置文件简介](https://linyaps.org.cn/guide/ll-builder/manifests.html) #### git拉取源码编译模式 -当玲珑应用构建工程需要通过git拉取开源项目仓库资源到本地进行构建时, 此时 `sources` 应当设置为 `git` 类型, 并根据要求填写 `linglong.yaml` + +当玲珑应用构建工程需要通过git拉取开源项目仓库资源到本地进行构建时,此时 `sources` 应当设置为 `git` 类型,并根据要求填写 `linglong.yaml` 此时需要根据规范编写 `sources` 与 `build` 模块 1. `sources` 示例: + ```yaml sources: - kind: git @@ -181,15 +196,17 @@ sources: commit: 4b4003d0fdc09a257a0841ad965b22533ed87a0d ``` -| 名称 | 描述 | -|------|-------| -| kind | 源文件类型 | -| url | 需要通过git拉取的源代码仓库地址, 该仓库需要支持git功能. 当网络状态不佳时, 可采用镜像地址代替 | -| version | 指定源代码仓库的版本号, 即 `tag标签`, 或拉取主线 `master` | -| commit | 根据该仓库 `commit` 变动历史拉取源码, 此处填入commit对应的值, 将会应用该仓库截止本commit的所有变更. *此字段优先级高于 `version`, 请勿填入 `version` 合并时间之后的任何 `commit`| +| 名称 | 描述 | +| ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| kind | 源文件类型 | +| url | 需要通过git拉取的源代码仓库地址, 该仓库需要支持git功能. 当网络状态不佳时, 可采用镜像地址代替 | +| version | 指定源代码仓库的版本号,即 `tag标签`,或拉取主线 `master` | +| commit | 根据该仓库 `commit` 变动历史拉取源码,此处填入commit对应的值,将会应用该仓库截止本commit的所有变更。\*此字段优先级高于 `version`,请勿填入 `version` 合并时间之后的任何 `commit` | + \* 支持同时添加多个git仓库作为 `sources` 拉取 2. `build` 示例: + ```yaml build: | mkdir -p ${PREFIX}/bin/ ${PREFIX}/share/ @@ -197,15 +214,18 @@ build: | cd /project/linglong/sources/qBittorrent.git git apply -v /project/patches/linyaps-qBittorrent-4.6.7-szbt2.patch ``` -此模块为构建规则正文, 路径遵守 `玲珑应用目录结构规范` -在 `sources` 拉取到本地后, 仓库文件将会存放在 `/project/linglong/sources` 目录中, 此时不同仓库目录以 `xxx.git` 命名 + +此模块为构建规则正文,路径遵守 `玲珑应用目录结构规范` +在 `sources` 拉取到本地后,仓库文件将会存放在 `/project/linglong/sources` 目录中,此时不同仓库目录以 `xxx.git` 命名 支持运用 `git patch` 功能对源代码进行便捷维护 #### 本地资源操作模式 -当玲珑应用构建工程需要对构建目录中的文件操作时, 此时 `kind` 应当设置为 `local` 类型, 并根据要求填写 `linglong.yaml` + +当玲珑应用构建工程需要对构建目录中的文件操作时,此时 `kind` 应当设置为 `local` 类型,并根据要求填写 `linglong.yaml` 此时需要根据规范编写 `sources` 与 `build` 模块 1. `sources` 示例: + ```yaml sources: source: @@ -213,14 +233,15 @@ source: name: "qBittorrent" ``` -| 名称 | 描述 | -|------|-------| -| kind | 源文件类型 | -| name | 源文件名称标识, 不具备实际用途 | +| 名称 | 描述 | +| ---- | ------------------------------ | +| kind | 源文件类型 | +| name | 源文件名称标识,不具备实际用途 | \* 当 `kind` 应当设置为 `local` 类型时, 构建工程将不会对任何源文件进行操作 2. `build` 示例: + ```yaml build: | ##Build main @@ -231,12 +252,13 @@ build: | make -j$(nproc) make install ``` -此模块为构建规则正文, 路径遵守 `玲珑应用目录结构规范` -此时 `build` 规则支持多种写法以模拟人为操作 -\* 需要确保此构建规则所有步骤均可以正常被执行, 否则将会中断当次构建任务 + +此模块为构建规则正文,路径遵守 `玲珑应用目录结构规范` +此时 `build` 规则支持多种写法以模拟人为操作 \* 需要确保此构建规则所有步骤均可以正常被执行,否则将会中断当次构建任务 #### 容器内部手动操作模式 -若计划直接进入玲珑容器手动操作而不是通过构建规则文件 `linglong.yaml`,那么应该参考 `本地资源操作模式` 填写 `linglong.yaml` + +若计划直接进入玲珑容器手动操作而不是通过构建规则文件 `linglong.yaml`,那么应该参考 `本地资源操作模式` 填写 `linglong.yaml` 1. `sources` 部分写法与 `本地资源操作模式` 一致 -2. 由于使用手动操作, 因此不需要完整且可以正常被执行的 `build` 规则, 此时 `linglong.yaml` 用于生成符合描述的玲珑容器而不是执行所有任务, 具体操作可查阅后续课程关于容器内部构建文件的案例 \ No newline at end of file +2. 由于使用手动操作,因此不需要完整且可以正常被执行的 `build` 规则,此时 `linglong.yaml` 用于生成符合描述的玲珑容器而不是执行所有任务,具体操作可查阅后续课程关于容器内部构建文件的案例 diff --git a/docs/pages/guide/lessons/build-git-patch.md b/docs/pages/guide/lessons/build-git-patch.md index 73820eb4e..b8a84d66d 100644 --- a/docs/pages/guide/lessons/build-git-patch.md +++ b/docs/pages/guide/lessons/build-git-patch.md @@ -1,4 +1,5 @@ # 将基于Qt5的开源应用--qBittorrent 适配为支持自动化的玲珑应用构建工程 + 书接上文, 我们继续探讨如何将 `linglong.yaml` 适配为支持自动构建的版本 由于上一环节我们已经确定了可以正常完成编译构建任务所使用的构建规则, 因此我们本节主要讨论如何利用 `git` 功能完成下列自动操作 @@ -6,14 +7,17 @@ 2. 自动应用自定义patch内容 ## 改造 `linglong.yaml` + 在上一节中我们已经获得了可以成功编译本地源代码的 `linglong.yaml`, 由于是同一款应用项目, 我们可以直接在其基础上进行改造 对于 `linglong.yaml` 而言, 核心部分之二主要是 `sources` 和 `build` 模块, 这次我们分开这两部分进行详解 ### `sources` 模块 + 根据 [玲珑应用构建工程 `linglong.yaml` 规范], 当构建工程的源文件为git仓库时(即通过git clone拉取源代码仓库), `sources` 的源文件类型 `kind` 应设为 `git` 并填写仓库的相关信息 根据 [玲珑应用构建工程 `linglong.yaml` 规范] 的 `git拉取源码编译模式` 规范, 我们需要掌握源代码仓库的以下信息: + 1. url, 即git clone 所使用的地址, 如普通git clone一样可以使用镜像地址 2. version, 即需要抓取仓库的某一个具体版本号, 一般为 `Tags` 标签 3. 需要应用的仓库commit编号, 此处填入commit对应的值, 将会应用该仓库截止本commit的所有变更. 此字段优先级高于 `version`, 请勿填入 `version` 合并时间之后的任何 `commit` @@ -33,17 +37,19 @@ sources: commit: 4b4003d0fdc09a257a0841ad965b22533ed87a0d ``` -![commit-1](image/4-commit-1.png) +![4-commit-1.png](https://free.picui.cn/free/2025/11/24/69234bfdc83a8.png) -![commit-2](image/4-commit-2.png) +![4-commit-2.png](https://free.picui.cn/free/2025/11/24/69234bfe1fce8.png) 由图可见, 填入的commit值均匹配了对应Tag生成时的commit ### `build` 模块 + 在完成源文件信息设置后, 我们开始修改构建规则 考虑到上一课时已经取得了执行性较强的构建规则, 因此我们仅需根据 [玲珑应用构建工程 `linglong.yaml` 规范] `git拉取源码编译模式` 中的相关规范修改源码路径即可 在完成修改后, 我们将会得到如下的构建规则: + ```yaml build: | mkdir -p ${PREFIX}/bin/ ${PREFIX}/share/ @@ -68,6 +74,7 @@ build: | ``` ### 自定义patch应用 + 在本次案例中, 我们同时引入了新场景: 当拉取开源项目某个具体版本号的仓库资源后, 需要在源码上进行修改以达到修复漏洞、bug的补丁效果 为此, 我们需要学习一个新知识: `git patch` 相关内容, git程序内置patch管理系统, 需要便捷地利用此功能对源码进行修订, 一般有以下步骤: @@ -78,7 +85,7 @@ build: | 比如在本次 `qBittorrent--4.6.7` 的仓库拉取后, 我需要添加一项与安全漏洞相关的合并: https://github.com/qbittorrent/qBittorrent/pull/21364 -![commit-3](image/4-commit-3.png) +![4-commit-3.png](https://free.picui.cn/free/2025/11/24/69234bfe54fd8.png) 需要注意的是, 该提交基于 `qBittorrent--5.x` 的版本进行, 这意味着如果我想要在 `qBittorrent--4.6.7` 上修复此漏洞, 需要手动修改源码 考虑到短期内维护的该应用主版本号将不会迭代至 `5.x`, 随着其他安全漏洞发生的可能性以及降低反复修改源代码的劳动成本, 我采用了增加patch的方式来协助我修改源码 @@ -96,17 +103,18 @@ origin https://ghp.ci/https://github.com/qbittorrent/qBittorrent.git (push) 可见, 执行指令后可以返回远程仓库的信息, 此目录满足要求 -3. 随后, 根据上述安全漏洞提交时文件变更对源码进行手动修改 -\* 此处需要维护者根据经验判断具体需要合入哪些提交 +3. 随后, 根据上述安全漏洞提交时文件变更对源码进行手动修改 \* 此处需要维护者根据经验判断具体需要合入哪些提交 4. 修改完成后, 返回源码根目录, 执行 `git diff` 可以查看存在的差异比对: 5. 确认无误后, 将此差异保存到本地中, 形成patch文件 + ```bash -ziggy@linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-local$ git diff > ./ +ziggy@linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-local$ git diff > ./qBittorrent.patch ``` 6. 在得到patch文件后, 我们将应用patch的内容添加到已有的 `build` 构建规则中: + ```yaml build: | mkdir -p ${PREFIX}/bin/ ${PREFIX}/share/ @@ -133,6 +141,7 @@ build: | ##Extract common res cp -rf /project/template_app/* ${PREFIX}/share/ ``` + 7. 此刻我们可以返回构建目录, 开始构建测试了, 执行: ```bash @@ -140,23 +149,29 @@ ziggy@linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-local$ ll-builder build ``` 此次构建很快就成功结束了, 我们执行以下指令来将容器导出为玲珑应用安装包 `binary.layer` : + ```bash ziggy@linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-local$ ll-builder export --layer ``` ## 本地构建结果测试 + 在得到玲珑应用安装包后, 我在不同支持玲珑环境的主流发行版上尝试体验, 来确认通过玲珑容器构建的二进制程序是否存在通用性 ### deepin 23 -#![deepin 23](image/4-test-1.png) + +![deepin 23](https://free.picui.cn/free/2025/11/24/69234b2085f30.png) ### openKylin 2.0 -#![openKylin 2.0](image/4-test-2.png) + +![openKylin 2.0](https://free.picui.cn/free/2025/11/24/69234b206d8c6.png) ### Ubuntu 2404 -#![Ubuntu 2404](image/4-test-3.png) + +![Ubuntu 2404](https://free.picui.cn/free/2025/11/24/69234b200d09f.png) ### OpenEuler 2403 -#![OpenEuler 2403](image/4-test-4.png) + +![OpenEuler 2403](https://free.picui.cn/free/2025/11/24/69234b205dca1.png) 至此, 足以证明 `基于Qt5的开源应用--qBittorrent` 在添加定制补丁以及修改构建规则后可以实现一站拉取项目源码并编译成可执行的二进制文件, 并在其他发行版上也可以使用 ! diff --git a/docs/pages/guide/lessons/build-in-env.md b/docs/pages/guide/lessons/build-in-env.md index 301f7f37f..d8dfd3dea 100644 --- a/docs/pages/guide/lessons/build-in-env.md +++ b/docs/pages/guide/lessons/build-in-env.md @@ -1,13 +1,16 @@ # 在玲珑容器中编译基于Qt5的开源应用--qBittorrent + 在学习上一章节 `玲珑应用构建工程基础知识` 后, 我们即将步入实操课堂, 利用所学知识去正式构建一款玲珑应用. 今天, 我们将演示进入玲珑容器并将一款开源图形应用 `qBittorrent` 的源代码编译为二进制文件并测试运行 ## 前期准备 + 根据 `玲珑应用构建工程基础知识` 中对于 `玲珑应用构建工程通用资源的规范` 要求, 我们应当为一款图形化应用同时提供保障桌面用户体验的 `icons` 图标文件及 `desktop` 启动文件 但本节实操课堂仅在玲珑容器中进行编译、测试操作, 因此暂时不需要准备通用资源 本次分享基于 `deepin 23` 发行版, 因此在进行以下任意步骤前均需要准备一个可以构建玲珑应用的 `deepin 23` 系统环境: + 1. 确保环境中已经安装 `ll-builder` 构建套件, 不同发行版安装方式参考: [安装玲珑](https://linyaps.org.cn/guide/start/install.html) 2. 由于在构建过程中我们需要联网获取玲珑容器的运行库以及可能需要的第三方库, 因此我们需要保障全操作过程能够得到顺畅的网络连接 @@ -16,10 +19,7 @@ 4. 结合上一节 [玲珑应用构建工程 `linglong.yaml` 规范] 并按照以下模板简单编写一版玲珑构建工程配置文件 `linglong.yaml`, 以此来生成一个符合要求的容器 -主要有以下需要关注的点: -\* 由于本次操作是直接进入容器进行操作, 因此 `build` 部分的构建规则可不详细写 -\* 由于本次涉及编译操作, 为了能够极大程度包含所需的运行库, 我们加入 `runtime` 段, 具体编写规范参考 [玲珑应用构建工程基础知识] - +主要有以下需要关注的点: \* 由于本次操作是直接进入容器进行操作, 因此 `build` 部分的构建规则可不详细写 \* 由于本次涉及编译操作, 为了能够极大程度包含所需的运行库, 我们加入 `runtime` 段, 具体编写规范参考 [玲珑应用构建工程基础知识] ```yaml # SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. @@ -51,6 +51,7 @@ build: | ``` ### 项目编译演示 + \*这里需要回顾一个知识点: 根据 [玲珑应用目录结构规范], 与构建工程配置文件 `linglong.yaml` 同级的构建目录将被映射为 `/project` 目录 万事俱备, 我们就可以开始编译了 @@ -63,35 +64,38 @@ szbt@szbt-linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-git$ ll-builder bui ``` 路径发生类似以下变化时, 即意味着我们已经进入玲珑容器中了 + ``` szbt@szbt-linyaps23:/project$ ``` 3. 通过 `普通操作` 窗口解压 `qBittorrent-4.6.7` 源码到构建目录中, 我这里单独解压到一个子目录中 + ``` szbt@szbt-linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-git$ tar -xvf qBittorrent-4.6.7-git-origin-src.tar.zst -C src/ ``` 4. 源码解压后, 根据 [玲珑应用构建基本步骤], 我们在编译任意源代码前应该正确选择使用何种编译系统/工具. 我们通过观察 `qBittorrent-4.6.7` 源码目录, 可以看到其存在 `CMakeLists.txt` 文件, 这是 `CMake` 构建项目. -![1](image/2-1.png) + ![2-1.png](https://free.picui.cn/free/2025/11/24/69234a3575f6f.png) 5. 由于 [qBittorrent INSTALL](https://github.com/qbittorrent/qBittorrent/blob/release-4.6.7/INSTALL) 中简要描述了本项目主要使用的运行库, 因此我们可以对照此文档来判断哪些运行库存在与玲珑提供的 `base`、 `runtime` 中或哪些运行库并未被提供的. 对于暂未被正式提供的运行库, 在编译主程序前我们可能需要先预编译必要的第三方库. 由于文档所述需要的运行库较少, 此次我们可以先直接进行一次测试编译来确认运行库缺失情况 6. 事不宜迟, 我们通过 `玲珑容器操作` 窗口进入源码目录, 为了尽量避免对源目录的干扰, 我这里新建一个 `build` 目录用于编译. 进入 `build` 目录后我们输入CMake相关配置参数来配置构建工程. -根据[玲珑应用目录结构规范], 我们将 `DCMAKE_INSTALL_PREFIX` 赋予 `$PREFIX` 的值, 最终我在本地执行了以下操作: + 根据[玲珑应用目录结构规范], 我们将 `DCMAKE_INSTALL_PREFIX` 赋予 `$PREFIX` 的值, 最终我在本地执行了以下操作: + ``` - cmake -DCMAKE_BUILD_TYPE=Release\ - -DCMAKE_INSTALL_PREFIX=$PREFIX .. + cmake -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=$PREFIX .. ``` -7. 可以从图中看到, 这里出现了一个错误导致无法完成配置. 我们看到 `pkg-config` 出现错误: `libtorrent-rasterbar>=1.2.19` 库不能满足条件: +7. 可以从图中看到, 这里出现了一个错误导致无法完成配置. 我们看到 `pkg-config` 出现错误: `libtorrent-rasterbar>=1.2.19` 库不能满足条件: -![error-1](image/2-error-1.png) + ![2-error-1.png](https://free.picui.cn/free/2025/11/24/69234a35d4640.png) ``` --- Found PkgConfig: /bin/pkg-config (found version "1.8.1") +-- Found PkgConfig: /bin/pkg-config (found version "1.8.1") -- Checking for module 'libtorrent-rasterbar>=1.2.19' ``` @@ -103,18 +107,18 @@ szbt@szbt-linyaps23:/project/src/qBittorrent-release-4.6.7-szbt2/build$ pkg-conf 结合此报错, 基本可以判断为该库缺失, 因此我们需要在编译主程序前编译并安装此第三方库 - 8. 我们返回`普通操作` 窗口将: `libtorrent-rasterbar>=1.2.19` 库对应的源码下载到当前构建目录中, 进入`玲珑容器操作` 窗口重新编译 9. 源码解压后, 根据 [玲珑应用构建基本步骤], 我们在编译任意源代码前应该正确选择使用何种编译系统/工具. 我们通过观察 `libtorrent-rasterbar-2.0.9` 源码目录, 可以看到其存在 `CMakeLists.txt` 文件, 这是 `CMake` 构建项目. -![2](image/2-2.png) + ![2-2.png](https://free.picui.cn/free/2025/11/24/69234a35a84bb.png) 10. 我们通过 `玲珑容器操作` 窗口进入源码目录, 为了尽量避免对源目录的干扰, 我这里新建一个 `build` 目录用于编译. 进入 `build` 目录后我们输入CMake相关配置参数来配置构建工程. -根据[玲珑应用目录结构规范], 我们将 `DCMAKE_INSTALL_PREFIX` 赋予 `$PREFIX` 的值, 最终我在本地执行了以下操作: + 根据[玲珑应用目录结构规范], 我们将 `DCMAKE_INSTALL_PREFIX` 赋予 `$PREFIX` 的值, 最终我在本地执行了以下操作: + ``` - cmake -DCMAKE_BUILD_TYPE=Release\ - -DCMAKE_INSTALL_PREFIX=$PREFIX .. + cmake -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=$PREFIX .. make -j$(nproc) make install ``` @@ -124,11 +128,11 @@ szbt@szbt-linyaps23:/project/src/qBittorrent-release-4.6.7-szbt2/build$ pkg-conf 11. 我们返回 `玲珑容器操作` 窗口进入 `qBittorrent-4.6.7` 源码目录,重新执行配置、编译、安装操作, 均不存在报错了. ### 编译结果测试 - 在流程结束后, 我们在 `$PREFIX` 目录中找到该项目的二进制执行文件 `/opt/apps/org.qbittorrent.qBittorrent/files/bin/qbittorrent` 并在容器中运行测试 -\* 该操作需要在图形化桌面的终端操作, 否则有可能无法调起程序的图形界面 + +在流程结束后, 我们在 `$PREFIX` 目录中找到该项目的二进制执行文件 `/opt/apps/org.qbittorrent.qBittorrent/files/bin/qbittorrent` 并在容器中运行测试 \* 该操作需要在图形化桌面的终端操作, 否则有可能无法调起程序的图形界面 看起来因为并不是直接通过容器启动, 发生了运行库无法找到的问题, 因为报错的库也在$PREFIX中, 因此我们直接通过变量 `LD_LIBRARY_PATH` 来指定动态运行库寻找路径 -![test](image/2-test.png) + ![2-test.png](https://free.picui.cn/free/2025/11/24/69234a367aecf.png) 至此, 足以证明 `基于Qt5的开源应用--qBittorrent` 可以在 `如意玲珑` 应用容器中成功编译并运行! diff --git a/docs/pages/guide/lessons/build-offline-src.md b/docs/pages/guide/lessons/build-offline-src.md index cbbde437f..5ea502910 100644 --- a/docs/pages/guide/lessons/build-offline-src.md +++ b/docs/pages/guide/lessons/build-offline-src.md @@ -1,4 +1,5 @@ # 将基于Qt5的开源应用--qBittorrent 适配为支持自动化的玲珑应用构建工程 + 在学习上一章节 `在玲珑容器中编译基于Qt5的开源应用--qBittorrent` 后, 我们已经大概了解了在玲珑容器中通过怎么样的操作可以将基于Qt5的开源应用--qBittorrent项目源代码编译为可以运行的二进制程序文件. 今天, 我们在此基础上补齐 `玲珑应用构建基本步骤` 中的最后步骤--编写一份完整的玲珑应用构建工程配置文件 `linglong.yaml`, 主要实现以下的目标: @@ -8,6 +9,7 @@ 3. 自动执行编译构建、安装操作 ## 前期准备 + 根据 `玲珑应用构建工程基础知识` 中对于 `玲珑应用构建工程通用资源的规范` 要求, 我们应当为一款图形化应用同时提供保障桌面用户体验的 `icons` 图标文件及 `desktop` 启动文件 因此, 我们今天为了能够编写自动编译 `qBittorrent` 的完整 `linglong.yaml`,需要额外准备以下材料: @@ -17,6 +19,7 @@ 3. 第三方运行库 libtorrent 开源项目的仓库git信息、tag版本、commit信息 ### 通用资源准备 + 由于在上节课堂中我们在玲珑容器内已经成功编译并运行了 `qBittorrent`, 并且这款应用在安装到$PREFIX之后一并提供了icons目录、desktop启动文件 我们对这两项进行检查, 确认均符合 `Freedesktop XDG规范`, 因此我们仅需要直接从容器中复制到本地即可, 即复制到构建目录 `/project` 中. @@ -31,6 +34,7 @@ qbittorrent.png ``` 于是, 我们得到了 `非二进制文件通用资源`, 为了方便被构建组件使用, 我这里将这些文件放到了构建目录的 `template_app` 子目录中, 现在呈现此类结构: + ``` template_app ├── linglong.yaml @@ -54,8 +58,10 @@ template_app ``` ### desktop 启动文件定制 + 根据基础知识课程的 `玲珑应用构建工程通用资源的规范`, 我们需要确保当前的desktop文件符合相关规范 我们打开从容器中导出的desktop文件, 检查Exec和Icon字段, 得出以下结果: + ``` [Desktop Entry] Categories=Network;FileTransfer;P2P;Qt; @@ -71,13 +77,11 @@ Icon=qbittorrent 2. Exec字段值不为玲珑容器内编译的结果, 需要修改为符合 `玲珑应用构建工程通用资源的规范` 的内容, 这里替换为绝对路径指向容器中的具体二进制文件, 用于唤醒容器并启动该应用 ## 构建工程配置文件 `linglong.yaml` 准备 + 在准备图形化应用所必备的通用资源后, 我们着手编写构建规则 由于在上节课程中我们已经准备了一版简单但不具备完整构建功能的 `linglong.yaml`, 因此我们可以在其基础上进行定制, 现在是初始状态: -```yaml -# SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. -# -# SPDX-License-Identifier: LGPL-3.0-or-later +```yaml version: "4.6.7.2" package: @@ -109,6 +113,7 @@ build: | 以下是正式开始改造的过程: 1. 通过 `普通操作` 窗口使用 `git` 将 `qBittorrent` 和 `libtorrent-rasterbar` 源码拉取或解压到构建目录中, 我这里通过源码压缩包单独解压到子目录中 + ``` ziggy@linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-local$ tar -xvf qBittorrent-4.6.7-git-origin-src.tar.zst -C src/ ziggy@linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-local$ tar -xvf libtorrent-rasterbar-2.0.9.tar.gz -C 3rd/ @@ -116,38 +121,35 @@ ziggy@linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-local$ tar -xvf libtorr ``` 2. 从 `玲珑应用目录结构规范` 得知, 构建目录会被映射为 `/project`, 因此我们需要将上节课程中使用的手动编译命令写入 `build` 模块中 + ``` build: | mkdir -p ${PREFIX}/bin/ ${PREFIX}/share/ - ##Build 3rd libs 注释:进入 `libtorrent-rasterbar` 源码目录并编译安装到容器内 + ##Build 3rd libs 注释:进入 `libtorrent-rasterbar` 源码目录并编译安装到容器内 mkdir /project/3rd/libtorrent-rasterbar-2.0.9/build cd /project/3rd/libtorrent-rasterbar-2.0.9/build cmake -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=$PREFIX .. make -j$(nproc) make install - ##Build main 注释:进入 `qBittorrent` 源码目录并编译安装到容器内 + ##Build main 注释:进入 `qBittorrent` 源码目录并编译安装到容器内 mkdir /project/src/qBittorrent-release-4.6.7-szbt2/build cd /project/src/qBittorrent-release-4.6.7-szbt2/build cmake -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=$PREFIX .. make -j$(nproc) make install - ##Extract common res 注释: 将通用文件复制安装到容器对应目录内, 符合 `玲珑应用目录结构规范` + ##Extract common res 注释: 将通用文件复制安装到容器对应目录内, 符合 `玲珑应用目录结构规范` cp -rf /project/template_app/* ${PREFIX}/share/ ``` -在将此块构建规则补全后, 我们可以开始尝试通过自动化构建来将本地源码编译为二进制程序并导出玲珑应用安装包 `binary.layer` 了 -\* 由于此版配置文件不提供解压、删除功能, 因此每次重新构建前均需要将这些目录清空并重新解压 +在将此块构建规则补全后, 我们可以开始尝试通过自动化构建来将本地源码编译为二进制程序并导出玲珑应用安装包 `binary.layer` 了 \* 由于此版配置文件不提供解压、删除功能, 因此每次重新构建前均需要将这些目录清空并重新解压 ### 本地一站构建测试 在补全 `build` 模块后, 此时的 `linglong.yaml` 状态: -```yaml -# SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. -# -# SPDX-License-Identifier: LGPL-3.0-or-later +```yaml version: "2" package: @@ -195,23 +197,29 @@ ziggy@linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-local$ ll-builder build ``` 得益于在玲珑容器中的编译笔记, 此次构建很快就成功结束了, 我们执行以下指令来将容器导出为玲珑应用安装包 `binary.layer` : + ``` ziggy@linyaps23:/media/szbt/Data/ll-build/QT/qBittorrent-local$ ll-builder export --layer ``` ## 本地构建结果测试 + 在得到玲珑应用安装包后, 我在不同支持玲珑环境的主流发行版上尝试体验, 来确认通过玲珑容器构建的二进制程序是否存在通用性 ### deepin 23 -![deepin 23](image/3-test-1.png) + +![deepin 23](https://free.picui.cn/free/2025/11/24/69234b2085f30.png) ### openKylin 2.0 -![openKylin 2.0](image/3-test-2.png) + +![openKylin 2.0](https://free.picui.cn/free/2025/11/24/69234b206d8c6.png) ### Ubuntu 2404 -![Ubuntu 2404](image/3-test-3.png) + +![Ubuntu 2404](https://free.picui.cn/free/2025/11/24/69234b200d09f.png) ### OpenEuler 2403 -![OpenEuler 2403](image/3-test-4.png) -至此, 足以证明 `基于Qt5的开源应用--qBittorrent` 可以构建完成后, 在支持 `如意玲珑` 应用方案的第三方发行版中成功运行! \ No newline at end of file +![OpenEuler 2403](https://free.picui.cn/free/2025/11/24/69234b205dca1.png) + +至此, 足以证明 `基于Qt5的开源应用--qBittorrent` 可以构建完成后, 在支持 `如意玲珑` 应用方案的第三方发行版中成功运行! diff --git a/docs/pages/guide/lessons/test-with-toolchains.md b/docs/pages/guide/lessons/test-with-toolchains.md index 5d7544c5a..c5cc42ef7 100644 --- a/docs/pages/guide/lessons/test-with-toolchains.md +++ b/docs/pages/guide/lessons/test-with-toolchains.md @@ -1,9 +1,11 @@ # 玲珑应用兼容性测试进阶--玲珑应用自动化测试套件 + 大家可以发现, 在我们前面的玲珑应用编译之后, 都是通过手动安装软件包、启动应用来检验兼容性的 但是这里会衍生出一个问题: 随着需要测试的应用不断增加, 人工测试的方式是否显得相对低效率? 为此, 我向各位介绍如意玲珑社区中目前开放给各生态贡献者使用、学习的 `玲珑应用自动化测试套件 -- Next Linyaps Testing Toolchains` ## 项目介绍 + `Next Linyaps Testing Toolchains` 是一套shell脚本组成的玲珑应用测试工具链,旨在为玲珑应用测试带来更多便捷的方案 本项目是[linglong-automan](https://gitee.com/ziggy615/linglong-automan)的正统精神传承,并承诺永久开源 @@ -13,29 +15,32 @@ 2. 指定整理完成的玲珑文件存放目录后,开启流水化安装进程 -3. 指定资源存放目录和应用信息表格后,根据 `安装情况`、 `desktop文件存在状态` 、`窗口生成状态` 来模拟通过desktop文件启动应用,并对测试结果进行截图 -\* 当前代码部分功能依赖 `deepin 23` 系统组件,在其他发行版使用时需要重新适配 +3. 指定资源存放目录和应用信息表格后,根据 `安装情况`、 `desktop文件存在状态` 、`窗口生成状态` 来模拟通过desktop文件启动应用,并对测试结果进行截图 \* 当前代码部分功能依赖 `deepin 23` 系统组件,在其他发行版使用时需要重新适配 4. 对已安装的玲珑应用进行图标文件扫描, 判断当前应用icons目录及文件是否符合 `Freedesktop XDG` 规范并收集图标 5. 对已安装的玲珑应用进行批量卸载 ## 代码结构解析 + 进入套件仓库, 可以看到该套件根据功能/作用划分为了数个关键独立脚本, 大体为: 1. `linyaps-auto-optimize.sh`, 玲珑应用安装包 `binary.layer` 整理工具. 将某目录下所有 `binary.layer` 文件整理为符合测试套件的结构并产出两个表格用于记录玲珑应用id、版本号如: + ``` org.qbittorrent.qBittorrent/package/org.qbittorrent.qBittorrent_4.6.7.22_x86_64_binary.layer com.poki.apple-knight-golf.linyaps/package/com.poki.apple-knight-golf.linyaps_28.3.3.2_x86_64_binary.layer ``` ll-pkg-name.csv + ``` org.qbittorrent.qBittorrent com.poki.apple-knight-golf.linyaps ``` ll-pkg-version.csv + ``` 4.6.7.22 28.3.3.2 @@ -50,34 +55,41 @@ ll-pkg-version.csv 5. `linyaps-auto-uninstall-release.sh`, 玲珑应用批量卸载工具 ## Next Linyaps Testing Toolchains运用实操 + 在介绍完总体功能、代码逻辑后, 我们基于 `deepin 23` 演示如何通过 `玲珑应用自动化测试套件` 完成对前面课时产出的玲珑应用安装包 `binary.layer` 进行批量测试 ### 环境预备 + 在开始使用测试套件前,你需要确保当前环境满足以下条件 + 1. 本次实操中所使用的自助兼容性测试套件部分功能需要使用 `Linux x11` 窗口管理工具,因此在使用前需要安装以下软件包: + ``` wmctrl x11-utils ``` + 2. 测试套件通过x11窗口管理工具来判断应用窗口启动状态,因此需要确保你的系统是 `x11` 环境而不是 `Wayland` 环境 3. `wmctrl` 与 `xwininfo` 组件可以正常生效,可以通过`xwininfo`查询窗口信息 4. 由于 `deepin 23` 下提供了兼容性测试结果截图功能, 因此需要安装相关的软件包: + ``` -deepin-screen-recorder imagemagick-6.q16 +deepin-screen-recorder imagesmagick-6.q16 ``` -5. 手动启动一次 `deepin-screen-recorder`, 确系统截图保存路径为当前用户的~/Pictures/Screenshots中,且该目录为空 +5. 手动启动一次 `deepin-screen-recorder`, 确认系统截图保存路径为当前用户的~/Pictures/Screenshots中,且该目录为空 ### 启动测试功能 -1. 在上节实操课时中, 我们得到了 `qBittorrent--4.6.7` 的玲珑安装包 `org.qbittorrent.qBittorrent_4.6.7.22_x86_64_binary.layer`, 为了方便演示套件的批量支持能力, 我这里单独另找一个安装包 +1. 在上节实操课时中, 我们得到了 `qBittorrent-4.6.7` 的玲珑安装包 `org.qbittorrent.qBittorrent_4.6.7.22_x86_64_binary.layer`, 为了方便演示套件的批量支持能力, 我这里单独另找一个安装包 2. 现在我们有两款玲珑应用的安装包, 首先执行 `linyaps-auto-optimize.sh` 脚本来整理目录 -此脚本主要使用两个参数, 用于指向当前存放玲珑应用安装包 `binary.layer` 的目录 `$ll_origin_pool` 及 需要整理的终点目录 `$ll_stored_pool` + 此脚本主要使用两个参数, 用于指向当前存放玲珑应用安装包 `binary.layer` 的目录 `$ll_origin_pool` 及 需要整理的终点目录 `$ll_stored_pool` 3. 我在本地目录创建了两个独立目录 `ll-bins` `ll-pool` 用于指向 `$ll_origin_pool` 及 `$ll_stored_pool` - `ll-bins` 现在的目录结构: + `ll-bins` 现在的目录结构: + ``` ├── ll-bins │ ├── org.qbittorrent.qBittorrent_4.6.7.22_x86_64_binary.layer @@ -85,6 +97,7 @@ deepin-screen-recorder imagemagick-6.q16 ``` 4. 执行目录整理操作 + ```bash ziggy@linyaps23:/media/szbt/Data/linyaps-testing-toolchains$ ./linyaps-auto-optimize.sh ./ll-bins ./ll-pool ``` @@ -105,13 +118,15 @@ ll-pool/ 5. 目录整理后生成了 `ll-pkg-name.csv` `ll-pkg-version.csv` 两个用于记录应用信息的表格, 我们将两列内容合并为一个新表格 `ll-pkg-info.csv` : ll-pkg-info.csv + ``` org.qbittorrent.qBittorrent,4.6.7.22 com.poki.apple-knight-golf.linyaps,28.3.3.2 ``` 6. 根据此文件, 我们可以开始批量安装玲珑应用了 -此脚本主要使用一个参数, 用于指向当前整理完成的终点目录 `$ll_stored_pool`: + 此脚本主要使用一个参数, 用于指向当前整理完成的终点目录 `$ll_stored_pool`: + ```bash ziggy@linyaps23:/media/szbt/Data/linyaps-testing-toolchains$ linyaps-auto-install-release.sh ./ll-pool ``` @@ -119,29 +134,32 @@ ziggy@linyaps23:/media/szbt/Data/linyaps-testing-toolchains$ linyaps-auto-instal 7. 安装完玲珑应用后以及完成所有前置工作后, 我们可以开展测试流程了. 这里我们新建一个 `res` 目录, 用于存放图标、截图等测试结果资源 8. 在图形化界面打开终端, 执行截图脚本, 由于我们是 `deepin 23 x11` 环境并安装了必要的程序, 因此运行 `linyaps-auto-screenshot-deepin23.sh` -此脚本主要使用两个参数, 用于指向用于放置测试结果资源的目录 `$ll_res_pool` 以及 记录应用信息的表格 `$ll_pkgname_list`, 这里指的是我们上一环节得到的新表格 `ll-pkg-info.csv` : + 此脚本主要使用两个参数, 用于指向用于放置测试结果资源的目录 `$ll_res_pool` 以及 记录应用信息的表格 `$ll_pkgname_list`, 这里指的是我们上一环节得到的新表格 `ll-pkg-info.csv` : ```bash ziggy@linyaps23:/media/szbt/Data/linyaps-testing-toolchains$ ./linyaps-auto-screenshot-deepin23.sh ./res ./ll-pkg-info.csv ``` + \* 谨记, 此脚本必须在图形化终端下执行, 否则无法正常拉起进程 9. 在脚本启动后, 将该终端设置为最小化窗口保留在背景运行, 测试套件将会判断应用安装情况、desktop文件存在情况来 `启动` 和 `关闭` 应用窗口 -![test-1](image/5-test-1.png) -![test-2](image/5-test-2.png) +![5-test-1.png](https://free.picui.cn/free/2025/11/24/69234cbd2353f.png) + +![5-test-2.png](https://free.picui.cn/free/2025/11/24/69234cbd95b5d.png) 10. 在满足运行要求后, 套件将会模拟通过desktop文件启动程序并在约 30s 延时后对窗口进行判断, 检查应用运行后是否生成新窗口 -![test-3](image/5-test-3.png) -![test-4](image/5-test-4.png) +![5-test-3.png](https://free.picui.cn/free/2025/11/24/69234cbdbb020.png) + +![5-test-4.png](https://free.picui.cn/free/2025/11/24/69234cbdd6788.png) 11. 应用成功运行后, 将会依次完成截图、图标检测&获取操作 12. 在测试完成后, 可以在`res` 目录看到不同状态的表格及测试结果的材料, 由于这里的两款应用均通过了兼容性测试, 因此会在 `all-good.csv` 中记录 -否则会出现两种异常情况: -a. 超时未生成窗口的应用则会被写入`failed.csv`文件中,以判断为应用无法启动 -b. 玲珑应用目录内不包含图标文件,则会被写入`icons-missing.csv`文件中,不满足如意玲珑社区中对于图形化应用的规范 + 否则会出现两种异常情况: + a. 超时未生成窗口的应用则会被写入`failed.csv`文件中,以判断为应用无法启动 + b. 玲珑应用目录内不包含图标文件,则会被写入`icons-missing.csv`文件中,不满足如意玲珑社区中对于图形化应用的规范 ``` res/ @@ -163,6 +181,6 @@ res/ └── 3.png ``` -![test-5](image/5-test-5.png) +![5-test-5.png](https://free.picui.cn/free/2025/11/24/69234cbd6ca3d.png) -至此, 我们成功通过玲珑应用自动化测试套件, 完成了针对历史课时中产出的玲珑应用的兼容性测试 \ No newline at end of file +至此, 我们成功通过玲珑应用自动化测试套件, 完成了针对历史课时中产出的玲珑应用的兼容性测试 diff --git a/docs/pages/guide/linyaps-devel/README.md b/docs/pages/guide/linyaps-devel/README.md new file mode 100644 index 000000000..14688039c --- /dev/null +++ b/docs/pages/guide/linyaps-devel/README.md @@ -0,0 +1 @@ +存放开发者相关文档。(待补充) diff --git a/docs/pages/guide/ll-appimage-convert/convert-appimage.md b/docs/pages/guide/ll-appimage-convert/convert-appimage.md deleted file mode 100644 index 9dd5aaba3..000000000 --- a/docs/pages/guide/ll-appimage-convert/convert-appimage.md +++ /dev/null @@ -1,88 +0,0 @@ - - -# 转换appimage应用 - -转换 `appimage` 包格式( `.appimage` 或 `.AppImage` ) 到如意玲珑包格式( `.layer` 或 `.uab` ) - -查看`ll-appimage-convert convert` 命令的帮助信息: - -```bash -ll-appimage-convert convert --help -``` - -`ll-appimage-convert convert` 命令的帮助信息如下: - -```text -Usage: - ll-appimage-convert convert [flags] -Flags: - -b, --build build linglong - -d, --description string detailed description of the package - -f, --file string app package file, it not required option, - you can ignore this option - when you set --url option and --hash option - --hash string pkg hash value, it must be used with --url option - -h, --help help for convert - -i, --id string the unique name of the package - -l, --layer export layer file - -n, --name string the description the package - -u, --url string pkg url, it not required option,you can ignore this option when you set -f option - -v, --version string the version of the package -Global Flags: - -V, --verbose verbose output -``` - -`ll-appimage-convert convert` 命令会根据指定的应用名称( `--name` 选项)生成一个目录,该目录会作为如意玲珑项目的根目录,即 `linglong.yaml` 文件所在的位置。它支持两种转换方法: - -1. 你可以使用 `--file` 选项将指定的 `appimage` 文件转换为如意玲珑包文件; -2. 你可以使用 `--url` 和 `--hash` 选项将指定的 `appimage url` 和 `hash` 值转换为如意玲珑包文件; -3. 你可以使用 `--layer` 选项导出 `.layer` 格式文件,否则将默认导出 `.uab` 格式文件。 - -`Tips: 在如意玲珑版本大于1.5.7时,convert 默认导出 uab 包,如果想要导出 layer 文件,需要加上 --layer 参数` - -你可以使用 `--output` 选项生成如意玲珑项目的配置文件( `linglong.yaml` )和构建如意玲珑 `.layer` ( `.uab` )的脚本文件 -然后你可以执行该脚本去生成对应的如意玲珑包当你修改 `linglong.yaml` 配置文件后。如果不指定该选项,将直接导出对应的如意玲珑包。 - -以通过 `--url` 选项将 [BrainWaves](https://github.com/makebrainwaves/BrainWaves/releases/download/v0.15.1/BrainWaves-0.15.1.AppImage) `appimage` 文件转换为如意玲珑 `.layer` 文件为例,主要步骤如下: - -指定要转换的如意玲珑包的相关参数,稍等片刻后你就可以得到 `io.github.brainwaves_0.15.1.0_x86_64_runtime.layer` 或者 `io.github.brainwaves_0.15.1.0_x86_64_runtime.uab` 包文件。 - -```bash -ll-appimage-convert convert --url "https://github.com/makebrainwaves/BrainWaves/releases/download/v0.15.1/BrainWaves-0.15.1.AppImage" --hash "04fcfb9ccf5c0437cd3007922fdd7cd1d0a73883fd28e364b79661dbd25a4093" --name "io.github.brainwaves" --id "io.github.brainwaves" --version "0.15.1.0" --description "io.github.brainwaves" -b -``` - -以通过 `--file` 选项将 `BrainWaves-0.15.1.AppImage` 转换为如意玲珑 `.uab` 为例,主要步骤如下: - -```bash -ll-appimage-convert convert -f ~/Downloads/BrainWaves-0.15.1.AppImage --name "io.github.brainwaves" --id "io.github.brainwaves" --version "0.15.1.0" --description "io.github.brainwaves" -b -``` - -转换完成的目录结构如下: - -```text -├── io.github.brainwaves_x86_64_0.15.1.0_main.uab -├── linglong -└── linglong.yaml -``` - -以通过 `--file` 选项将 `BrainWaves-0.15.1.AppImage` 转换为如意玲珑 `.layer` 为例,主要步骤如下: - -```bash -ll-appimage-convert convert -f ~/Downloads/BrainWaves-0.15.1.AppImage --name "io.github.brainwaves" --id "io.github.brainwaves" --version "0.15.1.0" --description "io.github.brainwaves" -b --layer -``` - -转换完成的目录结构如下: - -```text -├── io.github.brainwaves_0.15.1.0_x86_64_binary.layer -├── io.github.brainwaves_0.15.1.0_x86_64_develop.layer -├── linglong -└── linglong.yaml -``` - -`.uab` 或 `.layer` 文件验证 -导出的`.uab`或者`.layer`需要安装后进行验证,安装 layer 文件和运行应用参考:[安装应用](../ll-cli/install.md) diff --git a/docs/pages/guide/ll-appimage-convert/introduction.md b/docs/pages/guide/ll-appimage-convert/introduction.md deleted file mode 100644 index 073c106ab..000000000 --- a/docs/pages/guide/ll-appimage-convert/introduction.md +++ /dev/null @@ -1,38 +0,0 @@ -# ll-appimage-convert简介 - -本工具由`linglong-pica`包提供。它提供将appimage包转换为如意玲珑包的能力,生成构建如意玲珑应用需要的linglong.yaml文件,并依赖 ll-builder 来实现应用构建和导出。 - -:::tip - -转换工具只是辅助工具,并不能保证被转换的应用一定能运行,可能软件本身依赖库的安装路径或其他配置路径与如意玲珑内部路径不统一,导致无法运行,需要使用 `ll-builder run --exec bash` 命令进入容器调试。 - -::: - -查看 `ll-appimage-convert` 帮助信息: - -```bash -ll-appimage-convert --help -``` - -`ll-appimage-convert` 命令的帮助信息如下: - -```bash -Convert the appimage to uab. For example: - Simple: - ll-appimage-convert convert -f xxx.appimage -i "io.github.demo" -n "io.github.demo" -v "1.0.0.0" -d "this is a appimage convert demo" -b - ll-appimage-convert help - -Usage: - ll-appimage-convert [command] - -Available Commands: - convert Convert appimage to uab - help Help about any command - -Flags: - -h, --help help for ll-appimage-convert - -V, --verbose verbose output - -v, --version version for ll-appimage-convert - -Use "ll-appimage-convert [command] --help" for more information about a command. -``` diff --git a/docs/pages/guide/ll-builder/build.md b/docs/pages/guide/ll-builder/build.md deleted file mode 100644 index d0cd77995..000000000 --- a/docs/pages/guide/ll-builder/build.md +++ /dev/null @@ -1,70 +0,0 @@ - - -# 构建应用 - -`ll-builder build`命令用来构建如意玲珑应用。 - -查看 `ll-builder build`命令的帮助信息: - -```bash -ll-builder build --help -``` - -`ll-builder build`命令的帮助信息如下: - -```text -构建如意玲珑项目 -用法: ll-builder build [选项] [命令...] - -Positionals: - COMMAND TEXT ... 进入容器执行命令而不是构建应用 - -Options: - -h,--help 打印帮助信息并退出 - --help-all 展开所有帮助 - --file FILE:FILE [./linglong.yaml] - linglong.yaml的文件路径 - --arch ARCH 设置构建架构 - --offline 仅使用本地文件。这意味着将设置--skip-fetch-source和--skip-pull-depend - --skip-fetch-source 跳过获取源代码 - --skip-pull-depend 跳过拉取依赖项 - --skip-run-container 跳过运行容器 - --skip-commit-output 跳过提交构建输出 - --skip-output-check 跳过输出检查 - --skip-strip-symbols 跳过剥离调试符号 -``` - -`ll-builder build` 命令可以通过以下两种方式运行: - -1. 项目根目录,即 `linglong.yaml` 文件所在目录。 -2. 使用 `--file` 参数指定 linglong.yaml 文件路径。 - -以如意玲珑项目 `org.deepin.demo`为例,构建如意玲珑应用主要步骤如下: - -进入到 `org.deepin.demo`项目工程目录: - -```bash -cd org.deepin.demo -``` - -执行 `ll-builder build`命令将开始构建如意玲珑应用: - -```bash -ll-builder build -``` - -构建完成后,构建内容将自动提交到本地 `ostree`缓存中。导出构建内容见 `ll-builder export`。 - -使用 `--exec`参数可在构建脚本执行前进入如意玲珑容器: - -```bash -ll-builder build --exec /bin/bash -``` - -进入容器后,可执行 `shell`命令,如 `ps`、`ls` 等。 - -如意玲珑应用 `debug`版本更多调试信息请参考:[DEBUG](../debug/debug.md)。 diff --git a/docs/pages/guide/ll-builder/create.md b/docs/pages/guide/ll-builder/create.md deleted file mode 100644 index b5a5ee145..000000000 --- a/docs/pages/guide/ll-builder/create.md +++ /dev/null @@ -1,144 +0,0 @@ - - -# 创建项目 - -`ll-builder create`命令用来创建如意玲珑项目。 - -查看 `ll-builder create`命令的帮助信息: - -```bash -ll-builder create --help -``` - -`ll-builder create`命令的帮助信息如下: - -```text -创建如意玲珑构建模板 -用法: ll-builder create [选项] 名称 - -Positionals: - NAME TEXT REQUIRED 项目名称 - -Options: - -h,--help 打印帮助信息并退出 - --help-all 展开所有帮助 -``` - -`ll-builder create`命令根据输入的项目名称在当前目录创建对应的文件夹,同时生成构建所需的 `linglong.yaml`模板文件。示例如下: - -```bash -ll-builder create org.deepin.demo -``` - -`ll-builder create org.deepin.demo`命令输出如下: - -```text -org.deepin.demo/ -└── linglong.yaml -``` - -## 编辑 linglong.yaml - -### linglong.yaml 文件语法的版本 - -```text -version: "1" -``` - -### 软件包元信息配置 - -```yaml -package: - id: org.deepin.demo - name: hello - version: 0.0.0.1 - kind: app - description: | - simple Qt demo. -``` - -### 基础环境 - -最小的根文件系统。 - -```yaml -base: org.deepin.base/23.1.0 -``` - -### 运行时 - -在根文件系统基础上添加 Qt 等基础环境。 - -```yaml -runtime: org.deepin.runtime.dtk/23.1.0 -``` - -### 启动命令 - -如意玲珑应用的启动命令。 - -```yaml -command: [echo, -e, hello world] -``` - -### 源码 - -使用 git 源码 - -```yaml -sources: - kind: git - url: "https://github.com/linuxdeepin/linglong-builder-demo.git" - version: master - commit: a3b89c3aa34c1aff8d7f823f0f4a87d5da8d4dc0 -``` - -### 构建 - -在容器内构建项目需要的命令。 - -```yaml -build: | - cd /project/linglong/sources/linglong-builder-demo.git - qmake demo.pro - make -j${JOBS} - make install -``` - -### 完整的 linglong.yaml 配置 - -`linglong.yaml`文件内容如下: - -```yaml -version: "1" - -package: - id: @ID@ - name: your name #set your application name - version: 0.0.0.1 #set your version - kind: app - description: | - your description #set a brief text to introduce your application. - -command: [echo, -e, hello world] #the commands that your application need to run. - -base: org.deepin.base/23.1.0 #set the base environment, this can be changed. - -#set the runtime environment if you need, a example of setting deepin runtime is as follows. -#runtime: -#org.deepin.runtime.dtk/23.1.0 - -#set the source if you need, a simple example of git is as follows. -#sources: -# - kind: git -# url: https://github.com/linuxdeepin/linglong-builder-demo.git -# version: master\n -# commit: a3b89c3aa34c1aff8d7f823f0f4a87d5da8d4dc0 - -build: | - echo 'hello' #some operation to build this project -``` diff --git a/docs/pages/guide/ll-builder/demo.md b/docs/pages/guide/ll-builder/demo.md deleted file mode 100644 index ec9e018c0..000000000 --- a/docs/pages/guide/ll-builder/demo.md +++ /dev/null @@ -1,117 +0,0 @@ - - -# demo示例 - -## 初始化如意玲珑工程 - -```bash -ll-builder create org.deepin.demo -``` - -## 编辑linglong.yaml - -### 填写软件包元信息 - -```yaml -package: - id: org.deepin.demo - name: deepin-demo - version: 0.0.1 - kind: app - description: | - simple Qt demo. -``` - -### 填写运行时信息 - -```yaml -runtime: - id: org.deepin.Runtime - version: 23.0.0 -``` - -### 填写源码信息 - -使用git源码 - -```yaml -source: - kind: git - url: "https://github.com/linuxdeepin/linglong-builder-demo.git" - commit: 24f78c8463d87ba12b0ac393ec56218240315a9 -``` - -### 选择构建模板 - -源码为qmake工程,填写build 类型为qmake(模板内容见qmake.yaml)。 - -```yaml -build: - kind: qmake -``` - -### 完整linglong.yaml - -```yaml -package: - id: org.deepin.demo - name: deepin-demo - version: 0.0.1 - kind: app - description: | - simple Qt demo. - -runtime: - id: org.deepin.runtime.dtk - version: 23.1.0 - -source: - kind: git - url: "https://github.com/linuxdeepin/linglong-builder-demo.git" - commit: 24f78c8463d87ba12b0ac393ec56218240315a9 - -build: - kind: qmake -``` - -## 开始构建 - -在如意玲珑工程根目录下执行build子命令: - -```bash -ll-builder build -``` - -## 运行应用 - -构建成功后,在如意玲珑工程目录下执行run子命令,可以直接运行应用而无需安装。 - -```bash -ll-builder run -``` - -## 查看构建内容 - -在如意玲珑工程根目录下执行export子命令,检出构建内容。 - -```bash -ll-builder export --layer -``` - -目录结构如下: - -```text -org.deepin.demo -├── entries -│ └── applications -│ └── demo.desktop -├── files -│ └── bin -│ └── demo -├── info.json -└── linglong.yaml -``` diff --git a/docs/pages/guide/ll-builder/export.md b/docs/pages/guide/ll-builder/export.md deleted file mode 100644 index 7ca0d0e3b..000000000 --- a/docs/pages/guide/ll-builder/export.md +++ /dev/null @@ -1,88 +0,0 @@ - - -# 导出 - -`ll-builder export` 命令用于将本地构建缓存中的应用导出为 UAB (Universal Application Bundle) 文件。这是推荐的格式。也可以导出为已弃用的 linglong layer 文件格式。 - -## 基本用法 - -```bash -ll-builder export [OPTIONS] -``` - -要查看所有可用选项及其详细说明,请运行: - -```bash -ll-builder export --help -``` - -## 主要选项 - -* `-f, --file FILE`: 指定 `linglong.yaml` 配置文件的路径 (默认: `./linglong.yaml`),`linglong.yaml` 文件所在的目录为项目的工作目录。 -* `-o, --output FILE`: 指定输出文件的路径。对于 UAB,这通常是 `.uab` 文件的完整路径或文件名。对于 layer 这是输出文件名的前缀。 -* `-z, --compressor X`: 指定压缩算法。支持 `lz4` (UAB 默认), `lzma` (layer 默认), `zstd`。 -* `--icon FILE`: 为导出的 UAB 文件指定图标 (仅 UAB 模式,与 `--layer` 互斥)。 -* `--loader FILE`: 为导出的 UAB 文件指定自定义加载器 (仅 UAB 模式,与 `--layer` 互斥)。 -* `--layer`: **(已弃用)** 导出为 layer 文件格式,而不是 UAB (与 `--icon`, `--loader` 互斥)。 -* `--no-develop`: 在导出 layer 文件时,不包含 `develop` 模块。 - -## 导出 UAB 文件 (推荐) - -UAB (Universal Application Bundle) 文件一种自包含、可离线分发的文件格式,包含了应用运行所需的内容。这是推荐的导出格式。 - -`ll-builder export` 命令执行后会在项目工作目录(或使用 `-o` 指定的路径)生成一个 `.uab` 文件,例如 `__.uab`。 - -可以使用其他选项自定义 UAB 导出: - -```bash -# 导出 UAB 文件并指定图标和输出路径 -ll-builder export --icon assets/app.png -o dist/my-app-installer.uab - -# 导出 UAB 文件并使用 zstd 压缩 -ll-builder export -z zstd -o my-app-zstd.uab - -# 导出 UAB 文件并指定自定义加载器 -ll-builder export --loader /path/to/custom/loader -o my-app-custom-loader.uab -``` - -## 导出 layer 文件 (已弃用) - -**注意:导出 layer 文件格式已被弃用,推荐使用 UAB 格式。** - -通过命令 `ll-builder export --layer` 导出 layer 文件,其他示例: - -```bash -# 导出 layer 格式,且不包含 develop 模块 -ll-builder export --layer --no-develop - -# 导出 layer 格式,并指定输出文件前缀 -ll-builder export --layer -o my-app -# (会生成 my-app_binary.layer 和 my-app_develop.layer) -``` - -导出 layer 文件会生成以下文件: - -* `*_binary.layer`: 包含应用运行所需的基本文件。 -* `*_develop.layer`: (可选)包含用于开发和调试的文件。如果使用了 `--no-develop` 选项,则不会生成此文件。 - -## 进阶说明 - -UAB 是一个静态链接的 ELF 可执行文件,其目标是可以在任意 Linux 发行版上运行。默认情况下导出 UAB 文件属于 bundle 模式,而使用参数 `--loader` 导出 UAB 文件属于 custom loader 模式。 - -### Bundle 模式 - -bundle 模式主要用于分发,并尽可能的支持自运行功能。通常用户通过 `ll-cli install ` 安装离线分发的应用,并会自动补全应用所需的运行环境。安装后的 UAB 应用,使用方法和直接从仓库安装的应用一样。 - -bundle 模式在导出时,会尝试自动解析应用的依赖,并导出必要的内容(尽可能保证)。如果给 bundle 模式的 UAB 文件添加可执行权限并运行,应用不会被安装而是直接运行。此时应用仍然在独立的容器内运行,但是缺少的部分运行环境会直接使用宿主机的环境,因此无法保证应用一定能运行。 - -如果应用开发者需要依赖自运行功能,请保证应用带上必要的运行时依赖。 - -### Bustom Loader 模式 - -custom loader 模式导出的 UAB 文件仅包含应用数据,以及传入的 custom loader。UAB 文件在解压挂载后将控制器交给 custom loader,此时 loader 不在容器环境内。环境变量 `LINGLONG_UAB_APPROOT` 保存了应用所在目录,custom loader 负责初始化应用程序所需要的运行环境,比如库路径的搜索。 - -此模式下应用程序需要保证其本身在目标系统的兼容性。推荐做法为在想要支持的最低版本的系统上构建出应用,并带上所有依赖项。 diff --git a/docs/pages/guide/ll-builder/introduction.md b/docs/pages/guide/ll-builder/introduction.md deleted file mode 100644 index 6c43faebd..000000000 --- a/docs/pages/guide/ll-builder/introduction.md +++ /dev/null @@ -1,54 +0,0 @@ - - -# ll-builder简介 - -`ll-builder`是为应用开发者提供的一款构建如意玲珑应用工具。 - -主要功能如下: - -- 支持在独立容器内构建。 - - - -- 提供 DTK 开发套件。 - - - -查看 `ll-builder`命令的帮助信息: - -```bash -ll-builder --help -``` - -ll-builder 命令的帮助信息如下: - -```text -如意玲珑构建工具 CLI -一个用于构建如意玲珑应用的命令行工具 - -用法: ll-builder [选项] [子命令] - -Options: - -h,--help 打印帮助信息并退出 - --help-all 展开所有帮助 - --version 显示版本 - -Subcommands: - create 创建如意玲珑构建模板 - build 构建如意玲珑项目 - run 运行构建好的应用程序 - list 列出已构建的应用程序 - remove 删除已构建的应用程序 - export 导出如意玲珑layer或uab - push 推送如意玲珑应用到远程仓库 - import 导入如意玲珑layer文件到构建仓库 - extract 将如意玲珑layer文件解压到目录 - repo 显示和管理仓库 - -如果在使用过程中遇到任何问题, -您可以通过此项目向如意玲珑项目团队报告错误:https://github.com/OpenAtom-Linyaps/linyaps/issues -``` diff --git a/docs/pages/guide/ll-builder/push.md b/docs/pages/guide/ll-builder/push.md deleted file mode 100644 index 5a97d2ef3..000000000 --- a/docs/pages/guide/ll-builder/push.md +++ /dev/null @@ -1,37 +0,0 @@ - - -# 推送uab到远程仓库 - -`ll-builder push`命令用来将如意玲珑软件包推送至如意玲珑远程仓库。 - -查看`ll-builder push`命令的帮助信息: - -```bash -ll-builder push --help -``` - -`ll-builder push`命令的帮助信息如下: - -```text -推送如意玲珑应用到远程仓库 -用法: ll-builder push [选项] - -Options: - -h,--help 打印帮助信息并退出 - --help-all 展开所有帮助 - --file FILE:FILE [./linglong.yaml] - linglong.yaml的文件路径 - --repo-url URL 远程仓库URL - --repo-name NAME 远程仓库名 - --module TEXT 推送单个模块 -``` - -`ll-builder push`命令根据输入的文件路径,读取`bundle`格式软件包内容,将本地软件数据及`bundle`格式软件包传输到服务端。 - -```bash -ll-builder push -``` diff --git a/docs/pages/guide/ll-builder/run.md b/docs/pages/guide/ll-builder/run.md deleted file mode 100644 index f0e3a7b23..000000000 --- a/docs/pages/guide/ll-builder/run.md +++ /dev/null @@ -1,54 +0,0 @@ - - -# 运行编译后的应用 - -`ll-builder run`命令可以运行编译后的可执行程序。 - -查看 `ll-builder run`命令的帮助信息: - -```bash -ll-builder run --help -``` - -`ll-builder run`命令的帮助信息如下: - -```text -运行构建好的应用程序 -用法: ll-builder run [选项] [命令...] - -Positionals: - COMMAND TEXT ... 进入容器执行命令而不是运行应用 - -Options: - -h,--help 打印帮助信息并退出 - --help-all 展开所有帮助 - --file FILE:FILE [./linglong.yaml] - linglong.yaml的文件路径 - --offline 仅使用本地文件 - --modules modules ... 运行指定模块。例如: --modules binary,develop - --debug 在调试模式下运行(启用开发模块) -``` - -`ll-builder run`命令根据配置文件读取该程序相关的运行环境信息,构造一个容器环境,并在容器中执行该程序而无需安装。 - -```bash -ll-builder run -``` - -`ll-builder run`运行成功输出如下: - -```bash -hello world -``` - -为了便于调试,使用额外的 `--exec /bin/bash`参数可替换进入容器后默认执行的程序,如: - -```bash -ll-builder run --exec /bin/bash -``` - -使用该选项,`ll-builder`创建容器后将进入 `bash`终端,可在容器内执行其他操作。 diff --git a/docs/pages/guide/ll-cli/content.md b/docs/pages/guide/ll-cli/content.md deleted file mode 100644 index 608aca909..000000000 --- a/docs/pages/guide/ll-cli/content.md +++ /dev/null @@ -1,43 +0,0 @@ - - -# 显示应用导出文件 - -使用 `ll-cli content` 显示应用导出文件。 - -查看`ll-cli content`命令的帮助信息: - -```bash -ll-cli content --help -``` - -`ll-cli content`命令的帮助信息如下: - -```text -显示已安装应用导出的文件 -用法: ll-cli content [选项] 应用 - -Positionals: - APP TEXT REQUIRED 指定已安装应用程序名 - -Options: - -h,--help 打印帮助信息并退出 - --help-all 展开所有帮助 - -如果在使用过程中遇到任何问题, -您可以通过此项目向如意玲珑项目团队报告错误:https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -使用 `ll-cli content org.dde.calendar` 显示日历应用的导出的文件。 - -`ll-cli content org.dde.calendar`输出如下: - -```text -/var/lib/linglong/entries/share/applications -/var/lib/linglong/entries/share/applications/dde-calendar.desktop -/var/lib/linglong/entries/share/metainfo -/var/lib/linglong/entries/share/metainfo/org.deepin.calendar.metainfo.xml -``` diff --git a/docs/pages/guide/ll-cli/info.md b/docs/pages/guide/ll-cli/info.md deleted file mode 100644 index 6469e0dc6..000000000 --- a/docs/pages/guide/ll-cli/info.md +++ /dev/null @@ -1,58 +0,0 @@ - - -# 显示应用信息 - -使用`ll-cli info`显示已安装的应用程序或运行时的信息。 - -查看`ll-cli info`命令的帮助信息: - -```bash -ll-cli info --help -``` - -`ll-cli info`命令的帮助信息如下: - -```text -显示已安装的应用程序或运行时的信息 -用法: ll-cli info [选项] 应用 - -Positionals: - APP TEXT REQUIRED 指定应用程序名,也可以是如意玲珑.layer文件 - -Options: - -h,--help 打印帮助信息并退出 - --help-all 展开所有帮助 - -如果在使用过程中遇到任何问题, -您可以通过此项目向如意玲珑项目团队报告错误:https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -使用 `ll-cli info`显示已安装的应用程序或运行时的信息。 - -`ll-cli info org.dde.calendar`输出如下: - -```text -{ - "arch": [ - "x86_64" - ], - "base": "main:org.deepin.base/23.1.0/x86_64", - "channel": "main", - "command": [ - "dde-calendar" - ], - "description": "calendar for deepin os.\n", - "id": "org.dde.calendar", - "kind": "app", - "module": "binary", - "name": "dde-calendar", - "runtime": "main:org.deepin.runtime.dtk/23.1.0/x86_64", - "schema_version": "1.0", - "size": 13483249, - "version": "5.14.5.1" -} -``` diff --git a/docs/pages/guide/ll-cli/install.md b/docs/pages/guide/ll-cli/install.md deleted file mode 100644 index eb44e10d2..000000000 --- a/docs/pages/guide/ll-cli/install.md +++ /dev/null @@ -1,103 +0,0 @@ - - -# 安装应用 - -`ll-cli install`命令用来安装如意玲珑应用。 - -查看 `ll-cli install`命令的帮助信息: - -```bash -ll-cli install --help -``` - -`ll-cli install`命令的帮助信息如下: - -```text -安装应用程序或运行时 -用法: ll-cli install [选项] 应用程序 - -示例: -# 通过应用名安装应用程序 -ll-cli install org.deepin.demo -# 通过如意玲珑.layer文件安装应用程序 -ll-cli install demo_0.0.0.1_x86_64_binary.layer -# 通过通过如意玲珑.uab文件安装应用程序 -ll-cli install demo_x86_64_0.0.0.1_main.uab -# 安装应用的指定模块 -ll-cli install org.deepin.demo --module=binary -# 安装应用的指定版本 -ll-cli install org.deepin.demo/0.0.0.1 -# 通过特定标识安装应用程序 -ll-cli install stable:org.deepin.demo/0.0.0.1/x86_64 - - -Positionals: - APP TEXT REQUIRED 指定应用名,也可以是 .uab 或 .layer 文件 - -Options: - -h,--help 打印帮助信息并退出 - --help-all 展开所有帮助 - --module MODULE 安装指定模块 - --force 强制安装指定版本的应用程序 - -y 自动对所有问题回答是 - -如果在使用过程中遇到任何问题, -您可以通过此项目向如意玲珑项目团队报告错误:https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -运行 `ll-cli install`命令安装如意玲珑应用: - -```bash -ll-cli install -``` - -`ll-cli install`命令需要输入应用完整的 `appid`,若仓库有多个版本则会默认安装最高版本。 - -安装指定版本需在 `appid`后附加对应版本号: - -```bash -ll-cli install -``` - -`ll-cli install org.deepin.calculator`输出如下: - -```text -Install main:org.deepin.calculator/5.7.21.4/x86_64 success:100% -``` - -应用安装完成后,客户端会显示安装结果信息。 - -我们在使用 `ll-builder export` 命令导出的 layer 或者 uab 文件,可以使用 `ll-cli install` 进行安装。 - -`.layer` 文件 - -```bash -ll-cli install ./com.baidu.baidunetdisk_4.17.7.0_x86_64_runtime.layer -``` - -`.uab` 文件 -uab文件有以下两种安装方式 - -- 通过 `ll-cli install` 进行安装 - -```bash -ll-cli install com.baidu.baidunetdisk_x86_64_4.17.7.0_main.uab -``` - -- 通过直接运行`.uab`的方式进行安装 - -```bash -./com.baidu.baidunetdisk_x86_64_4.17.7.0_main.uab -``` - -可以使用 `ll-cli list | grep com.baidu.baidunetdisk` 命令来查看是否安装成功。 - -使用下面的命令运行应用。 - -```bash -ll-cli run com.baidu.baidunetdisk -``` diff --git a/docs/pages/guide/ll-cli/introduction.md b/docs/pages/guide/ll-cli/introduction.md deleted file mode 100644 index bfbfcca2d..000000000 --- a/docs/pages/guide/ll-cli/introduction.md +++ /dev/null @@ -1,55 +0,0 @@ - - -# ll-cli简介 - -`ll-cli`是一个包管理器前端,用于管理如意玲珑应用的安装、卸载、查看、启动、关闭、调试、更新等操作。 - -查看 `ll-cli`命令的帮助信息: - -```bash -ll-cli --help -``` - -`ll-cli`命令的帮助信息如下: - -```text -如意玲珑 CLI -一个用于运行应用程序和管理应用程序和运行时的命令行工具 - -用法: ll-cli [选项] [子命令] - -Options: - -h,--help 打印帮助信息并退出 - --help-all 展开所有帮助 - --version 显示版本 - --json 使用json格式输出结果 - - -管理正在运行的应用程序: - run 运行应用程序 - ps 列出正在运行的应用程序 - enter 进入应用程序正在运行的命名空间 - kill 停止运行的应用程序 - prune 移除未使用的最小系统或运行时 - -管理已安装的应用程序和运行时: - install 安装应用程序或运行时 - uninstall 卸载应用程序或运行时 - upgrade 升级应用程序或运行时 - list 列出已安装的应用程序或运行时 - info 显示已安装的应用程序或运行时的信息 - content 显示已安装应用导出的文件 - -查找应用程序和运行时: - search 从远程仓库中搜索包含指定关键词的应用程序/运行时 - -管理仓库: - repo 显示或修改当前使用的仓库信息 - -如果在使用过程中遇到任何问题, -您可以通过此项目向如意玲珑项目团队报告错误:https://github.com/OpenAtom-Linyaps/linyaps/issues -``` diff --git a/docs/pages/guide/ll-cli/kill.md b/docs/pages/guide/ll-cli/kill.md deleted file mode 100644 index 702662ba8..000000000 --- a/docs/pages/guide/ll-cli/kill.md +++ /dev/null @@ -1,38 +0,0 @@ - - -# 强制退出应用 - -`ll-cli kill`命令可以强制退出正在运行的玲珑应用。 - -查看`ll-cli kill`命令的帮助信息: - -```bash -ll-cli kill --help -``` - -`ll-cli kill` 命令的帮助信息如下: - -```text -停止运行的应用程序 -用法: ll-cli kill [选项] 应用 - -Positionals: - APP TEXT REQUIRED 指定正在运行的应用程序名 - -Options: - -h,--help 打印帮助信息并退出 - --help-all 展开所有帮助 - -如果在使用过程中遇到任何问题, -您可以通过此项目向如意玲珑项目团队报告错误:https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -使用 `ll-cli kill` 命令可以强制退出正在运行的玲珑应用: - -```bash -ll-cli kill org.deepin.calculator -``` diff --git a/docs/pages/guide/ll-cli/prune.md b/docs/pages/guide/ll-cli/prune.md deleted file mode 100644 index 98e802e0a..000000000 --- a/docs/pages/guide/ll-cli/prune.md +++ /dev/null @@ -1,43 +0,0 @@ - - -# 移除未使用的最小系统或运行时 - -使用`ll-cli prune`移除未使用的最小系统或运行时。 - -查看`ll-cli prune`命令的帮助信息: - -```bash -ll-cli prune --help -``` - -`ll-cli prune`命令的帮助信息如下: - -```text -移除未使用的最小系统或运行时 -用法: ll-cli prune [选项] - -Options: - -h,--help 打印帮助信息并退出 - --help-all 展开所有帮助 - -如果在使用过程中遇到任何问题, -您可以通过此项目向如意玲珑项目团队报告错误:https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -使用`ll-cli prune`移除未使用的最小系统或运行时。 - -`ll-cli prune`输出如下: - -```text -Unused base or runtime: -main:org.deepin.Runtime/23.0.1.2/x86_64 -main:org.deepin.foundation/20.0.0.27/x86_64 -main:org.deepin.Runtime/23.0.1.0/x86_64 -main:org.deepin.foundation/23.0.0.27/x86_64 -main:org.deepin.Runtime/20.0.0.8/x86_64 -5 unused base or runtime have been removed. -``` diff --git a/docs/pages/guide/ll-cli/ps.md b/docs/pages/guide/ll-cli/ps.md deleted file mode 100644 index c76a62b5e..000000000 --- a/docs/pages/guide/ll-cli/ps.md +++ /dev/null @@ -1,42 +0,0 @@ - - -# 查看运行中的应用 - -`ll-cli ps`命令可以查看正在运行的如意玲珑应用。 - -查看`ll-cli ps`命令的帮助信息: - -```bash -ll-cli ps --help -``` - -`ll-cli ps` 命令的帮助信息如下: - -```text -列出正在运行的应用程序 -用法: ll-cli ps [选项] - -Options: - -h,--help 打印帮助信息并退出 - --help-all 展开所有帮助 - -如果在使用过程中遇到任何问题, -您可以通过此项目向如意玲珑项目团队报告错误:https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -查看正在运行的应用,运行`ll-cli ps`命令: - -```bash -ll-cli ps -``` - -`ll-cli ps`命令输出如下: - -```text -应用 容器ID 进程ID -org.dde.calendar 4e3407a8a052 1279610 -``` diff --git a/docs/pages/guide/ll-cli/run.md b/docs/pages/guide/ll-cli/run.md deleted file mode 100644 index ed832e74e..000000000 --- a/docs/pages/guide/ll-cli/run.md +++ /dev/null @@ -1,67 +0,0 @@ - - -# 运行应用 - -`ll-cli run`命令可以启动一个如意玲珑应用。 - -查看 `ll-cli run`命令的帮助信息: - -```bash -ll-cli run --help -``` - -`ll-cli run`命令的帮助信息如下: - -```text -运行应用程序 -用法: ll-cli run [选项] 应用程序 [命令...] - -示例: -# 通过应用名运行应用程序 -ll-cli run org.deepin.demo -# 在容器中执行命令而不是运行应用程序 -ll-cli run org.deepin.demo bash -ll-cli run org.deepin.demo -- bash -ll-cli run org.deepin.demo -- bash -x /path/to/bash/script - -Positionals: - APP TEXT REQUIRED 指定应用程序名 - COMMAND TEXT ... 在正在运行的沙盒中运行命令 - -Options: - -h,--help 打印帮助信息并退出 - --help-all 展开所有帮助 - --file FILES:FILE ... 将文件传递到沙盒中运行的应用程序 - --url URLS ... 将URL传递到沙盒中运行的应用程序 - -如果在使用过程中遇到任何问题, -您可以通过此项目向如意玲珑项目团队报告错误:https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -当应用被正常安装后,使用 `ll-cli run`命令即可启动: - -```bash -ll-cli run org.deepin.calculator -``` - -使用 `ll-cli run`命令可以进入指定程序容器环境: - -```bash -ll-cli run org.deepin.calculator --exec /bin/bash -``` - -进入后可执行 `shell` 命令,如 `gdb`、`strace`、`ls`、`find`等。 - -由于如意玲珑应用都是在容器内运行,无法通过常规的方式直接调试,需要在容器内运行调试工具,如 `gdb`: - -```bash -gdb /opt/apps/org.deepin.calculator/files/bin/deepin-calculator -``` - -该路径为容器内应用程序的绝对路径。 - -如意玲珑应用 `release`版本更多调试信息请参考:[常见运行问题](../debug/faq.md)。 diff --git a/docs/pages/guide/ll-cli/search.md b/docs/pages/guide/ll-cli/search.md deleted file mode 100644 index 60b6dc604..000000000 --- a/docs/pages/guide/ll-cli/search.md +++ /dev/null @@ -1,67 +0,0 @@ - - -# 从远程仓库查询应用 - -`ll-cli search`命令可以查询如意玲珑远程仓库中的应用信息。 - -查看 `ll-cli search`命令的帮助信息: - -```bash -ll-cli search --help -``` - -`ll-cli search`命令的帮助信息如下: - -```text -从远程仓库中搜索包含指定关键词的应用程序/运行时 -用法: ll-cli search [选项] 关键词 - -示例: -# 通过应用名从远程仓库搜索应用程序 -ll-cli search org.deepin.demo -# 从远程仓库里搜索指定类型的应用程序 -ll-cli search org.deepin.base --type=runtime -# 从远程仓库搜索所有应用程序 -ll-cli search . -# 从远程仓库搜索所有运行时 -ll-cli search . --type=runtime - -Positionals: - KEYWORDS TEXT REQUIRED 指定搜索关键词 - -Options: - -h,--help 打印帮助信息并退出 - --help-all 展开所有帮助 - --type TYPE [app] 使用指定类型过滤结果。“runtime”、“app”或“all”之一 - --dev 搜索结果中包括应用调试包 - -如果在使用过程中遇到任何问题, -您可以通过此项目向如意玲珑项目团队报告错误:https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -通过 `ll-cli search`命令可以从远程 repo 中查找应用程序信息: - -```bash -ll-cli search calculator -``` - -该命令将返回包含 calculator关键词的所有应用程序信息,包含完整的 `appid`、应用程序名称、版本、平台及应用描述信息。 - -`ll-cli search calculator`输出如下: - -```text -appId name version arch channel module description -org.deepin.calculator deepin-calculator 5.5.23 x86_64 linglong runtime Calculator for UOS -org.deepin.calculator deepin-calculator 5.7.1 x86_64 linglong runtime Calculator for UOS - -``` - -如果需要查找 Base 和 Runtime 可以使用以下命令: - -```bash -ll-cli search . --type=runtime -``` diff --git a/docs/pages/guide/ll-cli/uninstall.md b/docs/pages/guide/ll-cli/uninstall.md deleted file mode 100644 index 130902314..000000000 --- a/docs/pages/guide/ll-cli/uninstall.md +++ /dev/null @@ -1,48 +0,0 @@ - - -# 卸载应用 - -`ll-cli uninstall`命令可以卸载玲珑应用。 - -查看`ll-cli uninstall`命令的帮助信息: - -```bash -ll-cli uninstall --help -``` - -`ll-cli uninstall`命令的帮助信息如下: - -```text -卸载应用程序或运行时 -用法: ll-cli uninstall [选项] 应用 - -Positionals: - APP TEXT REQUIRED 指定应用程序名 - -Options: - -h,--help 打印帮助信息并退出 - --help-all 展开所有帮助 - --module MODULE 卸载指定模块 - - -如果在使用过程中遇到任何问题, -您可以通过此项目向如意玲珑项目团队报告错误:https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -使用`ll-cli uninstall`命令卸载玲珑应用: - -```bash -ll-cli uninstall -``` - -`ll-cli uninstall org.deepin.calculator`命令输出如下: - -```text -Uninstall main:org.deepin.calculator/5.7.21.4/x86_64 success:100% -``` - -该命令执行成功后,该玲珑应用将从系统中被卸载掉。 diff --git a/docs/pages/guide/ll-cli/upgrade.md b/docs/pages/guide/ll-cli/upgrade.md deleted file mode 100644 index dad8c1aaf..000000000 --- a/docs/pages/guide/ll-cli/upgrade.md +++ /dev/null @@ -1,55 +0,0 @@ - - -# 更新应用 - -`ll-cli upgrade`命令可以更新玲珑应用。 - -查看 `ll-cli upgrade`命令的帮助信息: - -```bash -ll-cli upgrade --help -``` - -`ll-cli upgrade`命令的帮助信息如下: - -```text -升级应用程序或运行时 -用法: ll-cli upgrade [选项] [应用] - -Positionals: - APP TEXT 指定应用程序名。如果未指定,将升级所有可升级的应用程序 - -Options: - -h,--help 打印帮助信息并退出 - --help-all 展开所有帮助 - -如果在使用过程中遇到任何问题, -您可以通过此项目向如意玲珑项目团队报告错误:https://github.com/OpenAtom-Linyaps/linyaps/issues -``` - -使用 `ll-cli upgrade`将所有已安装的应用程序升级到最新版本 - -`ll-cli upgrade`命令输出如下: - -```text -Upgrade main:org.dde.calendar/5.14.5.0/x86_64 to main:org.dde.calendar/5.14.5.1/x86_64 success:100% -Upgrade main:org.deepin.mail/6.4.10.0/x86_64 to main:org.deepin.mail/6.4.10.1/x86_64 success:100% -Please restart the application after saving the data to experience the new version. -``` - -使用 `ll-cli upgrade org.deepin.calculator`将org.deepin.calculator应用程序升级到远程存储库中的最新版本,例如: - -```bash -ll-cli upgrade org.deepin.calculator -``` - -`ll-cli upgrade org.deepin.calculator`命令输出如下: - -```text -Upgrade main:org.deepin.calculator/5.7.21.3/x86_64 to main:org.deepin.calculator/5.7.21.4/x86_64 success:100% -Please restart the application after saving the data to experience the new version. -``` diff --git a/docs/pages/guide/ll-flatpak-convert/convert-flatpak.md b/docs/pages/guide/ll-flatpak-convert/convert-flatpak.md deleted file mode 100644 index 2daef5a58..000000000 --- a/docs/pages/guide/ll-flatpak-convert/convert-flatpak.md +++ /dev/null @@ -1,77 +0,0 @@ -## 转换 Flatpak 应用 - -`ll-pica-flatpak convert` 命令用来将 Flatpak 应用转换为玲珑应用。 - -查看 `ll-pica-flatpak convert` 命令的帮助信息: - -```bash -ll-pica-flatpak --help -``` - -`ll-pica-flatpak convert` 命令的帮助信息如下: - -```bash -Convert the flatpak to uab. For example: -Simple: - ll-pica-flatpak convert [flatpak name] --build - -Usage: - ll-pica-flatpak [command] - -Available Commands: - convert Convert flatpak to uab - help Help about any command - -Flags: - -h, --help help for ll-pica-flatpak -``` - -转换应用 - -```bash -ll-pica-flatpak convert org.videolan.VLC --build -``` - -:::tip - -org.videolan.VLC 为 Flatpak 的软件包名。可通过 https://flathub.org/ => 点击应用 => 点击 Install 下拉菜单=> 查看软件包名。 - -ll-pica-flatpak 使用 ostree 命令拉取 org.videolan.VLC 应用数据,根据 metadata 中定义的 runtime 对应生成玲珑的 base 环境。 - -::: - -转换应用默认生成,uab 文件。转换出 layer 文件,需要添加 --layer 参数。 - -```bash -ll-pica-flatpak convert org.videolan.VLC --build --layer -``` - -如果需要指定生成玲珑应用的版本,需要添加 --version 参数。 - -```bash -ll-pica-flatpak convert org.videolan.VLC --version "1.0.0.0" --build --layer -``` - -如果需要指定玲珑应用的 base 环境和版本,需要添加 --base 和 --base-version 参数。 - -```bash -ll-pica-flatpak convert org.videolan.VLC --base "org.deepin.base.flatpak.kde" --base-version "6.7.0.2" --build --layer -``` - -构建产物如下: - -```bash -├── org.videolan.VLC -│ ├── org.videolan.VLC_1.0.0.0_x86_64_develop.layer -│ ├── org.videolan.VLC_1.0.0.0_x86_64_binary.layer - or -│ ├── org.videolan.VLC_x86_64_1.0.0.0_main.uab -``` - -玲珑应用的产物 : - -layer 文件,layer 文件分为 binary 和 develop, binary 包含应用的运行环境,develop 在 binary 的基础上保留调试环境。 - -uab 文件,是玲珑软件包使用的离线分发格式,并不适合可以正常连接到玲珑仓库的系统使用,应当使用玲珑软件仓库提供的增量传输方案以减少网络传输体积。 - -安装 layer 文件和运行应用参考:[安装应用](../ll-cli/install.md) diff --git a/docs/pages/guide/ll-flatpak-convert/introduction.md b/docs/pages/guide/ll-flatpak-convert/introduction.md deleted file mode 100644 index a58c3ca38..000000000 --- a/docs/pages/guide/ll-flatpak-convert/introduction.md +++ /dev/null @@ -1,33 +0,0 @@ -# ll-pica-flatpak简介 - -本工具由`linglong-pica`提供。它提供将flatpak包转换为玲珑包的能力,生成构建玲珑应用需要的linglong.yaml文件,并依赖 ll-builder来实现应用构建和导出。 - -:::tip - -转换工具只是辅助工具,并不能保证被转换的应用一定能运行,可能软件本身依赖库的安装路径或其他配置路径与玲珑内部路径不统一,导致无法运行,需要使用 `ll-builder run --exec bash` 命令进入容器调试。 - -::: - -查看 `ll-pica-flatpak` 帮助信息: - -```bash -ll-pica-flatpak --help -``` - -`ll-pica-flatpak` 命令的帮助信息如下: - -```bash -Convert the flatpak to uab. For example: -Simple: - ll-pica-flatpak convert [flatpak name] --build - -Usage: - ll-pica [command] - -Available Commands: - convert Convert flatpak to uab - help Help about any command - -Flags: - -h, --help help for ll-pica-flatpak -``` diff --git a/docs/pages/guide/ll-pica/adep.md b/docs/pages/guide/ll-pica/adep.md deleted file mode 100644 index f91b74421..000000000 --- a/docs/pages/guide/ll-pica/adep.md +++ /dev/null @@ -1,34 +0,0 @@ -## 添加依赖 - -玲珑应用可能缺少包依赖,目前可以通过在 linglong.yaml 文件添加对应的包依赖。 - -`ll-pica adep` 命令用来给 linglong.yaml 文件添加包依赖。 - -查看 `ll-pica adep` 命令的帮助信息: - -```bash -ll-pica adep --help -``` - -`ll-pica adep` 命令的帮助信息如下: - -```bash -Add dependency packages to linglong.yaml - -Usage: - ll-pica adep [flags] - -Flags: - -d, --deps string dependencies to be added, separator is ',' - -h, --help help for adep - -p, --path string path to linglong.yaml (default "linglong.yaml") - -Global Flags: - -V, --verbose verbose output -``` - -```bash -ll-pica adep -d "dep1,dep2" -p /path/to/linglong.yaml -``` - -如果在 linglong.yaml 所在路径中执行不用添加 -p 参数。 diff --git a/docs/pages/guide/ll-pica/convert.md b/docs/pages/guide/ll-pica/convert.md deleted file mode 100644 index 4d7e30db3..000000000 --- a/docs/pages/guide/ll-pica/convert.md +++ /dev/null @@ -1,73 +0,0 @@ -## 转换应用 - -`ll-pica convert` 命令用来生成玲珑需要使用的 linglong.yaml 文件。 - -查看 `ll-pica convert` 命令的帮助信息: - -```bash -ll-pica convert --help -``` - -`ll-pica convert` 命令的帮助信息如下: - -```bash -Convert deb to uab - -Usage: - ll-pica convert [flags] - -Flags: - -b, --build build linglong - -c, --config string config file - --exportFile string export uab or layer (default "uab") - -h, --help help for convert - --pi string package id - --pn string package name - -t, --type string get app type (default "local") - --withDep Add dependency tree - -w, --workdir string work directory - -Global Flags: - -V, --verbose verbose output -``` - -在执行 `ll-pica init -w w --pi com.baidu.baidunetdisk --pn com.baidu.baidunetdisk -t repo` 命令后,我们仅需要执行 `ll-pica convert -w w -b --exportFile` 命令来转换出玲珑应用,这里会使用 `apt download` 命令去下载包名为 `com.baidu.baidunetdisk` 的 deb 包。 - -:::tip -这里使用 apt download 命令下载 deb 包,可能由于 deb 包过大而下载或者无法获取链接导致,失败推荐使用下面的命令。 - -如果直接使用下面的命令,就不需要执行 `ll-pica init -w w --pi com.baidu.baidunetdisk --pn com.baidu.baidunetdisk -t repo` 命令 -::: - -```bash -apt download com.baidu.baidunetdisk -``` - -```bash -ll-pica convert -c com.baidu.baidunetdisk_4.17.7_amd64.deb -w w -b --exportFile layer -``` - -- -w 表示工作目录。 -- -c 配置的方式,这里使用 deb 文件。 -- -b 表示需要进行构建,不添加该参数不会进行构建和导出 layer 文件。 -- --exportFile layer 导出产物为 layer 文件,如果到出 uab 文件,使用 --exportFile uab。 - -构建产物如下: - -```bash -├── package -│ └── com.baidu.baidunetdisk -│ ├── com.baidu.baidunetdisk_4.17.7.0_x86_64_develop.layer -│ ├── com.baidu.baidunetdisk_4.17.7.0_x86_64_binary.layer - or -│ ├── com.baidu.baidunetdisk_x86_64_4.17.7.0_main.uab -└── package.yaml -``` - -玲珑应用的产物 : - -layer 文件,layer 文件分为 binary 和 develop, binary 包含应用的运行环境,develop 在 binary 的基础上保留调试环境。 - -uab 文件,是玲珑软件包使用的离线分发格式,并不适合可以正常连接到玲珑仓库的系统使用,应当使用玲珑软件仓库提供的增量传输方案以减少网络传输体积。 - -安装 layer 文件和运行应用参考:[安装应用](../ll-cli/install.md) diff --git a/docs/pages/guide/ll-pica/init.md b/docs/pages/guide/ll-pica/init.md deleted file mode 100644 index 9c071a85c..000000000 --- a/docs/pages/guide/ll-pica/init.md +++ /dev/null @@ -1,79 +0,0 @@ -# 初始化配置 - -`ll-pica init` 命令用来初始化转换包的配置信息。会读取 `~/.pica/config.json` 文件来生成 package.yaml, - -查看 `ll-pica init` 命令的帮助信息: - -```bash -ll-pica init --help -``` - -`ll-pica init` 命令的帮助信息如下: - -```bash -init config template - -Usage: - ll-pica init [flags] - -Flags: - -a, --arch string runtime arch - -c, --config string config file - --dv string distribution Version - -h, --help help for init - --pi string package id - --pn string package name - -s, --source string runtime source - -t, --type string get type - -v, --version string runtime version - -w, --workdir string work directory - -Global Flags: - -V, --verbose verbose output -``` - -具体命令如下: - -```bash -ll-pica init -w w --pi com.baidu.baidunetdisk --pn com.baidu.baidunetdisk -t repo -``` - -- -w 表示工作目录 -- --pi 指定玲珑应用使用的 appid。 -- --pn 指定 apt 能搜索到的正确包名。 -- -t 指定获取类型,repo 从仓库中获取。 - -在 w 目录下会生成 package.yaml 文件。 - -具体配置如下: - -```bash -runtime: - version: 23.0.1 - base_version: 23.0.0 - source: https://community-packages.deepin.com/beige/ - distro_version: beige - arch: amd64 -file: - deb: - - type: repo - id: com.baidu.baidunetdisk - name: com.baidu.baidunetdisk -``` - -详细字段参考:[转换配置文件简介](../manifests.md)。 - -:::tip -默认使用的 `~/.pica/config.json` 使用的是 deepin v23,如果需要指定 UOS 20 版本作为 BASE 和 RUNTIME 使用以下命令修改默认配置。 -下面的 请修改成不需要鉴权的地址。 -::: - -```bash -ll-pica init --rv "20.0.0" --bv "20.0.0" -s "https://professional-packages.chinauos.com/desktop-professional" --dv "eagle/1070" -``` - -如果需要在 arm64 上使用,需要修改默认架构。 - -```bash -ll-pica init -a "arm64" -``` diff --git a/docs/pages/guide/ll-pica/install.md b/docs/pages/guide/ll-pica/install.md deleted file mode 100644 index d77113c6a..000000000 --- a/docs/pages/guide/ll-pica/install.md +++ /dev/null @@ -1,17 +0,0 @@ -# 玲珑转换工具(pica)安装 - -本工具提供 deb、appimage、flatpak包转换为如意玲珑包的能力,生成构建如意玲珑应用需要的 linglong.yaml 文件,并依赖 ll-builder 来实现应用构建和导出。 - -## deepin v23 - -```bash -sudo apt install linglong-pica -``` - -## UOS 1070 - -```bash -echo "deb [trusted=yes] https://ci.deepin.com/repo/deepin/deepin-community/linglong-repo/ unstable main" | sudo tee -a /etc/apt/sources.list -sudo apt update -sudo apt install linglong-pica -``` diff --git a/docs/pages/guide/ll-pica/introduction.md b/docs/pages/guide/ll-pica/introduction.md deleted file mode 100644 index ee817bd96..000000000 --- a/docs/pages/guide/ll-pica/introduction.md +++ /dev/null @@ -1,48 +0,0 @@ -# ll-pica 简介 - -本工具目前提供 deb 包转换为玲珑包的能力,生成构建玲珑应用需要的 linglong.yaml 文件,并依赖 ll-builder 来实现应用构建和导出。目前只支持转换符合[应用商店打包规范](https://doc.chinauos.com/content/M7kCi3QB_uwzIp6HyF5J)的软件包。 - -:::tip - -转换工具只是辅助工具,并不能保证被转换的应用一定能运行,可能软件本身依赖库的安装路径或其他配置路径与玲珑内部路径不统一,导致无法运行,需要使用 `ll-builder run --exec bash` 命令进入容器调试。 - -::: - -以下情况大概率无法运行成功: - -1. wine、安卓、输入法、安全类软件无法转换。 -2. 软件包中使用了 preinst、postinst、prerm、postrm 脚本。 -3. 需要读取固定路径的配置文件。 -4. 需要获取 root 权限。 - -查看 `ll-pica` 帮助信息: - -```bash -ll-pica --help -``` - -`ll-pica` 命令的帮助信息如下: - -```bash -Convert the deb to uab. For example: -Simple: - ll-pica init -c package -w work-dir - ll-pica convert -c package.yaml -w work-dir - ll-pica help - -Usage: - ll-pica [command] - -Available Commands: - adep Add dependency packages to linglong.yaml - convert Convert deb to uab - help Help about any command - init init config template - -Flags: - -h, --help help for ll-pica - -V, --verbose verbose output - -v, --version version for ll-pica - -Use "ll-pica [command] --help" for more information about a command. -``` diff --git a/docs/pages/guide/publishing/mirrors.md b/docs/pages/guide/publishing/mirrors.md new file mode 100644 index 000000000..e3b37d6f7 --- /dev/null +++ b/docs/pages/guide/publishing/mirrors.md @@ -0,0 +1,69 @@ +# 玲珑仓库 mirror 功能设计 + +在ll-cli和ll-builder中添加了enable-mirror和disable-mirror命令,用于启用和禁用镜像功能。 + +在对某个仓库启用mirror功能时,会更新ostree的config文件,添加contenturl配置项: + +```diff +url=$repo_url/repos/$repo_name +gpg-verify=false +http2=false ++ contenturl=mirrorlist=$repo_url/api/v2/mirrors/$repo_name +``` + +当添加contenturl配置项后,ostree会优先使用contenturl下载静态文件如files, url仅用于获取元数据如summary, contenturl支持file://、http://、https://三种协议。 + +如果在url前面添加mirrorlist=,则ostree会先从url获取按行分割的镜像列表,然后从镜像列表中选择镜像用于下载文件,具体逻辑见 [ostree_pull](#ostree-pull-步骤) 章节。 + +/api/v2/mirrors/$repo_name 是玲珑服务器的一个API接口,通过客户端IP获取客户端所在国家,从配置文件获取对应国家的镜像列表,然后返回给ostree,这样就实现了根据用户所在国家自动分流仓库文件下载的功能更。 + +## 镜像站配置 + +玲珑的镜像站只提供仓库静态文件的https访问即可,玲珑仓库支持rsync和ostree两种同步协议。 + +### 使用 rsync 同步配置 + +优点是同步速度快,缺点是需从支持rsync协议的镜像站或官方仓库同步仓库。 + +```bash +rsync rsync://rsync.linyaps.org.cn/repos/stable $www_root/repos/stable +``` + +### 使用 ostree 同步配置 + +优点是无需协议支持,可从任意镜像站同步仓库,缺点是同步速度较慢。 + +保存下面脚本,并命名为 sync.sh,然后执行`sh sync.sh https://mirror-repo-linglong.deepin.com/repos/stable/ $www_root/repos/stable` + +```bash +#!/bin/bash +set -e +url=$1 +dir=$2 +echo sync $url to $dir +sleep 3 +ostree init --repo=$dir --mode archive +ostree --repo=$dir remote add --if-not-exists --no-sign-verify remote $url +for ref in $(ostree --repo=$dir remote refs remote); do + echo pull $ref; + ostree --repo=$dir pull --mirror $ref; +done +``` + +## ostree pull 步骤 + +### 判断镜像是否可用 + +在pull时,ostree 先从contenturl获取镜像列表,然后从每个url获取/config文件,如果获取不到/config文件,则认为该mirror不可用,如果获取到/config文件,则认为该mirror可用。如果没有可用mirror,pull失败。 + +### 获取summary文件 + +ostree会从url获取summary文件,如果获取不到summary文件,或者summary文件不存在ref,pull失败。 + +### delta-indexes文件获取 + +ostree会在每个可用的mirror中获取delta-indexes,如果mirror服务器返回4xx或5xx,则在下一个mirror中获取delta-indexes,如果最后的mirror返回5xx,则pull失败,如果最后的mirror返回4xx,则跳过dalta步骤直接拉取files。 + +### files文件获取 + +ostree会按顺序从可用的mirror中获取files,如果mirror服务器返回403, 404, 410,则认为错误不可恢复,pull失败,如果mirror服务器返回其他错误码,则使用下一个mirror获取files。如果所有mirror都无法获取files,则pull失败。 diff --git a/docs/pages/guide/publishing/repositories.md b/docs/pages/guide/publishing/repositories.md new file mode 100644 index 000000000..a1a823e8f --- /dev/null +++ b/docs/pages/guide/publishing/repositories.md @@ -0,0 +1,13 @@ +# 仓库 + +如意玲珑官方提供的仓库是发布应用程序的主要机制,以便用户可以更方便的安装应用, 目前安装完玲珑组件后, 会默认使用此仓库。 + +- 仓库的一些基本概念已经在[仓库基础概念](../reference/basic-concepts.md)介绍过; +- 添加、更新、删除仓库可以使用 `ll-cli repo` 命令, 具体用法请参考[ll-cli-repo(1)](../reference/commands/ll-cli/repo.md); +- 使用自托管仓库:待补充; + +## 发布更新 + +如意玲珑仓库与Git仓库类似,它们通过记录每个版本之间的差异来存储应用程序的每个版本。这使得更新变得高效,因为当执行更新时,只需要下载两个版本之间的差异(或“增量”)。 + +当将应用程序的新版本添加到仓库中时,它立即对用户可用。应用商店能够自动检查并安装新版本。使用命令行必须手动运行`ll-cli list --upgradable`来检查并使用`ll-cli update`将已安装的应用程序更新到新版本。 diff --git a/docs/pages/guide/publishing/uab.md b/docs/pages/guide/publishing/uab.md new file mode 100644 index 000000000..a9d0cc896 --- /dev/null +++ b/docs/pages/guide/publishing/uab.md @@ -0,0 +1 @@ +补充使用UAB进行应用发布的相关内容。 diff --git a/docs/pages/guide/reference/basic-concepts.md b/docs/pages/guide/reference/basic-concepts.md new file mode 100644 index 000000000..446919f4f --- /dev/null +++ b/docs/pages/guide/reference/basic-concepts.md @@ -0,0 +1,24 @@ +# 如意玲珑基础概念介绍 + +## Base + +Base 可以理解为一个轻量化的“最小系统镜像”,包含操作系统核心组件(如glibc、bash等基础工具链),为应用提供跨发行版一致的底层依赖环境。它确保应用在不同 Linux 发行版(如 Debian、Ubuntu 等)上运行时,无需依赖宿主机的系统库,避免因环境差异导致的兼容性问题。 + +详细介绍见:[Base 组件](./runtime.md)。 + +## Runtime + +Runtime 是应用运行时依赖的环境,它包含了应用运行所需的特定框架库。例如,某些应用可能依赖于特定的图形界面框架(如 DTK)、浏览器引擎(如 QT WebEngine)等,Runtime 就为这些应用提供了相应的运行环境支持,确保应用能够正常启动和运行。它与应用的基础运行环境 Base 相配合,共同确保应用能够在不同 Linux 发行版上稳定、高效地运行。Runtime 与 Base 采用层级依赖关系,应用必须先选择合适的 Base,再选择与之兼容的 Runtime。这种设计确保了应用在不同发行版上的跨发行版兼容性。 + +详细介绍见:[Runtime 组件](./runtime.md)。 + +## 沙箱 + +使用如意玲珑,每个应用程序都在一个称为“沙盒”的隔离环境中构建和运行。每个沙盒都包含Base、Runtime以及应用程序。 +出于必要,沙盒内的一些资源需要被导出到主机系统以供使用。这些被称为“导出”的资源包括应用程序的桌面文件及其图标。 + +## 仓库 + +如意玲珑应用程序和运行时通常使用仓库进行存储和发布,其行为与Git仓库非常相似:一个如意玲珑仓库可以包含多个对象,每个对象都是版本化的,允许升级甚至降级。 +每个使用如意玲珑的系统都可以配置为访问任意数量的远程仓库。一旦系统配置为访问一个‘远程’,就可以检查、搜索远程仓库的内容,并将其作为应用程序和运行时的来源。 +当执行更新时,新版本的应用程序和运行时会从相关远程仓库下载。与Git类似,仅下载版本之间发生变化的部分,使该过程非常高效。 diff --git a/docs/pages/guide/reference/commands/ll-appimage-convert/ll-appimage-convert-convert.md b/docs/pages/guide/reference/commands/ll-appimage-convert/ll-appimage-convert-convert.md new file mode 100644 index 000000000..98c4aca91 --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-appimage-convert/ll-appimage-convert-convert.md @@ -0,0 +1,75 @@ +% ll-appimage-convert-convert 1 + +## NAME + +ll\-appimage\-convert\-convert - 将 AppImage 包转换为如意玲珑包格式 + +## SYNOPSIS + +**ll-appimage-convert convert** [*flags*] + +## DESCRIPTION + +ll-appimage-convert convert 命令根据指定的应用名称生成一个目录,该目录会作为如意玲珑项目的根目录,即 linglong.yaml 文件所在的位置。它支持两种转换方法: + +1. 使用 `--file` 选项将指定的 appimage 文件转换为如意玲珑包文件 +2. 使用 `--url` 和 `--hash` 选项将指定的 appimage url 和 hash 值转换为如意玲珑包文件 +3. 使用 `--layer` 选项导出 .layer 格式文件,否则将默认导出 .uab 格式文件 + +在如意玲珑版本大于1.5.7时,convert 默认导出 uab 包,如果想要导出 layer 文件,需要加上 --layer 参数。 + +可以使用 `--output` 选项生成如意玲珑项目的配置文件(linglong.yaml)和构建如意玲珑 .layer (.uab)的脚本文件,然后可以执行该脚本去生成对应的如意玲珑包当修改 linglong.yaml 配置文件后。如果不指定该选项,将直接导出对应的如意玲珑包。 + +## OPTIONS + +**-b, --build** +: 构建玲珑包 + +**-d, --description** _string_ +: 包的详细描述 + +**-f, --file** _string_ +: app 包文件,当设置了 --url 选项和 --hash 选项时,此选项不是必需的 + +**--hash** _string_ +: 包哈希值,必须与 --url 选项一起使用 + +**-i, --id** _string_ +: 包的唯一名称 + +**-l, --layer** +: 导出 layer 文件 + +**-n, --name** _string_ +: 包的描述名称 + +**-u, --url** _string_ +: 包 URL,当设置了 -f 选项时,此选项不是必需的 + +**-v, --version** _string_ +: 包的版本 + +**-V, --verbose** +: 详细输出 + +## EXAMPLES + +通过 --url 选项将 BrainWaves appimage 文件转换为如意玲珑 .layer 文件: + +```bash +ll-appimage-convert convert --url "https://github.com/makebrainwaves/BrainWaves/releases/download/v0.15.1/BrainWaves-0.15.1.AppImage" --hash "04fcfb9ccf5c0437cd3007922fdd7cd1d0a73883fd28e364b79661dbd25a4093" --name "io.github.brainwaves" --id "io.github.brainwaves" --version "0.15.1.0" --description "io.github.brainwaves" -b +``` + +通过 --file 选项将 BrainWaves-0.15.1.AppImage 转换为如意玲珑 .uab: + +```bash +ll-appimage-convert convert -f ~/Downloads/BrainWaves-0.15.1.AppImage --name "io.github.brainwaves" --id "io.github.brainwaves" --version "0.15.1.0" --description "io.github.brainwaves" -b +``` + +## SEE ALSO + +**[ll-appimage-convert(1)](ll-appimage-convert.md)**, **[ll-builder(1)](../ll-builder/ll-builder.md)** + +## HISTORY + +2024年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-appimage-convert/ll-appimage-convert.md b/docs/pages/guide/reference/commands/ll-appimage-convert/ll-appimage-convert.md new file mode 100644 index 000000000..9c407b450 --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-appimage-convert/ll-appimage-convert.md @@ -0,0 +1,29 @@ +% ll-appimage-convert 1 + +## NAME + +ll\-appimage\-convert - 将 AppImage 包转换为如意玲珑包格式 + +## SYNOPSIS + +**ll-appimage-convert** _subcommand_ + +## DESCRIPTION + +ll-appimage-convert 命令用于将 AppImage 包格式(.appimage 或 .AppImage)转换为如意玲珑包格式(.layer 或 .uab)。该工具会生成构建如意玲珑应用需要的 linglong.yaml 文件,并依赖 ll-builder 来实现应用构建和导出。 + +注意:转换工具只是辅助工具,并不能保证被转换的应用一定能运行。可能软件本身依赖库的安装路径或其他配置路径与如意玲珑内部路径不统一,导致无法运行,需要使用 `ll-builder run --exec bash` 命令进入容器调试。 + +## COMMANDS + +| Command | Man Page | Description | +| ------- | ---------------------------------------------------------------- | ---------------------------------- | +| convert | [ll-appimage-convert-convert(1)](ll-appimage-convert-convert.md) | 将 AppImage 包转换为如意玲珑包格式 | + +## SEE ALSO + +**[ll-appimage-convert-convert](ll-appimage-convert-convert.md)** + +## HISTORY + +2024年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-builder/build.md b/docs/pages/guide/reference/commands/ll-builder/build.md new file mode 100644 index 000000000..2a5be5d9f --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-builder/build.md @@ -0,0 +1,81 @@ +% ll-builder-build 1 + +## NAME + +ll-builder-build - 构建如意玲珑项目 + +## SYNOPSIS + +**ll-builder build** [*options*] [*command*...] + +## DESCRIPTION + +`ll-builder build` 命令用来构建如意玲珑应用。构建完成后,构建内容将自动提交到本地 `ostree` 缓存中。 + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +**-f, --file** _file_ [./linglong.yaml] +: linglong.yaml 的文件路径 + +**--offline** +: 仅使用本地文件。这意味着将设置 --skip-fetch-source 和 --skip-pull-depend + +**--skip-fetch-source** +: 跳过获取源代码 + +**--skip-pull-depend** +: 跳过拉取依赖项 + +**--skip-run-container** +: 跳过运行容器 + +**--skip-commit-output** +: 跳过提交构建输出 + +**--skip-output-check** +: 跳过输出检查 + +**--skip-strip-symbols** +: 跳过剥离调试符号 + +**--isolate-network** +: 在隔离的网络环境中构建 + +**command** -- _COMMAND_ ... +: 进入容器执行命令而不是构建应用 + +## EXAMPLES + +### 基本用法 + +在项目根目录(linglong.yaml 文件所在目录)构建应用: + +```bash +ll-builder build +``` + +或使用 `--file` 参数指定配置文件路径: + +```bash +ll-builder build --file /path/to/linglong.yaml +``` + +进入容器执行命令而不是构建应用: + +```bash +ll-builder build -- bash +``` + +## SEE ALSO + +**[ll-builder(1)](./ll-builder.md)**, **[ll-builder-export(1)](export.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-builder/create.md b/docs/pages/guide/reference/commands/ll-builder/create.md new file mode 100644 index 000000000..629e9b6e2 --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-builder/create.md @@ -0,0 +1,81 @@ +% ll-builder-create 1 + +## NAME + +ll-builder-create - 创建如意玲珑构建模板 + +## SYNOPSIS + +**ll-builder create** [*options*] _name_ + +## DESCRIPTION + +`ll-builder create` 命令根据输入的项目名称在当前目录创建对应的文件夹,同时生成构建所需的 `linglong.yaml` 模板文件。 + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +**name** (必需) +: 项目名称 + +## EXAMPLES + +创建名为 `org.deepin.demo` 的项目: + +```bash +ll-builder create org.deepin.demo +``` + +命令输出如下: + +```text +org.deepin.demo/ +└── linglong.yaml +``` + +### 完整的 linglong.yaml 配置 + +`linglong.yaml` 文件内容如下: + +```yaml +version: "1" + +package: + id: org.deepin.demo + name: your name #set your application name + version: 0.0.0.1 #set your version + kind: app + description: | + your description #set a brief text to introduce your application. + +command: [echo, -e, hello world] #the commands that your application need to run. + +base: org.deepin.base/23.1.0 #set the base environment, this can be changed. + +#set the runtime environment if you need, a example of setting deepin runtime is as follows. +#runtime: +#org.deepin.runtime.dtk/23.1.0 + +#set the source if you need, a simple example of git is as follows. +#sources: +# - kind: git +# url: https://github.com/linuxdeepin/linglong-builder-demo.git +# version: master\n +# commit: a3b89c3aa34c1aff8d7f823f0f4a87d5da8d4dc0 + +build: | + echo 'hello' #some operation to build this project +``` + +## SEE ALSO + +**[ll-builder(1)](./ll-builder.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-builder/export.md b/docs/pages/guide/reference/commands/ll-builder/export.md new file mode 100644 index 000000000..ee2c8713b --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-builder/export.md @@ -0,0 +1,99 @@ +% ll-builder-export 1 + +## NAME + +ll-builder-export - 导出如意玲珑 layer 或 UAB 文件 + +## SYNOPSIS + +**ll-builder export** [*options*] + +## DESCRIPTION + +`ll-builder export` 命令用于将本地构建缓存中的应用导出为 UAB (Universal Application Bundle) 文件。这是推荐的格式。也可以导出为已弃用的 linglong layer 文件格式。 + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +**-f, --file** _file_ [./linglong.yaml] +: 指定 `linglong.yaml` 配置文件的路径,`linglong.yaml` 文件所在的目录为项目的工作目录 + +**-o, --output** _file_ +: 指定输出文件的路径。对于 UAB,这通常是 `.uab` 文件的完整路径或文件名。对于 layer 这是输出文件名的前缀 + +**-z, --compressor** _x_ +: 指定压缩算法。支持 `lz4` (UAB 默认), `lzma` (layer 默认), `zstd` + +**--icon** _file_ +: 为导出的 UAB 文件指定图标 (仅 UAB 模式,与 `--layer` 互斥) + +**--loader** _file_ +: 为导出的 UAB 文件指定自定义加载器 (仅 UAB 模式,与 `--layer` 互斥) + +**--layer** +: **(已弃用)** 导出为 layer 文件格式,而不是 UAB (与 `--icon`, `--loader` 互斥) + +**--no-develop** +: 在导出 layer 文件时,不导出 `develop` 模块 + +**--ref** _ref_ +: 指定包的引用 + +**--modules** _modules_ +: 指定要导出的模块 + +## EXAMPLES + +### 导出 UAB 文件 (推荐) + +UAB (Universal Application Bundle) 文件一种自包含、可离线分发的文件格式,包含了应用运行所需的内容。这是推荐的导出格式。 + +```bash +# 基本导出 +ll-builder export + +# 导出 UAB 文件并指定图标和输出路径 +ll-builder export --icon assets/app.png -o dist/my-app-installer.uab + +# 导出 UAB 文件并使用 zstd 压缩 +ll-builder export -z zstd -o my-app-zstd.uab + +# 导出 UAB 文件并指定自定义加载器 +ll-builder export --loader /path/to/custom/loader -o my-app-custom-loader.uab +``` + +### 导出 layer 文件 + +```bash +# 导出 layer 格式,且不包含 develop 模块 +ll-builder export --layer --no-develop + +# 导出 layer 格式,并指定输出文件前缀 +ll-builder export --layer -o my-app +# (会生成 my-app_binary.layer 和 my-app_develop.layer) +``` + +## 进阶说明 + +UAB 是一个静态链接的 ELF 可执行文件,其目标是可以在任意 Linux 发行版上运行。默认情况下导出 UAB 文件属于 bundle 模式,而使用参数 `--loader` 导出 UAB 文件属于 custom loader 模式。 + +### Bundle 模式 + +bundle 模式主要用于分发,并尽可能的支持自运行功能。通常用户通过 `ll-cli install ` 安装离线分发的应用,并会自动补全应用所需的运行环境。 + +### Custom Loader 模式 + +custom loader 模式导出的 UAB 文件仅包含应用数据,以及传入的 custom loader。UAB 文件在解压挂载后将控制器交给 custom loader,此时 loader 不在容器环境内。 + +## SEE ALSO + +**[ll-builder(1)](./ll-builder.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-builder/extract.md b/docs/pages/guide/reference/commands/ll-builder/extract.md new file mode 100644 index 000000000..b326e2ed3 --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-builder/extract.md @@ -0,0 +1,43 @@ +% ll-builder-extract 1 + +## NAME + +ll-builder-extract - 将如意玲珑 layer 文件解压到目录 + +## SYNOPSIS + +**ll-builder extract** _file_ _directory_ + +## DESCRIPTION + +`ll-builder extract` 命令用于将如意玲珑 layer 文件解压到指定目录。 + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +**file** (必需) +: 要解压的 layer 文件路径 + +**directory** (必需) +: 解压目标目录 + +## EXAMPLES + +将 layer 文件解压到指定目录: + +```bash +ll-builder extract org.deepin.demo_binary.layer /tmp/extracted +``` + +## SEE ALSO + +**[ll-builder(1)](./ll-builder.md)**, **[ll-builder-export(1)](export.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/ll-builder/images/org.deepin.demo.png b/docs/pages/guide/reference/commands/ll-builder/images/org.deepin.demo.png similarity index 100% rename from docs/pages/guide/ll-builder/images/org.deepin.demo.png rename to docs/pages/guide/reference/commands/ll-builder/images/org.deepin.demo.png diff --git a/docs/pages/guide/ll-builder/images/org.deepin.demo.png.license b/docs/pages/guide/reference/commands/ll-builder/images/org.deepin.demo.png.license similarity index 100% rename from docs/pages/guide/ll-builder/images/org.deepin.demo.png.license rename to docs/pages/guide/reference/commands/ll-builder/images/org.deepin.demo.png.license diff --git a/docs/pages/guide/reference/commands/ll-builder/import.md b/docs/pages/guide/reference/commands/ll-builder/import.md new file mode 100644 index 000000000..25d051775 --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-builder/import.md @@ -0,0 +1,40 @@ +% ll-builder-import 1 + +## NAME + +ll-builder-import - 导入如意玲珑 layer 文件到构建仓库 + +## SYNOPSIS + +**ll-builder import** [*options*] _file_ + +## DESCRIPTION + +`ll-builder import` 命令用于导入如意玲珑 layer 文件到构建仓库。 + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +**file** (必需) +: 要导入的 layer 文件路径 + +## EXAMPLES + +导入 layer 文件到构建仓库: + +```bash +ll-builder import org.deepin.demo_binary.layer +``` + +## SEE ALSO + +**[ll-builder(1)](./ll-builder.md)**, **[ll-builder-export(1)](export.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-builder/list.md b/docs/pages/guide/reference/commands/ll-builder/list.md new file mode 100644 index 000000000..78450e1a8 --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-builder/list.md @@ -0,0 +1,37 @@ +% ll-builder-list 1 + +## NAME + +ll-builder-list - 列出已构建的应用程序 + +## SYNOPSIS + +**ll-builder list** [*options*] + +## DESCRIPTION + +`ll-builder list` 命令用于列出已构建的应用程序。 + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +## EXAMPLES + +列出所有已构建的应用程序: + +```bash +ll-builder list +``` + +## SEE ALSO + +**[ll-builder(1)](./ll-builder.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-builder/ll-builder.md b/docs/pages/guide/reference/commands/ll-builder/ll-builder.md new file mode 100644 index 000000000..6097832af --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-builder/ll-builder.md @@ -0,0 +1,41 @@ +% ll-builder 1 + +## NAME + +ll-builder - 如意玲珑应用构建工具 + +## SYNOPSIS + +**ll-builder** _subcommand_ + +## DESCRIPTION + +ll-builder 是为应用开发者提供的一款构建如意玲珑应用的工具。它支持在独立容器内构建应用,并包含完整的推送发布流程。 + +主要功能包括: + +- 在独立容器内构建应用 +- 完整的应用构建、测试、导出和发布流程 + +## COMMANDS + +| Command | Man Page | Description | +| ------- | ------------------------------------- | --------------------------------- | +| create | [ll-builder-create(1)](./create.md) | 创建如意玲珑构建模板 | +| build | [ll-builder-build(1)](./build.md) | 构建如意玲珑项目 | +| run | [ll-builder-run(1)](./run.md) | 运行构建好的应用程序 | +| list | [ll-builder-list(1)](./list.md) | 列出已构建的应用程序 | +| remove | [ll-builder-remove(1)](./remove.md) | 删除已构建的应用程序 | +| export | [ll-builder-export(1)](./export.md) | 导出如意玲珑 layer 或 UAB 文件 | +| push | [ll-builder-push(1)](./push.md) | 推送如意玲珑应用到远程仓库 | +| import | [ll-builder-import(1)](./import.md) | 导入如意玲珑 layer 文件到构建仓库 | +| extract | [ll-builder-extract(1)](./extract.md) | 将如意玲珑 layer 文件解压到目录 | +| repo | [ll-builder-repo(1)](./repo.md) | 显示和管理仓库 | + +## SEE ALSO + +**[ll-builder-create(1)](./create.md)**, **[ll-builder-build(1)](./build.md)**, **[ll-builder-run(1)](./run.md)**, **[ll-builder-export(1)](./export.md)**, **[ll-builder-push(1)](./push.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-builder/push.md b/docs/pages/guide/reference/commands/ll-builder/push.md new file mode 100644 index 000000000..ef94cf9e7 --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-builder/push.md @@ -0,0 +1,71 @@ +% ll-builder-push 1 + +## NAME + +ll-builder-push - 推送如意玲珑应用到远程仓库 + +## SYNOPSIS + +**ll-builder push** [*options*] + +## DESCRIPTION + +`ll-builder push` 命令用来将如意玲珑软件包推送至如意玲珑远程仓库。命令根据项目配置自动推送所有模块或指定的模块到远程仓库。 + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +**-f, --file** _file_ [./linglong.yaml] +: linglong.yaml 的文件路径 + +**--repo-url** _url_ +: 远程仓库 URL + +**--repo-name** _name_ +: 远程仓库名 + +**--module** _module_ +: 推送单个模块 + +## 推送模块说明 + +当不指定 `--module` 参数时,命令会自动推送项目中的所有模块,包括: + +- `binary` - 二进制模块 +- `develop` - 开发模块 +- 项目中定义的其他自定义模块 + +当指定 `--module` 参数时,只推送指定的单个模块。 + +## EXAMPLES + +推送项目中的所有模块到远程仓库: + +```bash +ll-builder push +``` + +推送指定模块到远程仓库: + +```bash +ll-builder push --module binary +``` + +推送模块到指定远程仓库: + +```bash +ll-builder push --repo-url https://repo.example.com --repo-name myrepo +``` + +## SEE ALSO + +**[ll-builder(1)](./ll-builder.md)**, **[ll-builder-export(1)](export.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-builder/remove.md b/docs/pages/guide/reference/commands/ll-builder/remove.md new file mode 100644 index 000000000..65eac4e86 --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-builder/remove.md @@ -0,0 +1,43 @@ +% ll-builder-remove 1 + +## NAME + +ll-builder-remove - 删除已构建的应用程序 + +## SYNOPSIS + +**ll-builder remove** [*options*] _package_ + +## DESCRIPTION + +`ll-builder remove` 命令用于删除已构建的应用程序。 + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +**--no-clean-objects** +: 删除应用前不清理对象文件 + +**package** (必需) +: 要删除的应用程序包名 + +## EXAMPLES + +删除指定的应用程序: + +```bash +ll-builder remove org.deepin.demo +``` + +## SEE ALSO + +**[ll-builder(1)](./ll-builder.md)**, **[ll-builder-list(1)](list.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-builder/repo.md b/docs/pages/guide/reference/commands/ll-builder/repo.md new file mode 100644 index 000000000..62d2fa588 --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-builder/repo.md @@ -0,0 +1,102 @@ +% ll-builder-repo 1 + +## NAME + +ll-builder-repo - 显示和管理仓库 + +## SYNOPSIS + +**ll-builder repo** [*options*] _subcommand_ + +## DESCRIPTION + +`ll-builder repo` 命令用于显示和管理如意玲珑仓库。 + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +## SUBCOMMANDS + +**show** +: 显示仓库信息 + +**add** _name_ _url_ [*options*] +: 添加新的仓库配置 + +**remove** _alias_ +: 移除仓库配置 + +**update** _alias_ _url_ +: 更新仓库 URL + +**set-default** _alias_ +: 设置默认仓库名称 + +**enable-mirror** _alias_ +: 启用仓库镜像 + +**disable-mirror** _alias_ +: 禁用仓库镜像 + +## EXAMPLES + +显示仓库信息: + +```bash +ll-builder repo show +``` + +添加新的仓库: + +```bash +ll-builder repo add myrepo https://repo.example.com +``` + +添加仓库并设置别名: + +```bash +ll-builder repo add myrepo https://repo.example.com --alias myalias +``` + +移除仓库: + +```bash +ll-builder repo remove myalias +``` + +更新仓库 URL: + +```bash +ll-builder repo update myalias https://new-repo.example.com +``` + +设置默认仓库: + +```bash +ll-builder repo set-default myalias +``` + +启用仓库镜像: + +```bash +ll-builder repo enable-mirror myalias +``` + +禁用仓库镜像: + +```bash +ll-builder repo disable-mirror myalias +``` + +## SEE ALSO + +**[ll-builder(1)](./ll-builder.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-builder/run.md b/docs/pages/guide/reference/commands/ll-builder/run.md new file mode 100644 index 000000000..5baa0ff42 --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-builder/run.md @@ -0,0 +1,80 @@ +% ll-builder-run 1 + +## NAME + +ll-builder-run - 运行构建好的应用程序 + +## SYNOPSIS + +**ll-builder run** [*options*] [*command*...] + +## DESCRIPTION + +`ll-builder run` 命令根据配置文件读取该程序相关的运行环境信息,构造一个容器环境,并在容器中执行该程序而无需安装。 + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +**-f, --file** _file_ [./linglong.yaml] +: linglong.yaml 的文件路径 + +**--modules** _modules_... +: 运行指定模块。例如: --modules binary,develop + +**--debug** +: 在调试模式下运行(启用开发模块) + +**--extensions** _extensions_ +: 指定应用运行时使用的扩展 + +**COMMAND** _TEXT_... +: 进入容器执行命令而不是运行应用 + +## EXAMPLES + +### 基本用法 + +运行构建好的应用程序, 进入项目目录: + +```bash +ll-builder run +``` + +### 调试模式 + +为了便于调试,可以进入容器执行 shell 命令而不是运行应用: + +```bash +ll-builder run /bin/bash +``` + +使用该命令,`ll-builder` 创建容器后将进入 `bash` 终端,可在容器内执行其他操作。 + +### 运行特定模块 + +运行指定的模块而不是默认的 binary 模块: + +```bash +ll-builder run --modules binary,develop +``` + +### 使用扩展运行应用 + +运行应用时使用指定的扩展: + +```bash +ll-builder run --extensions org.deepin.extension1,org.deepin.extension2 +``` + +## SEE ALSO + +**[ll-builder(1)](./ll-builder.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-cli/content.md b/docs/pages/guide/reference/commands/ll-cli/content.md new file mode 100644 index 000000000..50ba617c0 --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-cli/content.md @@ -0,0 +1,51 @@ +% ll-cli-content 1 + +## NAME + +ll\-cli\-content - 显示应用导出文件 + +## SYNOPSIS + +**ll-cli content** [*options*] _app_ + +## DESCRIPTION + +使用 `ll-cli content` 显示应用导出文件。该命令用于显示已安装应用程序导出的文件路径,包括桌面文件、元信息文件等。 + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +## POSITIONAL ARGUMENTS + +**APP** _TEXT_ _REQUIRED_ +: 指定已安装应用程序名 + +## EXAMPLES + +使用 `ll-cli content org.dde.calendar` 显示日历应用的导出的文件: + +```bash +ll-cli content org.dde.calendar +``` + +`ll-cli content org.dde.calendar` 输出如下: + +```text +/var/lib/linglong/entries/share/applications +/var/lib/linglong/entries/share/applications/dde-calendar.desktop +/var/lib/linglong/entries/share/metainfo +/var/lib/linglong/entries/share/metainfo/org.deepin.calendar.metainfo.xml +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-info(1)](info.md)**, **[ll-cli-list(1)](list.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/ll-cli/exec.md b/docs/pages/guide/reference/commands/ll-cli/enter.md similarity index 52% rename from docs/pages/guide/ll-cli/exec.md rename to docs/pages/guide/reference/commands/ll-cli/enter.md index 4ba702e09..a17d19ac6 100644 --- a/docs/pages/guide/ll-cli/exec.md +++ b/docs/pages/guide/reference/commands/ll-cli/enter.md @@ -1,55 +1,51 @@ - +## NAME -# 进入容器内部 +ll\-cli\-exec - 在当前运行的沙盒中执行命令 -`ll-cli exec`命令可以进入正在运行的容器内部。 +## SYNOPSIS -查看`ll-cli exec`命令的帮助信息: +**ll-cli enter** [*options*] _instance_ _command_... -```bash -ll-cli exec --help -``` +## DESCRIPTION -`ll-cli exec`命令的帮助信息如下: +`ll-cli enter` 命令可以进入正在运行的容器内部。该命令允许用户在正在运行的应用程序容器中执行指定的命令。 -```text -在当前运行的沙盒中执行命令。 -用法: ll-cli [选项] [子命令] +## OPTIONS -Positionals: - INSTANCE TEXT REQUIRED 指定正在运行的应用程序实例(可以通过 ps 命令获取) - COMMAND TEXT ... 在正在运行的沙盒中运行命令 +**-h, --help** +: 打印帮助信息并退出 -Options: - -h,--help 打印帮助信息并退出 - --help-all 展开所有帮助 - --working-directory PATH:DIR - 指定工作目录 +**--help-all** +: 展开所有帮助 -如果在使用过程中遇到任何问题, -您可以通过此项目向如意玲珑项目团队报告错误:https://github.com/OpenAtom-Linyaps/linyaps/issues -``` +**--working-directory** _PATH:DIR_ +: 指定工作目录 -新开一个终端,执行如下命令: +## POSITIONAL ARGUMENTS -使用`ll-cli exec`进入正在运行的容器内部: +**INSTANCE** _TEXT_ _REQUIRED_ +: 指定正在运行的应用程序实例(可以通过 ps 命令获取) -1. 使用 `ll-cli ps` 获取正在运行的容器ID: +**COMMAND** _TEXT_... +: 在正在运行的沙盒中运行命令 + +## EXAMPLES +使用 `ll-cli enter` 进入正在运行的容器内部: + +1. 使用 `ll-cli ps` 获取正在运行的容器ID: ```bash App ContainerID Pid main:org.dde.calendar/5.14.5.0/x86_64 c3b5ce363172 539537 ``` -2. 进入`the org.dde.calendar`容器内部: +2. 进入 `org.dde.calendar` 容器内部: ```bash -ll-cli exec main:org.dde.calendar/5.14.5.0/x86_64 /bin/bash +ll-cli enter main:org.dde.calendar/5.14.5.0/x86_64 /bin/bash ``` `ls -l /` 查看根目录结构,输出如下: @@ -73,3 +69,11 @@ drwxr-xr-x 3 root root 4096 7月 27 20:58 tmp drwxr-xr-x 15 nobody nogroup 4096 6月 30 16:22 usr drwxr-xr-x 13 nobody nogroup 4096 6月 30 16:23 var ``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-ps(1)](ps.md)**, **[ll-cli-run(1)](run.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-cli/info.md b/docs/pages/guide/reference/commands/ll-cli/info.md new file mode 100644 index 000000000..da55a759f --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-cli/info.md @@ -0,0 +1,66 @@ +% ll-cli-info 1 + +## NAME + +ll\-cli\-info - 显示已安装的应用程序或运行时的信息 + +## SYNOPSIS + +**ll-cli info** [*options*] _app_ + +## DESCRIPTION + +使用 `ll-cli info` 显示已安装的应用程序或运行时的信息。该命令以 JSON 格式显示应用程序或运行时的详细信息,包括架构、基础环境、运行时、描述等。 + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +## POSITIONAL ARGUMENTS + +**APP** _TEXT_ _REQUIRED_ +: 指定应用程序名,也可以是如意玲珑.layer文件 + +## EXAMPLES + +使用 `ll-cli info` 显示已安装的应用程序或运行时的信息: + +```bash +ll-cli info org.dde.calendar +``` + +`ll-cli info org.dde.calendar` 输出如下: + +```text +{ + "arch": [ + "x86_64" + ], + "base": "main:org.deepin.base/23.1.0/x86_64", + "channel": "main", + "command": [ + "dde-calendar" + ], + "description": "calendar for deepin os.\n", + "id": "org.dde.calendar", + "kind": "app", + "module": "binary", + "name": "dde-calendar", + "runtime": "main:org.deepin.runtime.dtk/23.1.0/x86_64", + "schema_version": "1.0", + "size": 13483249, + "version": "5.14.5.1" +} +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-list(1)](list.md)**, **[ll-cli-content(1)](content.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-cli/install.md b/docs/pages/guide/reference/commands/ll-cli/install.md new file mode 100644 index 000000000..659702a72 --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-cli/install.md @@ -0,0 +1,84 @@ +% ll-cli-install 1 + +## NAME + +ll\-cli\-install - 安装应用程序或运行时 + +## SYNOPSIS + +**ll-cli install** [*options*] _app_ + +## DESCRIPTION + +`ll-cli install` 命令用来安装如意玲珑应用。该命令支持通过应用名、.layer 文件或 .uab 文件安装应用程序或运行时。 + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +**--module** _MODULE_ +: 安装指定模块 + +**--repo** _REPO_ +: 从指定的仓库安装 + +**--force** +: 强制安装指定版本的应用程序 + +**-y** +: 自动对所有问题回答是 + +## POSITIONAL ARGUMENTS + +**APP** _TEXT_ _REQUIRED_ +: 指定应用名,也可以是 .uab 或 .layer 文件 + +## EXAMPLES + +通过应用名安装应用程序: + +```bash +ll-cli install org.deepin.demo +``` + +通过如意玲珑.layer文件安装应用程序: + +```bash +ll-cli install demo_0.0.0.1_x86_64_binary.layer +``` + +通过如意玲珑.uab文件安装应用程序: + +```bash +ll-cli install demo_x86_64_0.0.0.1_main.uab +``` + +安装应用的指定模块: + +```bash +ll-cli install org.deepin.demo --module=binary +``` + +安装应用的指定版本: + +```bash +ll-cli install org.deepin.demo/0.0.0.1 +``` + +通过特定标识安装应用程序: + +```bash +ll-cli install stable:org.deepin.demo/0.0.0.1/x86_64 +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-uninstall(1)](uninstall.md)**, **[ll-cli-upgrade(1)](upgrade.md)**, **[ll-cli-list(1)](list.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-cli/kill.md b/docs/pages/guide/reference/commands/ll-cli/kill.md new file mode 100644 index 000000000..b8aa5ace3 --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-cli/kill.md @@ -0,0 +1,45 @@ +% ll-cli-kill 1 + +## NAME + +ll\-cli\-kill - 停止运行的应用程序 + +## SYNOPSIS + +**ll-cli kill** [*options*] _app_ + +## DESCRIPTION + +`ll-cli kill` 命令可以强制退出正在运行的玲珑应用。该命令用于终止正在运行的应用程序进程。 + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +**-s, --signal** _SIGNAL_ [*SIGTERM*] +: 指定发送给应用程序的信号 + +## POSITIONAL ARGUMENTS + +**APP** _TEXT_ _REQUIRED_ +: 指定正在运行的应用程序名 + +## EXAMPLES + +使用 `ll-cli kill` 命令可以强制退出正在运行的玲珑应用: + +```bash +ll-cli kill org.deepin.calculator +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-ps(1)](ps.md)**, **[ll-cli-run(1)](run.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/ll-cli/list.md b/docs/pages/guide/reference/commands/ll-cli/list.md similarity index 58% rename from docs/pages/guide/ll-cli/list.md rename to docs/pages/guide/reference/commands/ll-cli/list.md index 16953e57a..2e6b1e590 100644 --- a/docs/pages/guide/ll-cli/list.md +++ b/docs/pages/guide/reference/commands/ll-cli/list.md @@ -1,45 +1,34 @@ - +## NAME -# 列出已安装的应用 +ll\-cli\-list - 列出已安装的应用程序或运行时 -`ll-cli list`命令可以查看已安装的玲珑应用。 +## SYNOPSIS -查看 `ll-cli list`命令的帮助信息: +**ll-cli list** [*options*] -```bash -ll-cli list --help -``` +## DESCRIPTION -`ll-cli list`命令的帮助信息如下: +`ll-cli list` 命令可以查看已安装的玲珑应用。该命令用于显示系统中已安装的应用程序、运行时和基础环境的详细信息。 -```text -列出已安装的应用程序或运行时 -用法: ll-cli list [选项] +## OPTIONS -示例: -# 显示已安装的应用程序 -ll-cli list -# 显示已安装的运行时 -ll-cli list --type=runtime -# 显示当前已安装应用程序的最新版本列表 -ll-cli list --upgradable +**-h, --help** +: 打印帮助信息并退出 +**--help-all** +: 展开所有帮助 -Options: - -h,--help 打印帮助信息并退出 - --help-all 展开所有帮助 - --type TYPE [app] 使用指定类型过滤结果。“runtime”、“app”或“all”之一 - --upgradable 显示当前已安装应用程序的最新版本列表,仅适用于应用程序 +**--type** _TYPE_ [*all*] +: 使用指定类型过滤结果。"runtime"、"base"、"app"或 "all"之一 -如果在使用过程中遇到任何问题, -您可以通过此项目向如意玲珑项目团队报告错误:https://github.com/OpenAtom-Linyaps/linyaps/issues -``` +**--upgradable** +: 显示当前已安装应用程序的最新版本列表,仅适用于应用程序 -查看已安装的应用,运行 `ll-cli list`命令: +## EXAMPLES + +查看已安装的应用,运行 `ll-cli list` 命令: ```bash ll-cli list @@ -53,13 +42,13 @@ org.dde.calendar dde-calendar 5.14.5.0 org.deepin.browser deepin-browser 6.5.5.4 x86_64 main binary browser for deepin os. ``` -查看已安装的运行环境,运行 `ll-cli list --type=runtime`命令: +查看已安装的运行环境,运行 `ll-cli list --type=runtime` 命令: ```bash ll-cli list --type=runtime ``` -Here is the output: +输出如下: ```text id name version arch channel module description @@ -71,10 +60,18 @@ org.deepin.foundation deepin-foundation 23.0.0.27 显示当前已安装应用程序的最新版本列表,仅适用于应用程序。运行 `ll-cli list --upgradable`: -`ll-cli list --upgradable`输出如下: +`ll-cli list --upgradable` 输出如下: ```text id installed new com.qq.wemeet.linyaps 3.19.2.402 3.19.2.403 org.dde.calendar 5.14.5.0 5.14.5.1 ``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-info(1)](info.md)**, **[ll-cli-search(1)](search.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-cli/ll-cli.md b/docs/pages/guide/reference/commands/ll-cli/ll-cli.md new file mode 100644 index 000000000..35b099b75 --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-cli/ll-cli.md @@ -0,0 +1,59 @@ +% ll-cli 1 + +## NAME + +ll\-cli - 如意玲珑命令行工具,用于管理应用程序和运行时 + +## SYNOPSIS + +**ll-cli** [*global-options*] _subcommand_ [*subcommand-options*] + +## DESCRIPTION + +ll-cli 是一个包管理器前端,用于管理如意玲珑应用的安装、卸载、查看、启动、关闭、调试、更新等操作。它提供了完整的应用程序生命周期管理功能。 + +## GLOBAL OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +**--version** +: 显示版本信息 + +**-v, --verbose** +: 显示调试信息(详细日志) + +**--json** +: 使用JSON格式输出结果 + +**--no-dbus** +: 使用点对点DBus,仅在DBus守护进程不可用时使用(内部使用) + +## COMMANDS + +| Command | Man Page | Description | +| --------- | ------------------------------------- | ----------------------------------------------- | +| run | [ll-cli-run(1)](./run.md) | 运行应用程序 | +| ps | [ll-cli-ps(1)](./ps.md) | 列出正在运行的应用程序 | +| enter | [ll-cli-exec(1)](./enter.md) | 进入应用程序正在运行的命名空间 | +| kill | [ll-cli-kill(1)](./kill.md) | 停止运行的应用程序 | +| prune | [ll-cli-prune(1)](./prune.md) | 移除未使用的最小系统或运行时 | +| install | [ll-cli-install(1)](./install.md) | 安装应用程序或运行时 | +| uninstall | [ll-cli-uninstall(1)](./uninstall.md) | 卸载应用程序或运行时 | +| upgrade | [ll-cli-upgrade(1)](./upgrade.md) | 升级应用程序或运行时 | +| list | [ll-cli-list(1)](./list.md) | 列出已安装的应用程序或运行时 | +| info | [ll-cli-info(1)](./info.md) | 显示已安装的应用程序或运行时的信息 | +| content | [ll-cli-content(1)](./content.md) | 显示已安装应用导出的文件 | +| search | [ll-cli-search(1)](./search.md) | 从远程仓库中搜索包含指定关键词的应用程序/运行时 | +| repo | [ll-cli-repo(1)](./repo.md) | 显示或修改当前使用的仓库信息 | + +## SEE ALSO + +**[ll-cli-run(1)](./run.md)**, **[ll-cli-ps(1)](./ps.md)**, **[ll-cli-exec(1)](./enter.md)**, **[ll-cli-kill(1)](./kill.md)**, **[ll-cli-prune(1)](./prune.md)**, **[ll-cli-install(1)](./install.md)**, **[ll-cli-uninstall(1)](./uninstall.md)**, **[ll-cli-upgrade(1)](./upgrade.md)**, **[ll-cli-list(1)](./list.md)**, **[ll-cli-info(1)](./info.md)**, **[ll-cli-content(1)](./content.md)**, **[ll-cli-search(1)](./search.md)**, **[ll-cli-repo(1)](./repo.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-cli/prune.md b/docs/pages/guide/reference/commands/ll-cli/prune.md new file mode 100644 index 000000000..0517ad891 --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-cli/prune.md @@ -0,0 +1,49 @@ +% ll-cli-prune 1 + +## NAME + +ll\-cli\-prune - 移除未使用的最小系统或运行时 + +## SYNOPSIS + +**ll-cli prune** [*options*] + +## DESCRIPTION + +使用 `ll-cli prune` 移除未使用的最小系统或运行时。该命令用于清理系统中不再被任何应用程序使用的基础环境或运行时组件,释放磁盘空间。 + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +## EXAMPLES + +使用 `ll-cli prune` 移除未使用的最小系统或运行时: + +```bash +ll-cli prune +``` + +`ll-cli prune` 输出如下: + +```text +Unused base or runtime: +main:org.deepin.Runtime/23.0.1.2/x86_64 +main:org.deepin.foundation/20.0.0.27/x86_64 +main:org.deepin.Runtime/23.0.1.0/x86_64 +main:org.deepin.foundation/23.0.0.27/x86_64 +main:org.deepin.Runtime/20.0.0.8/x86_64 +5 unused base or runtime have been removed. +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-list(1)](./list.md)**, **[ll-cli-uninstall(1)](./uninstall.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-cli/ps.md b/docs/pages/guide/reference/commands/ll-cli/ps.md new file mode 100644 index 000000000..f50e19ffb --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-cli/ps.md @@ -0,0 +1,44 @@ +% ll-cli-ps 1 + +## NAME + +ll\-cli\-ps - 列出正在运行的应用程序 + +## SYNOPSIS + +**ll-cli ps** [*options*] + +## DESCRIPTION + +`ll-cli ps` 命令可以查看正在运行的如意玲珑应用。该命令显示当前系统中所有正在运行的玲珑应用程序及其相关信息。 + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +## EXAMPLES + +查看正在运行的应用,运行 `ll-cli ps` 命令: + +```bash +ll-cli ps +``` + +`ll-cli ps` 命令输出如下: + +```text +应用 容器ID 进程ID +org.dde.calendar 4e3407a8a052 1279610 +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-run(1)](run.md)**, **[ll-cli-kill(1)](kill.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-cli/repo.md b/docs/pages/guide/reference/commands/ll-cli/repo.md new file mode 100644 index 000000000..dc7a3ae07 --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-cli/repo.md @@ -0,0 +1,191 @@ +% ll-cli-repo 1 + +## NAME + +ll\-cli\-repo - 显示或修改当前使用的仓库信息 + +## SYNOPSIS + +**ll-cli repo** _subcommand_ [*options*] + +## DESCRIPTION + +`ll-cli repo` 命令用于管理远程仓库。该命令提供了一系列子命令来添加、修改、删除、显示和配置仓库信息。 + +## SUBCOMMANDS + +### add + +添加一个新的仓库。 + +**用法**: `ll-cli repo add [OPTIONS] NAME URL` + +**参数**: + +- **NAME** _TEXT_ _REQUIRED_: 指定仓库名称 +- **URL** _TEXT_ _REQUIRED_: 仓库的URL地址 +- **--alias** _ALIAS_: 仓库名称的别名 + +**示例**: + +```bash +ll-cli repo add myrepo https://repo.example.com +``` + +### remove + +删除一个仓库。 + +**用法**: `ll-cli repo remove [OPTIONS] NAME` + +**参数**: + +- **ALIAS** _TEXT_ _REQUIRED_: 仓库名称的别名 + +**示例**: + +```bash +ll-cli repo remove myrepo +``` + +### update + +更新仓库URL。 + +**用法**: `ll-cli repo update [OPTIONS] NAME URL` + +**参数**: + +- **ALIAS** _TEXT_ _REQUIRED_: 仓库名称的别名 +- **URL** _TEXT_ _REQUIRED_: 新的仓库URL地址 + +**示例**: + +```bash +ll-cli repo update myrepo https://updated-repo.example.com +``` + +### set-default + +设置默认仓库名称。 + +**用法**: `ll-cli repo set-default [OPTIONS] NAME` + +**参数**: + +- **Alias** _TEXT_ _REQUIRED_: 仓库名称的别名 + +**示例**: + +```bash +ll-cli repo set-default myrepo +``` + +### show + +显示仓库信息。 + +**用法**: `ll-cli repo show [OPTIONS]` + +**示例**: + +```bash +ll-cli repo show +``` + +### set-priority + +设置仓库优先级。 + +**用法**: `ll-cli repo set-priority ALIAS PRIORITY` + +**参数**: + +- **ALIAS** _TEXT_ _REQUIRED_: 仓库名称的别名 +- **PRIORITY** _TEXT_ _REQUIRED_: 仓库的优先级 + +**示例**: + +```bash +ll-cli repo set-priority myrepo 100 +``` + +### enable-mirror + +为仓库启用镜像。 + +**用法**: `ll-cli repo enable-mirror [OPTIONS] ALIAS` + +**参数**: + +- **ALIAS** _TEXT_ _REQUIRED_: 仓库名称的别名 + +**示例**: + +```bash +ll-cli repo enable-mirror myrepo +``` + +### disable-mirror + +为仓库禁用镜像。 + +**用法**: `ll-cli repo disable-mirror [OPTIONS] ALIAS` + +**参数**: + +- **ALIAS** _TEXT_ _REQUIRED_: 仓库名称的别名 + +**示例**: + +```bash +ll-cli repo disable-mirror myrepo +``` + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +## EXAMPLES + +显示所有仓库信息: + +```bash +ll-cli repo show +``` + +添加一个新的仓库: + +```bash +ll-cli repo add deepin https://repo.deepin.com +``` + +更新仓库URL: + +```bash +ll-cli repo update deepin https://new-repo.deepin.com +``` + +设置仓库优先级: + +```bash +ll-cli repo set-priority deepin 50 +``` + +移除一个仓库: + +```bash +ll-cli repo remove deepin +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-search(1)](./search.md)**, **[ll-cli-install(1)](./install.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-cli/run.md b/docs/pages/guide/reference/commands/ll-cli/run.md new file mode 100644 index 000000000..7bdf2b9ff --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-cli/run.md @@ -0,0 +1,71 @@ +% ll-cli-run 1 + +## NAME + +ll\-cli\-run - 运行应用程序 + +## SYNOPSIS + +**ll-cli run** [*options*] _app_ [*command*...] + +## DESCRIPTION + +`ll-cli run` 命令可以启动一个如意玲珑应用。该命令支持通过应用名运行应用程序,也可以在容器中执行命令而不是运行应用程序。 + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +**--file** _FILES:FILE_... +: 将文件传递到沙盒中运行的应用程序 + +**--url** _URLS_... +: 将URL传递到沙盒中运行的应用程序 + +**--env** _ENV_... +: 为应用程序设置环境变量(格式:KEY=VALUE) + +**--base** _REF_ +: 指定应用程序运行使用的基础环境 + +**--runtime** _REF_ +: 指定应用程序运行使用的运行时 + +**--extensions** _REF_... +: 指定应用程序运行使用的扩展(多个扩展用逗号分隔) + +## POSITIONAL ARGUMENTS + +**APP** _TEXT_ _REQUIRED_ +: 指定应用程序名 + +**COMMAND** _TEXT_... +: 在正在运行的沙盒中运行命令 + +## EXAMPLES + +通过应用名运行应用程序: + +```bash +ll-cli run org.deepin.demo +``` + +在容器中执行命令而不是运行应用程序: + +```bash +ll-cli run org.deepin.demo bash +ll-cli run org.deepin.demo -- bash +ll-cli run org.deepin.demo -- bash -x /path/to/bash/script +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-ps(1)](./ps.md)**, **[ll-cli-exec(1)](./enter.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-cli/search.md b/docs/pages/guide/reference/commands/ll-cli/search.md new file mode 100644 index 000000000..f2de5984c --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-cli/search.md @@ -0,0 +1,117 @@ +% ll-cli-search 1 + +## NAME + +ll\-cli\-search - 从远程仓库中搜索包含指定关键词的应用程序/运行时 + +## SYNOPSIS + +**ll-cli search** [*options*] _keywords_ + +## DESCRIPTION + +`ll-cli search` 命令可以查询如意玲珑远程仓库中的应用信息。该命令用于从远程仓库中搜索包含指定关键词的应用程序、运行时或基础环境。 + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +**--type** _TYPE_ [*all*] +: 按指定类型过滤结果。可选类型:"runtime"、"base"、"app"或 "all"。 + +**--repo** _REPO_ +: 指定仓库 + +**--dev** +: 结果包括应用调试包 + +**--show-all-version** +: 显示应用,base或runtime的所有版本 + +## POSITIONAL ARGUMENTS + +**KEYWORDS** _TEXT_ _REQUIRED_ +: 指定搜索关键词 + +## EXAMPLES + +通过 `ll-cli search` 命令可以从远程 repo 中查找应用程序信息: + +```bash +ll-cli search calculator +``` + +该命令将返回包含 calculator 关键词的所有应用程序信息,包含完整的 `appid`、应用程序名称、版本、平台及应用描述信息。 + +`ll-cli search calculator` 输出如下: + +```text +ID 名称 版本 渠道 模块 仓库 描述 +com.bixense.passwordcalculator com.bixense.passwordcalculator 1.1.0.0 main binary nightly flatpak runtime environment on linglong +com.expidusos.calculator com.expidusos.calculator 0.1.1.0 main binary nightly flatpak runtime environment on linglong +dev.edfloreshz.calculator dev.edfloreshz.calculator 0.1.1.0 main binary nightly flatpak runtime environment on linglong +io.github.deaen.awesomecalculator io.github.deaen.awesomecalculator 2.2.0.0 main binary nightly flatpak runtime environment on linglong +org.deepin.calculator deepin-calculator 6.5.26.1 main binary nightly Calculator for UOS +org.gnome.calculator org.gnome.calculator 48.1.0.0 main binary nightly flatpak runtime environment on linglong +uno.platform.uno-calculator uno.platform.uno-calculator 1.2.9.0 main binary nightly flatpak runtime environment on linglong +com.github.matrix-calculator.linyaps com.github.matrix-calculator 3.3.0.0 main runtime stable convert from 3.3 build uos https://chinauos.com \Pyth... +com.github.thatonecalculator.discordrpcmaker discordrpcmaker 2.1.1.0 main binary stable 使用按钮制作和管理自定义 Discord 丰富存在的最佳方法! 。 +com.poki.true-love-calculator True Love Calculator 34.4.1.20250423 main binary stable True Love Calculator is an online mini-game provided ... +com.poki.your-love-calculator Your Love Calculator 34.4.1.20250423 main binary stable Your Love Calculator is an online mini-game provided ... +dev.edfloreshz.calculator dev.edfloreshz.calculator 0.1.1.0 main binary stable flatpak runtime environment on linglong +io.github.Calculator Calculator 0.0.1.1 main runtime stable C++ GUI Calculator app. +io.github.Huawei_modem_calculator_v2 Huawei_modem_calculator_v2 1.0.0.0 main runtime stable Is it Huawei modem unlock code calculator from forth3... +io.github.QT_GraphingCalculator QT_GraphingCalculator 0.0.1.0 main runtime stable Graphing calculator using QT and QTcustomplot +io.github.Qt-calculator Qt-calculator 1.0.0.0 main runtime stable A simple GUI calculator🧮 built using C++. +io.github.SolarCalculator SolarCalculator 1.0.0.0 main runtime stable Small app to calculate sunrise and sunset based on da... +io.github.StringCalculator StringCalculator 0.0.1.0 main runtime stable Full-featured calculator written in C++ with Qt frame... +io.github.cupcalculator cupcalculator 1.1.2.0 main runtime stable A program which calculates scorings from orienteering... +io.github.cyber-calculator cyber-calculator 1.0.0.0 main runtime stable CyberOS Calculator. +io.github.euduardop.faultcalculator-app io.github.euduardop.faultcalc... 31.7.24.0 main binary stable appimage convert +io.github.galaxy-calculator galaxy-calculator 0.0.2.0 main runtime stable Galaxy Calculator: Given the size of the Galaxy you c... +io.github.johannesboehler2.BmiCalculator io.github.johannesboehler2.Bm... 1.3.1.0 main binary stable Calculate your body mass index from weight, height an... +org.deepin.calculator deepin-calculator 6.5.26.1 main binary stable Calculator for UOS +uno.platform.uno-calculator uno.platform.uno-calculator 1.2.9.0 main binary stable flatpak runtime environment on linglong +``` + +如果需要查找远程所有的 base 可以使用以下命令: + +```bash +ll-cli search . --type=base +``` + +如果需要查找远程所有的 runtime 可以使用以下命令: + +```bash +ll-cli search . --type=runtime +``` + +按名称搜索远程 base: + +```bash +ll-cli search org.deepin.base --type=base +``` + +按名称搜索远程 runtime: + +```bash +ll-cli search org.deepin.runtime.dtk --type=runtime +``` + +搜索远程所有软件包: + +```bash +ll-cli search . +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-list(1)](./list.md)**, **[ll-cli-install(1)](./install.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-cli/uninstall.md b/docs/pages/guide/reference/commands/ll-cli/uninstall.md new file mode 100644 index 000000000..135340186 --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-cli/uninstall.md @@ -0,0 +1,53 @@ +% ll-cli-uninstall 1 + +## NAME + +ll\-cli\-uninstall - 卸载应用程序或运行时 + +## SYNOPSIS + +**ll-cli uninstall** [*options*] _app_ + +## DESCRIPTION + +`ll-cli uninstall` 命令可以卸载玲珑应用。该命令用于从系统中移除已安装的应用程序。 + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +**--module** _MODULE_ +: 卸载指定模块 + +## POSITIONAL ARGUMENTS + +**APP** _TEXT_ _REQUIRED_ +: 指定应用程序名 + +## EXAMPLES + +使用 `ll-cli uninstall` 命令卸载玲珑应用: + +```bash +ll-cli uninstall org.deepin.calculator +``` + +输出如下: + +```text +Uninstall main:org.deepin.calculator/5.7.21.4/x86_64 success:100% +``` + +该命令执行成功后,该玲珑应用将从系统中被卸载掉。 + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-install(1)](./install.md)**, **[ll-cli-list(1)](./list.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-cli/upgrade.md b/docs/pages/guide/reference/commands/ll-cli/upgrade.md new file mode 100644 index 000000000..d8d81358e --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-cli/upgrade.md @@ -0,0 +1,63 @@ +% ll-cli-upgrade 1 + +## NAME + +ll\-cli\-upgrade - 升级应用程序或运行时 + +## SYNOPSIS + +**ll-cli upgrade** [*options*] [*app*] + +## DESCRIPTION + +`ll-cli upgrade` 命令可以更新玲珑应用。该命令用于将已安装的应用程序或运行时升级到远程仓库中的最新版本。 + +## OPTIONS + +**-h, --help** +: 打印帮助信息并退出 + +**--help-all** +: 展开所有帮助 + +## POSITIONAL ARGUMENTS + +**APP** _TEXT_ +: 指定应用程序名。如果未指定,将升级所有可升级的应用程序 + +## EXAMPLES + +使用 `ll-cli upgrade` 将所有已安装的应用程序升级到最新版本: + +```bash +ll-cli upgrade +``` + +输出如下: + +```text +Upgrade main:org.dde.calendar/5.14.5.0/x86_64 to main:org.dde.calendar/5.14.5.1/x86_64 success:100% +Upgrade main:org.deepin.mail/6.4.10.0/x86_64 to main:org.deepin.mail/6.4.10.1/x86_64 success:100% +Please restart the application after saving the data to experience the new version. +``` + +使用 `ll-cli upgrade org.deepin.calculator` 将 org.deepin.calculator 应用程序升级到远程存储库中的最新版本: + +```bash +ll-cli upgrade org.deepin.calculator +``` + +输出如下: + +```text +Upgrade main:org.deepin.calculator/5.7.21.3/x86_64 to main:org.deepin.calculator/5.7.21.4/x86_64 success:100% +Please restart the application after saving the data to experience the new version. +``` + +## SEE ALSO + +**[ll-cli(1)](./ll-cli.md)**, **[ll-cli-install(1)](./install.md)**, **[ll-cli-list(1)](./list.md)** + +## HISTORY + +2023年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-pica-flatpak/ll-pica-flatpak-convert.md b/docs/pages/guide/reference/commands/ll-pica-flatpak/ll-pica-flatpak-convert.md new file mode 100644 index 000000000..240254355 --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-pica-flatpak/ll-pica-flatpak-convert.md @@ -0,0 +1,66 @@ +% ll-pica-flatpak-convert 1 + +## NAME + +ll\-pica\-flatpak\-convert - 将 Flatpak 应用转换为玲珑应用 + +## SYNOPSIS + +**ll-pica-flatpak convert** [*flags*] + +## DESCRIPTION + +ll-pica-flatpak convert 命令用于将 Flatpak 应用转换为玲珑应用。该命令使用 ostree 命令拉取 Flatpak 应用数据,根据 metadata 中定义的 runtime 对应生成玲珑的 base 环境。 + +转换应用默认生成 uab 文件。要转换出 layer 文件,需要添加 --layer 参数。 + +## OPTIONS + +**--build** +: 构建玲珑包 + +**--layer** +: 导出 layer 文件 + +**--version** _string_ +: 指定生成玲珑应用的版本 + +**--base** _string_ +: 指定玲珑应用的 base 环境 + +**--base-version** _string_ +: 指定玲珑应用的 base 版本 + +## EXAMPLES + +转换 Flatpak 应用 org.videolan.VLC: + +```bash +ll-pica-flatpak convert org.videolan.VLC --build +``` + +转换应用并生成 layer 文件: + +```bash +ll-pica-flatpak convert org.videolan.VLC --build --layer +``` + +指定生成玲珑应用的版本: + +```bash +ll-pica-flatpak convert org.videolan.VLC --version "1.0.0.0" --build --layer +``` + +指定玲珑应用的 base 环境和版本: + +```bash +ll-pica-flatpak convert org.videolan.VLC --base "org.deepin.base.flatpak.kde" --base-version "6.7.0.2" --build --layer +``` + +## SEE ALSO + +**[ll-pica-flatpak(1)](ll-pica-flatpak.md)**, **[ll-builder(1)](../ll-builder/ll-builder.md)** + +## HISTORY + +2024年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-pica-flatpak/ll-pica-flatpak.md b/docs/pages/guide/reference/commands/ll-pica-flatpak/ll-pica-flatpak.md new file mode 100644 index 000000000..154af7dfe --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-pica-flatpak/ll-pica-flatpak.md @@ -0,0 +1,29 @@ +% ll-pica-flatpak 1 + +## NAME + +ll\-pica\-flatpak - 将 Flatpak 应用转换为玲珑应用 + +## SYNOPSIS + +**ll-pica-flatpak** _subcommand_ + +## DESCRIPTION + +ll-pica-flatpak 命令用于将 Flatpak 应用转换为玲珑应用。该工具使用 ostree 命令拉取 Flatpak 应用数据,根据 metadata 中定义的 runtime 对应生成玲珑的 base 环境,并生成构建玲珑应用需要的 linglong.yaml 文件。 + +注意:转换工具只是辅助工具,并不能保证被转换的应用一定能运行。可能软件本身依赖库的安装路径或其他配置路径与玲珑内部路径不统一,导致无法运行,需要使用 `ll-builder run --exec bash` 命令进入容器调试。 + +## COMMANDS + +| Command | Man Page | Description | +| ------- | -------------------------------------------------------- | ----------------------------- | +| convert | [ll-pica-flatpak-convert(1)](ll-pica-flatpak-convert.md) | 将 Flatpak 应用转换为玲珑应用 | + +## SEE ALSO + +**[ll-builder(1)](../ll-builder/ll-builder.md)**, **[ll-pica-flatpak-convert(1)](ll-pica-flatpak-convert.md)** + +## HISTORY + +2024年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-pica/ll-pica-adep.md b/docs/pages/guide/reference/commands/ll-pica/ll-pica-adep.md new file mode 100644 index 000000000..b244aa587 --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-pica/ll-pica-adep.md @@ -0,0 +1,46 @@ +% ll-pica-adep 1 + +## NAME + +ll\-pica\-adep - 给 linglong.yaml 文件添加包依赖 + +## SYNOPSIS + +**ll-pica adep** [*flags*] + +## DESCRIPTION + +ll-pica adep 命令用于给 linglong.yaml 文件添加包依赖。玲珑应用可能缺少包依赖,可以通过此命令在 linglong.yaml 文件添加对应的包依赖。 + +## OPTIONS + +**-d, --deps** _string_ +: 要添加的依赖项,分隔符为 ',' + +**-p, --path** _string_ +: linglong.yaml 的路径(默认为 "linglong.yaml") + +**-V, --verbose** +: 详细输出 + +## EXAMPLES + +添加多个依赖项: + +```bash +ll-pica adep -d "dep1,dep2" -p /path/to/linglong.yaml +``` + +在 linglong.yaml 所在路径中执行(不需要添加 -p 参数): + +```bash +ll-pica adep -d "dep1,dep2" +``` + +## SEE ALSO + +**[ll-pica(1)](ll-pica.md)** + +## HISTORY + +2024年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-pica/ll-pica-convert.md b/docs/pages/guide/reference/commands/ll-pica/ll-pica-convert.md new file mode 100644 index 000000000..9750897bb --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-pica/ll-pica-convert.md @@ -0,0 +1,68 @@ +% ll-pica-convert 1 + +## NAME + +ll\-pica\-convert - 将 deb 包转换为玲珑包 + +## SYNOPSIS + +**ll-pica convert** [*flags*] + +## DESCRIPTION + +ll-pica convert 命令用来生成玲珑需要使用的 linglong.yaml 文件,并将 deb 包转换为玲珑包。该命令支持从本地 deb 文件或通过 apt download 命令从仓库下载 deb 包进行转换。 + +## OPTIONS + +**-b, --build** +: 构建玲珑包 + +**-c, --config** _string_ +: 配置文件 + +**--exportFile** _string_ +: 导出 uab 或 layer(默认为 "uab") + +**--pi** _string_ +: 包 ID + +**--pn** _string_ +: 包名称 + +**-t, --type** _string_ +: 获取应用类型(默认为 "local") + +**--withDep** +: 添加依赖树 + +**-w, --workdir** _string_ +: 工作目录 + +**-V, --verbose** +: 详细输出 + +## EXAMPLES + +从仓库下载 deb 包并转换: + +```bash +ll-pica init -w w --pi com.baidu.baidunetdisk --pn com.baidu.baidunetdisk -t repo +``` + +```bash +ll-pica convert -w w -b --exportFile +``` + +从本地 deb 文件转换: + +```bash +ll-pica convert -c com.baidu.baidunetdisk_4.17.7_amd64.deb -w w -b --exportFile layer +``` + +## SEE ALSO + +**[ll-pica(1)](ll-pica.md)**, **[ll-cli(1)](ll-pica-init.md)** + +## HISTORY + +2024年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/commands/ll-pica/ll-pica-init.md b/docs/pages/guide/reference/commands/ll-pica/ll-pica-init.md new file mode 100644 index 000000000..e7707d0fc --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-pica/ll-pica-init.md @@ -0,0 +1,77 @@ +% ll-pica-init 1 + +## NAME + +ll\-pica\-init - 初始化转换包的配置信息 + +## SYNOPSIS + +**ll-pica init** [*flags*] + +## DESCRIPTION + +ll-pica init 命令用来初始化转换包的配置信息。该命令会读取 ~/.pica/config.json 文件来生成 package.yaml 配置文件,该文件是 ll-pica 转换 deb 包的基础信息,包含构建的 base、runtime 的版本,以及需要被转换的 deb 包信息。 + +## OPTIONS + +**-a, --arch** _string_ +: 运行时架构 + +**-c, --config** _string_ +: 配置文件 + +**--dv** _string_ +: 发行版版本 + +**--pi** _string_ +: 包 ID + +**--pn** _string_ +: 包名称 + +**-s, --source** _string_ +: 运行时源 + +**-t, --type** _string_ +: 获取类型 + +**-v, --version** _string_ +: 运行时版本 + +**-w, --workdir** _string_ +: 工作目录 + +**-V, --verbose** +: 详细输出 + +## EXAMPLES + +从仓库中获取包信息: + +```bash +ll-pica init -w w --pi com.baidu.baidunetdisk --pn com.baidu.baidunetdisk -t repo +``` + +指定 UOS 20 版本作为 BASE 和 RUNTIME: + +```bash +ll-pica init --rv "20.0.0" --bv "20.0.0" -s "https://professional-packages.chinauos.com/desktop-professional" --dv "eagle/1070" +``` + +在 arm64 架构上使用: + +```bash +ll-pica init -a "arm64" +``` + +## NOTES + +package.yaml 文件生成后,用户可以根据需要进行修改。详细字段参考:[转换配置文件简介](./ll-pica-manifests.md)。 + +## SEE ALSO + +**[ll-pica(1)](ll-pica.md)**, **[ll-builder(1)](ll-pica-convert.md)** + +## HISTORY + +2024年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/ll-pica/manifests.md b/docs/pages/guide/reference/commands/ll-pica/ll-pica-manifests.md similarity index 98% rename from docs/pages/guide/ll-pica/manifests.md rename to docs/pages/guide/reference/commands/ll-pica/ll-pica-manifests.md index aafd77480..58ea3044a 100644 --- a/docs/pages/guide/ll-pica/manifests.md +++ b/docs/pages/guide/reference/commands/ll-pica/ll-pica-manifests.md @@ -33,7 +33,7 @@ runtime: | -------------- | ----------------------------------------------- | | runtime | 运行时(runtime) | | version | 运行时(runtime)版本,三位数可以模糊匹配第四位 | -| base_version | base 的版本号, 三位数可以模糊匹配第四位 | +| base_version | base 的版本号, 三位数可以模糊匹配第四位 | | source | 获取 deb 包依赖时使用的源 | | distro_version | 发行版的代号 | | arch | 获取 deb 包需要的架构 | diff --git a/docs/pages/guide/reference/commands/ll-pica/ll-pica.md b/docs/pages/guide/reference/commands/ll-pica/ll-pica.md new file mode 100644 index 000000000..8e8eb9993 --- /dev/null +++ b/docs/pages/guide/reference/commands/ll-pica/ll-pica.md @@ -0,0 +1,38 @@ +% ll-pica 1 + +## NAME + +ll\-pica - 将 deb 包转换为玲珑包的工具 + +## SYNOPSIS + +**ll-pica** _subcommand_ + +## DESCRIPTION + +ll-pica 命令提供将 deb 包转换为玲珑包的能力,生成构建玲珑应用需要的 linglong.yaml 文件,并依赖 ll-builder 来实现应用构建和导出。目前只支持转换符合应用商店打包规范的软件包。 + +注意:转换工具只是辅助工具,并不能保证被转换的应用一定能运行。可能软件本身依赖库的安装路径或其他配置路径与玲珑内部路径不统一,导致无法运行,需要使用 `ll-builder run --exec bash` 命令进入容器调试。 + +以下情况大概率无法运行成功: + +- 安卓、输入法、安全类软件无法转换 +- 软件包中使用了 preinst、postinst、prerm、postrm 脚本 +- 需要读取固定路径的配置文件 +- 需要获取 root 权限 + +## COMMANDS + +| Command | Man Page | Description | +| ------- | ---------------------------------------- | ------------------------------- | +| adep | [ll-pica-adep(1)](ll-pica-adep.md) | 给 linglong.yaml 文件添加包依赖 | +| convert | [ll-pica-convert(1)](ll-pica-convert.md) | 将 deb 包转换为玲珑包 | +| init | [ll-pica-init(1)](ll-pica-init.md) | 初始化转换包的配置信息 | + +## SEE ALSO + +**[ll-builder(1)](../ll-builder/ll-builder.md)**, **[ll-pica-adep(1)](ll-pica-adep.md)**, **[ll-pica-convert(1)](ll-pica-convert.md)**, **[ll-pica-init(1)](ll-pica-init.md)** + +## HISTORY + +2024年,由 UnionTech Software Technology Co., Ltd. 开发 diff --git a/docs/pages/guide/reference/driver.md b/docs/pages/guide/reference/driver.md new file mode 100644 index 000000000..af23ed9af --- /dev/null +++ b/docs/pages/guide/reference/driver.md @@ -0,0 +1,25 @@ +# 如意玲珑显卡驱动说明 + +如意玲珑运行环境是与宿主机环境隔离的,运行如意玲珑程序时如果需要使用显卡硬件加速功能,需要满足两个条件: + +1. 宿主机正确安装、配置了显卡驱动。 +2. 在如意玲珑环境中安装对应的驱动包。 + +## 已适配的显卡驱动列表 + +### Mesa 开源驱动 + +在应用依赖的 base 中已经携带了对应版本的 mesa,不需要额外的安装。mesa 开源驱动包括: + +- amdgpu,新的 AMD 显卡驱动。 +- intel,Intel 显卡驱动。 +- nouveau,开源的 nvidia 显卡驱动。 +- radeon,老的 AMD/ATI 显卡驱动。 + +### 其他驱动 + +不在 base 中携带的,需要额外安装的驱动: + +- 英伟达闭源驱动,推荐通过 `sudo ll-cli install org.deepin.driver.display.nvidia.570-124-04` 安装。其中 `570-124-04` 是驱动版本号,需要与宿主机安装的驱动版本匹配,通过宿主机 `/sys/module/nvidia/version` 文件查看宿主机驱动的版本。未安装扩展时,linyaps 会在运行时尝试从宿主机自动链接 NVIDIA 驱动文件。 +- 格兰菲显卡驱动,通过 `sudo ll-cli install com.glenfly.driver.display.arise` 安装。 +- 英特尔视频编解码驱动(VAAPI),通过 `sudo ll-cli install org.deepin.driver.media.intel` 安装,包含了新/旧 Intel 显卡的支持。 diff --git a/docs/pages/guide/ll-builder/runtime.md b/docs/pages/guide/reference/runtime.md similarity index 98% rename from docs/pages/guide/ll-builder/runtime.md rename to docs/pages/guide/reference/runtime.md index 027e05a66..36514e2b7 100644 --- a/docs/pages/guide/ll-builder/runtime.md +++ b/docs/pages/guide/reference/runtime.md @@ -1,6 +1,6 @@ # base 和 runtime 介绍 -在玲珑应用打包体系中,base 提供基础运行环境,runtime 提供应用框架支持,两者采用层级依赖关系。正确选型可确保应用跨发行版的兼容性,建议遵循以下选型原则: +在玲珑应用打包体系中,base 提供基础运行环境,runtime 提供应用框架支持,两者采用分层依赖关系。正确选型可确保应用跨发行版的兼容性,建议遵循以下选型原则: ‌base 优先原则‌:先选择应用已适配的发行版对应的base ‌runtime 继承原则‌:runtime必须和base保持兼容 @@ -11,7 +11,7 @@ _base 和 runtime 版本号遵循“主版本.次版本.修订版本.打包版 ## base 介绍 -玲珑的 base 提供最基础的运行环境,包含操作系统核心组件(如 glibc、bash 等基础工具链)‌ +玲珑的 base 提供最基础的运行环境,包括操作系统核心组件(如 glibc、bash 等基础工具链)‌ 作为容器化的"最小系统镜像",确保应用能在不同发行版上保持一致的底层依赖。base 通常由玲珑官方维护,开发者可直接引用而无需担心应用运行在不同发行版上的兼容性问题。 推荐使用以下稳定版本,未在文档中列出的 base 一般是实验性质的版本,不建议选用。更详细的信息见 [base 列表](#base-列表) @@ -24,7 +24,7 @@ _base 和 runtime 版本号遵循“主版本.次版本.修订版本.打包版 - org.deepin.base/25.2.0 + org.deepin.base/25.2.1 deepin 25 测试阶段 @@ -38,12 +38,12 @@ _base 和 runtime 版本号遵循“主版本.次版本.修订版本.打包版 uos 20 停止支持 - + ## runtime 介绍 -玲珑的 runtime 提供应用所需的特定运行环境(如 DTK/Wine/GNOME 等框架库),开发者可以根据应用需求选择合适的 runtime ,玲珑官方也提供了多种预编译好的 runtime 镜像供开发者选择。目前应用只能选择一个 runtime 使用,所以 runtime 可能会包含多个环境,例如 DTK 的 runtime 包含 QT 框架,Wine 的 runtime 包含 DTK 框架。_应用也可以不使用 runtime_ +玲珑的 runtime 提供应用所需的特定的运行环境(如 DTK/Wine/GNOME 等框架库),开发者可以根据应用需求选择合适的 runtime ,玲珑官方也提供了多种预编译好的 runtime 镜像供开发者选择。目前应用只能选择一个 runtime 使用,因此 runtime 可能会包含多个环境,例如 DTK 的 runtime 包含 QT 框架,Wine 的 runtime 包含 DTK 框架。_应用也可以不使用 runtime_ 官方维护的稳定 runtime 如下,未在文档中列出的 runtime 一般是实验性质的版本,不建议选用。更详细的信息见 [runtime 列表](#runtime-列表) @@ -55,8 +55,8 @@ _base 和 runtime 版本号遵循“主版本.次版本.修订版本.打包版 - org.deepin.runtime.dtk/25.2.0 - org.deepin.base/25.2.0 + org.deepin.runtime.dtk/25.2.1 + org.deepin.base/25.2.1 包含QT6和DTK6 @@ -74,12 +74,12 @@ _base 和 runtime 版本号遵循“主版本.次版本.修订版本.打包版 org.deepin.foundation/20.0.0 包含QT5和DTK5 - + ## base 列表 -#### org.deepin.foundation/20.0.0 +### org.deepin.foundation/20.0.0 使用 uos 1070 仓库制作的 base,支持 x86, arm64, loongarch64 三个架构。 @@ -89,7 +89,7 @@ _在容器中执行 `cat /var/lib/dpkg/status|grep "^Package: "|sort|awk '{print adduser adwaita-icon-theme apt base-files base-passwd bash bsdutils ca-certificates coreutils dash dbus dbus-user-session dconf-gsettings-backend dconf-service debconf debianutils deepin-desktop-base deepin-elf-verify deepin-keyring diffutils distro-info-data dlnfs dmsetup dpkg e2fsprogs eject fdisk findutils fontconfig fontconfig-config fonts-dejavu-core fonts-noto fonts-noto-core fonts-symbola fuse3 gcc-8-base glib-networking glib-networking-common glib-networking-services gpgv grep gsettings-desktop-schemas gtk-update-icon-cache gzip hicolor-icon-theme hostname init-system-helpers libacl1 libapparmor1 libapt-pkg5.0 libargon2-1 libasound2 libasound2-data libatk1.0-0 libatk1.0-data libatk-bridge2.0-0 libatomic1 libatspi2.0-0 libattr1 libaudit1 libaudit-common libavahi-client3 libavahi-common3 libavahi-common-data libblkid1 libbsd0 libbz2-1.0 libc6 libc6-dev libcairo2 libcairo-gobject2 libcap2 libcap-ng0 libc-bin libc-dev-bin libcolord2 libcom-err2 libcroco3 libcryptsetup12 libcups2 libcupsimage2 libdatrie1 libdb5.3 libdbus-1-3 libdconf1 libdebconfclient0 libdevmapper1.02.1 libdrm2 libdrm-amdgpu1 libdrm-common libdrm-intel1 libdrm-nouveau2 libdrm-radeon1 libedit2 libegl1 libegl1-mesa libegl-mesa0 libelf1 libepoxy0 libexpat1 libext2fs2 libfdisk1 libffi6 libfontconfig1 libfreetype6 libfribidi0 libfuse3-3 libgbm1 libgcc1 libgcrypt20 libgdk-pixbuf2.0-0 libgdk-pixbuf2.0-common libgl1 libgl1-mesa-dri libglapi-mesa libglib2.0-0 libglu1-mesa libglvnd0 libglx0 libglx-mesa0 libgmp10 libgnutls30 libgomp1 libgpg-error0 libgraphite2-3 libgssapi-krb5-2 libgtk2.0-0 libgtk2.0-common libgtk-3-0 libgtk-3-common libharfbuzz0b libhogweed4 libice6 libicu63 libidn11 libidn2-0 libip4tc0 libjbig0 libjpeg62-turbo libjson-c3 libjson-glib-1.0-0 libjson-glib-1.0-common libk5crypto3 libkeyutils1 libkmod2 libkrb5-3 libkrb5support0 liblcms2-2 libllvm7 liblocale-gettext-perl liblz4-1 liblzma5 libmagic1 libmagic-mgc libmount1 libncursesw6 libnettle6 libnspr4 libnss3 libopengl0 libp11-kit0 libpam0g libpam-deepin-security libpam-modules libpam-modules-bin libpam-runtime libpam-systemd libpango-1.0-0 libpango1.0-0 libpangocairo-1.0-0 libpangoft2-1.0-0 libpangox-1.0-0 libpangoxft-1.0-0 libpciaccess0 libpcre16-3 libpcre3 libpcre32-3 libpcsclite1 libpixman-1-0 libpng16-16 libproxy1v5 libpsl5 librest-0.7-0 librsvg2-2 librsvg2-common libseccomp2 libselinux1 libsemanage1 libsemanage-common libsensors5 libsensors-config libsepol1 libsm6 libsmartcols1 libsoup2.4-1 libsoup-gnome2.4-1 libsqlite3-0 libss2 libssl1.1 libstdc++6 libsystemd0 libtasn1-6 libtext-charwidth-perl libtext-iconv-perl libtext-wrapi18n-perl libthai0 libthai-data libtiff5 libtinfo6 libudev1 libunistring2 libuuid1 libwayland-client0 libwayland-cursor0 libwayland-egl1 libwayland-egl1-mesa libwayland-server0 libwebp6 libx11-6 libx11-data libx11-xcb1 libxau6 libxcb1 libxcb-composite0 libxcb-damage0 libxcb-doc libxcb-dpms0 libxcb-dri2-0 libxcb-dri3-0 libxcb-glx0 libxcb-present0 libxcb-randr0 libxcb-record0 libxcb-render0 libxcb-res0 libxcb-screensaver0 libxcb-shape0 libxcb-shm0 libxcb-sync1 libxcb-xf86dri0 libxcb-xfixes0 libxcb-xinerama0 libxcb-xinput0 libxcb-xkb1 libxcb-xtest0 libxcb-xv0 libxcb-xvmc0 libxcomposite1 libxcursor1 libxdamage1 libxdmcp6 libxext6 libxfixes3 libxft2 libxi6 libxinerama1 libxkbcommon0 libxml2 libxrandr2 libxrender1 libxshmfence1 libxss1 libxtst6 libxxf86vm1 libzstd1 linux-libc-dev login lsb-base mawk mime-support mount ncurses-base ncurses-bin openssl passwd perl-base sed sensible-utils shared-mime-info sudo systemd systemd-sysv sysvinit-utils tar tzdata ucf util-linux uuid-runtime x11-common xkb-data zlib1g ``` -#### org.deepin.foundation/23.0.0 +### org.deepin.foundation/23.0.0 使用 deepin 23 beta 仓库制作的 base,支持 x86 架构。 @@ -99,7 +99,7 @@ _在容器中执行 `cat /var/lib/dpkg/status|grep "^Package: "|sort|awk '{print adduser adwaita-icon-theme apt at-spi2-common base-files base-passwd bash binutils-common bsdutils ca-certificates coreutils dash dbus dbus-bin dbus-daemon dbus-session-bus-common dbus-system-bus-common dbus-user-session dconf-gsettings-backend dconf-service debconf debianutils deepin-desktop-base deepin-keyring diffutils distro-info-data dmsetup dpkg e2fsprogs eject findutils fontconfig fontconfig-config fonts-noto fonts-noto-core fonts-symbola gcc-13-base glib-networking glib-networking-common glib-networking-services gpgv grep gsettings-desktop-schemas gtk-update-icon-cache gzip hicolor-icon-theme hostname init-system-helpers libacl1 libapparmor1 libapt-pkg6.0 libarchive13 libargon2-1 libasan8 libasm1 libasound2 libasound2-data libatk1.0-0 libatk-bridge2.0-0 libatomic1 libatspi2.0-0 libattr1 libaudit1 libaudit-common libavahi-client3 libavahi-common3 libavahi-common-data libbabeltrace1 libbinutils libblkid1 libboost-regex1.74.0 libbrotli1 libbsd0 libbz2-1.0 libc6 libc6-dev libcairo2 libcairo-gobject2 libcairo-script-interpreter2 libcap2 libcap-ng0 libc-bin libcc1-0 libc-dev-bin libcolord2 libcom-err2 libcrypt1 libcrypt-dev libcryptsetup12 libctf0 libctf-nobfd0 libcups2 libcupsimage2 libcurl3-gnutls libcurl4 libdatrie1 libdb5.3 libdbus-1-3 libdconf1 libdebconfclient0 libdebuginfod1 libdebuginfod-common libdeflate0 libdevmapper1.02.1 libdpkg-perl libdrm2 libdrm-amdgpu1 libdrm-common libdrm-intel1 libdrm-nouveau2 libdrm-radeon1 libdw1 libedit2 libegl1 libegl-mesa0 libelf1 libepoxy0 libevent-2.1-7 libexpat1 libext2fs2 libfdisk1 libffi8 libfontconfig1 libfreetype6 libfribidi0 libgbm1 libgcc-s1 libgcrypt20 libgdbm6 libgdbm-compat4 libgdk-pixbuf-2.0-0 libgdk-pixbuf2.0-0 libgdk-pixbuf2.0-common libgdk-pixbuf-xlib-2.0-0 libgirepository-1.0-1 libgl1 libgl1-mesa-dri libglapi-mesa libgles1 libgles2 libglib2.0-0 libglib2.0-data libglu1-mesa libglvnd0 libglx0 libglx-mesa0 libgmp10 libgmpxx4ldbl libgnutls30 libgnutls-dane0 libgnutls-openssl27 libgnutlsxx30 libgomp1 libgpg-error0 libgprofng0 libgraphite2-3 libgssapi-krb5-2 libgtk2.0-0 libgtk2.0-common libgtk-3-0 libgtk-3-common libharfbuzz0b libharfbuzz-cairo0 libharfbuzz-gobject0 libharfbuzz-icu0 libharfbuzz-subset0 libhogweed6 libhwasan0 libice6 libicu73 libidn2-0 libip4tc2 libipt2 libisl23 libitm1 libjansson4 libjbig0 libjpeg62-turbo libjson-c5 libjsoncpp24 libk5crypto3 libkeyutils1 libkmod2 libkrb5-3 libkrb5support0 liblcms2-2 libldap-2.5-0 liblerc4 libllvm16 liblocale-gettext-perl liblsan0 liblz4-1 liblzma5 liblzo2-2 libmagic1 libmagic-mgc libmd0 libmount1 libmpc3 libmpfr6 libncursesw6 libnettle8 libnghttp2-14 libnsl2 libnsl-dev libnspr4 libnss3 libopengl0 libp11-kit0 libpam0g libpam-modules libpam-modules-bin libpam-runtime libpam-systemd libpango-1.0-0 libpango1.0-0 libpangocairo-1.0-0 libpangoft2-1.0-0 libpangoxft-1.0-0 libpciaccess0 libpcre16-3 libpcre2-16-0 libpcre2-32-0 libpcre2-8-0 libpcre2-posix3 libpcre3 libpcre32-3 libpcrecpp0v5 libperl5.36 libpixman-1-0 libpkgconf3 libpng16-16 libproc2-0 libproxy1v5 libpsl5 libpython3.11 libpython3.11-minimal libpython3.11-stdlib libpython3-stdlib libquadmath0 libreadline8 librhash0 librsvg2-2 librsvg2-common librtmp1 libsasl2-2 libsasl2-modules-db libseccomp2 libselinux1 libsemanage2 libsemanage-common libsensors5 libsensors-config libsepol2 libsframe1 libsharpyuv0 libsm6 libsmartcols1 libsource-highlight4v5 libsource-highlight-common libsqlite3-0 libss2 libssh2-1 libssl3 libstdc++6 libsystemd0 libsystemd-shared libtasn1-6 libtext-charwidth-perl libtext-iconv-perl libtext-wrapi18n-perl libthai0 libthai-data libtiff6 libtiffxx6 libtinfo6 libtirpc3 libtirpc-common libtirpc-dev libtsan2 libubsan1 libudev1 libunbound8 libunistring2 libuuid1 libuv1 libvulkan1 libwayland-client0 libwayland-cursor0 libwayland-egl1 libwayland-server0 libwebp7 libwebpdecoder3 libwebpdemux2 libwebpmux3 libx11-6 libx11-data libx11-xcb1 libxau6 libxcb1 libxcb-composite0 libxcb-damage0 libxcb-doc libxcb-dpms0 libxcb-dri2-0 libxcb-dri3-0 libxcb-glx0 libxcb-present0 libxcb-randr0 libxcb-record0 libxcb-render0 libxcb-res0 libxcb-screensaver0 libxcb-shape0 libxcb-shm0 libxcb-sync1 libxcb-xf86dri0 libxcb-xfixes0 libxcb-xinerama0 libxcb-xinput0 libxcb-xkb1 libxcb-xtest0 libxcb-xv0 libxcb-xvmc0 libxcomposite1 libxcursor1 libxdamage1 libxdmcp6 libxext6 libxfixes3 libxft2 libxi6 libxinerama1 libxkbcommon0 libxml2 libxrandr2 libxrender1 libxshmfence1 libxss1 libxtst6 libxxf86vm1 libxxhash0 libz3-4 libzstd1 linux-libc-dev login logsave mailcap mawk media-types mime-support mount ncurses-base ncurses-bin openssl passwd perl perl-base perl-modules-5.36 readline-common rpcsvc-proto sed sensible-utils shared-mime-info systemd systemd-dev systemd-sysv sysvinit-utils tar tzdata ucf usr-is-merged util-linux uuid-runtime x11-common xkb-data zlib1g ``` -#### org.deepin.base/23.1.0 +### org.deepin.base/23.1.0 基于 deepin v23 release 仓库制作的 base,支持 x86 架构。 @@ -109,7 +109,7 @@ _在容器中执行 `cat /var/lib/dpkg/status|grep "^Package: "|sort|awk '{print acl adduser adwaita-icon-theme apt at-spi2-common base-files base-passwd bash bc binutils binutils-common binutils-x86-64-linux-gnu bluez bluez-obexd bsdextrautils bsdutils busybox bzip2 ca-certificates coreutils cpio cryptsetup cryptsetup-bin cryptsetup-initramfs cups cups-bsd cups-client cups-common cups-core-drivers cups-daemon cups-filters cups-filters-core-drivers cups-ipp-utils cups-ppdc cups-server-common curl dash dbus dbus-bin dbus-daemon dbus-session-bus-common dbus-system-bus-common dbus-x11 dconf-gsettings-backend dconf-service debconf debianutils deepin-keyring dictionaries-common diffutils dirmngr dmeventd dmsetup dpkg e2fsprogs eject emacsen-common fcitx5-frontend-gtk2 fcitx5-frontend-gtk3 fdisk file findutils fontconfig fontconfig-config fonts-dejavu-core fonts-urw-base35 gawk gcc-13-base gettext-base ghostscript gir1.2-atk-1.0 gir1.2-freedesktop gir1.2-gdkpixbuf-2.0 gir1.2-glib-2.0 gir1.2-harfbuzz-0.0 gir1.2-pango-1.0 glib-networking glib-networking-common glib-networking-services gnupg gnupg-l10n gnupg-utils gnutls-bin gpg gpg-agent gpgconf gpgsm gpgv gpg-wks-client grep gsettings-desktop-schemas gtk-update-icon-cache gzip hicolor-icon-theme hostname initramfs-tools initramfs-tools-core init-system-helpers iso-codes kbd klibc-utils kmod libacl1 libaio1 libaom3 libapparmor1 libapt-pkg6.0 libarchive13 libargon2-1 libasound2 libasound2-data libasound2-plugins libassuan0 libasyncns0 libatk1.0-0 libatk-bridge2.0-0 libatspi2.0-0 libattr1 libaudit1 libaudit-common libavahi-client3 libavahi-common3 libavahi-common-data libavcodec60 libavutil58 libbinutils libblkid1 libbluetooth3 libbrotli1 libbsd0 libbz2-1.0 libc6 libc6-dev libcairo2 libcairo-gobject2 libcap2 libcap2-bin libcap-ng0 libc-bin libcbor0.8 libc-dev-bin libc-l10n libcloudproviders0 libcodec2-0.9 libcolord2 libcom-err2 libconfig++9v5 libcrypt1 libcrypt-dev libcryptsetup12 libctf0 libctf-nobfd0 libcups2 libcupsfilters1 libcupsimage2 libcurl3-gnutls libcurl4 libdaemon0 libdatrie1 libdav1d6 libdb5.3 libdbus-1-3 libdconf1 libdebconfclient0 libdecor-0-0 libdeflate0 libdevmapper1.02.1 libdevmapper-event1.02.1 libdrm2 libdrm-amdgpu1 libdrm-common libdrm-intel1 libdrm-nouveau2 libdrm-radeon1 libdw1 libedit2 libegl1 libegl-mesa0 libelf1 libencode-locale-perl libepoxy0 libevent-2.1-7 libexif12 libexpat1 libext2fs2 libfcitx5gclient2 libfdisk1 libffado2 libffi8 libfftw3-single3 libfido2-1 libfile-listing-perl libflac8 libfontconfig1 libfontembed1 libfontenc1 libfreeaptx0 libfreetype6 libfribidi0 libgbm1 libgcc-s1 libgcrypt20 libgdbm6 libgdbm-compat4 libgdk-pixbuf-2.0-0 libgdk-pixbuf2.0-common libgdk-pixbuf-xlib-2.0-0 libgl1 libgl1-mesa-dri libglapi-mesa libgle3 libgles2 libglib2.0-0 libglib2.0-bin libglib2.0-data libglibmm-2.4-1v5 libglu1-mesa libglvnd0 libglx0 libglx-mesa0 libgmp10 libgnutls30 libgnutls-dane0 libgomp1 libgpg-error0 libgprofng0 libgraphite2-3 libgs9 libgs9-common libgsm1 libgssapi-krb5-2 libgstreamer1.0-0 libgstreamer-plugins-base1.0-0 libgtk2.0-0 libgtk2.0-common libgtk-3-0 libgtk-3-common libharfbuzz0b libharfbuzz-gobject0 libharfbuzz-icu0 libharfbuzz-subset0 libhogweed6 libhtml-parser-perl libhtml-tagset-perl libhtml-tree-perl libhttp-cookies-perl libhttp-date-perl libhttp-message-perl libhttp-negotiate-perl libhwy1 libical3 libice6 libicu74 libidn12 libidn2-0 libiec61883-0 libijs-0.35 libio-html-perl libio-socket-ssl-perl libjack-jackd2-0 libjansson4 libjbig0 libjbig2dec0 libjpeg62-turbo libjpeg-turbo-progs libjson-c5 libjxl0.7 libk5crypto3 libkeyutils1 libklibc libkmod2 libkrb5-3 libkrb5support0 libksba8 liblc3-1 liblcms2-2 libldacbt-abr2 libldacbt-enc2 libldap-2.5-0 liblerc4 liblilv-0-0 libllvm17 libltdl7 liblvm2cmd2.03 liblwp-mediatypes-perl liblwp-protocol-https-perl liblz4-1 liblzma5 libmagic1 libmagic-mgc libmd0 libminizip1 libmnl0 libmount1 libmp3lame0 libmpfr6 libmysofa1 libnatspec0 libncurses6 libncursesw6 libnet-http-perl libnetpbm10 libnet-ssleay-perl libnettle8 libnghttp2-14 libnpth0 libnsl2 libnsl-dev libnspr4 libnss3 libnss-myhostname libnuma1 libogg0 libopengl0 libopenjp2-7 libopus0 liborc-0.4-0 libp11-kit0 libpam0g libpam-modules libpam-modules-bin libpam-runtime libpango-1.0-0 libpangocairo-1.0-0 libpangoft2-1.0-0 libpangoxft-1.0-0 libpaper1 libpciaccess0 libpcre2-16-0 libpcre2-8-0 libperl5.36 libpipewire-0.3-0 libpipewire-0.3-modules libpixman-1-0 libpng16-16 libpoppler118 libpoppler-cpp0v5 libpopt0 libproc2-0 libproxy1v5 libpsl5 libpulse0 libpulsedsp libpulse-mainloop-glib0 libpython3.11-minimal libpython3.11-stdlib libpython3.12 libpython3.12-minimal libpython3.12-stdlib libpython3-stdlib libqpdf29 librav1e0 libraw1394-11 libreadline8 libroc0.3 librsvg2-2 librtmp1 libsamplerate0 libsasl2-2 libsasl2-modules-db libsbc1 libseccomp2 libselinux1 libsemanage2 libsemanage-common libsensors5 libsensors-config libsepol2 libserd-0-0 libsframe1 libsharpyuv0 libshine3 libsigc++-2.0-0v5 libsigsegv2 libsm6 libsmartcols1 libsnappy1v5 libsndfile1 libsord-0-0 libsoxr0 libspa-0.2-bluetooth libspa-0.2-modules libspeex1 libspeexdsp1 libsqlite3-0 libsratom-0-0 libss2 libssh2-1 libssl3 libstdc++6 libsvtav1enc1d1 libswresample4 libsystemd0 libsystemd-shared libtasn1-6 libtdb1 libtext-iconv-perl libthai0 libthai-data libtheora0 libtiff6 libtimedate-perl libtinfo6 libtirpc3 libtirpc-common libtirpc-dev libtry-tiny-perl libtss2-esys-3.0.2-0 libtss2-mu0 libtss2-sys1 libtss2-tcti-cmd0 libtss2-tcti-device0 libtss2-tctildr0 libtss2-tcti-libtpms0 libtss2-tcti-mssim0 libtss2-tcti-spi-helper0 libtss2-tcti-swtpm0 libturbojpeg0 libtwolame0 libudev1 libunbound8 libunistring2 libunwind8 liburi-perl libusb-1.0-0 libuuid1 libuv1 libv4l-0 libv4lconvert0 libva2 libva-drm2 libva-x11-2 libvdpau1 libvorbis0a libvorbisenc2 libvpl2 libvpx7 libvulkan1 libwayland-client0 libwayland-cursor0 libwayland-egl1 libwayland-server0 libwebp7 libwebpdemux2 libwebpmux3 libwebrtc-audio-processing1 libwrap0 libwww-perl libwww-robotrules-perl libx11-6 libx11-data libx11-xcb1 libx264-160 libx265-199 libxau6 libxaw7 libxcb1 libxcb-composite0 libxcb-cursor0 libxcb-damage0 libxcb-dri2-0 libxcb-dri3-0 libxcb-ewmh2 libxcb-glx0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-present0 libxcb-randr0 libxcb-record0 libxcb-render0 libxcb-render-util0 libxcb-res0 libxcb-shape0 libxcb-shm0 libxcb-sync1 libxcb-util1 libxcb-xfixes0 libxcb-xinerama0 libxcb-xinput0 libxcb-xkb1 libxcb-xtest0 libxcomposite1 libxcursor1 libxdamage1 libxdmcp6 libxext6 libxfixes3 libxft2 libxi6 libxinerama1 libxkbcommon0 libxkbcommon-x11-0 libxkbfile1 libxml2 libxml++2.6-2v5 libxmu6 libxpm4 libxrandr2 libxrender1 libxshmfence1 libxt6 libxtst6 libxv1 libxvidcore4 libxxf86vm1 libxxhash0 libz3-4 libzstd1 libzvbi0 libzvbi-common linux-base linux-libc-dev locales login logsave lvm2 mawk media-types mesa-vdpau-drivers mesa-vulkan-drivers ncurses-base ncurses-bin netbase netpbm ocl-icd-libopencl1 openssl p11-kit p11-kit-modules passwd perl perl-base perl-modules-5.36 perl-openssl-defaults pinentry-curses pipewire pipewire-bin pipewire-pulse poppler-data poppler-utils procps pulseaudio pulseaudio-module-bluetooth pulseaudio-utils python3 python3.11 python3.11-minimal python3.12 python3.12-minimal python3-minimal readline-common rfkill rpcsvc-proto sed sensible-utils shared-mime-info sqlite3 ssl-cert systemd-dev systemd-standalone-sysusers sysvinit-utils tar tpm-udev tzdata tzdata-legacy ucf udev unzip usr-is-merged util-linux x11-common x11-xkb-utils xdg-user-dirs xfonts-encodings xfonts-utils xkb-data xscreensaver-data xscreensaver-data-extra xscreensaver-gl xscreensaver-gl-extra xz-utils zlib1g zstd ``` -#### org.deepin.base/25.2.0 +### org.deepin.base/25.2.1 基于 deepin 25 beta 仓库制作的 base,支持 x86, arm64, loong64 架构。 @@ -121,7 +121,7 @@ acl adduser at-spi2-common base-files base-passwd bash bc binutils binutils-comm ## runtime 列表 -#### org.deepin.Runtime/20.0.0 +### org.deepin.Runtime/20.0.0 使用 uos 1070 仓库制作的 runtime,支持 x86, arm64, loongarch64 三个架构。 @@ -131,7 +131,7 @@ _在容器中执行 `cat /runtime/packages.list|awk '{print $2}'` 查看包列 libqt5core5a libqt5gui5 qt5-gtk-platformtheme qt5-flatpak-platformtheme libqt5network5 libqt5opengl5 libqt5sql5 libqt5sql5-mysql libqt5sql5-odbc libqt5sql5-psql libqt5sql5-sqlite libqt5sql5-tds libqt5sql5-ibase libqt5xml5 libqt5dbus5 libqt5test5 libqt5concurrent5 libqt5widgets5 libqt5printsupport5 qtbase5-dev qtbase5-private-dev libqt5opengl5-dev qtbase5-dev-tools qt5-qmake-bin qt5-qmake qtbase5-examples qt5-default qtbase5-doc qtbase5-doc-html libqt5svg5 libqt5svg5-dev qtsvg5-examples qtsvg5-doc qtsvg5-doc-html libqt5qml5 libqt5quick5 libqt5quickparticles5 libqt5quicktest5 libqt5quickwidgets5 qml-module-qtquick-layouts qt5-qmltooling-plugins qml-module-qt-labs-folderlistmodel qml-module-qtquick-localstorage qml-module-qt-labs-sharedimage qml-module-qtqml-models2 qml-module-qtqml-statemachine qml-module-qtquick-particles2 qml-module-qtquick2 qml-module-qtquick-shapes qml-module-qt-labs-handlers qml-module-qt-labs-settings qml-module-qttest qml-module-qtquick-window2 qml-module-qtquick-xmllistmodel qtdeclarative5-dev qtdeclarative5-private-dev qtdeclarative5-dev-tools qmlscene qml qtdeclarative5-examples qtdeclarative5-doc qtdeclarative5-doc-html qml-module-qtgraphicaleffects qtgraphicaleffects5-doc qtgraphicaleffects5-doc-html qml-module-qtquick-controls qml-module-qtquick-extras qml-module-qtquick-dialogs qml-module-qtquick-privatewidgets qtquickcontrols5-examples qtquickcontrols5-doc qtquickcontrols5-doc-html libqt5quickcontrols2-5 libqt5quicktemplates2-5 qml-module-qt-labs-calendar qml-module-qt-labs-platform qml-module-qtquick-controls2 qml-module-qtquick-templates2 qtquickcontrols2-5-dev qtquickcontrols2-5-doc qtquickcontrols2-5-doc-html qtquickcontrols2-5-examples libqt5script5 libqt5scripttools5 qtscript5-dev qtscript5-examples qtscript5-doc qtscript5-doc-html libqt5xmlpatterns5 libqt5xmlpatterns5-dev qtxmlpatterns5-dev-tools qtxmlpatterns5-examples qtxmlpatterns5-doc qtxmlpatterns5-doc-html qt5-image-formats-plugins libqt5location5 libqt5positioningquick5 libqt5positioning5 libqt5location5-plugins libqt5positioning5-plugins qml-module-qtlocation qml-module-qtpositioning qml-module-qt-labs-location qtlocation5-dev qtpositioning5-dev qtlocation5-examples qtlocation5-doc qtlocation5-doc-html libqt5multimedia5 libqt5multimedia5-plugins libqt5multimediaquick5 libqt5multimediawidgets5 qml-module-qtmultimedia qml-module-qtaudioengine libqt5multimediagsttools5 qtmultimedia5-examples qtmultimedia5-dev qtmultimedia5-doc qtmultimedia5-doc-html libqt53dcore5 libqt53dquick5 libqt53dquickrender5 libqt53dinput5 libqt53drender5 libqt53dlogic5 libqt53dquickinput5 libqt53dquickextras5 libqt53dextras5 libqt53dquickscene2d5 libqt53danimation5 libqt53dquickanimation5 qt3d5-dev-tools qt3d-gltfsceneio-plugin qt3d-assimpsceneimport-plugin qt3d-defaultgeometryloader-plugin qt3d-scene2d-plugin qml-module-qt3d qml-module-qtquick-scene3d qml-module-qtquick-scene2d qt3d5-dev qt3d5-examples qt3d5-doc qt3d5-doc-html libqt5charts5 libqt5charts5-dev qml-module-qtcharts qtcharts5-examples qtcharts5-doc qtcharts5-doc-html libqt5bluetooth5 libqt5bluetooth5-bin qml-module-qtbluetooth libqt5nfc5 qml-module-qtnfc qtconnectivity5-dev qtconnectivity5-examples qtconnectivity5-doc qtconnectivity5-doc-html libqt5gamepad5-dev libqt5gamepad5 qtgamepad5-examples libqt5sensors5 qml-module-qtsensors libqt5sensors5-dev qtsensors5-examples qtsensors5-doc qtsensors5-doc-html libqt5texttospeech5-dev libqt5texttospeech5 qtspeech5-flite-plugin qtspeech5-speechd-plugin qtspeech5-examples qtspeech5-doc qtspeech5-doc-html qml-module-qtquick-virtualkeyboard qtvirtualkeyboard-plugin qtvirtualkeyboard5-examples qtvirtualkeyboard5-doc qtvirtualkeyboard5-doc-html libqt5serialport5 libqt5serialport5-dev qt5serialport-examples qtserialport5-doc qtserialport5-doc-html qtnetworkauth5-doc qtnetworkauth5-doc-html libqt5networkauth5-dev qtnetworkauth5-examples libqt5networkauth5 libqt5designer5 libqt5designercomponents5 qdbus-qt5 qdoc-qt5 libqt5help5 qttools5-dev qttools5-private-dev qttools5-dev-tools qt5-assistant qttools5-examples qttools5-doc qttools5-doc-html libqt5x11extras5 libqt5x11extras5-dev qtx11extras5-doc qtx11extras5-doc-html qtwayland5-examples libqt5waylandclient5 libqt5waylandcompositor5 qml-module-qtwayland-compositor qml-module-qtwayland-client-texturesharing libqt5waylandcompositor5-dev libqt5waylandclient5-dev qtwayland5-private-dev qtwayland5-dev-tools qtwayland5 qtwayland5-doc qtwayland5-doc-html lxqt-build-tools libqt5xdg3 libqt5xdgiconloader3 libqt5xdg-dev libqt5xdgiconloader-dev qtxdg-dev-tools libdtkcommon libdtkcommon-dev libdtkcore5 libdtkcore5-bin libdtkcore-dev libdtkcore-doc libdtkgui5 libdtkgui5-bin libdtkgui-dev libdtkgui-doc libdtkwidget5 libdtkwidget5-bin libdtkwidget-dev dtkwidget5-examples dtkwidget-doc googletest googletest-tools libgtest-dev libgmock-dev google-mock dde-qt5integration dde-qt5xcb-plugin dde-qt5wayland-plugin ``` -#### org.deepin.Runtime/23.0.1 +### org.deepin.Runtime/23.0.1 使用 deepin 23 beta 仓库制作的 runtime,支持 x86 架构。 @@ -141,7 +141,7 @@ _在容器中执行 `cat /runtime/packages.list|awk '{print $2}'` 查看包列 libqt5core5a libqt5gui5 qt5-gtk-platformtheme qt5-flatpak-platformtheme qt5-xdgdesktopportal-platformtheme libqt5network5 libqt5opengl5 libqt5sql5 libqt5sql5-mysql libqt5sql5-odbc libqt5sql5-psql libqt5sql5-sqlite libqt5sql5-tds libqt5sql5-ibase libqt5xml5 libqt5dbus5 libqt5test5 libqt5concurrent5 libqt5widgets5 libqt5printsupport5 qtbase5-dev qtbase5-private-dev libqt5opengl5-dev qtbase5-dev-tools qt5-qmake-bin qt5-qmake qtbase5-examples qt5-default qtbase5-doc qtbase5-doc-html qtbase5-doc-dev libqt5svg5 libqt5svg5-dev qtsvg5-examples qtsvg5-doc qtsvg5-doc-html libqt5qml5 libqt5qmlmodels5 libqt5qmlworkerscript5 libqt5quick5 libqt5quickparticles5 libqt5quickshapes5 libqt5quicktest5 libqt5quickwidgets5 qml-module-qtquick-layouts qt5-qmltooling-plugins qml-module-qt-labs-animation qml-module-qt-labs-folderlistmodel qml-module-qtquick-localstorage qml-module-qt-labs-sharedimage qml-module-qt-labs-qmlmodels qml-module-qt-labs-wavefrontmesh qml-module-qtqml qml-module-qtqml-models2 qml-module-qtqml-statemachine qml-module-qtqml-workerscript2 qml-module-qtquick-particles2 qml-module-qtquick2 qml-module-qtquick-shapes qml-module-qt-labs-settings qml-module-qttest qml-module-qtquick-window2 qtdeclarative5-dev qtdeclarative5-private-dev qtdeclarative5-dev-tools qmlscene qml qtdeclarative5-examples qtdeclarative5-doc qtdeclarative5-doc-html qtdeclarative5-doc-dev qml-module-qtgraphicaleffects qtgraphicaleffects5-doc qtgraphicaleffects5-doc-html qml-module-qtquick-controls qml-module-qtquick-extras qml-module-qtquick-dialogs qml-module-qtquick-privatewidgets qtquickcontrols5-examples qtquickcontrols5-doc qtquickcontrols5-doc-html libqt5quickcontrols2-5 libqt5quicktemplates2-5 qml-module-qt-labs-calendar qml-module-qt-labs-platform qml-module-qtquick-controls2 qml-module-qtquick-templates2 qtquickcontrols2-5-dev qtquickcontrols2-5-private-dev qtquickcontrols2-5-doc qtquickcontrols2-5-doc-html qtquickcontrols2-5-examples libqt5script5 libqt5scripttools5 qtscript5-dev qtscript5-examples qtscript5-doc qtscript5-doc-html libqt5xmlpatterns5 libqt5xmlpatterns5-dev qtxmlpatterns5-dev-tools qml-module-qtquick-xmllistmodel qtxmlpatterns5-examples qtxmlpatterns5-doc qtxmlpatterns5-doc-html qt5-image-formats-plugins libqt5location5 libqt5positioningquick5 libqt5positioning5 libqt5location5-plugins libqt5location5-plugin-mapboxgl libqt5positioning5-plugins qml-module-qtlocation qml-module-qtpositioning qml-module-qt-labs-location qtlocation5-dev qtpositioning5-dev qtlocation5-examples qtlocation5-doc qtlocation5-doc-html qtlocation5-doc-dev libqt5multimedia5 libqt5multimedia5-plugins libqt5multimediaquick5 libqt5multimediawidgets5 qml-module-qtmultimedia qml-module-qtaudioengine libqt5multimediagsttools5 qtmultimedia5-examples qtmultimedia5-dev qtmultimedia5-doc qtmultimedia5-doc-html libqt53dcore5 libqt53dquick5 libqt53dquickrender5 libqt53dinput5 libqt53drender5 libqt53dlogic5 libqt53dquickinput5 libqt53dquickextras5 libqt53dextras5 libqt53dquickscene2d5 libqt53danimation5 libqt53dquickanimation5 qt3d5-dev-tools qt3d-gltfsceneio-plugin qt3d-assimpsceneimport-plugin qt3d-defaultgeometryloader-plugin qt3d-scene2d-plugin qml-module-qt3d qml-module-qtquick-scene3d qml-module-qtquick-scene2d qt3d5-dev qt3d5-examples qt3d5-doc qt3d5-doc-html libqt5charts5 libqt5charts5-dev qml-module-qtcharts qtcharts5-examples qtcharts5-doc qtcharts5-doc-html libqt5bluetooth5 libqt5bluetooth5-bin qml-module-qtbluetooth libqt5nfc5 qml-module-qtnfc qtconnectivity5-dev qtconnectivity5-examples qtconnectivity5-doc qtconnectivity5-doc-html libqt5gamepad5-dev libqt5gamepad5 qtgamepad5-examples qml-module-qtgamepad qtgamepad5-doc qtgamepad5-doc-html libqt5sensors5 qml-module-qtsensors libqt5sensors5-dev qtsensors5-examples qtsensors5-doc qtsensors5-doc-html libqt5texttospeech5-dev libqt5texttospeech5 qtspeech5-flite-plugin qtspeech5-speechd-plugin qtspeech5-examples qtspeech5-doc qtspeech5-doc-html libqt5hunspellinputmethod5 libqt5virtualkeyboard5 libqt5virtualkeyboard5-dev qml-module-qtquick-virtualkeyboard qtvirtualkeyboard-plugin qtvirtualkeyboard5-examples qtvirtualkeyboard5-doc qtvirtualkeyboard5-doc-html libqt5serialport5 libqt5serialport5-dev qt5serialport-examples qtserialport5-doc qtserialport5-doc-html qtnetworkauth5-doc qtnetworkauth5-doc-html libqt5networkauth5-dev qtnetworkauth5-examples libqt5networkauth5 libqt5designer5 libqt5designercomponents5 qdbus-qt5 qdbus qdoc-qt5 qhelpgenerator-qt5 qtattributionsscanner-qt5 libqt5help5 qttools5-dev qttools5-private-dev qttools5-dev-tools qt5-assistant qttools5-examples qttools5-doc qttools5-doc-html libqt5x11extras5 libqt5x11extras5-dev qtx11extras5-doc qtx11extras5-doc-html qtwayland5-examples libqt5waylandclient5 libqt5waylandcompositor5 qml-module-qtwayland-compositor qml-module-qtwayland-client-texturesharing libqt5waylandcompositor5-dev libqt5waylandclient5-dev qtwayland5-private-dev qtwayland5-dev-tools qtwayland5 qtwayland5-doc qtwayland5-doc-html qtwebchannel5-doc qtwebchannel5-doc-html libqt5webchannel5-dev qtwebchannel5-examples libqt5webchannel5 qml-module-qtwebchannel libqt5websockets5 libqt5websockets5-dev qml-module-qtwebsockets qml-module-qt-websockets qtwebsockets5-examples qtwebsockets5-doc qtwebsockets5-doc-html qttranslations5-l10n lxqt-build-tools libqt5xdg3 libqt5xdgiconloader3 libqt5xdg-dev libqt5xdgiconloader-dev qtxdg-dev-tools libdtkdata libdtkcommon-dev libdtkcore5 libdtkcore5-bin libdtkcore-dev libdtkcore-doc libdtkgui5 libdtkgui5-bin libdtkgui-dev libdtkgui-doc libdtkwidget5 libdtkwidget5-bin libdtkwidget-dev dtkwidget5-examples dtkwidget-doc qml-module-qtquick-controls2-styles-chameleon libdtkdeclarative5 libdtkdeclarative-dev libdtkdeclarative-doc dtk-exhibition googletest libgtest-dev libgmock-dev google-mock dde-qt5integration dde-qt5xcb-plugin dde-qt5wayland-plugin qtchooser ``` -#### org.deepin.runtime.dtk/23.1.0 +### org.deepin.runtime.dtk/23.1.0 使用 deepin 23 release 仓库制作的 runtime,支持 x86 架构。 @@ -151,7 +151,7 @@ _在容器中执行 `cat /runtime/packages.list|awk '{print $2}'` 查看包列 libqt5core5a libqt5gui5 qt5-gtk-platformtheme qt5-flatpak-platformtheme qt5-xdgdesktopportal-platformtheme libqt5network5 libqt5opengl5 libqt5sql5 libqt5sql5-mysql libqt5sql5-odbc libqt5sql5-psql libqt5sql5-sqlite libqt5sql5-tds libqt5sql5-ibase libqt5xml5 libqt5dbus5 libqt5test5 libqt5concurrent5 libqt5widgets5 libqt5printsupport5 qtbase5-dev qtbase5-private-dev libqt5opengl5-dev qtbase5-dev-tools qt5-qmake-bin qt5-qmake qtbase5-examples qt5-default qtbase5-doc qtbase5-doc-html qtbase5-doc-dev libqt5core5a libqt5gui5 qt5-gtk-platformtheme qt5-flatpak-platformtheme qt5-xdgdesktopportal-platformtheme libqt5network5 libqt5opengl5 libqt5sql5 libqt5sql5-mysql libqt5sql5-odbc libqt5sql5-psql libqt5sql5-sqlite libqt5sql5-tds libqt5sql5-ibase libqt5xml5 libqt5dbus5 libqt5test5 libqt5concurrent5 libqt5widgets5 libqt5printsupport5 qtbase5-dev qtbase5-private-dev libqt5opengl5-dev qtbase5-dev-tools qt5-qmake-bin qt5-qmake qtbase5-examples qt5-default qtbase5-doc qtbase5-doc-html qtbase5-doc-dev libqt5svg5 libqt5svg5-dev qtsvg5-examples qtsvg5-doc qtsvg5-doc-html libqt5qml5 libqt5qmlmodels5 libqt5qmlworkerscript5 libqt5quick5 libqt5quickparticles5 libqt5quickshapes5 libqt5quicktest5 libqt5quickwidgets5 qml-module-qtquick-layouts qt5-qmltooling-plugins qml-module-qt-labs-animation qml-module-qt-labs-folderlistmodel qml-module-qtquick-localstorage qml-module-qt-labs-sharedimage qml-module-qt-labs-qmlmodels qml-module-qt-labs-wavefrontmesh qml-module-qtqml qml-module-qtqml-models2 qml-module-qtqml-statemachine qml-module-qtqml-workerscript2 qml-module-qtquick-particles2 qml-module-qtquick2 qml-module-qtquick-shapes qml-module-qt-labs-settings qml-module-qttest qml-module-qtquick-window2 qtdeclarative5-dev qtdeclarative5-private-dev qtdeclarative5-dev-tools qmlscene qml qtdeclarative5-examples qtdeclarative5-doc qtdeclarative5-doc-html qtdeclarative5-doc-dev qml-module-qtgraphicaleffects qtgraphicaleffects5-doc qtgraphicaleffects5-doc-html qml-module-qtquick-controls qml-module-qtquick-extras qml-module-qtquick-dialogs qml-module-qtquick-privatewidgets qtquickcontrols5-examples qtquickcontrols5-doc qtquickcontrols5-doc-html libqt5quickcontrols2-5 libqt5quicktemplates2-5 qml-module-qt-labs-calendar qml-module-qt-labs-platform qml-module-qtquick-controls2 qml-module-qtquick-templates2 qtquickcontrols2-5-dev qtquickcontrols2-5-private-dev qtquickcontrols2-5-doc qtquickcontrols2-5-doc-html qtquickcontrols2-5-examples qt5-image-formats-plugins libqt5multimedia5 libqt5multimedia5-plugins libqt5multimediaquick5 libqt5multimediawidgets5 qml-module-qtmultimedia qml-module-qtaudioengine libqt5multimediagsttools5 qtmultimedia5-examples qtmultimedia5-dev qtmultimedia5-doc qtmultimedia5-doc-html libqt5texttospeech5-dev libqt5texttospeech5 qtspeech5-flite-plugin qtspeech5-speechd-plugin qtspeech5-examples qtspeech5-doc qtspeech5-doc-html libqt5designer5 libqt5designercomponents5 qdbus-qt5 qdbus qdoc-qt5 qhelpgenerator-qt5 qtattributionsscanner-qt5 libqt5help5 qttools5-dev qttools5-private-dev qttools5-dev-tools qt5-assistant qttools5-examples qttools5-doc qttools5-doc-html libqt5x11extras5 libqt5x11extras5-dev qtx11extras5-doc qtx11extras5-doc-html qtwayland5-examples libqt5waylandclient5 libqt5waylandcompositor5 qml-module-qtwayland-compositor qml-module-qtwayland-client-texturesharing libqt5waylandcompositor5-dev libqt5waylandclient5-dev qtwayland5-private-dev qtwayland5-dev-tools qtwayland5 qtwayland5-doc qtwayland5-doc-html qttranslations5-l10n lxqt-build-tools libqt5xdg3 libqt5xdgiconloader3 libqt5xdg-dev libqt5xdgiconloader-dev qtxdg-dev-tools libdtkdata libdtkcommon-dev libdtkcore5 libdtkcore5-bin libdtkcore-dev libdtkcore-doc libdtkgui5 libdtkgui5-bin libdtkgui-dev libdtkgui-doc libdtkwidget5 libdtkwidget5-bin libdtkwidget-dev dtkwidget5-examples dtkwidget-doc qml-module-qtquick-controls2-styles-chameleon libdtkdeclarative5 libdtkdeclarative-dev libdtkdeclarative-doc dtk-exhibition googletest libgtest-dev libgmock-dev google-mock dde-qt5integration dde-qt5xcb-plugin dde-qt5wayland-plugin ``` -#### org.deepin.runtime.dtk/25.2.0 +### org.deepin.runtime.dtk/25.2.1 使用 deepin 25 beta 仓库制作的 runtime,支持 x86, arm64, loong64 架构。 @@ -161,7 +161,7 @@ _在容器中执行 `cat /runtime/packages.list|awk '{print $2}'` 查看包列 libmtdev1 libqt6core6 libvulkan-dev libinput10 qt6-wayland-private-dev libqt6quick6 libnorm1 libqt6opengl6 qml6-module-qt-labs-qmlmodels libqt6spatialaudio6 libqt6waylandcompositor6 qml6-module-qtquick-dialogs mailcap libqt6sql6-sqlite linguist-qt6 libqt6sql6-psql libsodium23 mime-support libbrotli-dev librist4 libdtk6widget gtk-update-icon-cache libqt6sql6 libjpeg-dev uuid-dev qmake6-bin libqt6xml6 libswscale7 qml6-module-qtwayland-compositor qml6-module-qtqml-base librabbitmq4 libdtk6core libqt6help6 xorg-sgml-doctools libxau-dev qt6-l10n-tools libopenmpt0 qml6-module-qttest libdeflate-dev qml6-module-qtquick3d-spatialaudio firebird3.0-common libqt6quicktemplates2-6 qt6-declarative-dev-tools libqt6sql6-ibase libsrt1.4-gnutls qt6-declarative-private-dev adwaita-icon-theme qml6-module-qtquick-controls2-styles-chameleon qml6-module-qtquick-window libglx-dev libjpeg62-turbo-dev qt6-5compat-dev qt6-wayland-dev-tools xtrans-dev qt6-tools-private-dev qt6-svg-private-dev libqt6qml6 qt6-qmltooling-plugins libcupsimage2-dev libcapstone4 pkg-config libqt6multimedia6 libwebp-dev libqt6qmlmodels6 libpciaccess-dev firebird3.0-common-doc libts0 libevdev2 libqt6quick3druntimerender6 icu-devtools libqt6svg6 qt6-speech-dev libdtk6log-dev qml-qt6 libdtk6widget-bin fonts-texgyre libdpkg-perl qml6-module-qtquick-shapes qml6-module-qmltime libmd4c0 libcolord2 libfontconfig-dev qml6-module-qtqml-workerscript libgstreamer-gl1.0-0 qt6-multimedia-dev qml6-module-qtmultimedia libavformat60 qml6-module-qtquick-effects libicu73 libodbc1 libqt6qmlcompiler6 libx11-dev libqt6quick3dutils6 libqt6svgwidgets6 qt6-tools-dev-tools libdtkcommon-dev libmariadb3 libb2-1 qml6-module-qt-labs-wavefrontmesh libexpat1-dev libsharpyuv-dev libtommath1 libstartup-notification0 libcups2-dev libspdlog1.12 dpkg-dev libcloudproviders0 libqt6printsupport6 libmbedcrypto3 qml6-module-qtquick-tooling liblerc-dev qml6-module-qtquick patch libgirepository-2.0-0 qml6-module-qtquick-particles libqt6shadertools6 qml6-module-qtquick-layouts libbluray2 libxcb-util-dev qt6-declarative-dev libwacom-common libmng1 libgl-dev libfile-find-rule-perl fonts-liberation libselinux1-dev libllvm17 libgtk-3-0 libudfread0 libzstd-dev libdtkdata qt6-speech-flite-plugin libsysprof-capture-4-dev qt6-documentation-tools qt6-gtk-platformtheme libdtk6core-dev qml6-module-qtqml-models libqt6network6 libwayland-bin libqt6test6 libwacom2 libwebpdecoder3 libdtk6log qml6-module-qtquick-localstorage qml6-module-qt5compat-graphicaleffects qml6-module-qt-labs-folderlistmodel qt6-base-private-dev libqt6designer6 libgtk-3-common qml6-module-qtquick-nativestyle libpq5 libicu-dev qt6-speech-speechd-plugin libwacom-dev qt6-image-formats-plugins fcitx5-frontend-qt6 qml6-module-qt-labs-animation dbus-broker libffi-dev libmount-dev libqt6gui6 qml6-module-qtquick-controls libpgm-5.3-0 libdtk6declarative libqt6dbus6 mysql-common libxcb1-dev pkgconf libpkgconf3 libfcitx5-qt-data qml6-module-qtcore libfcitx5-qt6-dev libspeechd2 qml6-module-qt-labs-platform qt6-translations-l10n qmlscene-qt6 dtk6-exhibition libqt6sql6-odbc libqt6designercomponents6 libpcre2-posix3 libdtk6widget-dev dde-qt6xcb-plugin libinput-bin libzmq5 liblzma-dev libjbig-dev libpcre2-dev libdtk6gui-dev libqt6waylandclient6 qml6-module-qt-labs-sharedimage qt6-base-dev libdtk6core-bin python3-packaging libssh-gcrypt-4 libxkbcommon-dev libqt6quickvectorimagegenerator6 libbz2-dev mariadb-common qml6-module-qttexttospeech libdtk6gui-bin libflite1 libgme0 libinput-dev lshw x11proto-dev libqt6quicktest6 libgumbo2 libqt6multimediawidgets6 libpng-dev libqt6wlshellintegration6 liblitehtml0 libpcre2-32-0 libqt6quickwidgets6 libxcb-util0-dev libchromaprint1 qml6-module-qtquick-templates libnumber-compare-perl gir1.2-gudev-1.0 qt6-qmllint-plugins qt6-svg-dev libudev-dev libmpg123-0 libqt6quickcontrols2-6 libqt6openglwidgets6 libwayland-dev libqt6concurrent6 fonts-freefont-otf usrmerge libclang1-17 libopengl-dev libtext-glob-perl libevdev-dev qt6-tools-dev libsepol-dev qml6-module-qtqml qt6-qpa-plugins libfcitx5-qt6-1 qt6-wayland designer-qt6 libvorbisfile3 libgudev-1.0-dev libdtk6declarative-dev qdbus-qt6 libfreetype-dev dde-qt6integration qt6-base-dev-tools libgudev-1.0-0 libqt6widgets6 x11proto-core-dev libcjson1 qml6-module-qt-labs-settings qml6-module-qtwayland-client-texturesharing libqt6texttospeech6 libdtk6gui libblkid-dev fonts-freefont-ttf make libmtdev-dev libglib2.0-dev libtiffxx6 assistant-qt6 libfcitx5utils2 libtiff-dev libclang-cpp17 qml6-module-qtqml-xmllistmodel libfmt10 libqt6core5compat6 libfbclient2 fonts-croscore libqt6quick3d6 libqt6uitools6 libdouble-conversion3 zlib1g-dev libxdmcp-dev libqt6sql6-mysql pkgconf-bin qt6-xdgdesktopportal-platformtheme libglib2.0-dev-bin libpthread-stubs0-dev qt6-wayland-dev qmake6 ``` -#### org.deepin.runtime.webengine/25.2.0 +### org.deepin.runtime.webengine/25.2.0 使用 deepin 25 beta 仓库制作的 runtime,支持 x86, arm64, loong64 架构。 diff --git a/docs/pages/guide/start/how_to_use.md b/docs/pages/guide/start/build_your_first_app.md similarity index 97% rename from docs/pages/guide/start/how_to_use.md rename to docs/pages/guide/start/build_your_first_app.md index 179c2361a..e7b656ab6 100644 --- a/docs/pages/guide/start/how_to_use.md +++ b/docs/pages/guide/start/build_your_first_app.md @@ -4,7 +4,7 @@ SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. SPDX-License-Identifier: LGPL-3.0-or-later --> -# 构建如意玲珑应用 +# 构建第一个如意玲珑应用 以 [deepin-calculator](https://github.com/linuxdeepin/deepin-calculator.git) 为例,介绍从源码构建如意玲珑包的过程。 @@ -85,7 +85,7 @@ build: | linglong.yaml 文件遵循 yaml 语法规范。 -linglong.yaml 中字段的详细解释参考:[构建配置文件简介](../ll-builder/manifests.md) +linglong.yaml 中字段的详细解释参考:[构建配置文件简介](../building/manifests.md) ## 构建 diff --git a/docs/pages/guide/start/install.md b/docs/pages/guide/start/install.md index 9b2ecc049..1f3cb9fd0 100644 --- a/docs/pages/guide/start/install.md +++ b/docs/pages/guide/start/install.md @@ -16,17 +16,17 @@ SPDX-License-Identifier: LGPL-3.0-or-later ### release 仓库 - 基于最新tag自动构建 +基于最新tag自动构建 - 1. 仓库地址 - 2. 构建地址 +1. 仓库地址 +2. 构建地址 ### latest 仓库 - 基于最新提交自动构建 +基于最新提交自动构建 - 1. 仓库地址 - 2. 构建地址 +1. 仓库地址 +2. 构建地址 :::tip @@ -34,14 +34,29 @@ SPDX-License-Identifier: LGPL-3.0-or-later ::: -## 安装说明 +## 如意玲珑安装说明 + +### Arch / Manjaro / Parabola Linux + +```sh +sudo pacman -Syu linyaps +``` + +如意玲珑网页商店安装工具需要通过 [AUR 仓库](https://aur.archlinux.org/packages/linyaps-web-store-installer) 或 [自建源仓库](https://github.com/taotieren/aur-repo) 安装。 + +```bash +# AUR +yay -Syu linyaps-web-store-installer +# 或自建源 +sudo pacman -Syu linyaps-web-store-installer +``` ### deepin 25 ```sh echo "deb [trusted=yes] https://ci.deepin.com/repo/obs/linglong:/CI:/release/Deepin_25/ ./" | sudo tee /etc/apt/sources.list.d/linglong.list sudo apt update -sudo apt install linglong-builder linglong-box linglong-bin +sudo apt install linglong-bin linglong-installer ``` ### deepin 23 @@ -49,7 +64,7 @@ sudo apt install linglong-builder linglong-box linglong-bin ```sh echo "deb [trusted=yes] https://ci.deepin.com/repo/obs/linglong:/CI:/release/Deepin_23/ ./" | sudo tee /etc/apt/sources.list.d/linglong.list sudo apt update -sudo apt install linglong-builder linglong-box linglong-bin +sudo apt install linglong-bin linglong-installer ``` ### Fedora 41 @@ -57,7 +72,15 @@ sudo apt install linglong-builder linglong-box linglong-bin ```sh sudo dnf config-manager addrepo --from-repofile "https://ci.deepin.com/repo/obs/linglong:/CI:/release/Fedora_41/linglong%3ACI%3Arelease.repo" sudo dnf update -sudo dnf install linglong-builder linglong-box linglong-bin +sudo dnf install linglong-bin linyaps-web-store-installer +``` + +### Fedora 42 + +```sh +sudo dnf config-manager addrepo --from-repofile "https://ci.deepin.com/repo/obs/linglong:/CI:/release/Fedora_42/linglong%3ACI%3Arelease.repo" +sudo dnf update +sudo dnf install linglong-bin linyaps-web-store-installer ``` ### Ubuntu 24.04 @@ -65,7 +88,7 @@ sudo dnf install linglong-builder linglong-box linglong-bin ```sh echo "deb [trusted=yes] https://ci.deepin.com/repo/obs/linglong:/CI:/release/xUbuntu_24.04/ ./" | sudo tee /etc/apt/sources.list.d/linglong.list sudo apt update -sudo apt install linglong-builder linglong-box linglong-bin +sudo apt install linglong-bin linglong-installer ``` ### Debian 12 @@ -73,7 +96,15 @@ sudo apt install linglong-builder linglong-box linglong-bin ```sh echo "deb [trusted=yes] https://ci.deepin.com/repo/obs/linglong:/CI:/release/Debian_12/ ./" | sudo tee /etc/apt/sources.list.d/linglong.list sudo apt update -sudo apt install linglong-builder linglong-box linglong-bin +sudo apt install linglong-bin linglong-installer +``` + +### Debian 13 + +```sh +echo "deb [trusted=yes] https://ci.deepin.com/repo/obs/linglong:/CI:/release/Debian_13/ ./" | sudo tee /etc/apt/sources.list.d/linglong.list +sudo apt update +sudo apt install linglong-bin linglong-installer ``` ### openEuler 23.09 @@ -82,7 +113,16 @@ sudo apt install linglong-builder linglong-box linglong-bin sudo dnf config-manager --add-repo "https://ci.deepin.com/repo/obs/linglong:/CI:/release/openEuler_23.09/linglong%3ACI%3Arelease.repo" sudo sh -c "echo gpgcheck=0 >> /etc/yum.repos.d/linglong%3ACI%3Arelease.repo" sudo dnf update -sudo dnf install linglong-builder linglong-box linglong-bin +sudo dnf install linglong-bin linyaps-web-store-installer +``` + +### openEuler 24.03 + +```sh +sudo dnf config-manager --add-repo "https://ci.deepin.com/repo/obs/linglong:/CI:/release/openEuler_24.03/linglong%3ACI%3Arelease.repo" +sudo sh -c "echo gpgcheck=0 >> /etc/yum.repos.d/linglong%3ACI%3Arelease.repo" +sudo dnf update +sudo dnf install linglong-bin linyaps-web-store-installer ``` ### UOS 1070 @@ -90,7 +130,7 @@ sudo dnf install linglong-builder linglong-box linglong-bin ```sh echo "deb [trusted=yes] https://ci.deepin.com/repo/obs/linglong:/CI:/release/uos_1070/ ./" | sudo tee /etc/apt/sources.list.d/linglong.list sudo apt update -sudo apt install linglong-builder linglong-box linglong-bin +sudo apt install linglong-bin linglong-installer ``` ### AnolisOS 8 @@ -98,7 +138,7 @@ sudo apt install linglong-builder linglong-box linglong-bin ```sh sudo dnf config-manager addrepo --from-repofile "https://ci.deepin.com/repo/obs/linglong:/CI:/release/AnolisOS_8/linglong%3ACI%3Arelease.repo" sudo dnf update -sudo dnf install linglong-builder linglong-box linglong-bin +sudo dnf install linglong-bin linyaps-web-store-installer ``` ### openkylin 2.0 @@ -106,5 +146,46 @@ sudo dnf install linglong-builder linglong-box linglong-bin ```sh echo "deb [trusted=yes] https://ci.deepin.com/repo/obs/linglong:/CI:/release/openkylin_2.0/ ./" | sudo tee /etc/apt/sources.list.d/linglong.list sudo apt update -sudo apt install linglong-builder linglong-box linglong-bin +sudo apt install linglong-bin linglong-installer +``` + +### NixOS + +在 NixOS 25.11或以上版本中,修改配置文件(一般是`/etc/nixos/configuration.nix`), 添加: + +```nix + services.linyaps.enable = true; +``` + +## 如意玲珑构建工具安装说明 + +### Debian系 + +```bash +sudo apt install linglong-builder +``` + +### RPM系 + +```bash +sudo dnf install linglong-builder +``` + +## 如意玲珑转换工具安装说明 + +### Deepin 23/25 + +```bash +sudo apt install linglong-pica +``` + +### Arch Linux + +通过 [AUR 仓库](https://aur.archlinux.org/packages/linglong-pica) 或 [自建源仓库](https://github.com/taotieren/aur-repo) 安装。 + +```bash +# AUR +yay -Syu linglong-pica +# 或自建源 +sudo pacman -Syu linglong-pica ``` diff --git a/docs/pages/guide/start/release_note.md b/docs/pages/guide/start/release_note.md new file mode 100644 index 000000000..ddb9f5231 --- /dev/null +++ b/docs/pages/guide/start/release_note.md @@ -0,0 +1,98 @@ +# 如意玲珑发布日志 + +--- + +## 1.10 版本 + +### 🚀 **新功能** + +* **GPU 支持:** 应用运行时现在实现了对图形处理器 (GPU) 功能的支持,以提升计算性能和渲染效率。 +* **容器进程管理:** 容器化运行时已增强,能够支持等待其子进程结束,确保资源管理和系统稳定性。 +* **仓库镜像控制:** 仓库配置新增启用和禁用镜像功能,允许用户灵活控制和优化依赖拉取速度。 +* **启动环境变量:** 应用启动命令现在支持使用 `--env` 参数来设置运行时环境变量,方便动态配置和调试。 +* **构建工具导出:** 构建工具已新增 `--ref` 选项,支持按特定引用导出 uab 包,优化了分发和部署流程。 + +### 🐞 **问题修复** + +* **桌面集成:** 修复了更新玲珑组件后,任务栏应用图标可能丢失的逻辑错误。 +* **文件 I/O:** 解决了打开包含特殊字符的文件路径时,导致操作失败的编码和解析问题。 +* **构建文件包含:** 修复了构建工具在导出包时,无法正确包含和导出隐藏文件的问题。 + +--- + +## 1.9 版本 + +### 🚀 **新功能** + +* **容器进程管理优化:** 引入 **`dumb-init`** 作为容器 `init` 进程,负责转发信号并清理僵尸进程,显著优化了容器内部的进程管理效率。 +* **UAB 文件生成重构:** 彻底重构了 UAB 文件的生成逻辑,将所有相关依赖封装到 **`ll-builder-utils`** 工具链中,解决了在部分发行版中导出时的兼容性问题。 +* **Qt 版本兼容:** 项目现已同时支持 **Qt5 和 Qt6**,编译应用时将自动选择合适的 Qt 版本,提升了灵活性。 +* **命令行工具多语言支持:** 命令行工具已支持更多国家和地区的语言,增强了国际化能力。 +* **架构特定配置加载:** 支持通过 **`ll-builder`** 加载架构特定的配置文件(例如 `linglong.arm64.yaml`),实现不同硬件架构的自动适配。 +* **构建产物压缩算法选择:** 玲珑构建工具在导出目标产物时,现在允许用户指定压缩算法。 +* **本地多仓库支持:** 新增支持本地多仓库管理功能,可用于安装和搜索应用。 + +### 🐞 **问题修复** + +* 修复了错误信息提示过于模糊的问题,现在提示更加清晰明了。 +* 修复了应用缓存加载和更新逻辑中的异常问题。 +* 修复了应用运行时,更新任务异常终止的缺陷。 +* 修复了卸载应用时可能发生的异常报错问题。 + +--- + +## 1.8 版本 + +### 🚀 **新功能** + +* **构建能力增强:** + * **依赖管理优化:** 改进了依赖管理机制,支持通过 **APT 包管理器**安装构建工具链的依赖项。 + * **压缩算法扩展:** 应用导出时,现在支持选择更多压缩算法,包括 **LZ4、LZMA 和 ZSTD**。 + * **编译环境升级:** 玲珑客户端现已支持在 **Qt6 环境**下进行构建。 +* **国际化支持:** 命令行工具新增对多种语言的支持,包括英语(en_US/en_GB)、西班牙语(es)、简体中文(zh_CN)、加泰罗尼亚语(ca)、芬兰语(fi)、波兰语(pl)、巴西葡萄牙语(pt_BR)、阿尔巴尼亚语(sq)和乌克兰语(uk)。 + +### 🐞 **问题修复** + +* **稳定性改进:** + * 修复了安装层(layer)后挂载目录未能完全清理的问题。 + * 解决了基础环境(base)与运行时(runtime)组件升级失败的缺陷。 + * 优化了应用卸载逻辑,确保残留目录能够被彻底清除。 +* **符号链接处理机制完善:** 修复了相对路径符号链接被错误地转换为空目录的异常;同时修正了无效符号链接未能被正确复制的问题。 + +--- + +## 1.7 版本 + +### 🚀 **新功能** + +* **仓库存储层结构优化:** 优化了仓库的存储层结构,使得应用管理不再强制依赖文件系统,提升了灵活性。 +* **玲珑数据文件导出优化:** 玲珑数据文件导出功能不再导出 `share` 目录下所有文件,减少了导出体积。 +* **龙芯新世界架构支持:** 如意玲珑现已支持**龙芯新世界架构**下的应用打包和运行。 +* **安装、卸载、更新行为调整优化:** + * 新版本不再支持在本地同时安装同一应用的多个版本。对于客户端升级后仍保留的多个旧版本,除卸载操作外,所有软件包管理操作将仅对最高版本生效。 + * 当应用处于运行状态时进行升级或降级,旧版本的卸载动作将延迟执行,以确保平滑过渡。 +* **如意玲珑命令行工具帮助信息国际化:** 命令行工具的帮助信息已开始国际化,目前支持中文、英文和西班牙语,后续将接入专业的国际化翻译平台。 +* **玲珑命令行参数解析优化:** 采用全新的命令行参数解析框架,使参数信息展示更清晰、易读。 +* **玲珑应用打包构建优化:** 使用新构建工具打包应用时,将剥离应用调试符号,以有效减小最终应用包的体积。 +* **`runtime/base` 管理命令调整:** `runtime/base` 不再支持使用 `uninstall` 命令卸载,转而提供 `prune` 命令用于清理未使用的 `runtime` 和 `base` 组件。 +* **新增 `ll-cli list --upgradable` 命令:** 该命令用于显示当前已安装应用程序的所有可更新版本列表。 + +### 🐞 **问题修复** + +* 解决了玲珑应用调试失败的问题。 +* 修复了在开启系统代理后,使用 `ll-cli search` 命令查找应用时可能导致应用崩溃的缺陷。 + +--- + +## 1.6 版本 + +### 🚀 **新功能** + +* **U 盘目录文件读取:** 玲珑应用现已支持直接读取 U 盘中的目录和文件。 +* **`ll-pica-flatpak` 工具新增:** 新增了 **`ll-pica-flatpak`** 工具,支持将 `Flatpak` 格式的应用程序转换为玲珑格式。 + +### 🐞 **问题修复** + +* 修复了升级玲珑包时脚本执行失败的问题。 +* 修复了在安装玲珑应用时执行其他命令可能被阻塞的缺陷。 +* 修复了应用名称过长时,在查看应用列表时显示不完整的问题。 diff --git a/docs/pages/guide/start/whatis.md b/docs/pages/guide/start/whatis.md index ce41f5b41..fae8fa21a 100644 --- a/docs/pages/guide/start/whatis.md +++ b/docs/pages/guide/start/whatis.md @@ -6,7 +6,7 @@ SPDX-License-Identifier: LGPL-3.0-or-later # 概述 -如意玲珑是统信软件自研的开源软件包格式,用于替代 `deb`、`rpm`等包管理工具,实现了应用包管理、分发、容器、集成开发工具等功能。 +如意玲珑是统信软件自研的开源软件包格式,用于替代 `deb`、`rpm` 等包管理工具,实现了应用包管理、分发、容器、集成开发工具等功能。 ## 当前包管理器存在的问题 @@ -25,30 +25,30 @@ SPDX-License-Identifier: LGPL-3.0-or-later ## 对比 -| 特性 | 如意玲珑 | Flatpak | Snap | AppImage | -| ------------------------- | ------------------------------- | ------------- | ---------------- | --------------------------------------- | -| 打包桌面应用 | ✔ | ✔ | ✔ | ✔ | -| 打包终端应用 | ✔ | ✔ | ✔ | ✔ | -| 处理服务器应用 | ✔ | ✘ | ✔ | ✘ | -| 打包系统服务(root 权限) | ✘ | ✘ | ✔ | ✘ | -| 主题功能正常 | ✔ | ✔ | ✔ | ✔ | -| 提供库托管服务 | ✔ | ✘ | ✘ | ✘ | -| 库/依赖来源 | 包自身携带 | | | | -| 宿主系统 | 包自身携带 | | | | -| SDK | 包自身携带 | | | | -| Snap Base | | | | | -| 商业支持 | ✔ | ✘ | ✔ | ✘ | -| 应用商店数量 | 预计 3000+ | 1400+ | 6600+ | 1300+ | -| 开发工具支持 | | GNOME Builder | electron-builder | | +| 特性 | 如意玲珑 | Flatpak | Snap | AppImage | +| ------------------------- | ------------------------------- | ------------- | ---------------- | -------------------------------------- | +| 打包桌面应用 | ✔ | ✔ | ✔ | ✔ | +| 打包终端应用 | ✔ | ✔ | ✔ | ✔ | +| 处理服务器应用 | ✔ | ✘ | ✔ | ✘ | +| 打包系统服务(root 权限) | ✘ | ✘ | ✔ | ✘ | +| 主题功能正常 | ✔ | ✔ | ✔ | ✔ | +| 提供库托管服务 | ✔ | ✘ | ✘ | ✘ | +| 库/依赖来源 | 包自身携带 | | | | +| 宿主系统 | 包自身携带 | | | | +| SDK | 包自身携带 | | | | +| Snap Base | | | | | +| 商业支持 | ✔ | ✘ | ✔ | ✘ | +| 应用商店数量 | 预计 4700+ | 1400+ | 6600+ | 1300+ | +| 开发工具支持 | linglong-builder | GNOME Builder | electron-builder | | | 容器支持 | ✔ | ✔ | ✔ | ◐ (官方不提供,技术上可行) | -| rootless 容器 | ✔ | ✘ | ✘ | ✘ | -| 不安装运行 | ✔ (提供 Bundle 模式) | ✘ | ✘ | ✔ | -| 不解压运行 | ✔ (提供 Bundle 模式) | ✘ | ✔ | ✔ | -| 自分发/绿色格式分发 | ◐ (技术可行,但是系统做限制) | ✘ | ✘ | ✔ | -| 支持 Wine 应用运行 | ◐   (适配中) | ◐ (理论可行 | ◐ (理论可行) | ◐ (使用 LD 修改 open 调用,兼容性差) | -| 离线环境支持 | ✔ | ✔ | ✔ | ✔ | +| rootless 容器 | ✔ | ✘ | ✘ | ✘ | +| 不安装运行 | ✔ (提供 Bundle 模式) | ✘ | ✘ | ✔ | +| 不解压运行 | ✔ (提供 Bundle 模式) | ✘ | ✔ | ✔ | +| 自分发/绿色格式分发 | ✔ | ✘ | ✘ | ✔ | +| 支持 Wine 应用运行 | ✔  | ◐ (理论可行 | ◐ (理论可行) | ◐ (使用 LD 修改 open 调用,兼容性差) | +| 离线环境支持 | ✔ | ✔ | ✔ | ✔ | | 权限管理 | ✔ | ✔ | ✔ | ✘ | -| 中心仓库 | mirror-repo-linglong.deepin.com | FlatHub | Snap Store | AppImageHub | -| 多版本共存 | ✔ | ✔ | ✔ | ✔ | -| 点对点分发 | ✔ | ✔ | ✔ | ✔ | -| 应用升级 | 仓库升级 | 仓库升级 | 仓库升级 | 官方工具升级 | +| 中心仓库 | mirror-repo-linglong.deepin.com | FlatHub | Snap Store | AppImageHub | +| 多版本共存 | ✔ | ✔ | ✔ | ✔ | +| 点对点分发 | ✔ | ✔ | ✔ | ✔ | +| 应用升级 | 仓库升级 | 仓库升级 | 仓库升级 | 官方工具升级 | diff --git a/docs/pages/guide/debug/faq.md b/docs/pages/guide/tips-and-faq/faq.md similarity index 94% rename from docs/pages/guide/debug/faq.md rename to docs/pages/guide/tips-and-faq/faq.md index b00bfab73..76e49629b 100644 --- a/docs/pages/guide/debug/faq.md +++ b/docs/pages/guide/tips-and-faq/faq.md @@ -9,64 +9,83 @@ SPDX-License-Identifier: LGPL-3.0-or-later 1. 应用运行读取 `/usr/share`下应用安装资源文件,为什么读取失败? 如意玲珑应用是在容器环境中运行,应用数据会挂载到 `/opt/apps/`/下,`/usr/share`目录下只会存在系统数据,不会存在应用相关数据。因此直接读取 `/usr/share` 会失败。建议处理:采用 `XDG_DATA_DIRS` 环境变量读取资源,`/opt/apps//files/share`会存在在此环境变量搜索路径中。 + 2. 应用运行时找不到字体库文件?为什么 `deb`包安装时能读取到对应的字体库? `deb`包安装时,会依赖带入对应的字体库文件。而如意玲珑包格式采用自给自足打包格式。除了基本的系统库,`runtime`里面提供的 `Qt`库与 `DTK`库文件不用自己提供外,其他依赖数据文件,均需自己提供。建议对应的数据文件放入 `files/share`下,采用环境变量 `XDG_DATA_DIRS`读取路径。 + 3. 如意玲珑应用 `runtime`里面有什么?能不能往里面添加一些库文件进去? 目前如意玲珑应用依赖的 `runtime`里面提供的是 `Qt`库与 `DTK`库。因 `runtime`有严格的大小限制。目前不允许往 `runtime`里面添加额外的库文件。 + 4. 应用在容器内运行,运行过程中能不能往容器任意路径下创建配置文件? 可以在 `XDG_CONFIG_HOME` 下创建配置文件。 + 5. 应用数据保存到哪里?在容器外哪里能找到? 因如意玲珑应用遵循互不干涉原则,`XDG_DATA_HOME`、`XDG_CONFIG_HOME`、`XDG_CACHE_HOME`环境变量被定义到宿主机 `~/.linglong/`/对应的路径下,因此用户应用数据会保存在此路径下,应用运行过程中写入数据时,也应该读取对应的环境变量写入数据。禁止读写其它应用的配置。 + 6. 应用提供了 `dbus service`文件,如何放置?`Exec`字段写什么? 应用提供 `dbus service`文件时,需要放到 `entries/dbus-1/services`目录下,如果 `Exec`执行如意玲珑包内二进制,使用 `--exec`选项参数执行对应的二进制。 + 7. 应用安装后,启动器无法找到? TryExec=xxx, 当xxx 在 $PATH 路径中不存在时,会认为该应用不存在不予显示。 + 8. 为什么图标显示为小黑点? desktop 写了 Icon 字段,Icon 字段名称错误或者使用了绝对路径。 + 9. 为什么图标显示为齿轮? desktop 未提供 Icon 字段。 + 10. 图标存放在哪个路径? - svg → $PREFIX/share/icons/hicolor/scalable/apps/ + svg → $PREFIX/share/icons/hicolor/scalable/apps/ 其他格式按分辨率存放,如16X16 png/xpm → $PREFIX/share/icons/hicolor/16X16/apps/ + 11. 应用自带的 `xdg-open`、`xdg-email`为什么失效? `runtime`中如意玲珑特殊处理了 `xdg-open`、`xdg-email`,因此应用禁止执行自己携带的xdg-open、xdg-email可执行文件或者脚本。 + 12. 应用使用系统环境变量未生效,为什么? 当使用环境变量时,需要确认容器内是否存在对应的环境变量,如果没有,需要联系如意玲珑团队处理。 + 13. 应用运行需要的库文件没找到,如何提供? 应用需要使用的资源文件,与库文件需要应用自身提供。库文件放到 `$PREFIX/lib` 路径下。 + 14. 应用运行时,为什么 `Qt WebEngine`渲染进程已崩溃? 因系统升级了 `glibc`,导致应用使用内置浏览器时失败,需要应用重新适配。临时解决方案是设置环境变量:`export QTWEBENGINE_DISABLE_SANDBOX=1`。 + 15. 应用运行时,找不到 `libqxcb.so`库或者 `qtwebengine` 报错? 存在 `qt.conf`文件时,在文件中配置正确路径,或者使用 `QTWEBENGINEPROCESS_PATH`、`QTWEBENGINE_RESOURCES_PATH`、`QT_QPA_PLATFORM_PLUGIN_PATH`、`QT_PLUGIN_PATH`环境变量配置搜索路径。 + 16. 应用能否自己携带数据库文件,并在运行中往数据库中写入数据? 容器内文件系统是只读文件系统,不允许往应用资源文件中写入数据。 + 17. 为什么执行携带 `suid`、`guid`权限二进制失效? 如意玲珑容器为保证系统安全,容器内禁止执行此类权限二进制。 + 18. uab离线包格式在 Debian、Ubuntu 下输入法无法使用? 建议安装 `fictx`输入法后体验。 + 19. 怎么知道容器环境中安装了哪些包? - `ll-builder run --exec bash` 进入容器环境,使用 `cat /var/lib/dpkg/status | grep "^Package: "` 命令查看预装的软件包,另外源码编译的库可以使用 `cat /runtime/packages.list` 查看。 + `ll-builder run --exec bash` 进入容器环境,使用 `cat /var/lib/dpkg/status | grep "^Package: "` 命令查看预装的软件包,另外源码编译的库可以使用 `cat /runtime/packages.list` 查看。 + 20. 应用启动后,为什么不显示应用托盘? 这可能是由应用注册托盘使用了相同的服务名,按照 KDE/freedesktop StatusNotifierItem 规范应用注册服务名为 org.kdeStatusNotifierItem-``-``,在如意玲珑应用中,应用运行时的 pid 为19,可以通过以下命令查看是否有注册过的服务,`dbus-send --session --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.NameHasOwner string:org.kde.StatusNotifierItem-19-1`,如果存在 `boolean true` 说明服务被注册过。 diff --git a/docs/pages/guide/debug/images/ll-box-start-failed.png b/docs/pages/guide/tips-and-faq/images/ll-box-start-failed.png similarity index 100% rename from docs/pages/guide/debug/images/ll-box-start-failed.png rename to docs/pages/guide/tips-and-faq/images/ll-box-start-failed.png diff --git a/docs/pages/guide/debug/images/ll-box-start-failed.png.license b/docs/pages/guide/tips-and-faq/images/ll-box-start-failed.png.license similarity index 100% rename from docs/pages/guide/debug/images/ll-box-start-failed.png.license rename to docs/pages/guide/tips-and-faq/images/ll-box-start-failed.png.license diff --git a/docs/pages/guide/tips-and-faq/ll-builder-faq.md b/docs/pages/guide/tips-and-faq/ll-builder-faq.md new file mode 100644 index 000000000..bcfb4ae00 --- /dev/null +++ b/docs/pages/guide/tips-and-faq/ll-builder-faq.md @@ -0,0 +1,31 @@ + + +# 常见构建问题 + +1. `cmake`类型构建,出现`-lxxx`失败,但`ldconfig`与`pkg-config`均能查询到该库信息。 + + 链接库路径不在常规路径,新路径为`/runtime/lib`。 + + 添加环境变量 `LIBRARY_PATH=`,目前构建环境已默认包含该环境变量。 + +2. 构建时`link`静态库失败,要求重新使用`fPIC`构建。 + + 构建静态库时使用`-fPIC`参数。 + +3. 构建时启动`box`失败,如下图: + + ![ll-box启动失败](images/ll-box-start-failed.png) + + 内核不支持`unprivilege namespace`,开启`unprivilege namespace`解决。 + + ```bash + sudo sysctl -w kernel.unprivileged_userns_clone=1 + ``` + +4. `qtbase`构建成功,但无法构建`qt`应用,提示`module,mkspec` 相关错误。 + + 低版本`fuse-overlay mount`存在问题,导致`qtbase commit`时文件内容被污染 ,无法正常使用。使用`fuse-overlayfs >= 1.7`版本。 diff --git a/docs/pages/guide/debug/ll-pica-faq.md b/docs/pages/guide/tips-and-faq/ll-pica-faq.md similarity index 99% rename from docs/pages/guide/debug/ll-pica-faq.md rename to docs/pages/guide/tips-and-faq/ll-pica-faq.md index 340ddc7cb..c526f86b9 100644 --- a/docs/pages/guide/debug/ll-pica-faq.md +++ b/docs/pages/guide/tips-and-faq/ll-pica-faq.md @@ -3,15 +3,17 @@ 1. ll-pica 生成的 linglong.yaml 文件的默认配置在哪里? ll-pica 配置文件在 `~/.pica/config.json`。 + 2. ll-pica 无法转换,wine、安卓、输入法、安全类软件吗? 如意玲珑应用目前不支持这类应用,ll-pica 也无法转换。 + 3. 为什么需要使用音频的软件没有声音? 提示 not found libpulsecommon-12.2.so 可以在linglong.yaml 文件build 字段的里面,添加一行 `mv $PREFIX/lib/$TRIPLET/pulseaudio/* $PREFIX/lib/$TRIPLET`。 + 4. 为什么生成出来的 linglong.yaml 文件中 command 字段是空的? ll-pica 是通过读取,deb 包中的 desktop 文件里来获取 Exec 字段,如果 command 为空,请检查 deb 包中的 desktop 文件路径是否在以下路径。 - - /opt/apps/$appid/entries/applications - /usr/share/applications diff --git a/docs/test/unit-testing.md b/docs/test/unit-testing.md deleted file mode 100644 index b0846dfa3..000000000 --- a/docs/test/unit-testing.md +++ /dev/null @@ -1,11 +0,0 @@ -# Unit Testing - -Linglong use gtest for unit test, just pull test code and testdata in test/ directory of project root. - -Seem some test is hard to run in ci envionment, we disable it by default. - -Here are some envionment variables to control if test run, all of them are empty by default. - -|name| vaule| -|-|-| -|LINGLONG_TEST_ALL|If set, will run all unit testing. | \ No newline at end of file diff --git a/external/CLI11/.all-contributorsrc b/external/CLI11/.all-contributorsrc deleted file mode 100644 index 14ba0211e..000000000 --- a/external/CLI11/.all-contributorsrc +++ /dev/null @@ -1,701 +0,0 @@ -{ - "projectName": "CLI11", - "projectOwner": "CLIUtils", - "repoType": "github", - "repoHost": "https://github.com", - "files": [ - "README.md" - ], - "imageSize": 100, - "commit": true, - "commitConvention": "atom", - "contributors": [ - { - "login": "henryiii", - "name": "Henry Schreiner", - "avatar_url": "https://avatars1.githubusercontent.com/u/4616906?v=4", - "profile": "http://iscinumpy.gitlab.io", - "contributions": [ - "bug", - "doc", - "code" - ] - }, - { - "login": "phlptp", - "name": "Philip Top", - "avatar_url": "https://avatars0.githubusercontent.com/u/20667153?v=4", - "profile": "https://github.com/phlptp", - "contributions": [ - "bug", - "doc", - "code" - ] - }, - { - "login": "cbachhuber", - "name": "Christoph Bachhuber", - "avatar_url": "https://avatars0.githubusercontent.com/u/27212661?v=4", - "profile": "https://www.linkedin.com/in/cbachhuber/", - "contributions": [ - "example", - "code" - ] - }, - { - "login": "lambdafu", - "name": "Marcus Brinkmann", - "avatar_url": "https://avatars1.githubusercontent.com/u/1138455?v=4", - "profile": "https://lambdafu.net/", - "contributions": [ - "bug", - "code" - ] - }, - { - "login": "SkyToGround", - "name": "Jonas Nilsson", - "avatar_url": "https://avatars1.githubusercontent.com/u/58835?v=4", - "profile": "https://github.com/SkyToGround", - "contributions": [ - "bug", - "code" - ] - }, - { - "login": "dvj", - "name": "Doug Johnston", - "avatar_url": "https://avatars2.githubusercontent.com/u/77217?v=4", - "profile": "https://github.com/dvj", - "contributions": [ - "bug", - "code" - ] - }, - { - "login": "lczech", - "name": "Lucas Czech", - "avatar_url": "https://avatars0.githubusercontent.com/u/4741887?v=4", - "profile": "http://lucas-czech.de", - "contributions": [ - "bug", - "code" - ] - }, - { - "login": "rafiw", - "name": "Rafi Wiener", - "avatar_url": "https://avatars3.githubusercontent.com/u/3034707?v=4", - "profile": "https://github.com/rafiw", - "contributions": [ - "bug", - "code" - ] - }, - { - "login": "mensinda", - "name": "Daniel Mensinger", - "avatar_url": "https://avatars3.githubusercontent.com/u/3407462?v=4", - "profile": "https://github.com/mensinda", - "contributions": [ - "platform" - ] - }, - { - "login": "jbriales", - "name": "Jesus Briales", - "avatar_url": "https://avatars1.githubusercontent.com/u/6850478?v=4", - "profile": "https://github.com/jbriales", - "contributions": [ - "code", - "bug" - ] - }, - { - "login": "seanfisk", - "name": "Sean Fisk", - "avatar_url": "https://avatars0.githubusercontent.com/u/410322?v=4", - "profile": "https://seanfisk.com/", - "contributions": [ - "bug", - "code" - ] - }, - { - "login": "fpeng1985", - "name": "fpeng1985", - "avatar_url": "https://avatars1.githubusercontent.com/u/87981?v=4", - "profile": "https://github.com/fpeng1985", - "contributions": [ - "code" - ] - }, - { - "login": "almikhayl", - "name": "almikhayl", - "avatar_url": "https://avatars2.githubusercontent.com/u/6747040?v=4", - "profile": "https://github.com/almikhayl", - "contributions": [ - "code", - "platform" - ] - }, - { - "login": "andrew-hardin", - "name": "Andrew Hardin", - "avatar_url": "https://avatars0.githubusercontent.com/u/16496326?v=4", - "profile": "https://github.com/andrew-hardin", - "contributions": [ - "code" - ] - }, - { - "login": "SX91", - "name": "Anton", - "avatar_url": "https://avatars2.githubusercontent.com/u/754754?v=4", - "profile": "https://github.com/SX91", - "contributions": [ - "code" - ] - }, - { - "login": "helmesjo", - "name": "Fred Helmesjö", - "avatar_url": "https://avatars0.githubusercontent.com/u/2501070?v=4", - "profile": "https://github.com/helmesjo", - "contributions": [ - "bug", - "code" - ] - }, - { - "login": "skannan89", - "name": "Kannan", - "avatar_url": "https://avatars0.githubusercontent.com/u/11918764?v=4", - "profile": "https://github.com/skannan89", - "contributions": [ - "bug", - "code" - ] - }, - { - "login": "kraj", - "name": "Khem Raj", - "avatar_url": "https://avatars3.githubusercontent.com/u/465279?v=4", - "profile": "http://himvis.com", - "contributions": [ - "code" - ] - }, - { - "login": "mogigoma", - "name": "Mak Kolybabi", - "avatar_url": "https://avatars2.githubusercontent.com/u/130862?v=4", - "profile": "https://www.mogigoma.com/", - "contributions": [ - "doc" - ] - }, - { - "login": "msoeken", - "name": "Mathias Soeken", - "avatar_url": "https://avatars0.githubusercontent.com/u/1998245?v=4", - "profile": "http://msoeken.github.io", - "contributions": [ - "doc" - ] - }, - { - "login": "nathanhourt", - "name": "Nathan Hourt", - "avatar_url": "https://avatars2.githubusercontent.com/u/271977?v=4", - "profile": "https://github.com/nathanhourt", - "contributions": [ - "bug", - "code" - ] - }, - { - "login": "pleroux0", - "name": "Paul le Roux", - "avatar_url": "https://avatars2.githubusercontent.com/u/39619854?v=4", - "profile": "https://github.com/pleroux0", - "contributions": [ - "code", - "platform" - ] - }, - { - "login": "chfast", - "name": "Paweł Bylica", - "avatar_url": "https://avatars1.githubusercontent.com/u/573380?v=4", - "profile": "https://github.com/chfast", - "contributions": [ - "platform" - ] - }, - { - "login": "peterazmanov", - "name": "Peter Azmanov", - "avatar_url": "https://avatars0.githubusercontent.com/u/15322318?v=4", - "profile": "https://github.com/peterazmanov", - "contributions": [ - "code" - ] - }, - { - "login": "delpinux", - "name": "Stéphane Del Pino", - "avatar_url": "https://avatars0.githubusercontent.com/u/35096584?v=4", - "profile": "https://github.com/delpinux", - "contributions": [ - "code" - ] - }, - { - "login": "metopa", - "name": "Viacheslav Kroilov", - "avatar_url": "https://avatars2.githubusercontent.com/u/3974178?v=4", - "profile": "https://github.com/metopa", - "contributions": [ - "code" - ] - }, - { - "login": "ChristosT", - "name": "christos", - "avatar_url": "https://avatars0.githubusercontent.com/u/6725596?v=4", - "profile": "http://cs.odu.edu/~ctsolakis", - "contributions": [ - "code" - ] - }, - { - "login": "deining", - "name": "deining", - "avatar_url": "https://avatars3.githubusercontent.com/u/18169566?v=4", - "profile": "https://github.com/deining", - "contributions": [ - "doc" - ] - }, - { - "login": "elszon", - "name": "elszon", - "avatar_url": "https://avatars0.githubusercontent.com/u/2971495?v=4", - "profile": "https://github.com/elszon", - "contributions": [ - "code" - ] - }, - { - "login": "ncihnegn", - "name": "ncihnegn", - "avatar_url": "https://avatars3.githubusercontent.com/u/12021721?v=4", - "profile": "https://github.com/ncihnegn", - "contributions": [ - "code" - ] - }, - { - "login": "nurelin", - "name": "nurelin", - "avatar_url": "https://avatars3.githubusercontent.com/u/5276274?v=4", - "profile": "https://github.com/nurelin", - "contributions": [ - "code" - ] - }, - { - "login": "ryan4729", - "name": "ryan4729", - "avatar_url": "https://avatars3.githubusercontent.com/u/40183301?v=4", - "profile": "https://github.com/ryan4729", - "contributions": [ - "test" - ] - }, - { - "login": "slurps-mad-rips", - "name": "Isabella Muerte", - "avatar_url": "https://avatars0.githubusercontent.com/u/63051?v=4", - "profile": "https://izzys.casa", - "contributions": [ - "platform" - ] - }, - { - "login": "KOLANICH", - "name": "KOLANICH", - "avatar_url": "https://avatars1.githubusercontent.com/u/240344?v=4", - "profile": "https://github.com/KOLANICH", - "contributions": [ - "platform" - ] - }, - { - "login": "jgerityneurala", - "name": "James Gerity", - "avatar_url": "https://avatars2.githubusercontent.com/u/57360646?v=4", - "profile": "https://github.com/jgerityneurala", - "contributions": [ - "doc" - ] - }, - { - "login": "jsoref", - "name": "Josh Soref", - "avatar_url": "https://avatars0.githubusercontent.com/u/2119212?v=4", - "profile": "https://github.com/jsoref", - "contributions": [ - "tool" - ] - }, - { - "login": "geir-t", - "name": "geir-t", - "avatar_url": "https://avatars3.githubusercontent.com/u/35292136?v=4", - "profile": "https://github.com/geir-t", - "contributions": [ - "platform" - ] - }, - { - "login": "certik", - "name": "Ondřej Čertík", - "avatar_url": "https://avatars3.githubusercontent.com/u/20568?v=4", - "profile": "https://ondrejcertik.com/", - "contributions": [ - "bug" - ] - }, - { - "login": "samhocevar", - "name": "Sam Hocevar", - "avatar_url": "https://avatars2.githubusercontent.com/u/245089?v=4", - "profile": "http://sam.hocevar.net/", - "contributions": [ - "code" - ] - }, - { - "login": "rcurtin", - "name": "Ryan Curtin", - "avatar_url": "https://avatars0.githubusercontent.com/u/1845039?v=4", - "profile": "http://www.ratml.org/", - "contributions": [ - "doc" - ] - }, - { - "login": "mbhall88", - "name": "Michael Hall", - "avatar_url": "https://avatars3.githubusercontent.com/u/20403931?v=4", - "profile": "https://mbh.sh", - "contributions": [ - "doc" - ] - }, - { - "login": "ferdymercury", - "name": "ferdymercury", - "avatar_url": "https://avatars3.githubusercontent.com/u/10653970?v=4", - "profile": "https://github.com/ferdymercury", - "contributions": [ - "doc" - ] - }, - { - "login": "jakoblover", - "name": "Jakob Lover", - "avatar_url": "https://avatars0.githubusercontent.com/u/14160441?v=4", - "profile": "https://github.com/jakoblover", - "contributions": [ - "code" - ] - }, - { - "login": "ZeeD26", - "name": "Dominik Steinberger", - "avatar_url": "https://avatars2.githubusercontent.com/u/2487468?v=4", - "profile": "https://github.com/ZeeD26", - "contributions": [ - "code" - ] - }, - { - "login": "dfleury2", - "name": "D. Fleury", - "avatar_url": "https://avatars1.githubusercontent.com/u/4805384?v=4", - "profile": "https://github.com/dfleury2", - "contributions": [ - "code" - ] - }, - { - "login": "dbarowy", - "name": "Dan Barowy", - "avatar_url": "https://avatars3.githubusercontent.com/u/573142?v=4", - "profile": "https://github.com/dbarowy", - "contributions": [ - "doc" - ] - }, - { - "login": "paddy-hack", - "name": "Olaf Meeuwissen", - "avatar_url": "https://avatars.githubusercontent.com/u/6804372?v=4", - "profile": "https://github.com/paddy-hack", - "contributions": [ - "code" - ] - }, - { - "login": "dryleev", - "name": "dryleev", - "avatar_url": "https://avatars.githubusercontent.com/u/83670813?v=4", - "profile": "https://github.com/dryleev", - "contributions": [ - "code" - ] - }, - { - "login": "AnticliMaxtic", - "name": "Max", - "avatar_url": "https://avatars.githubusercontent.com/u/43995389?v=4", - "profile": "https://github.com/AnticliMaxtic", - "contributions": [ - "code" - ] - }, - { - "login": "alexdewar", - "name": "Alex Dewar", - "avatar_url": "https://avatars.githubusercontent.com/u/23149834?v=4", - "profile": "https://profiles.sussex.ac.uk/p281168-alex-dewar/publications", - "contributions": [ - "code" - ] - }, - { - "login": "trokhymchuk", - "name": "Artem Trokhymchuk ", - "avatar_url": "https://avatars.githubusercontent.com/u/66204814?v=4", - "profile": "https://github.com/trokhymchuk", - "contributions": [ - "code" - ] - }, - { - "login": "dherrera-fb", - "name": "dherrera-fb", - "avatar_url": "https://avatars.githubusercontent.com/u/89840711?v=4", - "profile": "https://github.com/dherrera-fb", - "contributions": [ - "code" - ] - }, - { - "login": "VolkerChristian", - "name": "Volker Christian", - "avatar_url": "https://avatars.githubusercontent.com/u/18554540?v=4", - "profile": "https://github.com/VolkerChristian", - "contributions": [ - "code" - ] - }, - { - "login": "thewtex", - "name": "Matt McCormick", - "avatar_url": "https://avatars.githubusercontent.com/u/25432?v=4", - "profile": "https://www.mmmccormick.com/", - "contributions": [ - "code" - ] - }, - { - "login": "polistern", - "name": "polistern", - "avatar_url": "https://avatars.githubusercontent.com/u/55511995?v=4", - "profile": "http://polistern.i2p/", - "contributions": [ - "code" - ] - }, - { - "login": "andreasxp", - "name": "Andrey Zhukov", - "avatar_url": "https://avatars.githubusercontent.com/u/28830446?v=4", - "profile": "https://github.com/andreasxp", - "contributions": [ - "code" - ] - }, - { - "login": "SherlockInSpace", - "name": "Ryan Sherlock", - "avatar_url": "https://avatars.githubusercontent.com/u/5507786?v=4", - "profile": "https://github.com/SherlockInSpace", - "contributions": [ - "code" - ] - }, - { - "login": "Krzmbrzl", - "name": "Robert Adam", - "avatar_url": "https://avatars.githubusercontent.com/u/12751591?v=4", - "profile": "https://github.com/Krzmbrzl", - "contributions": [ - "code" - ] - }, - { - "login": "RangeMachine", - "name": "RangeMachine", - "avatar_url": "https://avatars.githubusercontent.com/u/11577601?v=4", - "profile": "https://github.com/RangeMachine", - "contributions": [ - "code" - ] - }, - { - "login": "ptheywood", - "name": "Peter Heywood", - "avatar_url": "https://avatars.githubusercontent.com/u/628937?v=4", - "profile": "http://ptheywood.uk/", - "contributions": [ - "code" - ] - }, - { - "login": "peterh", - "name": "Peter Harris", - "avatar_url": "https://avatars.githubusercontent.com/u/79339?v=4", - "profile": "https://github.com/peterh", - "contributions": [ - "code" - ] - }, - { - "login": "PeteAudinate", - "name": "PeteAudinate", - "avatar_url": "https://avatars.githubusercontent.com/u/99274874?v=4", - "profile": "https://github.com/PeteAudinate", - "contributions": [ - "code" - ] - }, - { - "login": "captainurist", - "name": "captainurist", - "avatar_url": "https://avatars.githubusercontent.com/u/73941350?v=4", - "profile": "https://github.com/captainurist", - "contributions": [ - "code" - ] - }, - { - "login": "djerius", - "name": "djerius", - "avatar_url": "https://avatars.githubusercontent.com/u/196875?v=4", - "profile": "https://github.com/djerius", - "contributions": [ - "code" - ] - }, - { - "login": "shameekganguly", - "name": "shameekganguly", - "avatar_url": "https://avatars.githubusercontent.com/u/2412842?v=4", - "profile": "https://github.com/shameekganguly", - "contributions": [ - "code" - ] - }, - { - "login": "ayum", - "name": "ayum", - "avatar_url": "https://avatars.githubusercontent.com/u/6747040?v=4", - "profile": "https://github.com/ayum", - "contributions": [ - "code" - ] - }, - { - "login": "BenjaminBeichler", - "name": "Benjamin Beichler", - "avatar_url": "https://avatars.githubusercontent.com/u/1441492?v=4", - "profile": "https://github.com/BenjaminBeichler", - "contributions": [ - "code" - ] - }, - { - "login": "DarkWingMcQuack", - "name": "DarkWingMcQuack", - "avatar_url": "https://avatars.githubusercontent.com/u/38857302?v=4", - "profile": "https://github.com/DarkWingMcQuack", - "contributions": [ - "code" - ] - }, - { - "login": "eli-schwartz", - "name": "Eli Schwartz", - "avatar_url": "https://avatars.githubusercontent.com/u/6551424?v=4", - "profile": "https://github.com/eli-schwartz", - "contributions": [ - "code" - ] - }, - { - "login": "bruxisma", - "name": "Izzy Muerte", - "avatar_url": "https://avatars.githubusercontent.com/u/63051?v=4", - "profile": "https://izzys.casa/", - "contributions": [ - "code" - ] - }, - { - "login": "j-rivero", - "name": "Jose Luis Rivero", - "avatar_url": "https://avatars.githubusercontent.com/u/2098802?v=4", - "profile": "https://github.com/j-rivero", - "contributions": [ - "code" - ] - }, - { - "login": "looopTools", - "name": "Lars Nielsen", - "avatar_url": "https://avatars.githubusercontent.com/u/1943536?v=4", - "profile": "https://github.com/looopTools", - "contributions": [ - "code" - ] - }, - { - "login": "cetius", - "name": "Marcin Ropa", - "avatar_url": "https://avatars.githubusercontent.com/u/6552472?v=4", - "profile": "https://github.com/cetius", - "contributions": [ - "code" - ] - }, - { - "login": "nathanielhourt", - "name": "Nathaniel Hourt", - "avatar_url": "https://avatars.githubusercontent.com/u/271977?v=4", - "profile": "https://github.com/nathanielhourt", - "contributions": [ - "code" - ] - } - ], - "contributorsSortAlphabetically": true, - "contributorsPerLine": 7, - "skipCi": true, - "commitType": "docs" -} diff --git a/external/CLI11/.ci/azure-build.yml b/external/CLI11/.ci/azure-build.yml deleted file mode 100644 index 04ee5d6be..000000000 --- a/external/CLI11/.ci/azure-build.yml +++ /dev/null @@ -1,23 +0,0 @@ -steps: - # Needed on GCC 4.8 docker image for some reason - - script: mkdir build - displayName: "Make build directory" - - - task: CMake@1 - inputs: - cmakeArgs: - .. -DCLI11_WARNINGS_AS_ERRORS=ON -DCLI11_SINGLE_FILE=$(cli11.single) - -DCMAKE_CXX_STANDARD=$(cli11.std) - -DCLI11_SINGLE_FILE_TESTS=$(cli11.single) - -DCMAKE_BUILD_TYPE=$(cli11.build_type) $(cli11.options) - displayName: "Configure" - - - script: cmake --build . -- -j2 --keep-going - displayName: "Build Unix" - workingDirectory: build - condition: ne( variables['Agent.OS'], 'Windows_NT' ) - - - script: cmake --build . - displayName: "Build Windows" - workingDirectory: build - condition: eq( variables['Agent.OS'], 'Windows_NT' ) diff --git a/external/CLI11/.ci/azure-cmake-new.yml b/external/CLI11/.ci/azure-cmake-new.yml deleted file mode 100644 index 56a2fb4d9..000000000 --- a/external/CLI11/.ci/azure-cmake-new.yml +++ /dev/null @@ -1,17 +0,0 @@ -steps: - # Note that silkeh/clang does not include ca-certificates, so check the shasum for verification - - bash: | - wget --no-check-certificate "https://cmake.org/files/v3.28/cmake-3.28.0-linux-x86_64.tar.gz" - echo "898f0b5ca6e2ea5286998e97bd33f030d7d09f18ca4b88be661fdfbad5dadd88 cmake-3.28.0-linux-x86_64.tar.gz" | shasum -sca 256 - displayName: Download CMake - - - task: ExtractFiles@1 - inputs: - archiveFilePatterns: "cmake*.tar.gz" - destinationFolder: "cmake_program" - displayName: Extract CMake - - - bash: - echo - "##vso[task.prependpath]$(Build.SourcesDirectory)/cmake_program/cmake-3.28.0-linux-x86_64/bin" - displayName: Add CMake to PATH diff --git a/external/CLI11/.ci/azure-cmake.yml b/external/CLI11/.ci/azure-cmake.yml deleted file mode 100644 index a2f3d983a..000000000 --- a/external/CLI11/.ci/azure-cmake.yml +++ /dev/null @@ -1,17 +0,0 @@ -steps: - # Note that silkeh/clang does not include ca-certificates, so check the shasum for verification - - bash: | - wget --no-check-certificate "https://cmake.org/files/v3.14/cmake-3.14.3-Linux-x86_64.tar.gz" - echo "29faa62fb3a0b6323caa3d9557e1a5f1205614c0d4c5c2a9917f16a74f7eff68 cmake-3.14.3-Linux-x86_64.tar.gz" | shasum -sca 256 - displayName: Download CMake - - - task: ExtractFiles@1 - inputs: - archiveFilePatterns: "cmake*.tar.gz" - destinationFolder: "cmake_program" - displayName: Extract CMake - - - bash: - echo - "##vso[task.prependpath]$(Build.SourcesDirectory)/cmake_program/cmake-3.14.3-Linux-x86_64/bin" - displayName: Add CMake to PATH diff --git a/external/CLI11/.ci/azure-test.yml b/external/CLI11/.ci/azure-test.yml deleted file mode 100644 index c9dc9a280..000000000 --- a/external/CLI11/.ci/azure-test.yml +++ /dev/null @@ -1,9 +0,0 @@ -steps: - - script: ctest --output-on-failure -C $(cli11.build_type) -T test - displayName: "Test" - workingDirectory: build - - - task: PublishTestResults@2 - inputs: - testResultsFormat: "cTest" - testResultsFiles: "**/Test.xml" diff --git a/external/CLI11/.clang-format b/external/CLI11/.clang-format deleted file mode 100644 index 6a5d1063d..000000000 --- a/external/CLI11/.clang-format +++ /dev/null @@ -1,86 +0,0 @@ -Language: Cpp -BasedOnStyle: LLVM -# AccessModifierOffset: -2 -# AlignAfterOpenBracket: Align -# AlignConsecutiveAssignments: false -# AlignConsecutiveDeclarations: false -# AlignEscapedNewlinesLeft: false -# AlignOperands: true -# AlignTrailingComments: true -# AllowAllParametersOfDeclarationOnNextLine: true -# AllowShortBlocksOnASingleLine: false -# AllowShortCaseLabelsOnASingleLine: false -# AllowShortFunctionsOnASingleLine: All -# AllowShortIfStatementsOnASingleLine: false -# AllowShortLoopsOnASingleLine: false -# AlwaysBreakAfterDefinitionReturnType: None -# AlwaysBreakAfterReturnType: None -# AlwaysBreakBeforeMultilineStrings: false -# AlwaysBreakTemplateDeclarations: false -BinPackArguments: false -BinPackParameters: false -# BraceWrapping: -# AfterClass: false -# AfterControlStatement: false -# AfterEnum: false -# AfterFunction: false -# AfterNamespace: false -# AfterObjCDeclaration: false -# AfterStruct: false -# AfterUnion: false -# BeforeCatch: false -# BeforeElse: false -# IndentBraces: false -# BreakBeforeBinaryOperators: None -# BreakBeforeBraces: Attach -# BreakBeforeTernaryOperators: true -# BreakConstructorInitializersBeforeComma: false -# BreakAfterJavaFieldAnnotations: false -# BreakStringLiterals: true -ColumnLimit: 120 -# CommentPragmas: '^ IWYU pragma:' -# ConstructorInitializerAllOnOneLineOrOnePerLine: false -# ConstructorInitializerIndentWidth: 4 -# ContinuationIndentWidth: 4 -# Cpp11BracedListStyle: true -# DerivePointerAlignment: false -# DisableFormat: false -# ExperimentalAutoDetectBinPacking: false -# ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] -# IncludeIsMainRegex: '$' -# IndentCaseLabels: false -IndentWidth: 4 -# IndentWrappedFunctionNames: false -# JavaScriptQuotes: Leave -# JavaScriptWrapImports: true -# KeepEmptyLinesAtTheStartOfBlocks: true -# MacroBlockBegin: '' -# MacroBlockEnd: '' -# MaxEmptyLinesToKeep: 1 -# NamespaceIndentation: None -# ObjCBlockIndentWidth: 2 -# ObjCSpaceAfterProperty: false -# ObjCSpaceBeforeProtocolList: true -# PenaltyBreakBeforeFirstCallParameter: 19 -# PenaltyBreakComment: 300 -# PenaltyBreakFirstLessLess: 120 -# PenaltyBreakString: 1000 -# PenaltyExcessCharacter: 1000000 -# PenaltyReturnTypeOnItsOwnLine: 60 -# PointerAlignment: Right -# ReflowComments: true -SortIncludes: true -# SpaceAfterCStyleCast: false -# SpaceAfterTemplateKeyword: true -# SpaceBeforeAssignmentOperators: true -SpaceBeforeParens: Never -# SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 2 -# SpacesInAngles: false -# SpacesInContainerLiterals: true -# SpacesInCStyleCastParentheses: false -# SpacesInParentheses: false -# SpacesInSquareBrackets: false -Standard: Cpp11 -TabWidth: 4 -UseTab: Never diff --git a/external/CLI11/.clang-tidy b/external/CLI11/.clang-tidy deleted file mode 100644 index 727b76525..000000000 --- a/external/CLI11/.clang-tidy +++ /dev/null @@ -1,83 +0,0 @@ -# Checks that will be implemented in future PRs: -# performance-unnecessary-value-param, hints to ~110 issues. Be careful with implementing the suggested changes of this one, as auto-fixes may break the code -# bugprone-forwarding-reference-overload probably should be enabled and fixed. -# clang-diagnostic-float-equal can be fixed by using _a from Catch::literals -# bugprone-exception-escape due to main being a bit simple in examples -# modernize-avoid-c-arrays trips up in TEMPLATE_TEST_CASE catch macro -# modernize-return-braced-init-list triggers on lambdas ? -# modernize-make-unique requires C++14 -# modernize-type_traits requires C++17 -# readability-avoid-const-params-in-decls Affected by the pre-compile split - -Checks: | - *bugprone*, - -bugprone-easily-swappable-parameters, - -bugprone-forwarding-reference-overload, - -bugprone-exception-escape, - clang-analyzer-optin.cplusplus.VirtualCall, - clang-analyzer-optin.performance.Padding, - -clang-diagnostic-float-equal, - cppcoreguidelines-init-variables, - cppcoreguidelines-prefer-member-initializer, - cppcoreguidelines-pro-type-static-cast-downcast, - cppcoreguidelines-slicing, - google-*, - -google-runtime-references, - llvm-include-order, - llvm-namespace-comment, - misc-definitions-in-headers, - misc-misplaced-const, - misc-non-copyable-objects, - misc-static-assert, - misc-throw-by-value-catch-by-reference, - misc-throw-by-value-catch-by-reference, - misc-uniqueptr-reset-release, - misc-unused-parameters, - modernize*, - -modernize-use-trailing-return-type, - -modernize-concat-nested-namespaces, - -modernize-return-braced-init-list, - -modernize-make-unique, - -modernize-type-traits, - -modernize-macro-to-enum, - *performance*, - -performance-unnecessary-value-param, - -performance-inefficient-string-concatenation, - readability-const-return-type, - readability-container-size-empty, - readability-delete-null-pointer, - readability-else-after-return, - readability-implicit-bool-conversion, - readability-inconsistent-declaration-parameter-name, - readability-make-member-function-const, - readability-misplaced-array-index, - readability-non-const-parameter, - readability-qualified-auto, - readability-redundant-function-ptr-dereference, - readability-redundant-smartptr-get, - readability-redundant-string-cstr, - readability-simplify-subscript-expr, - readability-static-accessed-through-instance, - readability-static-definition-in-anonymous-namespace, - readability-string-compare, - readability-suspicious-call-argument, - readability-uniqueptr-delete-release, - -CheckOptions: - - key: google-readability-braces-around-statements.ShortStatementLines - value: "3" - - key: performance-for-range-copy.WarnOnAllAutoCopies - value: true - - key: performance-inefficient-string-concatenation.StrictMode - value: true - - key: performance-unnecessary-value-param.AllowedTypes - value: "exception_ptr$;" - - key: readability-implicit-bool-conversion.AllowPointerConditions - value: true - - key: modernize-use-nodiscard.ReplacementString - value: "CLI11_NODISCARD" - -HeaderFilterRegex: "CLI.*hpp" - -FormatStyle: file -# WarningsAsErrors: "*" diff --git a/external/CLI11/.cmake-format.yaml b/external/CLI11/.cmake-format.yaml deleted file mode 100644 index 543ddf19f..000000000 --- a/external/CLI11/.cmake-format.yaml +++ /dev/null @@ -1,6 +0,0 @@ -format: - line_width: 99 - -# Causes a few issues - can be solved later, possibly. -markup: - enable_markup: false diff --git a/external/CLI11/.codacy.yml b/external/CLI11/.codacy.yml deleted file mode 100644 index 03a1e522b..000000000 --- a/external/CLI11/.codacy.yml +++ /dev/null @@ -1,18 +0,0 @@ ---- -engines: - rubocop: - enabled: true - duplication: - enabled: true - metrics: - enabled: true - coverage: - enabled: false -languages: - -exclude_paths: - - "fuzz/**/*" - - "fuzz/*" - - "scripts/**/*" - - "scripts/*" - - "**.md" diff --git a/external/CLI11/.codecov.yml b/external/CLI11/.codecov.yml deleted file mode 100644 index 61c2e2f21..000000000 --- a/external/CLI11/.codecov.yml +++ /dev/null @@ -1,7 +0,0 @@ -ignore: - - "tests" - - "examples" - - "book" - - "docs" - - "test_package" - - "fuzz" diff --git a/external/CLI11/.editorconfig b/external/CLI11/.editorconfig deleted file mode 100644 index 3c6f665e6..000000000 --- a/external/CLI11/.editorconfig +++ /dev/null @@ -1,13 +0,0 @@ -root = true - -[*] -indent_style = space -insert_final_newline = true -end_of_line = lf -trim_trailing_whitespace = true - -[*.cpp,*.hpp,*.py] -indent_size = 4 - -[*.yml] -indent_size = 2 diff --git a/external/CLI11/.github/CONTRIBUTING.md b/external/CLI11/.github/CONTRIBUTING.md deleted file mode 100644 index 7e4abed11..000000000 --- a/external/CLI11/.github/CONTRIBUTING.md +++ /dev/null @@ -1,90 +0,0 @@ -# Contributing - -Thanks for considering to write a Pull Request (PR) for CLI11! Here are a few -guidelines to get you started: - -Make sure you are comfortable with the license; all contributions are licensed -under the original license. - -## Adding functionality - -Make sure any new functions you add are are: - -- Documented by `///` documentation for Doxygen -- Mentioned in the instructions in the README, though brief mentions are okay -- Explained in your PR (or previously explained in an Issue mentioned in the PR) -- Completely covered by tests - -In general, make sure the addition is well thought out and does not increase the -complexity of CLI11 needlessly. - -## Things you should know - -- Once you make the PR, tests will run to make sure your code works on all - supported platforms -- The test coverage is also measured, and that should remain 100% -- Formatting should be done with pre-commit, otherwise the format check will not - pass. However, it is trivial to apply this to your PR, so don't worry about - this check. If you do want to run it, see below. -- Everything must pass clang-tidy as well, run with - `-DCMAKE_CXX_CLANG_TIDY="$(which clang-tidy)"` (if you set - `"$(which clang-tidy) -fix"`, make sure you use a single threaded build - process, or just build one example target). -- Your changes must also conform to most of the - [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) - rules checked by [cpplint](https://github.com/cpplint/cpplint). For unused - cpplint filters and justifications, see [CPPLINT.cfg](/CPPLINT.cfg). - -## Pre-commit - -Format is handled by pre-commit. You should install it (or use -[pipx](https://pypa.github.io/pipx/)): - -```bash -python3 -m pip install pre-commit -``` - -Then, you can run it on the items you've added to your staging area, or all -files: - -```bash -pre-commit run -# OR -pre-commit run --all-files -``` - -And, if you want to always use it, you can install it as a git hook (hence the -name, pre-commit): - -```bash -pre-commit install -``` - -## For maintainers: remember to add contributions - -In a commit to a PR, just add -"`@all-contributors please add for `" or similar (see -). Use `code` for code, `bug` if an issue was -submitted, `platform` for packaging stuff, and `doc` for documentation updates. - -To run locally, do: - -```bash -yarn add --dev all-contributors-cli -yarn all-contributors add username code,bug -``` - -## For maintainers: Making a release - -Remember to replace the emoji in the readme, being careful not to replace the -ones in all-contributors if any overlap. - -Steps: - -- Update changelog if needed -- Update the version in `include/CLI/Version.hpp`. -- Find and replace in README (new minor/major release only): - - Replace " 🆕" and "🆕 " with "" (ignores the description line) - - Check for `\/\/$` (vi syntax) to catch leftover `// 🆕` - - Replace "🚧" with "🆕" (manually ignore the description line) -- Make a release in the GitHub UI, use a name such as "Version X.Y(.Z): Title" diff --git a/external/CLI11/.github/actions/quick_cmake/action.yml b/external/CLI11/.github/actions/quick_cmake/action.yml deleted file mode 100644 index d2b3825fe..000000000 --- a/external/CLI11/.github/actions/quick_cmake/action.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Quick CMake config -description: "Runs CMake 3.5+ (if already setup)" -inputs: - args: - description: "Other arguments" - required: false - default: "" - cmake-version: - description: "The CMake version to run" - required: true - -runs: - using: composite - steps: - - name: CMake ${{ inputs.cmake-version }} - uses: jwlawson/actions-setup-cmake@v1.14 - with: - cmake-version: "${{ inputs.cmake-version }}" - - run: | - mkdir -p build-tmp - touch build-tmp/tmp - rm -r build-tmp/* - (cd build-tmp && cmake .. ${{ inputs.args }}) - rm -r build-tmp - shell: bash diff --git a/external/CLI11/.github/codecov.yml b/external/CLI11/.github/codecov.yml deleted file mode 100644 index 0e106f710..000000000 --- a/external/CLI11/.github/codecov.yml +++ /dev/null @@ -1,7 +0,0 @@ -codecov: - notify: - after_n_builds: 8 -coverage: - status: - project: - informational: true diff --git a/external/CLI11/.github/dependabot.yml b/external/CLI11/.github/dependabot.yml deleted file mode 100644 index 40aaf098f..000000000 --- a/external/CLI11/.github/dependabot.yml +++ /dev/null @@ -1,13 +0,0 @@ -version: 2 -updates: - # Maintain dependencies for GitHub Actions - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" - target-branch: "main" - open-pull-requests-limit: 10 - groups: - actions: - patterns: - - "*" diff --git a/external/CLI11/.github/labeler_merged.yml b/external/CLI11/.github/labeler_merged.yml deleted file mode 100644 index 96e1ca701..000000000 --- a/external/CLI11/.github/labeler_merged.yml +++ /dev/null @@ -1,4 +0,0 @@ -needs changelog: - - all: ["!CHANGELOG.md"] -needs README: - - all: ["!README.md"] diff --git a/external/CLI11/.github/workflows/build.yml b/external/CLI11/.github/workflows/build.yml deleted file mode 100644 index 57d54dc16..000000000 --- a/external/CLI11/.github/workflows/build.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Build -on: - push: - branches: - - main - - v* - tags: - - "*" - pull_request: - -jobs: - single-header: - name: Single header - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - - uses: actions/setup-python@v5 - with: - python-version: "3.x" - - - name: Prepare CMake config - run: cmake -S . -B build -DCLI11_SINGLE_FILE=ON - - - name: Make package - run: cmake --build build --target package_source - - - name: Copy source packages - run: | - mkdir -p CLI11-Source - cp build/CLI11-*-Source.* CLI11-Source - cp build/CLI11-*-Source.* . - - - name: Make header - run: cmake --build build --target CLI11-generate-single-file - - - name: Copy file to main folder - run: cp build/include/CLI11.hpp CLI11.hpp - - - uses: actions/upload-artifact@v4 - with: - name: CLI11.hpp - path: CLI11.hpp - - - uses: actions/upload-artifact@v4 - with: - name: CLI11-Source - path: CLI11-Source - - - name: Release - uses: softprops/action-gh-release@v1 - if: startsWith(github.ref, 'refs/tags/') - with: - files: | - CLI11.hpp - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/external/CLI11/.github/workflows/docs.yml b/external/CLI11/.github/workflows/docs.yml deleted file mode 100644 index 6b79b352f..000000000 --- a/external/CLI11/.github/workflows/docs.yml +++ /dev/null @@ -1,91 +0,0 @@ -name: Docs - -on: - workflow_dispatch: - pull_request: - push: - branches: - - main - -permissions: - contents: read - pages: write - id-token: write - -concurrency: - group: "pages" - cancel-in-progress: false - -jobs: - apidocs: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: mattnotmitt/doxygen-action@v1 - with: - doxyfile-path: ./docs/Doxyfile - - - uses: actions/upload-artifact@v4 - with: - name: api-docs - path: html - - gitbook: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-node@v4 - with: - node-version: 16 - - - uses: awalsh128/cache-apt-pkgs-action@v1 - with: - packages: calibre calibre-bin libxss1 libasound2 - version: 1 - - - name: Install JS requirements - working-directory: book - run: | - npm install - - - name: Build book - working-directory: book - run: | - npx gitbook build . public - npx gitbook pdf . public/cli11.pdf - - - uses: actions/upload-artifact@v4 - with: - name: gitbook - path: book/public - - pages: - runs-on: ubuntu-latest - needs: [apidocs, gitbook] - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - if: > - success() - && github.ref == 'refs/heads/main' - && github.repository == 'CLIUtils/CLI11' - steps: - - uses: actions/configure-pages@v4 - id: pages - - - uses: actions/download-artifact@v4 - with: - name: api-docs - path: _site - - - uses: actions/download-artifact@v4 - with: - name: gitbook - path: _site/book - - - uses: actions/upload-pages-artifact@v3 - - - uses: actions/deploy-pages@v4 - id: deployment diff --git a/external/CLI11/.github/workflows/fuzz.yml b/external/CLI11/.github/workflows/fuzz.yml deleted file mode 100644 index 413f150fb..000000000 --- a/external/CLI11/.github/workflows/fuzz.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: Fuzz -on: - workflow_dispatch: - push: - branches: - - main - - v* - pull_request: - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - quick_fuzz1: - name: quickfuzz1 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Configure - run: | - cmake -S . -B build \ - -DCMAKE_CXX_STANDARD=17 \ - -DCLI11_SINGLE_FILE_TESTS=OFF \ - -DCLI11_BUILD_EXAMPLES=OFF \ - -DCLI11_FUZZ_TARGET=ON \ - -DCLI11_BUILD_TESTS=OFF \ - -DCLI11_BUILD_DOCS=OFF \ - -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_CXX_COMPILER_FORCED=ON \ - -DCMAKE_CXX_FLAGS="-g -O1 -fsanitize=fuzzer,undefined,address" - - - name: Build - run: cmake --build build -j4 - - - name: Test_app - run: | - cd build - make QUICK_CLI11_APP_FUZZ - - - name: Test_file - run: | - cd build - make QUICK_CLI11_FILE_FUZZ - - - - name: artifacts - if: failure() - uses: actions/upload-artifact@v4 - with: - name: file_failure - path: ./build/fuzz/cli11_*_fail_artifact.txt diff --git a/external/CLI11/.github/workflows/pr_merged.yml b/external/CLI11/.github/workflows/pr_merged.yml deleted file mode 100644 index 56f6f741f..000000000 --- a/external/CLI11/.github/workflows/pr_merged.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: PR merged -on: - pull_request_target: - types: [closed] - -jobs: - label-merged: - name: Changelog needed - runs-on: ubuntu-latest - if: github.event.pull_request.merged == true - steps: - - uses: actions/labeler@main - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - configuration-path: .github/labeler_merged.yml diff --git a/external/CLI11/.github/workflows/tests.yml b/external/CLI11/.github/workflows/tests.yml deleted file mode 100644 index d2c44e008..000000000 --- a/external/CLI11/.github/workflows/tests.yml +++ /dev/null @@ -1,377 +0,0 @@ -name: Tests -on: - push: - branches: - - main - - v* - pull_request: - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -env: - CTEST_OUTPUT_ON_FAILURE: "1" - -jobs: - coverage: - name: Coverage - runs-on: ubuntu-latest - strategy: - matrix: - std: ["11", "14", "17", "20"] - precompile: ["ON", "OFF"] - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Get LCov - run: | - wget https://github.com/linux-test-project/lcov/releases/download/v1.16/lcov-1.16.tar.gz - tar -xzf lcov-1.16.tar.gz - cd lcov-1.16 - sudo make install - - - name: Configure - run: | - cmake -S . -B build \ - -DCMAKE_CXX_STANDARD=${{matrix.std}} \ - -DCLI11_SINGLE_FILE_TESTS=OFF \ - -DCLI11_BUILD_EXAMPLES=OFF \ - -DCLI11_PRECOMPILED=${{matrix.precompile}} \ - -DCMAKE_BUILD_TYPE=Coverage - - - name: Build - run: cmake --build build -j4 - - - name: Test - run: cmake --build build --target CLI11_coverage - - - name: Prepare coverage - run: | - lcov --directory . --capture --output-file coverage.info - lcov --remove coverage.info '*/tests/*' '*/examples/*' '/usr/*' '*/book/*' '*/fuzz/*' --output-file coverage.info - lcov --list coverage.info - working-directory: build - - - uses: codecov/codecov-action@v4 - with: - files: build/coverage.info - functionalities: fixes - - catch2-3: - name: Catch 2 3.x - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - - - name: Get Catch 2 - run: brew install catch2 - - - name: Configure - run: | - cmake -S . -B build \ - -DCMAKE_CXX_STANDARD=14 \ - -DCLI11_SINGLE_FILE_TESTS=OFF \ - -DCLI11_BUILD_EXAMPLES=OFF \ - -DCLI11_PRECOMPILED=ON - - - name: Build - run: cmake --build build -j4 - - - name: Test - run: cmake --build build --target test - - - clang-tidy: - name: Clang-Tidy - runs-on: ubuntu-latest - container: silkeh/clang:17 - steps: - - uses: actions/checkout@v4 - - - name: Configure - run: > - cmake -S . -B build -DCMAKE_CXX_STANDARD=17 - -DCMAKE_CXX_CLANG_TIDY="$(which - clang-tidy);--use-color;--warnings-as-errors=*" - - - name: Build - run: cmake --build build -j4 -- --keep-going - - cuda11-build: - name: CUDA 11 build only - runs-on: ubuntu-latest - container: nvidia/cuda:11.8.0-devel-ubuntu22.04 - steps: - - name: Add build tools - run: apt-get update && apt-get install -y wget git cmake - - uses: actions/checkout@v4 - with: - submodules: true - - name: Configure - run: cmake -S . -B build -DCLI11_CUDA_TESTS=ON - - name: Build - run: cmake --build build -j2 - - cuda12-build: - name: CUDA 12 build only - runs-on: ubuntu-latest - container: nvidia/cuda:12.3.1-devel-ubuntu22.04 - steps: - - name: Add build tools - run: apt-get update && apt-get install -y wget git cmake - - uses: actions/checkout@v4 - with: - submodules: true - - name: Configure - run: cmake -S . -B build -DCLI11_CUDA_TESTS=ON - - name: Build - run: cmake --build build -j2 - - boost-build: - name: Boost build - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Add boost - run: sudo apt-get update && sudo apt-get install -y libboost-dev - # NOTE: If a boost version matching all requirements cannot be found, - # this build step will fail - - name: Configure - run: cmake -S . -B build -DCLI11_BOOST=ON - - name: Build - run: cmake --build build -j2 - - name: Run tests - run: ctest --output-on-failure - working-directory: build - - meson-build: - name: Meson build - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Prepare commands - run: | - pipx install meson - pipx install ninja - - - name: Configure - run: meson setup build-meson . -Dtests=true - - - name: Build - run: meson compile -C build-meson - - install: - name: install tests - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Configure - run: cmake -S . -B build -DCLI11_INSTALL_PACKAGE_TESTS=ON -DCMAKE_INSTALL_PREFIX=/home/runner/work/install - - name: Build - run: cmake --build build -j2 - - name: install - run: cmake --install build - - name: Run tests - run: ctest --output-on-failure -L Packaging - working-directory: build - - install-precompiled: - name: install tests precompiled - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Configure - run: cmake -S . -B build -DCLI11_INSTALL_PACKAGE_TESTS=ON -DCMAKE_INSTALL_PREFIX=/home/runner/work/install -DCLI11_PRECOMPILED=ON - - name: Build - run: cmake --build build -j2 - - name: install - run: cmake --install build - - name: Run tests - run: ctest --output-on-failure -L Packaging - working-directory: build - - install-single_file: - name: install tests single file - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Configure - run: cmake -S . -B build -DCLI11_INSTALL_PACKAGE_TESTS=ON -DCMAKE_INSTALL_PREFIX=/home/runner/work/install -DCLI11_SINGLE_FILE=ON - - name: Build - run: cmake --build build -j2 - - name: install - run: cmake --install build - - name: Run tests - run: ctest --output-on-failure -L Packaging - working-directory: build - - cmake-config-ubuntu-2004: - name: CMake config check (Ubuntu 20.04) - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v4 - - - name: Check CMake 3.5 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.5" - if: success() || failure() - - - name: Check CMake 3.6 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.6" - if: success() || failure() - - - name: Check CMake 3.7 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.7" - if: success() || failure() - - - name: Check CMake 3.8 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.8" - if: success() || failure() - - - name: Check CMake 3.9 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.9" - if: success() || failure() - - - name: Check CMake 3.10 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.10" - if: success() || failure() - - - name: Check CMake 3.11 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.11" - if: success() || failure() - - - name: Check CMake 3.12 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.12" - if: success() || failure() - - - name: Check CMake 3.13 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.13" - if: success() || failure() - - - name: Check CMake 3.14 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.14" - args: -DCLI11_SANITIZERS=ON -DCLI11_BUILD_EXAMPLES_JSON=ON - if: success() || failure() - - - name: Check CMake 3.15 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.15" - if: success() || failure() - - - name: Check CMake 3.16 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.16" - if: success() || failure() - - cmake-config-ubuntu-2204: - name: CMake config check (Ubuntu 22.04) - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v4 - - - name: Check CMake 3.17 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.17" - if: success() || failure() - - - name: Check CMake 3.18 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.18" - if: success() || failure() - - - name: Check CMake 3.19 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.19" - if: success() || failure() - - - name: Check CMake 3.20 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.20" - if: success() || failure() - - - name: Check CMake 3.21 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.21" - if: success() || failure() - - - name: Check CMake 3.22 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.22" - if: success() || failure() - - - name: Check CMake 3.23 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.23" - if: success() || failure() - - - name: Check CMake 3.24 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.24" - if: success() || failure() - - - name: Check CMake 3.25 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.25" - if: success() || failure() - - - name: Check CMake 3.26 (full) - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.26" - args: -DCLI11_SANITIZERS=ON -DCLI11_BUILD_EXAMPLES_JSON=ON - if: success() || failure() - - - name: Check CMake 3.27 - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.27" - if: success() || failure() - - - name: Check CMake 3.28 (full) - uses: ./.github/actions/quick_cmake - with: - cmake-version: "3.28" - args: -DCLI11_SANITIZERS=ON -DCLI11_BUILD_EXAMPLES_JSON=ON - if: success() || failure() diff --git a/external/CLI11/.gitignore b/external/CLI11/.gitignore deleted file mode 100644 index 7b9bcb27f..000000000 --- a/external/CLI11/.gitignore +++ /dev/null @@ -1,20 +0,0 @@ -a.out* -*.swp -/*build* -/test_package/build -/Makefile -/CMakeFiles/* -/cmake_install.cmake -/*.kdev4 -/.vscode -/html/* -!/meson.build -/CMakeUserPresets.json - -/node_modules/* -/package.json -/yarn.lock -/CLI11.hpp - -/subprojects/Catch2-* -/subprojects/packagecache diff --git a/external/CLI11/.pre-commit-config.yaml b/external/CLI11/.pre-commit-config.yaml deleted file mode 100644 index 5c0fd894b..000000000 --- a/external/CLI11/.pre-commit-config.yaml +++ /dev/null @@ -1,93 +0,0 @@ -exclude: ^(.github/workflows/|docs/img/) -ci: - autoupdate_commit_msg: "chore(deps): pre-commit.ci autoupdate" - autofix_commit_msg: "style: pre-commit.ci fixes" - -repos: - - repo: https://github.com/psf/black - rev: 24.1.1 - hooks: - - id: black - - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 - hooks: - - id: check-added-large-files - - id: check-case-conflict - - id: check-merge-conflict - - id: check-symlinks - - id: check-yaml - - id: check-toml - - id: end-of-file-fixer - - id: mixed-line-ending - - id: trailing-whitespace - - id: check-shebang-scripts-are-executable - - id: check-executables-have-shebangs - - id: debug-statements - - - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v17.0.6 - hooks: - - id: clang-format - types_or: [c++, c, cuda] - - - repo: https://github.com/cheshirekow/cmake-format-precommit - rev: v0.6.13 - hooks: - - id: cmake-format - additional_dependencies: [pyyaml] - - - repo: https://github.com/pre-commit/mirrors-prettier - rev: "v4.0.0-alpha.8" - hooks: - - id: prettier - types_or: [yaml, markdown, html, css, scss, javascript, json] - args: [--prose-wrap=always] - - - repo: https://github.com/markdownlint/markdownlint - rev: v0.12.0 - hooks: - - id: markdownlint - args: ["--style=scripts/mdlint_style.rb"] - # Uncomment on macOS - Apple has deprecated Ruby, so macOS is stuck on 2.6 - # language_version: 3.1.2 - - # - repo: local - # hooks: - # - id: remarklint - # name: remarklint - # language: node - # entry: remark - # types: [markdown] - # args: ["--frail", "--quiet"] - # additional_dependencies: - # [ - # remark, - # remark-lint, - # remark-cli, - # remark-preset-lint-recommended, - # remark-lint-list-item-indent, - # remark-lint-no-undefined-references, - # ] - - - repo: local - hooks: - - id: disallow-caps - name: Disallow improper capitalization - language: pygrep - entry: PyBind|Numpy|Cmake|CCache|PyTest|Github - exclude: .pre-commit-config.yaml - - - repo: local - hooks: - - id: avoid-msvc-macro - name: Avoid MSVC <=2017 min/max macro (use extra parens) - language: pygrep - entry: \b(min|max)\( - exclude: .pre-commit-config.yaml - - - repo: https://github.com/codespell-project/codespell - rev: v2.2.6 - hooks: - - id: codespell - args: ["-L", "atleast,ans,doub,inout"] diff --git a/external/CLI11/.remarkrc b/external/CLI11/.remarkrc deleted file mode 100644 index 73cad8328..000000000 --- a/external/CLI11/.remarkrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "plugins": [ - "remark-preset-lint-recommended", - ["remark-lint-list-item-indent", "space"], - ["remark-lint-no-undefined-references", {"allow": ["^1"]}] - ] -} diff --git a/external/CLI11/CHANGELOG.md b/external/CLI11/CHANGELOG.md deleted file mode 100644 index 8293b13de..000000000 --- a/external/CLI11/CHANGELOG.md +++ /dev/null @@ -1,1116 +0,0 @@ -# Changelog - -## Version 2.4: Unicode and TOML support - -This version adds Unicode support, support for TOML standard including multiline -strings, digit separators, string escape sequences,and dot notation. An initial -round of a fuzzer was added to testing which has caught several bugs related to -config file processing, and a few other edge cases not previously observed. - -- Add Unicode support and bug fixes [#804][], [#923][], [#876][], [#848][], - [#832][], [#987][] -- Match TOML standard for string and numerical entries, multiline strings - [#968][], [#967][],[#964][], [#935][] -- Add validation for environmental variables [#926][] -- Add an escape string transform [#970][] -- Add A REVERSE multi-option policy to support multiple config files and other - applications [#918][] -- Add usage message replacement [#768][] -- Allow using dot notation for subcommand arguments such as `--sub1.field` - [#789][] -- Bugfix: Fuzzing tests and fixes [#930][], [#905][], [#874][], [#846][] -- Bugfix: Missing coverage tests [#928][] -- Bugfix: CMake package and package config tests and fixes [#916][] -- Bugfix: Support for Windows ARM compilation and tests [#913][], [#914][] -- Bugfix: Environmental variable checks in non-triggered subcommands [#904][] -- Bugfix: Environmental variables were not being correctly process by config - pointer [#891][] -- Bugfix: Undefined behavior in `sum_string_vector` [#893][] -- Bugfix: Warnings and updates for CUDA 11 support [#851][] -- Backend: Add tests for newer compilers (lost with Travis CI) [#972][] -- Backend: Increase minimum CMake to 3.5 [#898][] -- Backend: Remove integrated Conan support (provided now by Conan center) - [#853][] -- Tests: Support Catch2 Version 3 [#896][], [#980][] - -[#768]: https://github.com/CLIUtils/CLI11/pull/768 -[#789]: https://github.com/CLIUtils/CLI11/pull/789 -[#804]: https://github.com/CLIUtils/CLI11/pull/804 -[#832]: https://github.com/CLIUtils/CLI11/pull/832 -[#846]: https://github.com/CLIUtils/CLI11/pull/846 -[#848]: https://github.com/CLIUtils/CLI11/pull/848 -[#851]: https://github.com/CLIUtils/CLI11/pull/851 -[#853]: https://github.com/CLIUtils/CLI11/pull/853 -[#874]: https://github.com/CLIUtils/CLI11/pull/874 -[#876]: https://github.com/CLIUtils/CLI11/pull/876 -[#891]: https://github.com/CLIUtils/CLI11/pull/891 -[#893]: https://github.com/CLIUtils/CLI11/pull/893 -[#896]: https://github.com/CLIUtils/CLI11/pull/896 -[#898]: https://github.com/CLIUtils/CLI11/pull/898 -[#904]: https://github.com/CLIUtils/CLI11/pull/904 -[#905]: https://github.com/CLIUtils/CLI11/pull/905 -[#913]: https://github.com/CLIUtils/CLI11/pull/913 -[#914]: https://github.com/CLIUtils/CLI11/pull/914 -[#916]: https://github.com/CLIUtils/CLI11/pull/916 -[#918]: https://github.com/CLIUtils/CLI11/pull/918 -[#923]: https://github.com/CLIUtils/CLI11/pull/923 -[#926]: https://github.com/CLIUtils/CLI11/pull/926 -[#928]: https://github.com/CLIUtils/CLI11/pull/928 -[#930]: https://github.com/CLIUtils/CLI11/pull/930 -[#935]: https://github.com/CLIUtils/CLI11/pull/935 -[#964]: https://github.com/CLIUtils/CLI11/pull/964 -[#967]: https://github.com/CLIUtils/CLI11/pull/967 -[#968]: https://github.com/CLIUtils/CLI11/pull/968 -[#970]: https://github.com/CLIUtils/CLI11/pull/970 -[#972]: https://github.com/CLIUtils/CLI11/pull/972 -[#980]: https://github.com/CLIUtils/CLI11/pull/980 -[#987]: https://github.com/CLIUtils/CLI11/pull/987 - -### Version 2.4.1: Missing header - -A transitive include that might be present in some standard libraries is now -included directly. This also fixes a test on architectures that need libatomic -linked and fix an inadvertent breaking change regarding unused defaults for -config files - -- Bugfix: Include cstdint [#996][] -- Bugfix: Fix change in operation of config_ptr with unused default in the count - method [#1003][] -- Tests: Include libatomic if required for fuzzing test [#1000][] - -[#996]: https://github.com/CLIUtils/CLI11/pull/996 -[#1000]: https://github.com/CLIUtils/CLI11/pull/1000 -[#1003]: https://github.com/CLIUtils/CLI11/pull/1003 - -## Version 2.3: Precompilation Support - -This version adds a pre-compiled mode to CLI11, which allows you to precompile -the library, saving time on incremental rebuilds, making CLI11 more competitive -on compile time with classic compiled CLI libraries. The header-only mode is -still default, and is not yet distributed via binaries. - -- Add `CLI11_PRECOMPILED` as an option [#762][] -- Bugfix: Include `` in `FormatterFwd` [#727][] -- Bugfix: Add missing `Macros.hpp` to `Error.hpp` [#755][] -- Bugfix: Fix subcommand callback trigger [#733][] -- Bugfix: Variable rename to avoid warning [#734][] -- Bugfix: `split_program_name` single file name error [#740][] -- Bugfix: Better support for min/max overrides on MSVC [#741][] -- Bugfix: Support MSVC 2022 [#748][] -- Bugfix: Support negated flag in config file [#775][] -- Bugfix: Better errors for some confusing config file situations [#781][] -- Backend: Restore coverage testing (lost with Travis CI) [#747][] - -[#727]: https://github.com/CLIUtils/CLI11/pull/727 -[#733]: https://github.com/CLIUtils/CLI11/pull/733 -[#734]: https://github.com/CLIUtils/CLI11/pull/734 -[#740]: https://github.com/CLIUtils/CLI11/pull/740 -[#741]: https://github.com/CLIUtils/CLI11/pull/741 -[#747]: https://github.com/CLIUtils/CLI11/pull/747 -[#748]: https://github.com/CLIUtils/CLI11/pull/748 -[#755]: https://github.com/CLIUtils/CLI11/pull/755 -[#762]: https://github.com/CLIUtils/CLI11/pull/762 -[#775]: https://github.com/CLIUtils/CLI11/pull/775 -[#781]: https://github.com/CLIUtils/CLI11/pull/781 - -### Version 2.3.1: Missing implementation - -A function implementation was missing after the pre-compile move, missed due to -the fact we lost 100% after losing coverage checking. We are working on filling -out 100% coverage again to ensure this doesn't happen again! - -- Bugfix: `App::get_option_group` implementation missing [#793][] -- Bugfix: Fix spacing when setting an empty footer [#796][] -- Bugfix: Address Klocwork static analysis checking issues [#785][] - -[#785]: https://github.com/CLIUtils/CLI11/pull/785 -[#793]: https://github.com/CLIUtils/CLI11/pull/793 -[#796]: https://github.com/CLIUtils/CLI11/pull/796 - -### Version 2.3.2: Minor maintenance - -This version provides a few fixes collected over the last three months before -adding features for 2.4. - -- Bugfix: Consistently use ADL for `lexical_cast`, making it easier to extend - for custom template types [#820][] -- Bugfix: Tweak the parsing of files for flags with `disable_flag_override` - [#800][] -- Bugfix: Handle out of bounds long long [#807][] -- Bugfix: Spacing of `make_description` min option output [#808][] -- Bugfix: Print last parsed subcommand's help message [#822][] -- Bugfix: Avoid floating point warning in GCC 12 [#803][] -- Bugfix: Fix a few gcc warnings [#813][] -- Backend: Max CMake tested 3.22 -> 3.24 [#823][] - -[#800]: https://github.com/CLIUtils/CLI11/pull/800 -[#803]: https://github.com/CLIUtils/CLI11/pull/803 -[#807]: https://github.com/CLIUtils/CLI11/pull/807 -[#808]: https://github.com/CLIUtils/CLI11/pull/808 -[#813]: https://github.com/CLIUtils/CLI11/pull/813 -[#820]: https://github.com/CLIUtils/CLI11/pull/820 -[#822]: https://github.com/CLIUtils/CLI11/pull/822 -[#823]: https://github.com/CLIUtils/CLI11/pull/823 - -## Version 2.2: Option and Configuration Flexibility - -New features include support for output of an empty vector, a summing option -policy that can be applied more broadly, and an option to validate optional -arguments to discriminate from positional arguments. A new validator to check -for files on a default path is included to allow one or more default paths for -configuration files or other file arguments. A number of bug fixes and code -cleanup for various build configurations. Clean up of some error outputs and -extension of existing capability to new types or situations. - -There is a possible minor breaking change in behavior of certain types which -wrapped an integer, such as `std::atomic` or `std::optional` when used -in a flag. The default behavior is now as a single argument value vs. summing -all the arguments. The default summing behavior is now restricted to pure -integral types, int64_t, int, uint32_t, etc. Use the new `sum` multi option -policy to revert to the older behavior. The summing behavior on wrapper types -was not originally intended. - -- Add `MultiOptionPolicy::Sum` and refactor the `add_flag` to fix a bug when - using `std::optional` as type. [#709][] -- Add support for an empty vector result in TOML and as a default string. - [#660][] -- Add `.validate_optional_arguments()` to support discriminating positional - arguments from vector option arguments. [#668][] -- Add `CLI::FileOnDefaultPath` to check for files on a specified default path. - [#698][] -- Change default value display in help messages from `=XXXX` to `[XXXXX]` to - make it clearer. [#666][] -- Modify the Range Validator to support additional types and clean up the error - output. [#690][] -- Bugfix: The trigger on parse modifier did not work on positional argument.s - [#713][] -- Bugfix: The single header file generation was missing custom namespace - generation. [#707][] -- Bugfix: Clean up File Error handling in the argument processing. [#678][] -- Bugfix: Fix a stack overflow error if nameless commands had fallthrough. - [#665][] -- Bugfix: A subcommand callback could be executed multiple times if it was a - member of an option group. [#666][] -- Bugfix: Fix an issue with vectors of multi argument types where partial - argument sets did not result in an error. [#661][] -- Bugfix: Fix an issue with type the template matching on C++20 and add some CI - builds for C++20. [#663][] -- Bugfix: Fix typo in C++20 detection on MSVC. [#706][] -- Bugfix: An issue where the detection of RTTI being disabled on certain MSVC - platforms did not disable the use of dynamic cast calls. [#666][] -- Bugfix: Resolve strict-overflow warning on some GCC compilers. [#666][] -- Backend: Add additional tests concerning the use of aliases for option groups - in config files. [#666][] -- Build: Add support for testing in meson and cleanup symbolic link generation. - [#701][], [#697][] -- Build: Support building in WebAssembly. [#679][] - -[#660]: https://github.com/CLIUtils/CLI11/pull/660 -[#661]: https://github.com/CLIUtils/CLI11/pull/661 -[#663]: https://github.com/CLIUtils/CLI11/pull/663 -[#665]: https://github.com/CLIUtils/CLI11/pull/665 -[#666]: https://github.com/CLIUtils/CLI11/pull/666 -[#668]: https://github.com/CLIUtils/CLI11/pull/668 -[#678]: https://github.com/CLIUtils/CLI11/pull/678 -[#679]: https://github.com/CLIUtils/CLI11/pull/679 -[#690]: https://github.com/CLIUtils/CLI11/pull/690 -[#697]: https://github.com/CLIUtils/CLI11/pull/697 -[#698]: https://github.com/CLIUtils/CLI11/pull/698 -[#701]: https://github.com/CLIUtils/CLI11/pull/701 -[#706]: https://github.com/CLIUtils/CLI11/pull/706 -[#707]: https://github.com/CLIUtils/CLI11/pull/707 -[#709]: https://github.com/CLIUtils/CLI11/pull/709 -[#713]: https://github.com/CLIUtils/CLI11/pull/713 - -## Version 2.1: Names and callbacks - -The name restrictions for options and subcommands are now much looser, allowing -a wider variety of characters than before, even spaces can be used (use quotes -to include a space in most shells). The default configuration parser was -improved, allowing your configuration to sit in a larger file. And option -callbacks have a few new settings, allowing them to be run even if the option is -not passed, or every time the option is parsed. - -- Option/subcommand name restrictions have been relaxed. Most characters are now - allowed. [#627][] -- The config parser can accept streams, specify a specific section, and inline - comment characters are supported [#630][] -- `force_callback` & `trigger_on_parse` added, allowing a callback to always run - on parse even if not present or every time the option is parsed [#631][] -- Bugfix(cmake): Only add `CONFIGURE_DEPENDS` if CLI11 is the main project - [#633][] -- Bugfix(cmake): Ensure the cmake/pkg-config files install to a arch independent - path [#635][] -- Bugfix: The single header file generation was missing the include guard. - [#620][] - -[#620]: https://github.com/CLIUtils/CLI11/pull/620 -[#627]: https://github.com/CLIUtils/CLI11/pull/627 -[#630]: https://github.com/CLIUtils/CLI11/pull/630 -[#631]: https://github.com/CLIUtils/CLI11/pull/631 -[#633]: https://github.com/CLIUtils/CLI11/pull/633 -[#635]: https://github.com/CLIUtils/CLI11/pull/635 - -### Version 2.1.1: Quick Windows fix - -- A collision with `min`/`max` macros on Windows has been fixed. [#642][] -- Tests pass with Boost again [#646][] -- Running the pre-commit hooks in development no longer requires docker for - clang-format [#647][] - -[#642]: https://github.com/CLIUtils/CLI11/pull/642 -[#646]: https://github.com/CLIUtils/CLI11/pull/646 -[#647]: https://github.com/CLIUtils/CLI11/pull/647 - -## Version 2.1.2: Better subproject builds - -- Use `main` for the main branch of the repository [#657][] -- Bugfix(cmake): Enforce at least C++11 when using CMake target [#656][] -- Build: Don't run doxygen and CTest includes if a submodule [#656][] -- Build: Avoid a warning on CMake 3.22 [#656][] -- Build: Support compiling the tests with an external copy of Catch2 [#653][] - -[#653]: https://github.com/CLIUtils/CLI11/pull/653 -[#656]: https://github.com/CLIUtils/CLI11/pull/656 -[#657]: https://github.com/CLIUtils/CLI11/pull/657 - -## Version 2.0: Simplification - -This version focuses on cleaning up deprecated functionality, and some minor -default changes. The config processing is TOML compliant now. Atomics and -complex numbers are directly supported, along with other container improvements. -A new version flag option has finally been added. Subcommands are significantly -improved with new features and bugfixes for corner cases. This release contains -a lot of backend cleanup, including a complete overhaul of the testing system -and single file generation system. - -- Built-in config format is TOML compliant now [#435][] - - Support multiline TOML [#528][] - - Support for configurable quotes [#599][] - - Support short/positional options in config mode [#443][] -- More powerful containers, support for `%%` separator [#423][] -- Support atomic types [#520][] and complex types natively [#423][] -- Add a type validator `CLI::TypeValidator` [#526][] -- Add a version flag easily [#452][], with help message [#601][] -- Support `->silent()` on subcommands. [#529][] -- Add alias section to help for subcommands [#545][] -- Allow quotes to specify a program name [#605][] -- Backend: redesigned MakeSingleFiles to have a higher level of manual control, - to support future features. [#546][] -- Backend: moved testing from GTest to Catch2 [#574][] -- Bugfix: avoid duplicated and missed calls to the final callback [#584][] -- Bugfix: support embedded newlines in more places [#592][] -- Bugfix: avoid listing helpall as a required flag [#530][] -- Bugfix: avoid a clash with WINDOWS define [#563][] -- Bugfix: the help flag didn't get processed when a config file was required - [#606][] -- Bugfix: fix description of non-configurable subcommands in config [#604][] -- Build: support pkg-config [#523][] - -> ### Converting from CLI11 1.9 -> -> - Removed deprecated set commands, use validators instead. [#565][] -> - The final "defaulted" bool has been removed, use `->capture_default_str()` -> instead. Use `app.option_defaults()->always_capture_default()` to set this -> for all future options. [#597][] -> - Use `add_option` on a complex number instead of `add_complex`, which has -> been removed. - -[#423]: https://github.com/CLIUtils/CLI11/pull/423 -[#435]: https://github.com/CLIUtils/CLI11/pull/435 -[#443]: https://github.com/CLIUtils/CLI11/pull/443 -[#452]: https://github.com/CLIUtils/CLI11/pull/452 -[#520]: https://github.com/CLIUtils/CLI11/pull/520 -[#523]: https://github.com/CLIUtils/CLI11/pull/523 -[#526]: https://github.com/CLIUtils/CLI11/pull/526 -[#528]: https://github.com/CLIUtils/CLI11/pull/528 -[#529]: https://github.com/CLIUtils/CLI11/pull/529 -[#530]: https://github.com/CLIUtils/CLI11/pull/530 -[#545]: https://github.com/CLIUtils/CLI11/pull/545 -[#546]: https://github.com/CLIUtils/CLI11/pull/546 -[#563]: https://github.com/CLIUtils/CLI11/pull/563 -[#565]: https://github.com/CLIUtils/CLI11/pull/565 -[#574]: https://github.com/CLIUtils/CLI11/pull/574 -[#584]: https://github.com/CLIUtils/CLI11/pull/584 -[#592]: https://github.com/CLIUtils/CLI11/pull/592 -[#597]: https://github.com/CLIUtils/CLI11/pull/597 -[#599]: https://github.com/CLIUtils/CLI11/pull/599 -[#601]: https://github.com/CLIUtils/CLI11/pull/601 -[#604]: https://github.com/CLIUtils/CLI11/pull/604 -[#605]: https://github.com/CLIUtils/CLI11/pull/605 -[#606]: https://github.com/CLIUtils/CLI11/pull/606 - -## Version 1.9: Config files and cleanup - -Config file handling was revamped to fix common issues, and now supports reading -[TOML](https://github.com/toml-lang/toml). - -Adding options is significantly more powerful with support for things like -`std::tuple` and `std::array`, including with transforms. Several new -configuration options were added to facilitate a wider variety of apps. GCC 4.7 -is no longer supported. - -- Config files refactored, supports TOML (may become default output in 2.0) - [#362][] -- Added two template parameter form of `add_option`, allowing `std::optional` to - be supported without a special import [#285][] -- `string_view` now supported in reasonable places [#300][], [#285][] -- `immediate_callback`, `final_callback`, and `parse_complete_callback` added to - support controlling the App callback order [#292][], [#313][] -- Multiple positional arguments maintain order if `positionals_at_end` is set. - [#306][] -- Pair/tuple/array now supported, and validators indexed to specific components - in the objects [#307][], [#310][] -- Footer callbacks supported [#309][] -- Subcommands now support needs (including nameless subcommands) [#317][] -- More flexible type size, more useful `add_complex` [#325][], [#370][] -- Added new validators `CLI::NonNegativeNumber` and `CLI::PositiveNumber` - [#342][] -- Transform now supports arrays [#349][] -- Option groups can be hidden [#356][] -- Add `CLI::deprecate_option` and `CLI::retire_option` functions [#358][] -- More flexible and safer Option `default_val` [#387][] -- Backend: Cleaner type traits [#286][] -- Backend: File checking updates [#341][] -- Backend: Using pre-commit to format, checked in GitHub Actions [#336][] -- Backend: Clang-tidy checked again, CMake option now `CL11_CLANG_TIDY` [#390][] -- Backend: Warning cleanup, more checks from klocwork [#350][], Effective C++ - [#354][], clang-tidy [#360][], CUDA NVCC [#365][], cross compile [#373][], - sign conversion [#382][], and cpplint [#400][] -- Docs: CLI11 Tutorial now hosted in the same repository [#304][], [#318][], - [#374][] -- Bugfix: Fixed undefined behavior in `checked_multiply` [#290][] -- Bugfix: `->check()` was adding the name to the wrong validator [#320][] -- Bugfix: Resetting config option works properly [#301][] -- Bugfix: Hidden flags were showing up in error printout [#333][] -- Bugfix: Enum conversion no longer broken if stream operator added [#348][] -- Build: The meson build system supported [#299][] -- Build: GCC 4.7 is no longer supported, due mostly to GoogleTest. GCC 4.8+ is - now required. [#160][] -- Build: Restructured significant portions of CMake build system [#394][] - -> ### Converting from CLI11 1.8 -> -> - Some deprecated methods dropped -> - `add_set*` should be replaced with `->check`/`->transform` and -> `CLI::IsMember` since 1.8 -> - `get_defaultval` was replaced by `get_default_str` in 1.8 -> - The true/false 4th argument to `add_option` is expected to be removed in -> 2.0, use `->capture_default_str()` since 1.8 - -[#160]: https://github.com/CLIUtils/CLI11/pull/160 -[#285]: https://github.com/CLIUtils/CLI11/pull/285 -[#286]: https://github.com/CLIUtils/CLI11/pull/286 -[#290]: https://github.com/CLIUtils/CLI11/pull/290 -[#292]: https://github.com/CLIUtils/CLI11/pull/292 -[#299]: https://github.com/CLIUtils/CLI11/pull/299 -[#300]: https://github.com/CLIUtils/CLI11/pull/300 -[#301]: https://github.com/CLIUtils/CLI11/pull/301 -[#304]: https://github.com/CLIUtils/CLI11/pull/304 -[#306]: https://github.com/CLIUtils/CLI11/pull/306 -[#307]: https://github.com/CLIUtils/CLI11/pull/307 -[#309]: https://github.com/CLIUtils/CLI11/pull/309 -[#310]: https://github.com/CLIUtils/CLI11/pull/310 -[#313]: https://github.com/CLIUtils/CLI11/pull/313 -[#317]: https://github.com/CLIUtils/CLI11/pull/317 -[#318]: https://github.com/CLIUtils/CLI11/pull/318 -[#320]: https://github.com/CLIUtils/CLI11/pull/320 -[#325]: https://github.com/CLIUtils/CLI11/pull/325 -[#333]: https://github.com/CLIUtils/CLI11/pull/333 -[#336]: https://github.com/CLIUtils/CLI11/pull/336 -[#341]: https://github.com/CLIUtils/CLI11/pull/341 -[#342]: https://github.com/CLIUtils/CLI11/pull/342 -[#348]: https://github.com/CLIUtils/CLI11/pull/348 -[#349]: https://github.com/CLIUtils/CLI11/pull/349 -[#350]: https://github.com/CLIUtils/CLI11/pull/350 -[#354]: https://github.com/CLIUtils/CLI11/pull/354 -[#356]: https://github.com/CLIUtils/CLI11/pull/356 -[#358]: https://github.com/CLIUtils/CLI11/pull/358 -[#360]: https://github.com/CLIUtils/CLI11/pull/360 -[#362]: https://github.com/CLIUtils/CLI11/pull/362 -[#365]: https://github.com/CLIUtils/CLI11/pull/365 -[#370]: https://github.com/CLIUtils/CLI11/pull/370 -[#373]: https://github.com/CLIUtils/CLI11/pull/373 -[#374]: https://github.com/CLIUtils/CLI11/pull/374 -[#382]: https://github.com/CLIUtils/CLI11/pull/382 -[#387]: https://github.com/CLIUtils/CLI11/pull/387 -[#390]: https://github.com/CLIUtils/CLI11/pull/390 -[#394]: https://github.com/CLIUtils/CLI11/pull/394 -[#400]: https://github.com/CLIUtils/CLI11/pull/400 - -### Version 1.9.1: Backporting fixes - -This is a patch version that backports fixes from the development of 2.0. - -- Support relative inclusion [#475][] -- Fix cases where spaces in paths could break CMake support [#471][] -- Fix an issue with string conversion [#421][] -- Cross-compiling improvement for Conan.io [#430][] -- Fix option group default propagation [#450][] -- Fix for C++20 [#459][] -- Support compiling with RTTI off [#461][] - -[#421]: https://github.com/CLIUtils/CLI11/pull/421 -[#430]: https://github.com/CLIUtils/CLI11/pull/430 -[#450]: https://github.com/CLIUtils/CLI11/pull/450 -[#459]: https://github.com/CLIUtils/CLI11/pull/459 -[#461]: https://github.com/CLIUtils/CLI11/pull/461 -[#471]: https://github.com/CLIUtils/CLI11/pull/471 -[#475]: https://github.com/CLIUtils/CLI11/pull/475 - -## Version 1.8: Transformers, default strings, and flags - -Set handling has been completely replaced by a new backend that works as a -Validator or Transformer. This provides a single interface instead of the 16 -different functions in App. It also allows ordered collections to be used, -custom functions for filtering, and better help and error messages. You can also -use a collection of pairs (like `std::map`) to transform the match into an -output. Also new are inverted flags, which can cancel or reduce the count of -flags, and can also support general flag types. A new `add_option_fn` lets you -more easily program CLI11 options with the types you choose. Vector options now -support a custom separator. Apps can now be composed with unnamed subcommand -support. The final bool "defaults" flag when creating options has been replaced -by `->capture_default_str()` (ending an old limitation in construction made this -possible); the old method is still available but may be removed in future -versions. - -- Replaced default help capture: `.add_option("name", value, "", True)` becomes - `.add_option("name", value)->capture_default_str()` [#242][] -- Added `.always_capture_default()` [#242][] -- New `CLI::IsMember` validator replaces set validation [#222][] -- `IsMember` also supports container of pairs, transform allows modification of - result [#228][] -- Added new Transformers, `CLI::AsNumberWithUnit` and `CLI::AsSizeValue` - [#253][] -- Much more powerful flags with different values [#211][], general types - [#235][] -- `add_option` now supports bool due to unified bool handling [#211][] -- Support for composable unnamed subcommands [#216][] -- Reparsing is better supported with `.remaining_for_passthrough()` [#265][] -- Custom vector separator using `->delimiter(char)` [#209][], [#221][], [#240][] -- Validators added for IP4 addresses and positive numbers [#210][] and numbers - [#262][] -- Minimum required Boost for optional Optionals has been corrected to 1.61 - [#226][] -- Positionals can stop options from being parsed with `app.positionals_at_end()` - [#223][] -- Added `validate_positionals` [#262][] -- Positional parsing is much more powerful [#251][], duplicates supported - [#247][] -- Validators can be negated with `!` [#230][], and now handle tname functions - [#228][] -- Better enum support and streaming helper [#233][] and [#228][] -- Cleanup for shadow warnings [#232][] -- Better alignment on multiline descriptions [#269][] -- Better support for aarch64 [#266][] -- Respect `BUILD_TESTING` only if CLI11 is the main project; otherwise, - `CLI11_TESTING` must be used [#277][] -- Drop auto-detection of experimental optional and boost::optional; must be - enabled explicitly (too fragile) [#277][] [#279][] - -> ### Converting from CLI11 1.7 -> -> - `.add_option(..., true)` should be replaced by -> `.add_option(...)->capture_default_str()` or -> `app.option_defaults()->always_capture_default()` can be used -> - `app.add_set("--name", value, {"choice1", "choice2"})` should become -> `app.add_option("--name", value)->check(CLI::IsMember({"choice1", "choice2"}))` -> - The `_ignore_case` version of this can be replaced by adding -> `CLI::ignore_case` to the argument list in `IsMember` -> - The `_ignore_underscore` version of this can be replaced by adding -> `CLI::ignore_underscore` to the argument list in `IsMember` -> - The `_ignore_case_underscore` version of this can be replaced by adding both -> functions listed above to the argument list in `IsMember` -> - If you want an exact match to the original choice after one of the modifier -> functions matches, use `->transform` instead of `->check` -> - The `_mutable` versions of this can be replaced by passing a pointer or -> shared pointer into `IsMember` -> - An error with sets now produces a `ValidationError` instead of a -> `ConversionError` - -[#209]: https://github.com/CLIUtils/CLI11/pull/209 -[#210]: https://github.com/CLIUtils/CLI11/pull/210 -[#211]: https://github.com/CLIUtils/CLI11/pull/211 -[#216]: https://github.com/CLIUtils/CLI11/pull/216 -[#221]: https://github.com/CLIUtils/CLI11/pull/221 -[#222]: https://github.com/CLIUtils/CLI11/pull/222 -[#223]: https://github.com/CLIUtils/CLI11/pull/223 -[#226]: https://github.com/CLIUtils/CLI11/pull/226 -[#228]: https://github.com/CLIUtils/CLI11/pull/228 -[#230]: https://github.com/CLIUtils/CLI11/pull/230 -[#232]: https://github.com/CLIUtils/CLI11/pull/232 -[#233]: https://github.com/CLIUtils/CLI11/pull/233 -[#235]: https://github.com/CLIUtils/CLI11/pull/235 -[#240]: https://github.com/CLIUtils/CLI11/pull/240 -[#242]: https://github.com/CLIUtils/CLI11/pull/242 -[#247]: https://github.com/CLIUtils/CLI11/pull/247 -[#251]: https://github.com/CLIUtils/CLI11/pull/251 -[#253]: https://github.com/CLIUtils/CLI11/pull/253 -[#262]: https://github.com/CLIUtils/CLI11/pull/262 -[#265]: https://github.com/CLIUtils/CLI11/pull/265 -[#266]: https://github.com/CLIUtils/CLI11/pull/266 -[#269]: https://github.com/CLIUtils/CLI11/pull/269 -[#277]: https://github.com/CLIUtils/CLI11/pull/277 -[#279]: https://github.com/CLIUtils/CLI11/pull/279 - -## Version 1.7: Parse breakup - -The parsing procedure now maps much more sensibly to complex, nested subcommand -structures. Each phase of the parsing happens on all subcommands before moving -on with the next phase of the parse. This allows several features, like required -environment variables, to work properly even through subcommand boundaries. -Passing the same subcommand multiple times is better supported. Several new -features were added as well, including Windows style option support, parsing -strings directly, and ignoring underscores in names. Adding a set that you plan -to change later must now be done with `add_mutable_set`. - -- Support Windows style options with `->allow_windows_style_options`. [#187][] - On by default on Windows. [#190][] -- Added `parse(string)` to split up and parse a command-line style string - directly. [#186][] -- Added `ignore_underscore` and related functions, to ignore underscores when - matching names. [#185][] -- The default INI Config will now add quotes to strings with spaces [#195][] -- The default message now will mention the help-all flag also if present - [#197][] -- Added `->description` to set Option descriptions [#199][] -- Mutating sets (introduced in Version 1.6) now have a clear add method, - `add_mutable_set*`, since the set reference should not expire [#200][] -- Subcommands now track how many times they were parsed in a parsing process. - `count()` with no arguments will return the number of times a subcommand was - encountered. [#178][] -- Parsing is now done in phases: `shortcurcuits`, `ini`, `env`, `callbacks`, and - `requirements`; all subcommands complete a phase before moving on. [#178][] -- Calling parse multiple times is now officially supported without `clear` - (automatic). [#178][] -- Dropped the mostly undocumented `short_circuit` property, as help flag parsing - is a bit more complex, and the default callback behavior of options now works - properly. [#179][] -- Use the standard `BUILD_TESTING` over `CLI11_TESTING` if defined [#183][] -- Cleanup warnings [#191][] -- Remove deprecated names: `set_footer`, `set_name`, `set_callback`, and - `set_type_name`. Use without the `set_` instead. [#192][] - -> ### Converting from CLI11 1.6 -> -> - `->short_circuit()` is no longer needed, just remove it if you were using -> it - raising an exception will happen in the proper place now without it. -> - `->add_set*` becomes `->add_mutable_set*` if you were using the editable set -> feature -> - `footer`, `name`, `callback`, and `type_name` must be used instead of the -> `set_*` versions (deprecated previously). - -[#178]: https://github.com/CLIUtils/CLI11/pull/178 -[#183]: https://github.com/CLIUtils/CLI11/pull/183 -[#185]: https://github.com/CLIUtils/CLI11/pull/185 -[#186]: https://github.com/CLIUtils/CLI11/pull/186 -[#187]: https://github.com/CLIUtils/CLI11/pull/187 -[#190]: https://github.com/CLIUtils/CLI11/pull/190 -[#191]: https://github.com/CLIUtils/CLI11/pull/191 -[#192]: https://github.com/CLIUtils/CLI11/pull/192 -[#197]: https://github.com/CLIUtils/CLI11/pull/197 -[#195]: https://github.com/CLIUtils/CLI11/issues/195 -[#199]: https://github.com/CLIUtils/CLI11/pull/199 -[#200]: https://github.com/CLIUtils/CLI11/pull/200 - -### Version 1.7.1: Quick patch - -This version provides a quick patch for a (correct) warning from GCC 8 for the -windows options code. - -- Fix for Windows style option parsing [#201][] -- Improve `add_subcommand` when throwing an exception [#204][] -- Better metadata for Conan package [#202][] - -[#201]: https://github.com/CLIUtils/CLI11/pull/201 -[#202]: https://github.com/CLIUtils/CLI11/pull/202 -[#204]: https://github.com/CLIUtils/CLI11/pull/204 - -## Version 1.6: Formatting help - -Added a new formatting system [#109][]. You can now set the formatter on Apps. -This has also simplified the internals of Apps and Options a bit by separating -most formatting code. - -- Added `CLI::Formatter` and `formatter` slot for apps, inherited. -- `FormatterBase` is the minimum required. -- `FormatterLambda` provides for the easy addition of an arbitrary function. -- Added `help_all` support (not added by default). - -Changes to the help system (most normal users will not notice this): - -- Renamed `single_name` to `get_name(false, false)` (the default). -- The old `get_name()` is now `get_name(false, true)`. -- The old `get_pname()` is now `get_name(true, false)`. -- Removed `help_*` functions. -- Protected function `_has_help_positional` removed. -- `format_help` can now be chained. -- Added getters for the missing parts of options (help no longer uses any - private parts). -- Help flags now use new `short_circuit` property to simplify parsing. [#121][] - -New for Config file reading and writing [#121][]: - -- Overridable, bidirectional Config. -- ConfigINI provided and used by default. -- Renamed ini to config in many places. -- Has `config_formatter()` and `get_config_formatter()`. -- Dropped prefix argument from `config_to_str`. -- Added `ConfigItem`. -- Added an example of a custom config format using [nlohmann/json][]. [#138][] - -Validators are now much more powerful [#118][], all built in validators upgraded -to the new form: - -- A subclass of `CLI::Validator` is now also accepted. -- They now can set the type name to things like `PATH` and `INT in [1-4]`. -- Validators can be combined with `&` and `|`. -- Old form simple validators are still accepted. - -Other changes: - -- Fixing `parse(args)`'s `args` setting and ordering after parse. [#141][] -- Replaced `set_custom_option` with `type_name` and `type_size` instead of - `set_custom_option`. Methods return `this`. [#136][] -- Dropped `set_` on Option's `type_name`, `default_str`, and `default_val`. - [#136][] -- Removed `set_` from App's `failure_message`, `footer`, `callback`, and `name`. - [#136][] -- Fixed support `N<-1` for `type_size`. [#140][] -- Added `->each()` to make adding custom callbacks easier. [#126][] -- Allow empty options `add_option("-n",{})` to be edited later with `each` - [#142][] -- Added filter argument to `get_subcommands`, `get_options`; use empty filter - `{}` to avoid filtering. -- Added `get_groups()` to get groups. -- Better support for manual options with `get_option`, `set_results`, and - `empty`. [#119][] -- `lname` and `sname` have getters, added `const get_parent`. [#120][] -- Using `add_set` will now capture L-values for sets, allowing further - modification. [#113][] -- Dropped duplicate way to run `get_type_name` (`get_typeval`). -- Removed `requires` in favor of `needs` (deprecated in last version). [#112][] -- Const added to argv. [#126][] - -Backend and testing changes: - -- Internally, `type_name` is now a lambda function; for sets, this reads the set - live. [#116][] -- Cleaner tests without `app.reset()` (and `reset` is now `clear`). [#141][] -- Better CMake policy handling. [#110][] -- Includes are properly sorted. [#120][] -- Testing (only) now uses submodules. [#111][] - -[#109]: https://github.com/CLIUtils/CLI11/pull/109 -[#110]: https://github.com/CLIUtils/CLI11/pull/110 -[#111]: https://github.com/CLIUtils/CLI11/pull/111 -[#112]: https://github.com/CLIUtils/CLI11/pull/112 -[#113]: https://github.com/CLIUtils/CLI11/issues/113 -[#116]: https://github.com/CLIUtils/CLI11/pull/116 -[#118]: https://github.com/CLIUtils/CLI11/pull/118 -[#119]: https://github.com/CLIUtils/CLI11/pull/119 -[#120]: https://github.com/CLIUtils/CLI11/pull/120 -[#121]: https://github.com/CLIUtils/CLI11/pull/121 -[#126]: https://github.com/CLIUtils/CLI11/pull/126 -[#136]: https://github.com/CLIUtils/CLI11/pull/136 -[#138]: https://github.com/CLIUtils/CLI11/pull/138 -[#140]: https://github.com/CLIUtils/CLI11/pull/140 -[#141]: https://github.com/CLIUtils/CLI11/pull/141 -[#142]: https://github.com/CLIUtils/CLI11/pull/142 -[nlohmann/json]: https://github.com/nlohmann/json - -### Version 1.6.1: Platform fixes - -This version provides a few fixes for special cases, such as mixing with -`Windows.h` and better defaults for systems like Hunter. The one new feature is -the ability to produce "branded" single file output for providing custom -namespaces or custom macro names. - -- Added fix and test for including Windows.h [#145][] -- No longer build single file by default if main project, supports systems stuck - on Python 2.6 [#149][], [#151][] -- Branding support for single file output [#150][] - -[#145]: https://github.com/CLIUtils/CLI11/pull/145 -[#149]: https://github.com/CLIUtils/CLI11/pull/149 -[#150]: https://github.com/CLIUtils/CLI11/pull/150 -[#151]: https://github.com/CLIUtils/CLI11/pull/151 - -### Version 1.6.2: Help-all - -This version fixes some formatting bugs with help-all. It also adds fixes for -several warnings, including an experimental optional error on Clang 7. Several -smaller fixes. - -- Fixed help-all formatting [#163][] - - Printing help-all on nested command now fixed (App) - - Missing space after help-all restored (Default formatter) - - More detail printed on help all (Default formatter) - - Help-all subcommands get indented with inner blank lines removed (Default - formatter) - - `detail::find_and_replace` added to utilities -- Fixed CMake install as subproject with `CLI11_INSTALL` flag. [#156][] -- Fixed warning about local variable hiding class member with MSVC [#157][] -- Fixed compile error with default settings on Clang 7 and libc++ [#158][] -- Fixed special case of `--help` on subcommands (general fix planned for 1.7) - [#168][] -- Removing an option with links [#179][] - -[#156]: https://github.com/CLIUtils/CLI11/issues/156 -[#157]: https://github.com/CLIUtils/CLI11/issues/157 -[#158]: https://github.com/CLIUtils/CLI11/issues/158 -[#163]: https://github.com/CLIUtils/CLI11/pull/163 -[#168]: https://github.com/CLIUtils/CLI11/issues/168 -[#179]: https://github.com/CLIUtils/CLI11/pull/179 - -## Version 1.5: Optionals - -This version introduced support for optionals, along with clarification and -examples of custom conversion overloads. Enums now have been dropped from the -automatic conversion system, allowing explicit protection for out-of-range ints -(or a completely custom conversion). This version has some internal cleanup and -improved support for the newest compilers. Several bugs were fixed, as well. - -Note: This is the final release with `requires`, please switch to `needs`. - -- Fix unlimited short options eating two values before checking for positionals - when no space present [#90][] -- Symmetric exclude text when excluding options, exclude can be called multiple - times [#64][] -- Support for `std::optional`, `std::experimental::optional`, and - `boost::optional` added if `__has_include` is supported [#95][] -- All macros/CMake variables now start with `CLI11_` instead of just `CLI_` - [#95][] -- The internal stream was not being cleared before use in some cases. Fixed. - [#95][] -- Using an enum now requires explicit conversion overload [#97][] -- The separator `--` now is removed when it ends unlimited arguments [#100][] - -Other, non-user facing changes: - -- Added `Macros.hpp` with better C++ mode discovery [#95][] -- Deprecated macros added for all platforms -- C++17 is now tested on supported platforms [#95][] -- Informational printout now added to CTest [#95][] -- Better single file generation [#95][] -- Added support for GTest on MSVC 2017 (but not in C++17 mode, will need next - version of GTest) -- Types now have a specific size, separate from the expected number - cleaner - and more powerful internally [#92][] -- Examples now run as part of testing [#99][] - -[#64]: https://github.com/CLIUtils/CLI11/issues/64 -[#90]: https://github.com/CLIUtils/CLI11/issues/90 -[#92]: https://github.com/CLIUtils/CLI11/issues/92 -[#95]: https://github.com/CLIUtils/CLI11/pull/95 -[#97]: https://github.com/CLIUtils/CLI11/pull/97 -[#99]: https://github.com/CLIUtils/CLI11/pull/99 -[#100]: https://github.com/CLIUtils/CLI11/pull/100 - -### Version 1.5.1: Access - -This patch release adds better access to the App programmatically, to assist -with writing custom converters to other formats. It also improves the help -output, and uses a new feature in CLI11 1.5 to fix an old "quirk" in the way -unlimited options and positionals interact. - -- Make mixing unlimited positionals and options more intuitive [#102][] -- Add missing getters `get_options` and `get_description` to App [#105][] -- The app name now can be set, and will override the auto name if present - [#105][] -- Add `(REQUIRED)` for required options [#104][] -- Print simple name for Needs/Excludes [#104][] -- Use Needs instead of Requires in help print [#104][] -- Groups now are listed in the original definition order [#106][] - -[#102]: https://github.com/CLIUtils/CLI11/issues/102 -[#104]: https://github.com/CLIUtils/CLI11/pull/104 -[#105]: https://github.com/CLIUtils/CLI11/pull/105 -[#106]: https://github.com/CLIUtils/CLI11/pull/106 - -### Version 1.5.2: LICENSE in single header mode - -This is a quick patch release that makes LICENSE part of the single header file, -making it easier to include. Minor cleanup from codacy. No significant code -changes from 1.5.1. - -### Version 1.5.3: Compiler compatibility - -This version fixes older AppleClang compilers by removing the optimization for -casting. The minimum version of Boost Optional supported has been clarified to -be 1.58. CUDA 7.0 NVCC is now supported. - -### Version 1.5.4: Optionals - -This version fixes the optional search in the single file version; some macros -were not yet defined when it did the search. You can define the -`CLI11_*_OPTIONAL` macros to 0 if needed to eliminate the search. - -## Version 1.4: More feedback - -This version adds lots of smaller fixes and additions after the refactor in -version 1.3. More ways to download and use CLI11 in CMake have been added. INI -files have improved support. - -- Lexical cast is now more strict than before [#68][] and fails on overflow - [#84][] -- Added `get_parent()` to access the parent from a subcommand -- Added `ExistingPath` validator [#73][] -- `app.allow_ini_extras()` added to allow extras in INI files [#70][] -- Multiline INI comments now supported -- Descriptions can now be written with `config_to_str` [#66][] -- Double printing of error message fixed [#77][] -- Renamed `requires` to `needs` to avoid C++20 keyword [#75][], [#82][] -- MakeSingleHeader now works if outside of git [#78][] -- Adding install support for CMake [#79][], improved support for `find_package` - [#83][], [#84][] -- Added support for Conan.io [#83][] - -[#70]: https://github.com/CLIUtils/CLI11/issues/70 -[#75]: https://github.com/CLIUtils/CLI11/issues/75 -[#84]: https://github.com/CLIUtils/CLI11/pull/84 -[#83]: https://github.com/CLIUtils/CLI11/pull/83 -[#82]: https://github.com/CLIUtils/CLI11/pull/82 -[#79]: https://github.com/CLIUtils/CLI11/pull/79 -[#78]: https://github.com/CLIUtils/CLI11/pull/78 -[#77]: https://github.com/CLIUtils/CLI11/pull/77 -[#73]: https://github.com/CLIUtils/CLI11/pull/73 -[#68]: https://github.com/CLIUtils/CLI11/pull/68 -[#66]: https://github.com/CLIUtils/CLI11/pull/66 - -## Version 1.3: Refactor - -This version focused on refactoring several key systems to ensure correct -behavior in the interaction of different settings. Most caveats about features -only working on the main App have been addressed, and extra arguments have been -reworked. Inheritance of defaults makes configuring CLI11 much easier without -having to subclass. Policies add new ways to handle multiple arguments to match -your favorite CLI programs. Error messages and help messages are better and more -flexible. Several bugs and odd behaviors in the parser have been fixed. - -- Added a version macro, `CLI11_VERSION`, along with `*_MAJOR`, `*_MINOR`, and - `*_PATCH`, for programmatic access to the version. -- Reworked the way defaults are set and inherited; explicit control given to - user with `->option_defaults()` - [#48](https://github.com/CLIUtils/CLI11/pull/48) -- Hidden options now are based on an empty group name, instead of special - "hidden" keyword [#48](https://github.com/CLIUtils/CLI11/pull/48) -- `parse` no longer returns (so `CLI11_PARSE` is always usable) - [#37](https://github.com/CLIUtils/CLI11/pull/37) -- Added `remaining()` and `remaining_size()` - [#37](https://github.com/CLIUtils/CLI11/pull/37) -- `allow_extras` and `prefix_command` are now valid on subcommands - [#37](https://github.com/CLIUtils/CLI11/pull/37) -- Added `take_last` to only take last value passed - [#40](https://github.com/CLIUtils/CLI11/pull/40) -- Added `multi_option_policy` and shortcuts to provide more control than just a - take last policy [#59](https://github.com/CLIUtils/CLI11/pull/59) -- More detailed error messages in a few cases - [#41](https://github.com/CLIUtils/CLI11/pull/41) -- Footers can be added to help [#42](https://github.com/CLIUtils/CLI11/pull/42) -- Help flags are easier to customize - [#43](https://github.com/CLIUtils/CLI11/pull/43) -- Subcommand now support groups [#46](https://github.com/CLIUtils/CLI11/pull/46) -- `CLI::RuntimeError` added, for easy exit with error codes - [#45](https://github.com/CLIUtils/CLI11/pull/45) -- The clang-format script is now no longer "hidden" - [#48](https://github.com/CLIUtils/CLI11/pull/48) -- The order is now preserved for subcommands (list and callbacks) - [#49](https://github.com/CLIUtils/CLI11/pull/49) -- Tests now run individually, utilizing CMake 3.10 additions if possible - [#50](https://github.com/CLIUtils/CLI11/pull/50) -- Failure messages are now customizable, with a shorter default - [#52](https://github.com/CLIUtils/CLI11/pull/52) -- Some improvements to error codes - [#53](https://github.com/CLIUtils/CLI11/pull/53) -- `require_subcommand` now offers a two-argument form and negative values on the - one-argument form are more useful - [#51](https://github.com/CLIUtils/CLI11/pull/51) -- Subcommands no longer match after the max required number is obtained - [#51](https://github.com/CLIUtils/CLI11/pull/51) -- Unlimited options no longer prioritize over remaining/unlimited positionals - [#51](https://github.com/CLIUtils/CLI11/pull/51) -- Added `->transform` which modifies the string parsed - [#54](https://github.com/CLIUtils/CLI11/pull/54) -- Changed of API in validators to `void(std::string &)` (const for users), - throwing providing nicer errors - [#54](https://github.com/CLIUtils/CLI11/pull/54) -- Added `CLI::ArgumentMismatch` [#56](https://github.com/CLIUtils/CLI11/pull/56) - and fixed missing failure if one arg expected - [#55](https://github.com/CLIUtils/CLI11/issues/55) -- Support for minimum unlimited expected arguments - [#56](https://github.com/CLIUtils/CLI11/pull/56) -- Single internal arg parse function - [#56](https://github.com/CLIUtils/CLI11/pull/56) -- Allow options to be disabled from INI file, rename `add_config` to - `set_config` [#60](https://github.com/CLIUtils/CLI11/pull/60) - -> ### Converting from CLI11 1.2 -> -> - `app.parse` no longer returns a vector. Instead, use `app.remaining(true)`. -> - `"hidden"` is no longer a special group name, instead use `""` -> - Validators API has changed to return an error string; use `.empty()` to get -> the old bool back -> - Use `.set_help_flag` instead of accessing the help pointer directly -> (discouraged, but not removed yet) -> - `add_config` has been renamed to `set_config` -> - Errors thrown in some cases are slightly more specific - -## Version 1.2: Stability - -This release focuses on making CLI11 behave properly in corner cases, and with -config files on the command line. This includes fixes for a variety of reported -issues. A few features were added to make life easier, as well; such as a new -flag callback and a macro for the parse command. - -- Added functional form of flag - [#33](https://github.com/CLIUtils/CLI11/pull/33), automatic on C++14 -- Fixed Config file search if passed on command line - [#30](https://github.com/CLIUtils/CLI11/issues/30) -- Added `CLI11_PARSE(app, argc, argv)` macro for simple parse commands (does not - support returning arg) -- The name string can now contain spaces around commas - [#29](https://github.com/CLIUtils/CLI11/pull/29) -- `set_default_str` now only sets string, and `set_default_val` will evaluate - the default string given [#26](https://github.com/CLIUtils/CLI11/issues/26) -- Required positionals now take priority over subcommands - [#23](https://github.com/CLIUtils/CLI11/issues/23) -- Extra requirements enforced by Travis - -## Version 1.1: Feedback - -This release incorporates feedback from the release announcement. The examples -are slowly being expanded, some corner cases improved, and some new -functionality for tricky parsing situations. - -- Added simple support for enumerations, allow non-printable objects - [#12](https://github.com/CLIUtils/CLI11/issues/12) -- Added `app.parse_order()` with original parse order - ([#13](https://github.com/CLIUtils/CLI11/issues/13), - [#16](https://github.com/CLIUtils/CLI11/pull/16)) -- Added `prefix_command()`, which is like `allow_extras` but instantly stops and - returns. ([#8](https://github.com/CLIUtils/CLI11/issues/8), - [#17](https://github.com/CLIUtils/CLI11/pull/17)) -- Removed Windows warning ([#10](https://github.com/CLIUtils/CLI11/issues/10), - [#20](https://github.com/CLIUtils/CLI11/pull/20)) -- Some improvements to CMake, detect Python and no dependencies on Python 2 - (like Python 3) ([#18](https://github.com/CLIUtils/CLI11/issues/18), - [#21](https://github.com/CLIUtils/CLI11/pull/21)) - -## Version 1.0: Official release - -This is the first stable release for CLI11. Future releases will try to remain -backward compatible and will follow semantic versioning if possible. There were -a few small changes since version 0.9: - -- Cleanup using `clang-tidy` and `clang-format` -- Small improvements to Timers, easier to subclass Error -- Move to 3-Clause BSD license - -## Version 0.9: Polish - -This release focused on cleaning up the most exotic compiler warnings, fixing a -few oddities of the config parser, and added a more natural method to check -subcommands. - -- Better CMake named target (CLI11) -- More warnings added, fixed -- Ini output now includes `=false` when `default_also` is true -- Ini no longer lists the help pointer -- Added test for inclusion in multiple files and linking, fixed issues (rarely - needed for CLI, but nice for tools) -- Support for complex numbers -- Subcommands now test true/false directly or with `->parsed()`, cleaner parse - -## Version 0.8: CLIUtils - -This release moved the repository to the CLIUtils main organization. - -- Moved to CLIUtils on GitHub -- Fixed docs build and a few links - -## Version 0.7: Code coverage 100% - -Lots of small bugs fixed when adding code coverage, better in edge cases. Much -more powerful ini support. - -- Allow comments in ini files (lines starting with `;`) -- Ini files support flags, vectors, subcommands -- Added CodeCov code coverage reports -- Lots of small bugfixes related to adding tests to increase coverage to 100% -- Error handling now uses scoped enum in errors -- Reparsing rules changed a little to accommodate Ini files. Callbacks are now - called when parsing INI, and reset any time results are added. -- Adding extra utilities in full version only, `Timer` (not needed for parsing, - but useful for general CLI applications). -- Better support for custom `add_options` like functions. - -## Version 0.6: Cleanup - -Lots of cleanup and docs additions made it into this release. Parsing is simpler -and more robust; fall through option added and works as expected; much more -consistent variable names internally. - -- Simplified parsing to use `vector` only -- Fixed fallthrough, made it optional as well (default: off): `.fallthrough()`. -- Added string versions of `->requires()` and `->excludes()` for consistency. -- Renamed protected members for internal consistency, grouped docs. -- Added the ability to add a number to `.require_subcommand()`. - -## Version 0.5: Windows support - -- Allow `Hidden` options. -- Throw `OptionAlreadyAdded` errors for matching subcommands or options, with - ignore-case included, tests -- `->ignore_case()` added to subcommands, options, and `add_set_ignore_case`. - Subcommands inherit setting from parent App on creation. -- Subcommands now can be "chained", that is, left over arguments can now include - subcommands that then get parsed. Subcommands are now a list - (`get_subcommands`). Added `got_subcommand(App_or_name)` to check for - subcommands. -- Added `.allow_extras()` to disable error on failure. Parse returns a vector of - leftover options. Renamed error to `ExtrasError`, and now triggers on extra - options too. -- Added `require_subcommand` to `App`, to simplify forcing subcommands. Do - **not** do `add_subcommand()->require_subcommand`, since that is the - subcommand, not the main `App`. -- Added printout of ini file text given parsed options, skips flags. -- Support for quotes and spaces in ini files -- Fixes to allow support for Windows (added Appveyor) (Uses `-`, not `/` syntax) - -## Version 0.4: Ini support - -- Updates to help print -- Removed `run`, please use `parse` unless you subclass and add it -- Supports ini files mixed with command line, tested -- Added Range for further Plumbum compatibility -- Added function to print out ini file - -## Version 0.3: Plumbum compatibility - -- Added `->requires`, `->excludes`, and `->envname` from - [Plumbum](http://plumbum.readthedocs.io/en/latest/) -- Supports `->mandatory` from Plumbum -- More tests for help strings, improvements in formatting -- Support type and set syntax in positionals help strings -- Added help groups, with `->group("name")` syntax -- Added initial support for ini file reading with `add_config` option. -- Supports GCC 4.7 again -- Clang 3.5 now required for tests due to googlemock usage, 3.4 should still - work otherwise -- Changes `setup` for an explicit help bool in constructor/`add_subcommand` - -## Version 0.2: Leaner and meaner - -- Moved to simpler syntax, where `Option` pointers are returned and operated on -- Removed `make_` style options -- Simplified Validators, now only requires `->check(function)` -- Removed Combiners -- Fixed pointers to Options, stored in `unique_ptr` now -- Added `Option_p` and `App_p`, mostly for internal use -- Startup sequence, including help flag, can be modified by subclasses - -## Version 0.1: First release - -First release before major cleanup. Still has make syntax and combiners; very -clever syntax but not the best or most commonly expected way to work. diff --git a/external/CLI11/CLI/CLI.hpp b/external/CLI11/CLI/CLI.hpp new file mode 100644 index 000000000..993823959 --- /dev/null +++ b/external/CLI11/CLI/CLI.hpp @@ -0,0 +1,12045 @@ +// CLI11: Version 2.6.1 +// Originally designed by Henry Schreiner +// https://github.com/CLIUtils/CLI11 +// +// This is a standalone header file generated by MakeSingleHeader.py in CLI11/scripts +// from: v2.6.1 +// +// CLI11 2.6.1 Copyright (c) 2017-2025 University of Cincinnati, developed by Henry +// Schreiner under NSF AWARD 1414736. All rights reserved. +// +// Redistribution and use in source and binary forms of CLI11, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// 3. Neither the name of the copyright holder nor the names of its contributors +// may be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#pragma once + +// Standard combined includes: +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define CLI11_VERSION_MAJOR 2 +#define CLI11_VERSION_MINOR 6 +#define CLI11_VERSION_PATCH 1 +#define CLI11_VERSION "2.6.1" + + + + +// The following version macro is very similar to the one in pybind11 +#if !(defined(_MSC_VER) && __cplusplus == 199711L) && !defined(__INTEL_COMPILER) +#if __cplusplus >= 201402L +#define CLI11_CPP14 +#if __cplusplus >= 201703L +#define CLI11_CPP17 +#if __cplusplus > 201703L +#define CLI11_CPP20 +#if __cplusplus > 202002L +#define CLI11_CPP23 +#if __cplusplus > 202302L +#define CLI11_CPP26 +#endif +#endif +#endif +#endif +#endif +#elif defined(_MSC_VER) && __cplusplus == 199711L +// MSVC sets _MSVC_LANG rather than __cplusplus (supposedly until the standard was fully implemented) +// Unless you use the /Zc:__cplusplus flag on Visual Studio 2017 15.7 Preview 3 or newer +#if _MSVC_LANG >= 201402L +#define CLI11_CPP14 +#if _MSVC_LANG > 201402L && _MSC_VER >= 1910 +#define CLI11_CPP17 +#if _MSVC_LANG > 201703L && _MSC_VER >= 1910 +#define CLI11_CPP20 +#if _MSVC_LANG > 202002L && _MSC_VER >= 1922 +#define CLI11_CPP23 +#endif +#endif +#endif +#endif +#endif + +#if defined(CLI11_CPP14) +#define CLI11_DEPRECATED(reason) [[deprecated(reason)]] +#elif defined(_MSC_VER) +#define CLI11_DEPRECATED(reason) __declspec(deprecated(reason)) +#else +#define CLI11_DEPRECATED(reason) __attribute__((deprecated(reason))) +#endif + +// GCC < 10 doesn't ignore this in unevaluated contexts +#if !defined(CLI11_CPP17) || \ + (defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER) && __GNUC__ < 10 && __GNUC__ > 4) +#define CLI11_NODISCARD +#else +#define CLI11_NODISCARD [[nodiscard]] +#endif + +/** detection of rtti */ +#ifndef CLI11_USE_STATIC_RTTI +#if (defined(_HAS_STATIC_RTTI) && _HAS_STATIC_RTTI) +#define CLI11_USE_STATIC_RTTI 1 +#elif defined(__cpp_rtti) +#if (defined(_CPPRTTI) && _CPPRTTI == 0) +#define CLI11_USE_STATIC_RTTI 1 +#else +#define CLI11_USE_STATIC_RTTI 0 +#endif +#elif (defined(__GCC_RTTI) && __GXX_RTTI) +#define CLI11_USE_STATIC_RTTI 0 +#else +#define CLI11_USE_STATIC_RTTI 1 +#endif +#endif + +/** availability */ +#if defined CLI11_CPP17 && defined __has_include && !defined CLI11_HAS_FILESYSTEM +#if __has_include() +// Filesystem cannot be used if targeting macOS < 10.15 +#if defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 +#define CLI11_HAS_FILESYSTEM 0 +#elif defined(__wasi__) +// As of wasi-sdk-14, filesystem is not implemented +#define CLI11_HAS_FILESYSTEM 0 +#else +#include +#if defined __cpp_lib_filesystem && __cpp_lib_filesystem >= 201703 +#if defined _GLIBCXX_RELEASE && _GLIBCXX_RELEASE >= 9 +#define CLI11_HAS_FILESYSTEM 1 +#elif defined(__GLIBCXX__) +// if we are using gcc and Version <9 default to no filesystem +#define CLI11_HAS_FILESYSTEM 0 +#else +#define CLI11_HAS_FILESYSTEM 1 +#endif +#else +#define CLI11_HAS_FILESYSTEM 0 +#endif +#endif +#endif +#endif + +/** availability */ +#if !defined(CLI11_CPP26) && !defined(CLI11_HAS_CODECVT) +#if defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER) && __GNUC__ < 5 +#define CLI11_HAS_CODECVT 0 +#else +#define CLI11_HAS_CODECVT 1 +#include +#endif +#else +#if defined(CLI11_HAS_CODECVT) +#if CLI11_HAS_CODECVT > 0 +#include +#endif +#else +#define CLI11_HAS_CODECVT 0 +#endif +#endif + +/** rtti enabled */ +#ifndef CLI11_HAS_RTTI +#if defined(__GXX_RTTI) && __GXX_RTTI == 1 +// gcc +#define CLI11_HAS_RTTI 1 +#elif defined(_CPPRTTI) && _CPPRTTI == 1 +// msvc +#define CLI11_HAS_RTTI 1 +#elif defined(__NO_RTTI__) && __NO_RTTI__ == 1 +// intel +#define CLI11_HAS_RTTI 0 +#elif defined(__has_feature) +// clang and other newer compilers +#if __has_feature(cxx_rtti) +#define CLI11_HAS_RTTI 1 +#else +#define CLI11_HAS_RTTI 0 +#endif +#elif defined(__RTTI) || defined(__INTEL_RTTI__) +// more intel and some other compilers +#define CLI11_HAS_RTTI 1 +#else +#define CLI11_HAS_RTTI 0 +#endif +#endif + +/** disable deprecations */ +#if defined(__GNUC__) // GCC or clang +#define CLI11_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") +#define CLI11_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") + +#define CLI11_DIAGNOSTIC_IGNORE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") + +#elif defined(_MSC_VER) +#define CLI11_DIAGNOSTIC_PUSH __pragma(warning(push)) +#define CLI11_DIAGNOSTIC_POP __pragma(warning(pop)) + +#define CLI11_DIAGNOSTIC_IGNORE_DEPRECATED __pragma(warning(disable : 4996)) + +#else +#define CLI11_DIAGNOSTIC_PUSH +#define CLI11_DIAGNOSTIC_POP + +#define CLI11_DIAGNOSTIC_IGNORE_DEPRECATED + +#endif + +/** Inline macro **/ +#ifdef CLI11_COMPILE +#define CLI11_INLINE +#else +#define CLI11_INLINE inline +#endif + + + +#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0 +#include // NOLINT(build/include) +#else +#include +#include +#endif + + + + +#ifdef CLI11_CPP17 +#include +#endif // CLI11_CPP17 + +#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0 +#include +#include // NOLINT(build/include) +#endif // CLI11_HAS_FILESYSTEM + + + +#if defined(_WIN32) +#if !(defined(_AMD64_) || defined(_X86_) || defined(_ARM_)) +#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || \ + defined(_M_AMD64) +#define _AMD64_ +#elif defined(i386) || defined(__i386) || defined(__i386__) || defined(__i386__) || defined(_M_IX86) +#define _X86_ +#elif defined(__arm__) || defined(_M_ARM) || defined(_M_ARMT) +#define _ARM_ +#elif defined(__aarch64__) || defined(_M_ARM64) +#define _ARM64_ +#elif defined(_M_ARM64EC) +#define _ARM64EC_ +#endif +#endif + +// first +#ifndef NOMINMAX +// if NOMINMAX is already defined we don't want to mess with that either way +#define NOMINMAX +#include +#undef NOMINMAX +#else +#include +#endif + +// second +#include +// third +#include +#include +#endif + + +namespace CLI { + + +/// Convert a wide string to a narrow string. +CLI11_INLINE std::string narrow(const std::wstring &str); +CLI11_INLINE std::string narrow(const wchar_t *str); +CLI11_INLINE std::string narrow(const wchar_t *str, std::size_t size); + +/// Convert a narrow string to a wide string. +CLI11_INLINE std::wstring widen(const std::string &str); +CLI11_INLINE std::wstring widen(const char *str); +CLI11_INLINE std::wstring widen(const char *str, std::size_t size); + +#ifdef CLI11_CPP17 +CLI11_INLINE std::string narrow(std::wstring_view str); +CLI11_INLINE std::wstring widen(std::string_view str); +#endif // CLI11_CPP17 + +#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0 +/// Convert a char-string to a native path correctly. +CLI11_INLINE std::filesystem::path to_path(std::string_view str); +#endif // CLI11_HAS_FILESYSTEM + + + + +namespace detail { + +#if !CLI11_HAS_CODECVT +/// Attempt to set one of the acceptable unicode locales for conversion +CLI11_INLINE void set_unicode_locale() { + static const std::array unicode_locales{{"C.UTF-8", "en_US.UTF-8", ".UTF-8"}}; + + for(const auto &locale_name : unicode_locales) { + if(std::setlocale(LC_ALL, locale_name) != nullptr) { + return; + } + } + throw std::runtime_error("CLI::narrow: could not set locale to C.UTF-8"); +} + +template struct scope_guard_t { + F closure; + + explicit scope_guard_t(F closure_) : closure(closure_) {} + ~scope_guard_t() { closure(); } +}; + +template CLI11_NODISCARD CLI11_INLINE scope_guard_t scope_guard(F &&closure) { + return scope_guard_t{std::forward(closure)}; +} + +#endif // !CLI11_HAS_CODECVT + +CLI11_DIAGNOSTIC_PUSH +CLI11_DIAGNOSTIC_IGNORE_DEPRECATED + +CLI11_INLINE std::string narrow_impl(const wchar_t *str, std::size_t str_size) { +#if CLI11_HAS_CODECVT +#ifdef _WIN32 + return std::wstring_convert>().to_bytes(str, str + str_size); + +#else + return std::wstring_convert>().to_bytes(str, str + str_size); + +#endif // _WIN32 +#else // CLI11_HAS_CODECVT + (void)str_size; + std::mbstate_t state = std::mbstate_t(); + const wchar_t *it = str; + + std::string old_locale = std::setlocale(LC_ALL, nullptr); + auto sg = scope_guard([&] { std::setlocale(LC_ALL, old_locale.c_str()); }); + set_unicode_locale(); + + std::size_t new_size = std::wcsrtombs(nullptr, &it, 0, &state); + if(new_size == static_cast(-1)) { + throw std::runtime_error("CLI::narrow: conversion error in std::wcsrtombs at offset " + + std::to_string(it - str)); + } + std::string result(new_size, '\0'); + std::wcsrtombs(const_cast(result.data()), &str, new_size, &state); + + return result; + +#endif // CLI11_HAS_CODECVT +} + +CLI11_INLINE std::wstring widen_impl(const char *str, std::size_t str_size) { +#if CLI11_HAS_CODECVT +#ifdef _WIN32 + return std::wstring_convert>().from_bytes(str, str + str_size); + +#else + return std::wstring_convert>().from_bytes(str, str + str_size); + +#endif // _WIN32 +#else // CLI11_HAS_CODECVT + (void)str_size; + std::mbstate_t state = std::mbstate_t(); + const char *it = str; + + std::string old_locale = std::setlocale(LC_ALL, nullptr); + auto sg = scope_guard([&] { std::setlocale(LC_ALL, old_locale.c_str()); }); + set_unicode_locale(); + + std::size_t new_size = std::mbsrtowcs(nullptr, &it, 0, &state); + if(new_size == static_cast(-1)) { + throw std::runtime_error("CLI::widen: conversion error in std::mbsrtowcs at offset " + + std::to_string(it - str)); + } + std::wstring result(new_size, L'\0'); + std::mbsrtowcs(const_cast(result.data()), &str, new_size, &state); + + return result; + +#endif // CLI11_HAS_CODECVT +} + +CLI11_DIAGNOSTIC_POP + +} // namespace detail + +CLI11_INLINE std::string narrow(const wchar_t *str, std::size_t str_size) { return detail::narrow_impl(str, str_size); } +CLI11_INLINE std::string narrow(const std::wstring &str) { return detail::narrow_impl(str.data(), str.size()); } +// Flawfinder: ignore +CLI11_INLINE std::string narrow(const wchar_t *str) { return detail::narrow_impl(str, std::wcslen(str)); } + +CLI11_INLINE std::wstring widen(const char *str, std::size_t str_size) { return detail::widen_impl(str, str_size); } +CLI11_INLINE std::wstring widen(const std::string &str) { return detail::widen_impl(str.data(), str.size()); } +// Flawfinder: ignore +CLI11_INLINE std::wstring widen(const char *str) { return detail::widen_impl(str, std::strlen(str)); } + +#ifdef CLI11_CPP17 +CLI11_INLINE std::string narrow(std::wstring_view str) { return detail::narrow_impl(str.data(), str.size()); } +CLI11_INLINE std::wstring widen(std::string_view str) { return detail::widen_impl(str.data(), str.size()); } +#endif // CLI11_CPP17 + +#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0 +CLI11_INLINE std::filesystem::path to_path(std::string_view str) { + return std::filesystem::path{ +#ifdef _WIN32 + widen(str) +#else + str +#endif // _WIN32 + }; +} +#endif // CLI11_HAS_FILESYSTEM + + + + +namespace detail { +#ifdef _WIN32 +/// Decode and return UTF-8 argv from GetCommandLineW. +CLI11_INLINE std::vector compute_win32_argv(); +#endif +} // namespace detail + + + +namespace detail { + +#ifdef _WIN32 +CLI11_INLINE std::vector compute_win32_argv() { + std::vector result; + int argc = 0; + + auto deleter = [](wchar_t **ptr) { LocalFree(ptr); }; + // NOLINTBEGIN(*-avoid-c-arrays) + auto wargv = std::unique_ptr(CommandLineToArgvW(GetCommandLineW(), &argc), deleter); + // NOLINTEND(*-avoid-c-arrays) + + if(wargv == nullptr) { + throw std::runtime_error("CommandLineToArgvW failed with code " + std::to_string(GetLastError())); + } + + result.reserve(static_cast(argc)); + for(size_t i = 0; i < static_cast(argc); ++i) { + result.push_back(narrow(wargv[i])); + } + + return result; +} +#endif + +} // namespace detail + + + + +/// Include the items in this namespace to get free conversion of enums to/from streams. +/// (This is available inside CLI as well, so CLI11 will use this without a using statement). +namespace enums { + +/// output streaming for enumerations +template ::value>::type> +std::ostream &operator<<(std::ostream &in, const T &item) { + // make sure this is out of the detail namespace otherwise it won't be found when needed + // https://isocpp.org/wiki/faq/input-output#print-char-or-ptr-as-number + return in << +static_cast::type>(item); +} + +} // namespace enums + +/// Export to CLI namespace +using enums::operator<<; + +namespace detail { +/// a constant defining an expected max vector size defined to be a big number that could be multiplied by 4 and not +/// produce overflow for some expected uses +constexpr int expected_max_vector_size{1 << 29}; +// Based on http://stackoverflow.com/questions/236129/split-a-string-in-c +/// Split a string by a delim +CLI11_INLINE std::vector split(const std::string &s, char delim); + +/// Simple function to join a string +template std::string join(const T &v, std::string delim = ",") { + std::ostringstream s; + auto beg = std::begin(v); + auto end = std::end(v); + if(beg != end) + s << *beg++; + while(beg != end) { + s << delim << *beg++; + } + auto rval = s.str(); + if(!rval.empty() && delim.size() == 1 && rval.back() == delim[0]) { + // remove trailing delimiter if the last entry was empty + rval.pop_back(); + } + return rval; +} + +/// Simple function to join a string from processed elements +template ::value>::type> +std::string join(const T &v, Callable func, std::string delim = ",") { + std::ostringstream s; + auto beg = std::begin(v); + auto end = std::end(v); + auto loc = s.tellp(); + while(beg != end) { + auto nloc = s.tellp(); + if(nloc > loc) { + s << delim; + loc = nloc; + } + s << func(*beg++); + } + return s.str(); +} + +/// Join a string in reverse order +template std::string rjoin(const T &v, std::string delim = ",") { + std::ostringstream s; + for(std::size_t start = 0; start < v.size(); start++) { + if(start > 0) + s << delim; + s << v[v.size() - start - 1]; + } + return s.str(); +} + +// Based roughly on http://stackoverflow.com/questions/25829143/c-trim-whitespace-from-a-string + +/// Trim whitespace from left of string +CLI11_INLINE std::string <rim(std::string &str); + +/// Trim anything from left of string +CLI11_INLINE std::string <rim(std::string &str, const std::string &filter); + +/// Trim whitespace from right of string +CLI11_INLINE std::string &rtrim(std::string &str); + +/// Trim anything from right of string +CLI11_INLINE std::string &rtrim(std::string &str, const std::string &filter); + +/// Trim whitespace from string +inline std::string &trim(std::string &str) { return ltrim(rtrim(str)); } + +/// Trim anything from string +inline std::string &trim(std::string &str, const std::string filter) { return ltrim(rtrim(str, filter), filter); } + +/// Make a copy of the string and then trim it +inline std::string trim_copy(const std::string &str) { + std::string s = str; + return trim(s); +} + +/// remove quotes at the front and back of a string either '"' or '\'' +CLI11_INLINE std::string &remove_quotes(std::string &str); + +/// remove quotes from all elements of a string vector and process escaped components +CLI11_INLINE void remove_quotes(std::vector &args); + +/// Add a leader to the beginning of all new lines (nothing is added +/// at the start of the first line). `"; "` would be for ini files +/// +/// Can't use Regex, or this would be a subs. +CLI11_INLINE std::string fix_newlines(const std::string &leader, std::string input); + +/// Make a copy of the string and then trim it, any filter string can be used (any char in string is filtered) +inline std::string trim_copy(const std::string &str, const std::string &filter) { + std::string s = str; + return trim(s, filter); +} + +/// Print subcommand aliases +CLI11_INLINE std::ostream &format_aliases(std::ostream &out, const std::vector &aliases, std::size_t wid); + +/// Verify the first character of an option +/// - is a trigger character, ! has special meaning and new lines would just be annoying to deal with +template bool valid_first_char(T c) { + return ((c != '-') && (static_cast(c) > 33)); // space and '!' not allowed +} + +/// Verify following characters of an option +template bool valid_later_char(T c) { + // = and : are value separators, { has special meaning for option defaults, + // and control codes other than tab would just be annoying to deal with in many places allowing space here has too + // much potential for inadvertent entry errors and bugs + return ((c != '=') && (c != ':') && (c != '{') && ((static_cast(c) > 32) || c == '\t')); +} + +/// Verify an option/subcommand name +CLI11_INLINE bool valid_name_string(const std::string &str); + +/// Verify an app name +inline bool valid_alias_name_string(const std::string &str) { + return ((str.find_first_of('\n') == std::string::npos) && (str.find_first_of('\0') == std::string::npos)); +} + +/// check if a string is a container segment separator (empty or "%%") +inline bool is_separator(const std::string &str) { + return (str.empty() || (str.size() == 2 && str[0] == '%' && str[1] == '%')); +} + +/// Verify that str consists of letters only +inline bool isalpha(const std::string &str) { + return std::all_of(str.begin(), str.end(), [](char c) { return std::isalpha(c, std::locale()); }); +} + +/// Return a lower case version of a string +inline std::string to_lower(std::string str) { + std::transform(std::begin(str), std::end(str), std::begin(str), [](const std::string::value_type &x) { + return std::tolower(x, std::locale()); + }); + return str; +} + +/// remove underscores from a string +inline std::string remove_underscore(std::string str) { + str.erase(std::remove(std::begin(str), std::end(str), '_'), std::end(str)); + return str; +} + +/// @brief get valid group separators _' + local separator if different +/// @return a string containing the group separators +CLI11_INLINE std::string get_group_separators(); + +/// Find and replace a substring with another substring +CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to); + +/// check if the flag definitions has possible false flags +inline bool has_default_flag_values(const std::string &flags) { + return (flags.find_first_of("{!") != std::string::npos); +} + +CLI11_INLINE void remove_default_flag_values(std::string &flags); + +/// Check if a string is a member of a list of strings and optionally ignore case or ignore underscores +CLI11_INLINE std::ptrdiff_t find_member(std::string name, + const std::vector names, + bool ignore_case = false, + bool ignore_underscore = false); + +/// Find a trigger string and call a modify callable function that takes the current string and starting position of the +/// trigger and returns the position in the string to search for the next trigger string +template inline std::string find_and_modify(std::string str, std::string trigger, Callable modify) { + std::size_t start_pos = 0; + while((start_pos = str.find(trigger, start_pos)) != std::string::npos) { + start_pos = modify(str, start_pos); + } + return str; +} + +/// close a sequence of characters indicated by a closure character. Brackets allows sub sequences +/// recognized bracket sequences include "'`[(<{ other closure characters are assumed to be literal strings +CLI11_INLINE std::size_t close_sequence(const std::string &str, std::size_t start, char closure_char); + +/// Split a string '"one two" "three"' into 'one two', 'three' +/// Quote characters can be ` ' or " or bracket characters [{(< with matching to the matching bracket +CLI11_INLINE std::vector split_up(std::string str, char delimiter = '\0'); + +/// get the value of an environmental variable or empty string if empty +CLI11_INLINE std::string get_environment_value(const std::string &env_name); + +/// This function detects an equal or colon followed by an escaped quote after an argument +/// then modifies the string to replace the equality with a space. This is needed +/// to allow the split up function to work properly and is intended to be used with the find_and_modify function +/// the return value is the offset+1 which is required by the find_and_modify function. +CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset); + +/// @brief detect if a string has escapable characters +/// @param str the string to do the detection on +/// @return true if the string has escapable characters +CLI11_INLINE bool has_escapable_character(const std::string &str); + +/// @brief escape all escapable characters +/// @param str the string to escape +/// @return a string with the escapable characters escaped with '\' +CLI11_INLINE std::string add_escaped_characters(const std::string &str); + +/// @brief replace the escaped characters with their equivalent +CLI11_INLINE std::string remove_escaped_characters(const std::string &str); + +/// generate a string with all non printable characters escaped to hex codes +CLI11_INLINE std::string binary_escape_string(const std::string &string_to_escape, bool force = false); + +CLI11_INLINE bool is_binary_escaped_string(const std::string &escaped_string); + +/// extract an escaped binary_string +CLI11_INLINE std::string extract_binary_string(const std::string &escaped_string); + +/// process a quoted string, remove the quotes and if appropriate handle escaped characters +CLI11_INLINE bool process_quoted_string(std::string &str, + char string_char = '\"', + char literal_char = '\'', + bool disable_secondary_array_processing = false); + +/// This function formats the given text as a paragraph with fixed width and applies correct line wrapping +/// with a custom line prefix. The paragraph will get streamed to the given ostream. +CLI11_INLINE std::ostream &streamOutAsParagraph(std::ostream &out, + const std::string &text, + std::size_t paragraphWidth, + const std::string &linePrefix = "", + bool skipPrefixOnFirstLine = false); + +} // namespace detail + + + + +namespace detail { +CLI11_INLINE std::vector split(const std::string &s, char delim) { + std::vector elems; + // Check to see if empty string, give consistent result + if(s.empty()) { + elems.emplace_back(); + } else { + std::stringstream ss; + ss.str(s); + std::string item; + while(std::getline(ss, item, delim)) { + elems.push_back(item); + } + } + return elems; +} + +CLI11_INLINE std::string <rim(std::string &str) { + auto it = std::find_if(str.begin(), str.end(), [](char ch) { return !std::isspace(ch, std::locale()); }); + str.erase(str.begin(), it); + return str; +} + +CLI11_INLINE std::string <rim(std::string &str, const std::string &filter) { + auto it = std::find_if(str.begin(), str.end(), [&filter](char ch) { return filter.find(ch) == std::string::npos; }); + str.erase(str.begin(), it); + return str; +} + +CLI11_INLINE std::string &rtrim(std::string &str) { + auto it = std::find_if(str.rbegin(), str.rend(), [](char ch) { return !std::isspace(ch, std::locale()); }); + str.erase(it.base(), str.end()); + return str; +} + +CLI11_INLINE std::string &rtrim(std::string &str, const std::string &filter) { + auto it = + std::find_if(str.rbegin(), str.rend(), [&filter](char ch) { return filter.find(ch) == std::string::npos; }); + str.erase(it.base(), str.end()); + return str; +} + +CLI11_INLINE std::string &remove_quotes(std::string &str) { + if(str.length() > 1 && (str.front() == '"' || str.front() == '\'' || str.front() == '`')) { + if(str.front() == str.back()) { + str.pop_back(); + str.erase(str.begin(), str.begin() + 1); + } + } + return str; +} + +CLI11_INLINE std::string &remove_outer(std::string &str, char key) { + if(str.length() > 1 && (str.front() == key)) { + if(str.front() == str.back()) { + str.pop_back(); + str.erase(str.begin(), str.begin() + 1); + } + } + return str; +} + +CLI11_INLINE std::string fix_newlines(const std::string &leader, std::string input) { + std::string::size_type n = 0; + while(n != std::string::npos && n < input.size()) { + n = input.find_first_of("\r\n", n); + if(n != std::string::npos) { + input = input.substr(0, n + 1) + leader + input.substr(n + 1); + n += leader.size(); + } + } + return input; +} + +CLI11_INLINE std::ostream &format_aliases(std::ostream &out, const std::vector &aliases, std::size_t wid) { + if(!aliases.empty()) { + out << std::setw(static_cast(wid)) << " aliases: "; + bool front = true; + for(const auto &alias : aliases) { + if(!front) { + out << ", "; + } else { + front = false; + } + out << detail::fix_newlines(" ", alias); + } + out << "\n"; + } + return out; +} + +CLI11_INLINE bool valid_name_string(const std::string &str) { + if(str.empty() || !valid_first_char(str[0])) { + return false; + } + auto e = str.end(); + for(auto c = str.begin() + 1; c != e; ++c) + if(!valid_later_char(*c)) + return false; + return true; +} + +CLI11_INLINE std::string get_group_separators() { + std::string separators{"_'"}; +#if CLI11_HAS_RTTI != 0 + char group_separator = std::use_facet>(std::locale()).thousands_sep(); + separators.push_back(group_separator); +#endif + return separators; +} + +CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to) { + + std::size_t start_pos = 0; + + while((start_pos = str.find(from, start_pos)) != std::string::npos) { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); + } + + return str; +} + +CLI11_INLINE void remove_default_flag_values(std::string &flags) { + auto loc = flags.find_first_of('{', 2); + while(loc != std::string::npos) { + auto finish = flags.find_first_of("},", loc + 1); + if((finish != std::string::npos) && (flags[finish] == '}')) { + flags.erase(flags.begin() + static_cast(loc), + flags.begin() + static_cast(finish) + 1); + } + loc = flags.find_first_of('{', loc + 1); + } + flags.erase(std::remove(flags.begin(), flags.end(), '!'), flags.end()); +} + +CLI11_INLINE std::ptrdiff_t +find_member(std::string name, const std::vector names, bool ignore_case, bool ignore_underscore) { + auto it = std::end(names); + if(ignore_case) { + if(ignore_underscore) { + name = detail::to_lower(detail::remove_underscore(name)); + it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) { + return detail::to_lower(detail::remove_underscore(local_name)) == name; + }); + } else { + name = detail::to_lower(name); + it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) { + return detail::to_lower(local_name) == name; + }); + } + + } else if(ignore_underscore) { + name = detail::remove_underscore(name); + it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) { + return detail::remove_underscore(local_name) == name; + }); + } else { + it = std::find(std::begin(names), std::end(names), name); + } + + return (it != std::end(names)) ? (it - std::begin(names)) : (-1); +} + +static const std::string escapedChars("\b\t\n\f\r\"\\"); +static const std::string escapedCharsCode("btnfr\"\\"); +static const std::string bracketChars{"\"'`[(<{"}; +static const std::string matchBracketChars("\"'`])>}"); + +CLI11_INLINE bool has_escapable_character(const std::string &str) { + return (str.find_first_of(escapedChars) != std::string::npos); +} + +CLI11_INLINE std::string add_escaped_characters(const std::string &str) { + std::string out; + out.reserve(str.size() + 4); + for(char s : str) { + auto sloc = escapedChars.find_first_of(s); + if(sloc != std::string::npos) { + out.push_back('\\'); + out.push_back(escapedCharsCode[sloc]); + } else { + out.push_back(s); + } + } + return out; +} + +CLI11_INLINE std::uint32_t hexConvert(char hc) { + int hcode{0}; + if(hc >= '0' && hc <= '9') { + hcode = (hc - '0'); + } else if(hc >= 'A' && hc <= 'F') { + hcode = (hc - 'A' + 10); + } else if(hc >= 'a' && hc <= 'f') { + hcode = (hc - 'a' + 10); + } else { + hcode = -1; + } + return static_cast(hcode); +} + +CLI11_INLINE char make_char(std::uint32_t code) { return static_cast(static_cast(code)); } + +CLI11_INLINE void append_codepoint(std::string &str, std::uint32_t code) { + if(code < 0x80) { // ascii code equivalent + str.push_back(static_cast(code)); + } else if(code < 0x800) { // \u0080 to \u07FF + // 110yyyyx 10xxxxxx; 0x3f == 0b0011'1111 + str.push_back(make_char(0xC0 | code >> 6)); + str.push_back(make_char(0x80 | (code & 0x3F))); + } else if(code < 0x10000) { // U+0800...U+FFFF + if(0xD800 <= code && code <= 0xDFFF) { + throw std::invalid_argument("[0xD800, 0xDFFF] are not valid UTF-8."); + } + // 1110yyyy 10yxxxxx 10xxxxxx + str.push_back(make_char(0xE0 | code >> 12)); + str.push_back(make_char(0x80 | (code >> 6 & 0x3F))); + str.push_back(make_char(0x80 | (code & 0x3F))); + } else if(code < 0x110000) { // U+010000 ... U+10FFFF + // 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx + str.push_back(make_char(0xF0 | code >> 18)); + str.push_back(make_char(0x80 | (code >> 12 & 0x3F))); + str.push_back(make_char(0x80 | (code >> 6 & 0x3F))); + str.push_back(make_char(0x80 | (code & 0x3F))); + } +} + +CLI11_INLINE std::string remove_escaped_characters(const std::string &str) { + + std::string out; + out.reserve(str.size()); + for(auto loc = str.begin(); loc < str.end(); ++loc) { + if(*loc == '\\') { + if(str.end() - loc < 2) { + throw std::invalid_argument("invalid escape sequence " + str); + } + auto ecloc = escapedCharsCode.find_first_of(*(loc + 1)); + if(ecloc != std::string::npos) { + out.push_back(escapedChars[ecloc]); + ++loc; + } else if(*(loc + 1) == 'u') { + // must have 4 hex characters + if(str.end() - loc < 6) { + throw std::invalid_argument("unicode sequence must have 4 hex codes " + str); + } + std::uint32_t code{0}; + std::uint32_t mplier{16 * 16 * 16}; + for(int ii = 2; ii < 6; ++ii) { + std::uint32_t res = hexConvert(*(loc + ii)); + if(res > 0x0F) { + throw std::invalid_argument("unicode sequence must have 4 hex codes " + str); + } + code += res * mplier; + mplier = mplier / 16; + } + append_codepoint(out, code); + loc += 5; + } else if(*(loc + 1) == 'U') { + // must have 8 hex characters + if(str.end() - loc < 10) { + throw std::invalid_argument("unicode sequence must have 8 hex codes " + str); + } + std::uint32_t code{0}; + std::uint32_t mplier{16 * 16 * 16 * 16 * 16 * 16 * 16}; + for(int ii = 2; ii < 10; ++ii) { + std::uint32_t res = hexConvert(*(loc + ii)); + if(res > 0x0F) { + throw std::invalid_argument("unicode sequence must have 8 hex codes " + str); + } + code += res * mplier; + mplier = mplier / 16; + } + append_codepoint(out, code); + loc += 9; + } else if(*(loc + 1) == '0') { + out.push_back('\0'); + ++loc; + } else { + throw std::invalid_argument(std::string("unrecognized escape sequence \\") + *(loc + 1) + " in " + str); + } + } else { + out.push_back(*loc); + } + } + return out; +} + +CLI11_INLINE std::size_t close_string_quote(const std::string &str, std::size_t start, char closure_char) { + std::size_t loc{0}; + for(loc = start + 1; loc < str.size(); ++loc) { + if(str[loc] == closure_char) { + break; + } + if(str[loc] == '\\') { + // skip the next character for escaped sequences + ++loc; + } + } + return loc; +} + +CLI11_INLINE std::size_t close_literal_quote(const std::string &str, std::size_t start, char closure_char) { + auto loc = str.find_first_of(closure_char, start + 1); + return (loc != std::string::npos ? loc : str.size()); +} + +CLI11_INLINE std::size_t close_sequence(const std::string &str, std::size_t start, char closure_char) { + + auto bracket_loc = matchBracketChars.find(closure_char); + switch(bracket_loc) { + case 0: + return close_string_quote(str, start, closure_char); + case 1: + case 2: +#if defined(_MSC_VER) && _MSC_VER < 1920 + case(std::size_t)-1: +#else + case std::string::npos: +#endif + return close_literal_quote(str, start, closure_char); + default: + break; + } + + std::string closures(1, closure_char); + auto loc = start + 1; + + while(loc < str.size()) { + if(str[loc] == closures.back()) { + closures.pop_back(); + if(closures.empty()) { + return loc; + } + } + bracket_loc = bracketChars.find(str[loc]); + if(bracket_loc != std::string::npos) { + switch(bracket_loc) { + case 0: + loc = close_string_quote(str, loc, str[loc]); + break; + case 1: + case 2: + loc = close_literal_quote(str, loc, str[loc]); + break; + default: + closures.push_back(matchBracketChars[bracket_loc]); + break; + } + } + ++loc; + } + if(loc > str.size()) { + loc = str.size(); + } + return loc; +} + +CLI11_INLINE std::vector split_up(std::string str, char delimiter) { + + auto find_ws = [delimiter](char ch) { + return (delimiter == '\0') ? std::isspace(ch, std::locale()) : (ch == delimiter); + }; + trim(str); + + std::vector output; + while(!str.empty()) { + if(bracketChars.find_first_of(str[0]) != std::string::npos) { + auto bracketLoc = bracketChars.find_first_of(str[0]); + auto end = close_sequence(str, 0, matchBracketChars[bracketLoc]); + if(end >= str.size()) { + output.push_back(std::move(str)); + str.clear(); + } else { + output.push_back(str.substr(0, end + 1)); + if(end + 2 < str.size()) { + str = str.substr(end + 2); + } else { + str.clear(); + } + } + + } else { + auto it = std::find_if(std::begin(str), std::end(str), find_ws); + if(it != std::end(str)) { + std::string value = std::string(str.begin(), it); + output.push_back(value); + str = std::string(it + 1, str.end()); + } else { + output.push_back(str); + str.clear(); + } + } + trim(str); + } + return output; +} + +CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset) { + auto next = str[offset + 1]; + if((next == '\"') || (next == '\'') || (next == '`')) { + auto astart = str.find_last_of("-/ \"\'`", offset - 1); + if(astart != std::string::npos) { + if(str[astart] == ((str[offset] == '=') ? '-' : '/')) + str[offset] = ' '; // interpret this as a space so the split_up works properly + } + } + return offset + 1; +} + +CLI11_INLINE std::string binary_escape_string(const std::string &string_to_escape, bool force) { + // s is our escaped output string + std::string escaped_string{}; + // loop through all characters + for(char c : string_to_escape) { + // check if a given character is printable + // the cast is necessary to avoid undefined behaviour + if(isprint(static_cast(c)) == 0) { + std::stringstream stream; + // if the character is not printable + // we'll convert it to a hex string using a stringstream + // note that since char is signed we have to cast it to unsigned first + stream << std::hex << static_cast(static_cast(c)); + std::string code = stream.str(); + escaped_string += std::string("\\x") + (code.size() < 2 ? "0" : "") + code; + } else if(c == 'x' || c == 'X') { + // need to check for inadvertent binary sequences + if(!escaped_string.empty() && escaped_string.back() == '\\') { + escaped_string += std::string("\\x") + (c == 'x' ? "78" : "58"); + } else { + escaped_string.push_back(c); + } + + } else { + escaped_string.push_back(c); + } + } + if(escaped_string != string_to_escape || force) { + auto sqLoc = escaped_string.find('\''); + while(sqLoc != std::string::npos) { + escaped_string[sqLoc] = '\\'; + escaped_string.insert(sqLoc + 1, "x27"); + sqLoc = escaped_string.find('\''); + } + escaped_string.insert(0, "'B\"("); + escaped_string.push_back(')'); + escaped_string.push_back('"'); + escaped_string.push_back('\''); + } + return escaped_string; +} + +CLI11_INLINE bool is_binary_escaped_string(const std::string &escaped_string) { + size_t ssize = escaped_string.size(); + if(escaped_string.compare(0, 3, "B\"(") == 0 && escaped_string.compare(ssize - 2, 2, ")\"") == 0) { + return true; + } + return (escaped_string.compare(0, 4, "'B\"(") == 0 && escaped_string.compare(ssize - 3, 3, ")\"'") == 0); +} + +CLI11_INLINE std::string extract_binary_string(const std::string &escaped_string) { + std::size_t start{0}; + std::size_t tail{0}; + size_t ssize = escaped_string.size(); + if(escaped_string.compare(0, 3, "B\"(") == 0 && escaped_string.compare(ssize - 2, 2, ")\"") == 0) { + start = 3; + tail = 2; + } else if(escaped_string.compare(0, 4, "'B\"(") == 0 && escaped_string.compare(ssize - 3, 3, ")\"'") == 0) { + start = 4; + tail = 3; + } + + if(start == 0) { + return escaped_string; + } + std::string outstring; + + outstring.reserve(ssize - start - tail); + std::size_t loc = start; + while(loc < ssize - tail) { + // ssize-2 to skip )" at the end + if(escaped_string[loc] == '\\' && (escaped_string[loc + 1] == 'x' || escaped_string[loc + 1] == 'X')) { + auto c1 = escaped_string[loc + 2]; + auto c2 = escaped_string[loc + 3]; + + std::uint32_t res1 = hexConvert(c1); + std::uint32_t res2 = hexConvert(c2); + if(res1 <= 0x0F && res2 <= 0x0F) { + loc += 4; + outstring.push_back(static_cast(res1 * 16 + res2)); + continue; + } + } + outstring.push_back(escaped_string[loc]); + ++loc; + } + return outstring; +} + +CLI11_INLINE void remove_quotes(std::vector &args) { + for(auto &arg : args) { + if(arg.front() == '\"' && arg.back() == '\"') { + remove_quotes(arg); + // only remove escaped for string arguments not literal strings + arg = remove_escaped_characters(arg); + } else { + remove_quotes(arg); + } + } +} + +CLI11_INLINE void handle_secondary_array(std::string &str) { + if(str.size() >= 2 && str.front() == '[' && str.back() == ']') { + // handle some special array processing for arguments if it might be interpreted as a secondary array + std::string tstr{"[["}; + for(std::size_t ii = 1; ii < str.size(); ++ii) { + tstr.push_back(str[ii]); + tstr.push_back(str[ii]); + } + str = std::move(tstr); + } +} + +CLI11_INLINE bool +process_quoted_string(std::string &str, char string_char, char literal_char, bool disable_secondary_array_processing) { + if(str.size() <= 1) { + return false; + } + if(detail::is_binary_escaped_string(str)) { + str = detail::extract_binary_string(str); + if(!disable_secondary_array_processing) + handle_secondary_array(str); + return true; + } + if(str.front() == string_char && str.back() == string_char) { + detail::remove_outer(str, string_char); + if(str.find_first_of('\\') != std::string::npos) { + str = detail::remove_escaped_characters(str); + } + if(!disable_secondary_array_processing) + handle_secondary_array(str); + return true; + } + if((str.front() == literal_char || str.front() == '`') && str.back() == str.front()) { + detail::remove_outer(str, str.front()); + if(!disable_secondary_array_processing) + handle_secondary_array(str); + return true; + } + return false; +} + +std::string get_environment_value(const std::string &env_name) { + char *buffer = nullptr; + std::string ename_string; + +#ifdef _MSC_VER + // Windows version + std::size_t sz = 0; + if(_dupenv_s(&buffer, &sz, env_name.c_str()) == 0 && buffer != nullptr) { + ename_string = std::string(buffer); + free(buffer); + } +#else + // This also works on Windows, but gives a warning + buffer = std::getenv(env_name.c_str()); + if(buffer != nullptr) { + ename_string = std::string(buffer); + } +#endif + return ename_string; +} + +CLI11_INLINE std::ostream &streamOutAsParagraph(std::ostream &out, + const std::string &text, + std::size_t paragraphWidth, + const std::string &linePrefix, + bool skipPrefixOnFirstLine) { + if(!skipPrefixOnFirstLine) + out << linePrefix; // First line prefix + + std::istringstream lss(text); + std::string line = ""; + while(std::getline(lss, line)) { + std::istringstream iss(line); + std::string word = ""; + std::size_t charsWritten = 0; + + while(iss >> word) { + if(word.length() + charsWritten > paragraphWidth) { + out << '\n' << linePrefix; + charsWritten = 0; + } + + out << word << " "; + charsWritten += word.length() + 1; + } + + if(!lss.eof()) + out << '\n' << linePrefix; + } + return out; +} + +} // namespace detail + + + +// Use one of these on all error classes. +// These are temporary and are undef'd at the end of this file. +#define CLI11_ERROR_DEF(parent, name) \ + protected: \ + name(std::string ename, std::string msg, int exit_code) : parent(std::move(ename), std::move(msg), exit_code) {} \ + name(std::string ename, std::string msg, ExitCodes exit_code) \ + : parent(std::move(ename), std::move(msg), exit_code) {} \ + \ + public: \ + name(std::string msg, ExitCodes exit_code) : parent(#name, std::move(msg), exit_code) {} \ + name(std::string msg, int exit_code) : parent(#name, std::move(msg), exit_code) {} + +// This is added after the one above if a class is used directly and builds its own message +#define CLI11_ERROR_SIMPLE(name) \ + explicit name(std::string msg) : name(#name, msg, ExitCodes::name) {} + +/// These codes are part of every error in CLI. They can be obtained from e using e.exit_code or as a quick shortcut, +/// int values from e.get_error_code(). +enum class ExitCodes : int { + Success = 0, + IncorrectConstruction = 100, + BadNameString, + OptionAlreadyAdded, + FileError, + ConversionError, + ValidationError, + RequiredError, + RequiresError, + ExcludesError, + ExtrasError, + ConfigError, + InvalidError, + HorribleError, + OptionNotFound, + ArgumentMismatch, + BaseClass = 127 +}; + +// Error definitions + +/// @defgroup error_group Errors +/// @brief Errors thrown by CLI11 +/// +/// These are the errors that can be thrown. Some of them, like CLI::Success, are not really errors. +/// @{ + +/// All errors derive from this one +class Error : public std::runtime_error { + int actual_exit_code; + std::string error_name{"Error"}; + + public: + CLI11_NODISCARD int get_exit_code() const { return actual_exit_code; } + + CLI11_NODISCARD std::string get_name() const { return error_name; } + + Error(std::string name, std::string msg, int exit_code = static_cast(ExitCodes::BaseClass)) + : runtime_error(msg), actual_exit_code(exit_code), error_name(std::move(name)) {} + + Error(std::string name, std::string msg, ExitCodes exit_code) : Error(name, msg, static_cast(exit_code)) {} +}; + +// Note: Using Error::Error constructors does not work on GCC 4.7 + +/// Construction errors (not in parsing) +class ConstructionError : public Error { + CLI11_ERROR_DEF(Error, ConstructionError) +}; + +/// Thrown when an option is set to conflicting values (non-vector and multi args, for example) +class IncorrectConstruction : public ConstructionError { + CLI11_ERROR_DEF(ConstructionError, IncorrectConstruction) + CLI11_ERROR_SIMPLE(IncorrectConstruction) + static IncorrectConstruction PositionalFlag(std::string name) { + return IncorrectConstruction(name + ": Flags cannot be positional"); + } + static IncorrectConstruction Set0Opt(std::string name) { + return IncorrectConstruction(name + ": Cannot set 0 expected, use a flag instead"); + } + static IncorrectConstruction SetFlag(std::string name) { + return IncorrectConstruction(name + ": Cannot set an expected number for flags"); + } + static IncorrectConstruction ChangeNotVector(std::string name) { + return IncorrectConstruction(name + ": You can only change the expected arguments for vectors"); + } + static IncorrectConstruction AfterMultiOpt(std::string name) { + return IncorrectConstruction( + name + ": You can't change expected arguments after you've changed the multi option policy!"); + } + static IncorrectConstruction MissingOption(std::string name) { + return IncorrectConstruction("Option " + name + " is not defined"); + } + static IncorrectConstruction MultiOptionPolicy(std::string name) { + return IncorrectConstruction(name + ": multi_option_policy only works for flags and exact value options"); + } +}; + +/// Thrown on construction of a bad name +class BadNameString : public ConstructionError { + CLI11_ERROR_DEF(ConstructionError, BadNameString) + CLI11_ERROR_SIMPLE(BadNameString) + static BadNameString OneCharName(std::string name) { return BadNameString("Invalid one char name: " + name); } + static BadNameString MissingDash(std::string name) { + return BadNameString("Long names strings require 2 dashes " + name); + } + static BadNameString BadLongName(std::string name) { return BadNameString("Bad long name: " + name); } + static BadNameString BadPositionalName(std::string name) { + return BadNameString("Invalid positional Name: " + name); + } + static BadNameString ReservedName(std::string name) { + return BadNameString("Names '-','--','++' are reserved and not allowed as option names " + name); + } + static BadNameString MultiPositionalNames(std::string name) { + return BadNameString("Only one positional name allowed, remove: " + name); + } +}; + +/// Thrown when an option already exists +class OptionAlreadyAdded : public ConstructionError { + CLI11_ERROR_DEF(ConstructionError, OptionAlreadyAdded) + explicit OptionAlreadyAdded(std::string name) + : OptionAlreadyAdded(name + " is already added", ExitCodes::OptionAlreadyAdded) {} + static OptionAlreadyAdded Requires(std::string name, std::string other) { + return {name + " requires " + other, ExitCodes::OptionAlreadyAdded}; + } + static OptionAlreadyAdded Excludes(std::string name, std::string other) { + return {name + " excludes " + other, ExitCodes::OptionAlreadyAdded}; + } +}; + +// Parsing errors + +/// Anything that can error in Parse +class ParseError : public Error { + CLI11_ERROR_DEF(Error, ParseError) +}; + +// Not really "errors" + +/// This is a successful completion on parsing, supposed to exit +class Success : public ParseError { + CLI11_ERROR_DEF(ParseError, Success) + Success() : Success("Successfully completed, should be caught and quit", ExitCodes::Success) {} +}; + +/// -h or --help on command line +class CallForHelp : public Success { + CLI11_ERROR_DEF(Success, CallForHelp) + CallForHelp() : CallForHelp("This should be caught in your main function, see examples", ExitCodes::Success) {} +}; + +/// Usually something like --help-all on command line +class CallForAllHelp : public Success { + CLI11_ERROR_DEF(Success, CallForAllHelp) + CallForAllHelp() + : CallForAllHelp("This should be caught in your main function, see examples", ExitCodes::Success) {} +}; + +/// -v or --version on command line +class CallForVersion : public Success { + CLI11_ERROR_DEF(Success, CallForVersion) + CallForVersion() + : CallForVersion("This should be caught in your main function, see examples", ExitCodes::Success) {} +}; + +/// Does not output a diagnostic in CLI11_PARSE, but allows main() to return with a specific error code. +class RuntimeError : public ParseError { + CLI11_ERROR_DEF(ParseError, RuntimeError) + explicit RuntimeError(int exit_code = 1) : RuntimeError("Runtime error", exit_code) {} +}; + +/// Thrown when parsing an INI file and it is missing +class FileError : public ParseError { + CLI11_ERROR_DEF(ParseError, FileError) + CLI11_ERROR_SIMPLE(FileError) + static FileError Missing(std::string name) { return FileError(name + " was not readable (missing?)"); } +}; + +/// Thrown when conversion call back fails, such as when an int fails to coerce to a string +class ConversionError : public ParseError { + CLI11_ERROR_DEF(ParseError, ConversionError) + CLI11_ERROR_SIMPLE(ConversionError) + ConversionError(std::string member, std::string name) + : ConversionError("The value " + member + " is not an allowed value for " + name) {} + ConversionError(std::string name, std::vector results) + : ConversionError("Could not convert: " + name + " = " + detail::join(results)) {} + static ConversionError TooManyInputsFlag(std::string name) { + return ConversionError(name + ": too many inputs for a flag"); + } + static ConversionError TrueFalse(std::string name) { + return ConversionError(name + ": Should be true/false or a number"); + } +}; + +/// Thrown when validation of results fails +class ValidationError : public ParseError { + CLI11_ERROR_DEF(ParseError, ValidationError) + CLI11_ERROR_SIMPLE(ValidationError) + explicit ValidationError(std::string name, std::string msg) : ValidationError(name + ": " + msg) {} +}; + +/// Thrown when a required option is missing +class RequiredError : public ParseError { + CLI11_ERROR_DEF(ParseError, RequiredError) + explicit RequiredError(std::string name) : RequiredError(name + " is required", ExitCodes::RequiredError) {} + static RequiredError Subcommand(std::size_t min_subcom) { + if(min_subcom == 1) { + return RequiredError("A subcommand"); + } + return {"Requires at least " + std::to_string(min_subcom) + " subcommands", ExitCodes::RequiredError}; + } + static RequiredError + Option(std::size_t min_option, std::size_t max_option, std::size_t used, const std::string &option_list) { + if((min_option == 1) && (max_option == 1) && (used == 0)) + return RequiredError("Exactly 1 option from [" + option_list + "]"); + if((min_option == 1) && (max_option == 1) && (used > 1)) { + return {"Exactly 1 option from [" + option_list + "] is required but " + std::to_string(used) + + " were given", + ExitCodes::RequiredError}; + } + if((min_option == 1) && (used == 0)) + return RequiredError("At least 1 option from [" + option_list + "]"); + if(used < min_option) { + return {"Requires at least " + std::to_string(min_option) + " options used but only " + + std::to_string(used) + " were given from [" + option_list + "]", + ExitCodes::RequiredError}; + } + if(max_option == 1) + return {"Requires at most 1 options be given from [" + option_list + "]", ExitCodes::RequiredError}; + + return {"Requires at most " + std::to_string(max_option) + " options be used but " + std::to_string(used) + + " were given from [" + option_list + "]", + ExitCodes::RequiredError}; + } +}; + +/// Thrown when the wrong number of arguments has been received +class ArgumentMismatch : public ParseError { + CLI11_ERROR_DEF(ParseError, ArgumentMismatch) + CLI11_ERROR_SIMPLE(ArgumentMismatch) + ArgumentMismatch(std::string name, int expected, std::size_t received) + : ArgumentMismatch(expected > 0 ? ("Expected exactly " + std::to_string(expected) + " arguments to " + name + + ", got " + std::to_string(received)) + : ("Expected at least " + std::to_string(-expected) + " arguments to " + name + + ", got " + std::to_string(received)), + ExitCodes::ArgumentMismatch) {} + + static ArgumentMismatch AtLeast(std::string name, int num, std::size_t received) { + return ArgumentMismatch(name + ": At least " + std::to_string(num) + " required but received " + + std::to_string(received)); + } + static ArgumentMismatch AtMost(std::string name, int num, std::size_t received) { + return ArgumentMismatch(name + ": At most " + std::to_string(num) + " required but received " + + std::to_string(received)); + } + static ArgumentMismatch TypedAtLeast(std::string name, int num, std::string type) { + return ArgumentMismatch(name + ": " + std::to_string(num) + " required " + type + " missing"); + } + static ArgumentMismatch FlagOverride(std::string name) { + return ArgumentMismatch(name + " was given a disallowed flag override"); + } + static ArgumentMismatch PartialType(std::string name, int num, std::string type) { + return ArgumentMismatch(name + ": " + type + " only partially specified: " + std::to_string(num) + + " required for each element"); + } +}; + +/// Thrown when a requires option is missing +class RequiresError : public ParseError { + CLI11_ERROR_DEF(ParseError, RequiresError) + RequiresError(std::string curname, std::string subname) + : RequiresError(curname + " requires " + subname, ExitCodes::RequiresError) {} +}; + +/// Thrown when an excludes option is present +class ExcludesError : public ParseError { + CLI11_ERROR_DEF(ParseError, ExcludesError) + ExcludesError(std::string curname, std::string subname) + : ExcludesError(curname + " excludes " + subname, ExitCodes::ExcludesError) {} +}; + +/// Thrown when too many positionals or options are found +class ExtrasError : public ParseError { + CLI11_ERROR_DEF(ParseError, ExtrasError) + explicit ExtrasError(std::vector args) + : ExtrasError((args.size() > 1 ? "The following arguments were not expected: " + : "The following argument was not expected: ") + + detail::join(args, " "), + ExitCodes::ExtrasError) {} + ExtrasError(const std::string &name, std::vector args) + : ExtrasError(name, + (args.size() > 1 ? "The following arguments were not expected: " + : "The following argument was not expected: ") + + detail::join(args, " "), + ExitCodes::ExtrasError) {} +}; + +/// Thrown when extra values are found in an INI file +class ConfigError : public ParseError { + CLI11_ERROR_DEF(ParseError, ConfigError) + CLI11_ERROR_SIMPLE(ConfigError) + static ConfigError Extras(std::string item) { return ConfigError("INI was not able to parse " + item); } + static ConfigError NotConfigurable(std::string item) { + return ConfigError(item + ": This option is not allowed in a configuration file"); + } +}; + +/// Thrown when validation fails before parsing +class InvalidError : public ParseError { + CLI11_ERROR_DEF(ParseError, InvalidError) + explicit InvalidError(std::string name) + : InvalidError(name + ": Too many positional arguments with unlimited expected args", ExitCodes::InvalidError) { + } +}; + +/// This is just a safety check to verify selection and parsing match - you should not ever see it +/// Strings are directly added to this error, but again, it should never be seen. +class HorribleError : public ParseError { + CLI11_ERROR_DEF(ParseError, HorribleError) + CLI11_ERROR_SIMPLE(HorribleError) +}; + +// After parsing + +/// Thrown when counting a nonexistent option +class OptionNotFound : public Error { + CLI11_ERROR_DEF(Error, OptionNotFound) + explicit OptionNotFound(std::string name) : OptionNotFound(name + " not found", ExitCodes::OptionNotFound) {} +}; + +#undef CLI11_ERROR_DEF +#undef CLI11_ERROR_SIMPLE + +/// @} + + + + +// Type tools + +// Utilities for type enabling +namespace detail { +// Based generally on https://rmf.io/cxx11/almost-static-if +/// Simple empty scoped class +enum class enabler : std::uint8_t {}; + +/// An instance to use in EnableIf +constexpr enabler dummy = {}; +} // namespace detail + +/// A copy of enable_if_t from C++14, compatible with C++11. +/// +/// We could check to see if C++14 is being used, but it does not hurt to redefine this +/// (even Google does this: https://github.com/google/skia/blob/main/include/private/SkTLogic.h) +/// It is not in the std namespace anyway, so no harm done. +template using enable_if_t = typename std::enable_if::type; + +/// A copy of std::void_t from C++17 (helper for C++11 and C++14) +template struct make_void { + using type = void; +}; + +/// A copy of std::void_t from C++17 - same reasoning as enable_if_t, it does not hurt to redefine +template using void_t = typename make_void::type; + +/// A copy of std::conditional_t from C++14 - same reasoning as enable_if_t, it does not hurt to redefine +template using conditional_t = typename std::conditional::type; + +/// Check to see if something is bool (fail check by default) +template struct is_bool : std::false_type {}; + +/// Check to see if something is bool (true if actually a bool) +template <> struct is_bool : std::true_type {}; + +/// Check to see if something is a shared pointer +template struct is_shared_ptr : std::false_type {}; + +/// Check to see if something is a shared pointer (True if really a shared pointer) +template struct is_shared_ptr> : std::true_type {}; + +/// Check to see if something is a shared pointer (True if really a shared pointer) +template struct is_shared_ptr> : std::true_type {}; + +/// Check to see if something is copyable pointer +template struct is_copyable_ptr { + static bool const value = is_shared_ptr::value || std::is_pointer::value; +}; + +/// This can be specialized to override the type deduction for IsMember. +template struct IsMemberType { + using type = T; +}; + +/// The main custom type needed here is const char * should be a string. +template <> struct IsMemberType { + using type = std::string; +}; + +namespace adl_detail { +/// Check for existence of user-supplied lexical_cast. +/// +/// This struct has to be in a separate namespace so that it doesn't see our lexical_cast overloads in CLI::detail. +/// Standard says it shouldn't see them if it's defined before the corresponding lexical_cast declarations, but this +/// requires a working implementation of two-phase lookup, and not all compilers can boast that (msvc, ahem). +template class is_lexical_castable { + template + static auto test(int) -> decltype(lexical_cast(std::declval(), std::declval()), std::true_type()); + + template static auto test(...) -> std::false_type; + + public: + static constexpr bool value = decltype(test(0))::value; +}; +} // namespace adl_detail + +namespace detail { + +// These are utilities for IsMember and other transforming objects + +/// Handy helper to access the element_type generically. This is not part of is_copyable_ptr because it requires that +/// pointer_traits be valid. + +/// not a pointer +template struct element_type { + using type = T; +}; + +template struct element_type::value>::type> { + using type = typename std::pointer_traits::element_type; +}; + +/// Combination of the element type and value type - remove pointer (including smart pointers) and get the value_type of +/// the container +template struct element_value_type { + using type = typename element_type::type::value_type; +}; + +/// Adaptor for set-like structure: This just wraps a normal container in a few utilities that do almost nothing. +template struct pair_adaptor : std::false_type { + using value_type = typename T::value_type; + using first_type = typename std::remove_const::type; + using second_type = typename std::remove_const::type; + + /// Get the first value (really just the underlying value) + template static auto first(Q &&pair_value) -> decltype(std::forward(pair_value)) { + return std::forward(pair_value); + } + /// Get the second value (really just the underlying value) + template static auto second(Q &&pair_value) -> decltype(std::forward(pair_value)) { + return std::forward(pair_value); + } +}; + +/// Adaptor for map-like structure (true version, must have key_type and mapped_type). +/// This wraps a mapped container in a few utilities access it in a general way. +template +struct pair_adaptor< + T, + conditional_t, void>> + : std::true_type { + using value_type = typename T::value_type; + using first_type = typename std::remove_const::type; + using second_type = typename std::remove_const::type; + + /// Get the first value (really just the underlying value) + template static auto first(Q &&pair_value) -> decltype(std::get<0>(std::forward(pair_value))) { + return std::get<0>(std::forward(pair_value)); + } + /// Get the second value (really just the underlying value) + template static auto second(Q &&pair_value) -> decltype(std::get<1>(std::forward(pair_value))) { + return std::get<1>(std::forward(pair_value)); + } +}; + +// Warning is suppressed due to "bug" in gcc<5.0 and gcc 7.0 with c++17 enabled that generates a -Wnarrowing warning +// in the unevaluated context even if the function that was using this wasn't used. The standard says narrowing in +// brace initialization shouldn't be allowed but for backwards compatibility gcc allows it in some contexts. It is a +// little fuzzy what happens in template constructs and I think that was something GCC took a little while to work out. +// But regardless some versions of gcc generate a warning when they shouldn't from the following code so that should be +// suppressed +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnarrowing" +#endif +// check for constructibility from a specific type and copy assignable used in the parse detection +template class is_direct_constructible { + template + static auto test(int, std::true_type) -> decltype( +// NVCC warns about narrowing conversions here +#ifdef __CUDACC__ +#ifdef __NVCC_DIAG_PRAGMA_SUPPORT__ +#pragma nv_diag_suppress 2361 +#else +#pragma diag_suppress 2361 +#endif +#endif + TT{std::declval()} +#ifdef __CUDACC__ +#ifdef __NVCC_DIAG_PRAGMA_SUPPORT__ +#pragma nv_diag_default 2361 +#else +#pragma diag_default 2361 +#endif +#endif + , + std::is_move_assignable()); + + template static auto test(int, std::false_type) -> std::false_type; + + template static auto test(...) -> std::false_type; + + public: + static constexpr bool value = decltype(test(0, typename std::is_constructible::type()))::value; +}; +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +// Check for output streamability +// Based on https://stackoverflow.com/questions/22758291/how-can-i-detect-if-a-type-can-be-streamed-to-an-stdostream + +template class is_ostreamable { + template + static auto test(int) -> decltype(std::declval() << std::declval(), std::true_type()); + + template static auto test(...) -> std::false_type; + + public: + static constexpr bool value = decltype(test(0))::value; +}; + +/// Check for input streamability +template class is_istreamable { + template + static auto test(int) -> decltype(std::declval() >> std::declval(), std::true_type()); + + template static auto test(...) -> std::false_type; + + public: + static constexpr bool value = decltype(test(0))::value; +}; + +/// Check for complex +template class is_complex { + template + static auto test(int) -> decltype(std::declval().real(), std::declval().imag(), std::true_type()); + + template static auto test(...) -> std::false_type; + + public: + static constexpr bool value = decltype(test(0))::value; +}; + +/// Templated operation to get a value from a stream +template ::value, detail::enabler> = detail::dummy> +bool from_stream(const std::string &istring, T &obj) { + std::istringstream is; + is.str(istring); + is >> obj; + return !is.fail() && !is.rdbuf()->in_avail(); +} + +template ::value, detail::enabler> = detail::dummy> +bool from_stream(const std::string & /*istring*/, T & /*obj*/) { + return false; +} + +// check to see if an object is a mutable container (fail by default) +template struct is_mutable_container : std::false_type {}; + +/// type trait to test if a type is a mutable container meaning it has a value_type, it has an iterator, a clear, and +/// end methods and an insert function. And for our purposes we exclude std::string and types that can be constructed +/// from a std::string +template +struct is_mutable_container< + T, + conditional_t().end()), + decltype(std::declval().clear()), + decltype(std::declval().insert(std::declval().end())>(), + std::declval()))>, + void>> : public conditional_t::value || + std::is_constructible::value, + std::false_type, + std::true_type> {}; + +// check to see if an object is a mutable container (fail by default) +template struct is_readable_container : std::false_type {}; + +/// type trait to test if a type is a container meaning it has a value_type, it has an iterator, and an end +/// method. +template +struct is_readable_container< + T, + conditional_t().end()), decltype(std::declval().begin())>, void>> + : public std::true_type {}; + +// check to see if an object is a wrapper (fail by default) +template struct is_wrapper : std::false_type {}; + +// check if an object is a wrapper (it has a value_type defined) +template +struct is_wrapper, void>> : public std::true_type {}; + +// Check for tuple like types, as in classes with a tuple_size type trait +// Even though in C++26 std::complex gains a std::tuple interface, for our purposes we treat is as NOT a tuple +template class is_tuple_like { + template ::value, detail::enabler> = detail::dummy> + // static auto test(int) + // -> decltype(std::conditional<(std::tuple_size::value > 0), std::true_type, std::false_type>::type()); + static auto test(int) -> decltype(std::tuple_size::type>::value, std::true_type{}); + template static auto test(...) -> std::false_type; + + public: + static constexpr bool value = decltype(test(0))::value; +}; + +/// This will only trigger for actual void type +template struct type_count_base { + static const int value{0}; +}; + +/// Type size for regular object types that do not look like a tuple +template +struct type_count_base::value && !is_mutable_container::value && + !std::is_void::value>::type> { + static constexpr int value{1}; +}; + +/// the base tuple size +template +struct type_count_base::value && !is_mutable_container::value>::type> { + static constexpr int value{// cppcheck-suppress unusedStructMember + std::tuple_size::type>::value}; +}; + +/// Type count base for containers is the type_count_base of the individual element +template struct type_count_base::value>::type> { + static constexpr int value{type_count_base::value}; +}; + +/// Convert an object to a string (directly forward if this can become a string) +template ::value, detail::enabler> = detail::dummy> +auto to_string(T &&value) -> decltype(std::forward(value)) { + return std::forward(value); +} + +/// Construct a string from the object +template ::value && !std::is_convertible::value, + detail::enabler> = detail::dummy> +std::string to_string(T &&value) { + return std::string(value); // NOLINT(google-readability-casting) +} + +/// Convert an object to a string (streaming must be supported for that type) +template ::value && !std::is_constructible::value && + is_ostreamable::value, + detail::enabler> = detail::dummy> +std::string to_string(T &&value) { + std::stringstream stream; + stream << value; + return stream.str(); +} + +// additional forward declarations + +/// Print tuple value string for tuples of size ==1 +template ::value && !std::is_constructible::value && + !is_ostreamable::value && is_tuple_like::value && type_count_base::value == 1, + detail::enabler> = detail::dummy> +inline std::string to_string(T &&value); + +/// Print tuple value string for tuples of size > 1 +template ::value && !std::is_constructible::value && + !is_ostreamable::value && is_tuple_like::value && type_count_base::value >= 2, + detail::enabler> = detail::dummy> +inline std::string to_string(T &&value); + +/// If conversion is not supported, return an empty string (streaming is not supported for that type) +template < + typename T, + enable_if_t::value && !std::is_constructible::value && + !is_ostreamable::value && !is_readable_container::type>::value && + !is_tuple_like::value, + detail::enabler> = detail::dummy> +inline std::string to_string(T &&) { + return {}; +} + +/// convert a readable container to a string +template ::value && !std::is_constructible::value && + !is_ostreamable::value && is_readable_container::value && !is_tuple_like::value, + detail::enabler> = detail::dummy> +inline std::string to_string(T &&variable) { + auto cval = variable.begin(); + auto end = variable.end(); + if(cval == end) { + return {"{}"}; + } + std::vector defaults; + while(cval != end) { + defaults.emplace_back(CLI::detail::to_string(*cval)); + ++cval; + } + return {"[" + detail::join(defaults) + "]"}; +} + +/// Convert a tuple like object to a string + +/// forward declarations for tuple_value_strings +template +inline typename std::enable_if::value, std::string>::type tuple_value_string(T && /*value*/); + +/// Recursively generate the tuple value string +template +inline typename std::enable_if<(I < type_count_base::value), std::string>::type tuple_value_string(T &&value); + +/// Print tuple value string for tuples of size ==1 +template ::value && !std::is_constructible::value && + !is_ostreamable::value && is_tuple_like::value && type_count_base::value == 1, + detail::enabler>> +inline std::string to_string(T &&value) { + return to_string(std::get<0>(value)); +} + +/// Print tuple value string for tuples of size > 1 +template ::value && !std::is_constructible::value && + !is_ostreamable::value && is_tuple_like::value && type_count_base::value >= 2, + detail::enabler>> +inline std::string to_string(T &&value) { + auto tname = std::string(1, '[') + tuple_value_string(value); + tname.push_back(']'); + return tname; +} + +/// Empty string if the index > tuple size +template +inline typename std::enable_if::value, std::string>::type tuple_value_string(T && /*value*/) { + return std::string{}; +} + +/// Recursively generate the tuple value string +template +inline typename std::enable_if<(I < type_count_base::value), std::string>::type tuple_value_string(T &&value) { + auto str = std::string{to_string(std::get(value))} + ',' + tuple_value_string(value); + if(str.back() == ',') + str.pop_back(); + return str; +} + +/// special template overload +template ::value, detail::enabler> = detail::dummy> +auto checked_to_string(T &&value) -> decltype(to_string(std::forward(value))) { + return to_string(std::forward(value)); +} + +/// special template overload +template ::value, detail::enabler> = detail::dummy> +std::string checked_to_string(T &&) { + return std::string{}; +} +/// get a string as a convertible value for arithmetic types +template ::value, detail::enabler> = detail::dummy> +std::string value_string(const T &value) { + return std::to_string(value); +} +/// get a string as a convertible value for enumerations +template ::value, detail::enabler> = detail::dummy> +std::string value_string(const T &value) { + return std::to_string(static_cast::type>(value)); +} +/// for other types just use the regular to_string function +template ::value && !std::is_arithmetic::value, detail::enabler> = detail::dummy> +auto value_string(const T &value) -> decltype(to_string(value)) { + return to_string(value); +} + +/// template to get the underlying value type if it exists or use a default +template struct wrapped_type { + using type = def; +}; + +/// Type size for regular object types that do not look like a tuple +template struct wrapped_type::value>::type> { + using type = typename T::value_type; +}; + +/// Set of overloads to get the type size of an object + +/// forward declare the subtype_count structure +template struct subtype_count; + +/// forward declare the subtype_count_min structure +template struct subtype_count_min; + +/// This will only trigger for actual void type +template struct type_count { + static const int value{0}; +}; + +/// Type size for regular object types that do not look like a tuple +template +struct type_count::value && !is_tuple_like::value && !is_complex::value && + !std::is_void::value>::type> { + static constexpr int value{1}; +}; + +/// Type size for complex since it sometimes looks like a wrapper +template struct type_count::value>::type> { + static constexpr int value{2}; +}; + +/// Type size of types that are wrappers,except complex and tuples(which can also be wrappers sometimes) +template struct type_count::value>::type> { + static constexpr int value{subtype_count::value}; +}; + +/// Type size of types that are wrappers,except containers complex and tuples(which can also be wrappers sometimes) +template +struct type_count::value && !is_complex::value && !is_tuple_like::value && + !is_mutable_container::value>::type> { + static constexpr int value{type_count::value}; +}; + +/// 0 if the index > tuple size +template +constexpr typename std::enable_if::value, int>::type tuple_type_size() { + return 0; +} + +/// Recursively generate the tuple type name +template + constexpr typename std::enable_if < I::value, int>::type tuple_type_size() { + return subtype_count::type>::value + tuple_type_size(); +} + +/// Get the type size of the sum of type sizes for all the individual tuple types +template struct type_count::value>::type> { + static constexpr int value{tuple_type_size()}; +}; + +/// definition of subtype count +template struct subtype_count { + static constexpr int value{is_mutable_container::value ? expected_max_vector_size : type_count::value}; +}; + +/// This will only trigger for actual void type +template struct type_count_min { + static const int value{0}; +}; + +/// Type size for regular object types that do not look like a tuple +template +struct type_count_min< + T, + typename std::enable_if::value && !is_tuple_like::value && !is_wrapper::value && + !is_complex::value && !std::is_void::value>::type> { + static constexpr int value{type_count::value}; +}; + +/// Type size for complex since it sometimes looks like a wrapper +template struct type_count_min::value>::type> { + static constexpr int value{1}; +}; + +/// Type size min of types that are wrappers,except complex and tuples(which can also be wrappers sometimes) +template +struct type_count_min< + T, + typename std::enable_if::value && !is_complex::value && !is_tuple_like::value>::type> { + static constexpr int value{subtype_count_min::value}; +}; + +/// 0 if the index > tuple size +template +constexpr typename std::enable_if::value, int>::type tuple_type_size_min() { + return 0; +} + +/// Recursively generate the tuple type name +template + constexpr typename std::enable_if < I::value, int>::type tuple_type_size_min() { + return subtype_count_min::type>::value + tuple_type_size_min(); +} + +/// Get the type size of the sum of type sizes for all the individual tuple types +template struct type_count_min::value>::type> { + static constexpr int value{tuple_type_size_min()}; +}; + +/// definition of subtype count +template struct subtype_count_min { + static constexpr int value{is_mutable_container::value + ? ((type_count::value < expected_max_vector_size) ? type_count::value : 0) + : type_count_min::value}; +}; + +/// This will only trigger for actual void type +template struct expected_count { + static const int value{0}; +}; + +/// For most types the number of expected items is 1 +template +struct expected_count::value && !is_wrapper::value && + !std::is_void::value>::type> { + static constexpr int value{1}; +}; +/// number of expected items in a vector +template struct expected_count::value>::type> { + static constexpr int value{expected_max_vector_size}; +}; + +/// number of expected items in a vector +template +struct expected_count::value && is_wrapper::value>::type> { + static constexpr int value{expected_count::value}; +}; + +// Enumeration of the different supported categorizations of objects +enum class object_category : std::uint8_t { + char_value = 1, + integral_value = 2, + unsigned_integral = 4, + enumeration = 6, + boolean_value = 8, + floating_point = 10, + number_constructible = 12, + double_constructible = 14, + integer_constructible = 16, + // string like types + string_assignable = 23, + string_constructible = 24, + wstring_assignable = 25, + wstring_constructible = 26, + other = 45, + // special wrapper or container types + wrapper_value = 50, + complex_number = 60, + tuple_value = 70, + container_value = 80, + +}; + +/// Set of overloads to classify an object according to type + +/// some type that is not otherwise recognized +template struct classify_object { + static constexpr object_category value{object_category::other}; +}; + +/// Signed integers +template +struct classify_object< + T, + typename std::enable_if::value && !std::is_same::value && std::is_signed::value && + !is_bool::value && !std::is_enum::value>::type> { + static constexpr object_category value{object_category::integral_value}; +}; + +/// Unsigned integers +template +struct classify_object::value && std::is_unsigned::value && + !std::is_same::value && !is_bool::value>::type> { + static constexpr object_category value{object_category::unsigned_integral}; +}; + +/// single character values +template +struct classify_object::value && !std::is_enum::value>::type> { + static constexpr object_category value{object_category::char_value}; +}; + +/// Boolean values +template struct classify_object::value>::type> { + static constexpr object_category value{object_category::boolean_value}; +}; + +/// Floats +template struct classify_object::value>::type> { + static constexpr object_category value{object_category::floating_point}; +}; +#if defined _MSC_VER +// in MSVC wstring should take precedence if available this isn't as useful on other compilers due to the broader use of +// utf-8 encoding +#define WIDE_STRING_CHECK \ + !std::is_assignable::value && !std::is_constructible::value +#define STRING_CHECK true +#else +#define WIDE_STRING_CHECK true +#define STRING_CHECK !std::is_assignable::value && !std::is_constructible::value +#endif + +/// String and similar direct assignment +template +struct classify_object< + T, + typename std::enable_if::value && !std::is_integral::value && WIDE_STRING_CHECK && + std::is_assignable::value>::type> { + static constexpr object_category value{object_category::string_assignable}; +}; + +/// String and similar constructible and copy assignment +template +struct classify_object< + T, + typename std::enable_if::value && !std::is_integral::value && + !std::is_assignable::value && (type_count::value == 1) && + WIDE_STRING_CHECK && std::is_constructible::value>::type> { + static constexpr object_category value{object_category::string_constructible}; +}; + +/// Wide strings +template +struct classify_object::value && !std::is_integral::value && + STRING_CHECK && std::is_assignable::value>::type> { + static constexpr object_category value{object_category::wstring_assignable}; +}; + +template +struct classify_object< + T, + typename std::enable_if::value && !std::is_integral::value && + !std::is_assignable::value && (type_count::value == 1) && + STRING_CHECK && std::is_constructible::value>::type> { + static constexpr object_category value{object_category::wstring_constructible}; +}; + +/// Enumerations +template struct classify_object::value>::type> { + static constexpr object_category value{object_category::enumeration}; +}; + +template struct classify_object::value>::type> { + static constexpr object_category value{object_category::complex_number}; +}; + +/// Handy helper to contain a bunch of checks that rule out many common types (integers, string like, floating point, +/// vectors, and enumerations +template struct uncommon_type { + using type = typename std::conditional< + !std::is_floating_point::value && !std::is_integral::value && + !std::is_assignable::value && !std::is_constructible::value && + !std::is_assignable::value && !std::is_constructible::value && + !is_complex::value && !is_mutable_container::value && !std::is_enum::value, + std::true_type, + std::false_type>::type; + static constexpr bool value = type::value; +}; + +/// wrapper type +template +struct classify_object::value && is_wrapper::value && + !is_tuple_like::value && uncommon_type::value)>::type> { + static constexpr object_category value{object_category::wrapper_value}; +}; + +/// Assignable from double or int +template +struct classify_object::value && type_count::value == 1 && + !is_wrapper::value && is_direct_constructible::value && + is_direct_constructible::value>::type> { + static constexpr object_category value{object_category::number_constructible}; +}; + +/// Assignable from int +template +struct classify_object::value && type_count::value == 1 && + !is_wrapper::value && !is_direct_constructible::value && + is_direct_constructible::value>::type> { + static constexpr object_category value{object_category::integer_constructible}; +}; + +/// Assignable from double +template +struct classify_object::value && type_count::value == 1 && + !is_wrapper::value && is_direct_constructible::value && + !is_direct_constructible::value>::type> { + static constexpr object_category value{object_category::double_constructible}; +}; + +/// Tuple type +template +struct classify_object< + T, + typename std::enable_if::value && + ((type_count::value >= 2 && !is_wrapper::value) || + (uncommon_type::value && !is_direct_constructible::value && + !is_direct_constructible::value) || + (uncommon_type::value && type_count::value >= 2))>::type> { + static constexpr object_category value{object_category::tuple_value}; + // the condition on this class requires it be like a tuple, but on some compilers (like Xcode) tuples can be + // constructed from just the first element so tuples of can be constructed from a string, which + // could lead to issues so there are two variants of the condition, the first isolates things with a type size >=2 + // mainly to get tuples on Xcode with the exception of wrappers, the second is the main one and just separating out + // those cases that are caught by other object classifications +}; + +/// container type +template struct classify_object::value>::type> { + static constexpr object_category value{object_category::container_value}; +}; + +// Type name print + +/// Was going to be based on +/// http://stackoverflow.com/questions/1055452/c-get-name-of-type-in-template +/// But this is cleaner and works better in this case + +template ::value == object_category::char_value, detail::enabler> = detail::dummy> +constexpr const char *type_name() { + return "CHAR"; +} + +template ::value == object_category::integral_value || + classify_object::value == object_category::integer_constructible, + detail::enabler> = detail::dummy> +constexpr const char *type_name() { + return "INT"; +} + +template ::value == object_category::unsigned_integral, detail::enabler> = detail::dummy> +constexpr const char *type_name() { + return "UINT"; +} + +template ::value == object_category::floating_point || + classify_object::value == object_category::number_constructible || + classify_object::value == object_category::double_constructible, + detail::enabler> = detail::dummy> +constexpr const char *type_name() { + return "FLOAT"; +} + +/// Print name for enumeration types +template ::value == object_category::enumeration, detail::enabler> = detail::dummy> +constexpr const char *type_name() { + return "ENUM"; +} + +/// Print name for enumeration types +template ::value == object_category::boolean_value, detail::enabler> = detail::dummy> +constexpr const char *type_name() { + return "BOOLEAN"; +} + +/// Print name for enumeration types +template ::value == object_category::complex_number, detail::enabler> = detail::dummy> +constexpr const char *type_name() { + return "COMPLEX"; +} + +/// Print for all other types +template ::value >= object_category::string_assignable && + classify_object::value <= object_category::other, + detail::enabler> = detail::dummy> +constexpr const char *type_name() { + return "TEXT"; +} +/// typename for tuple value +template ::value == object_category::tuple_value && type_count_base::value >= 2, + detail::enabler> = detail::dummy> +std::string type_name(); // forward declaration + +/// Generate type name for a wrapper or container value +template ::value == object_category::container_value || + classify_object::value == object_category::wrapper_value, + detail::enabler> = detail::dummy> +std::string type_name(); // forward declaration + +/// Print name for single element tuple types +template ::value == object_category::tuple_value && type_count_base::value == 1, + detail::enabler> = detail::dummy> +inline std::string type_name() { + return type_name::type>::type>(); +} + +/// Empty string if the index > tuple size +template +inline typename std::enable_if::value, std::string>::type tuple_name() { + return std::string{}; +} + +/// Recursively generate the tuple type name +template +inline typename std::enable_if<(I < type_count_base::value), std::string>::type tuple_name() { + auto str = std::string{type_name::type>::type>()} + ',' + + tuple_name(); + if(str.back() == ',') + str.pop_back(); + return str; +} + +/// Print type name for tuples with 2 or more elements +template ::value == object_category::tuple_value && type_count_base::value >= 2, + detail::enabler>> +inline std::string type_name() { + auto tname = std::string(1, '[') + tuple_name(); + tname.push_back(']'); + return tname; +} + +/// get the type name for a type that has a value_type member +template ::value == object_category::container_value || + classify_object::value == object_category::wrapper_value, + detail::enabler>> +inline std::string type_name() { + return type_name(); +} + +// Lexical cast + +/// Convert to an unsigned integral +template ::value, detail::enabler> = detail::dummy> +bool integral_conversion(const std::string &input, T &output) noexcept { + if(input.empty() || input.front() == '-') { + return false; + } + char *val{nullptr}; + errno = 0; + std::uint64_t output_ll = std::strtoull(input.c_str(), &val, 0); + if(errno == ERANGE) { + return false; + } + output = static_cast(output_ll); + if(val == (input.c_str() + input.size()) && static_cast(output) == output_ll) { + return true; + } + val = nullptr; + std::int64_t output_sll = std::strtoll(input.c_str(), &val, 0); + if(val == (input.c_str() + input.size())) { + output = (output_sll < 0) ? static_cast(0) : static_cast(output_sll); + return (static_cast(output) == output_sll); + } + // remove separators if present + auto group_separators = get_group_separators(); + if(input.find_first_of(group_separators) != std::string::npos) { + std::string nstring = input; + for(auto &separator : group_separators) { + if(input.find_first_of(separator) != std::string::npos) { + nstring.erase(std::remove(nstring.begin(), nstring.end(), separator), nstring.end()); + } + } + return integral_conversion(nstring, output); + } + + if(std::isspace(static_cast(input.back()))) { + return integral_conversion(trim_copy(input), output); + } + if(input.compare(0, 2, "0o") == 0 || input.compare(0, 2, "0O") == 0) { + val = nullptr; + errno = 0; + output_ll = std::strtoull(input.c_str() + 2, &val, 8); + if(errno == ERANGE) { + return false; + } + output = static_cast(output_ll); + return (val == (input.c_str() + input.size()) && static_cast(output) == output_ll); + } + if(input.compare(0, 2, "0b") == 0 || input.compare(0, 2, "0B") == 0) { + // LCOV_EXCL_START + // In some new compilers including the coverage testing one binary strings are handled properly in strtoull + // automatically so this coverage is missing but is well tested in other compilers + val = nullptr; + errno = 0; + output_ll = std::strtoull(input.c_str() + 2, &val, 2); + if(errno == ERANGE) { + return false; + } + output = static_cast(output_ll); + return (val == (input.c_str() + input.size()) && static_cast(output) == output_ll); + // LCOV_EXCL_STOP + } + return false; +} + +/// Convert to a signed integral +template ::value, detail::enabler> = detail::dummy> +bool integral_conversion(const std::string &input, T &output) noexcept { + if(input.empty()) { + return false; + } + char *val = nullptr; + errno = 0; + std::int64_t output_ll = std::strtoll(input.c_str(), &val, 0); + if(errno == ERANGE) { + return false; + } + output = static_cast(output_ll); + if(val == (input.c_str() + input.size()) && static_cast(output) == output_ll) { + return true; + } + if(input == "true") { + // this is to deal with a few oddities with flags and wrapper int types + output = static_cast(1); + return true; + } + // remove separators if present + auto group_separators = get_group_separators(); + if(input.find_first_of(group_separators) != std::string::npos) { + for(auto &separator : group_separators) { + if(input.find_first_of(separator) != std::string::npos) { + std::string nstring = input; + nstring.erase(std::remove(nstring.begin(), nstring.end(), separator), nstring.end()); + return integral_conversion(nstring, output); + } + } + } + if(std::isspace(static_cast(input.back()))) { + return integral_conversion(trim_copy(input), output); + } + if(input.compare(0, 2, "0o") == 0 || input.compare(0, 2, "0O") == 0) { + val = nullptr; + errno = 0; + output_ll = std::strtoll(input.c_str() + 2, &val, 8); + if(errno == ERANGE) { + return false; + } + output = static_cast(output_ll); + return (val == (input.c_str() + input.size()) && static_cast(output) == output_ll); + } + if(input.compare(0, 2, "0b") == 0 || input.compare(0, 2, "0B") == 0) { + // LCOV_EXCL_START + // In some new compilers including the coverage testing one binary strings are handled properly in strtoll + // automatically so this coverage is missing but is well tested in other compilers + val = nullptr; + errno = 0; + output_ll = std::strtoll(input.c_str() + 2, &val, 2); + if(errno == ERANGE) { + return false; + } + output = static_cast(output_ll); + return (val == (input.c_str() + input.size()) && static_cast(output) == output_ll); + // LCOV_EXCL_STOP + } + return false; +} + +/// Convert a flag into an integer value typically binary flags sets errno to nonzero if conversion failed +inline std::int64_t to_flag_value(std::string val) noexcept { + static const std::string trueString("true"); + static const std::string falseString("false"); + if(val == trueString) { + return 1; + } + if(val == falseString) { + return -1; + } + val = detail::to_lower(val); + std::int64_t ret = 0; + if(val.size() == 1) { + if(val[0] >= '1' && val[0] <= '9') { + return (static_cast(val[0]) - '0'); + } + switch(val[0]) { + case '0': + case 'f': + case 'n': + case '-': + ret = -1; + break; + case 't': + case 'y': + case '+': + ret = 1; + break; + default: + errno = EINVAL; + return -1; + } + return ret; + } + if(val == trueString || val == "on" || val == "yes" || val == "enable") { + ret = 1; + } else if(val == falseString || val == "off" || val == "no" || val == "disable") { + ret = -1; + } else { + char *loc_ptr{nullptr}; + ret = std::strtoll(val.c_str(), &loc_ptr, 0); + if(loc_ptr != (val.c_str() + val.size()) && errno == 0) { + errno = EINVAL; + } + } + return ret; +} + +/// Integer conversion +template ::value == object_category::integral_value || + classify_object::value == object_category::unsigned_integral, + detail::enabler> = detail::dummy> +bool lexical_cast(const std::string &input, T &output) { + return integral_conversion(input, output); +} + +/// char values +template ::value == object_category::char_value, detail::enabler> = detail::dummy> +bool lexical_cast(const std::string &input, T &output) { + if(input.size() == 1) { + output = static_cast(input[0]); + return true; + } + std::int8_t res{0}; + // we do it this way as some systems have char as signed and not, this ensures consistency in the way things are + // handled + bool result = integral_conversion(input, res); + if(result) { + output = static_cast(res); + } + return result; +} + +/// Boolean values +template ::value == object_category::boolean_value, detail::enabler> = detail::dummy> +bool lexical_cast(const std::string &input, T &output) { + errno = 0; + auto out = to_flag_value(input); + if(errno == 0) { + output = (out > 0); + } else if(errno == ERANGE) { + output = (input[0] != '-'); + } else { + return false; + } + return true; +} + +/// Floats +template ::value == object_category::floating_point, detail::enabler> = detail::dummy> +bool lexical_cast(const std::string &input, T &output) { + if(input.empty()) { + return false; + } + char *val = nullptr; + auto output_ld = std::strtold(input.c_str(), &val); + output = static_cast(output_ld); + if(val == (input.c_str() + input.size())) { + return true; + } + while(std::isspace(static_cast(*val))) { + ++val; + if(val == (input.c_str() + input.size())) { + return true; + } + } + + // remove separators if present + auto group_separators = get_group_separators(); + if(input.find_first_of(group_separators) != std::string::npos) { + for(auto &separator : group_separators) { + if(input.find_first_of(separator) != std::string::npos) { + std::string nstring = input; + nstring.erase(std::remove(nstring.begin(), nstring.end(), separator), nstring.end()); + return lexical_cast(nstring, output); + } + } + } + return false; +} + +/// complex +template ::value == object_category::complex_number, detail::enabler> = detail::dummy> +bool lexical_cast(const std::string &input, T &output) { + using XC = typename wrapped_type::type; + XC x{0.0}, y{0.0}; + auto str1 = input; + bool worked = false; + auto nloc = str1.find_last_of("+-"); + if(nloc != std::string::npos && nloc > 0) { + worked = lexical_cast(str1.substr(0, nloc), x); + str1 = str1.substr(nloc); + if(str1.back() == 'i' || str1.back() == 'j') + str1.pop_back(); + worked = worked && lexical_cast(str1, y); + } else { + if(str1.back() == 'i' || str1.back() == 'j') { + str1.pop_back(); + worked = lexical_cast(str1, y); + x = XC{0}; + } else { + worked = lexical_cast(str1, x); + y = XC{0}; + } + } + if(worked) { + output = T{x, y}; + return worked; + } + return from_stream(input, output); +} + +/// String and similar direct assignment +template ::value == object_category::string_assignable, detail::enabler> = detail::dummy> +bool lexical_cast(const std::string &input, T &output) { + output = input; + return true; +} + +/// String and similar constructible and copy assignment +template < + typename T, + enable_if_t::value == object_category::string_constructible, detail::enabler> = detail::dummy> +bool lexical_cast(const std::string &input, T &output) { + output = T(input); + return true; +} + +/// Wide strings +template < + typename T, + enable_if_t::value == object_category::wstring_assignable, detail::enabler> = detail::dummy> +bool lexical_cast(const std::string &input, T &output) { + output = widen(input); + return true; +} + +template < + typename T, + enable_if_t::value == object_category::wstring_constructible, detail::enabler> = detail::dummy> +bool lexical_cast(const std::string &input, T &output) { + output = T{widen(input)}; + return true; +} + +/// Enumerations +template ::value == object_category::enumeration, detail::enabler> = detail::dummy> +bool lexical_cast(const std::string &input, T &output) { + typename std::underlying_type::type val; + if(!integral_conversion(input, val)) { + return false; + } + output = static_cast(val); + return true; +} + +/// wrapper types +template ::value == object_category::wrapper_value && + std::is_assignable::value, + detail::enabler> = detail::dummy> +bool lexical_cast(const std::string &input, T &output) { + typename T::value_type val; + if(lexical_cast(input, val)) { + output = val; + return true; + } + return from_stream(input, output); +} + +template ::value == object_category::wrapper_value && + !std::is_assignable::value && std::is_assignable::value, + detail::enabler> = detail::dummy> +bool lexical_cast(const std::string &input, T &output) { + typename T::value_type val; + if(lexical_cast(input, val)) { + output = T{val}; + return true; + } + return from_stream(input, output); +} + +/// Assignable from double or int +template < + typename T, + enable_if_t::value == object_category::number_constructible, detail::enabler> = detail::dummy> +bool lexical_cast(const std::string &input, T &output) { + int val = 0; + if(integral_conversion(input, val)) { + output = T(val); + return true; + } + + double dval = 0.0; + if(lexical_cast(input, dval)) { + output = T{dval}; + return true; + } + + return from_stream(input, output); +} + +/// Assignable from int +template < + typename T, + enable_if_t::value == object_category::integer_constructible, detail::enabler> = detail::dummy> +bool lexical_cast(const std::string &input, T &output) { + int val = 0; + if(integral_conversion(input, val)) { + output = T(val); + return true; + } + return from_stream(input, output); +} + +/// Assignable from double +template < + typename T, + enable_if_t::value == object_category::double_constructible, detail::enabler> = detail::dummy> +bool lexical_cast(const std::string &input, T &output) { + double val = 0.0; + if(lexical_cast(input, val)) { + output = T{val}; + return true; + } + return from_stream(input, output); +} + +/// Non-string convertible from an int +template ::value == object_category::other && std::is_assignable::value, + detail::enabler> = detail::dummy> +bool lexical_cast(const std::string &input, T &output) { + int val = 0; + if(integral_conversion(input, val)) { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4800) +#endif + // with Atomic this could produce a warning due to the conversion but if atomic gets here it is an old style + // so will most likely still work + output = val; +#ifdef _MSC_VER +#pragma warning(pop) +#endif + return true; + } + // LCOV_EXCL_START + // This version of cast is only used for odd cases in an older compilers the fail over + // from_stream is tested elsewhere an not relevant for coverage here + return from_stream(input, output); + // LCOV_EXCL_STOP +} + +/// Non-string parsable by a stream +template ::value == object_category::other && !std::is_assignable::value && + is_istreamable::value, + detail::enabler> = detail::dummy> +bool lexical_cast(const std::string &input, T &output) { + return from_stream(input, output); +} + +/// Fallback overload that prints a human-readable error for types that we don't recognize and that don't have a +/// user-supplied lexical_cast overload. +template ::value == object_category::other && !std::is_assignable::value && + !is_istreamable::value && !adl_detail::is_lexical_castable::value, + detail::enabler> = detail::dummy> +bool lexical_cast(const std::string & /*input*/, T & /*output*/) { + static_assert(!std::is_same::value, // Can't just write false here. + "option object type must have a lexical cast overload or streaming input operator(>>) defined, if it " + "is convertible from another type use the add_option(...) with XC being the known type"); + return false; +} + +/// Assign a value through lexical cast operations +/// Strings can be empty so we need to do a little different +template ::value && + (classify_object::value == object_category::string_assignable || + classify_object::value == object_category::string_constructible || + classify_object::value == object_category::wstring_assignable || + classify_object::value == object_category::wstring_constructible), + detail::enabler> = detail::dummy> +bool lexical_assign(const std::string &input, AssignTo &output) { + return lexical_cast(input, output); +} + +/// Assign a value through lexical cast operations +template ::value && std::is_assignable::value && + classify_object::value != object_category::string_assignable && + classify_object::value != object_category::string_constructible && + classify_object::value != object_category::wstring_assignable && + classify_object::value != object_category::wstring_constructible, + detail::enabler> = detail::dummy> +bool lexical_assign(const std::string &input, AssignTo &output) { + if(input.empty()) { + output = AssignTo{}; + return true; + } + + return lexical_cast(input, output); +} // LCOV_EXCL_LINE + +/// Assign a value through lexical cast operations +template ::value && !std::is_assignable::value && + classify_object::value == object_category::wrapper_value, + detail::enabler> = detail::dummy> +bool lexical_assign(const std::string &input, AssignTo &output) { + if(input.empty()) { + typename AssignTo::value_type emptyVal{}; + output = emptyVal; + return true; + } + return lexical_cast(input, output); +} + +/// Assign a value through lexical cast operations for int compatible values +/// mainly for atomic operations on some compilers +template ::value && !std::is_assignable::value && + classify_object::value != object_category::wrapper_value && + std::is_assignable::value, + detail::enabler> = detail::dummy> +bool lexical_assign(const std::string &input, AssignTo &output) { + if(input.empty()) { + output = 0; + return true; + } + int val{0}; + if(lexical_cast(input, val)) { +#if defined(__clang__) +/* on some older clang compilers */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wsign-conversion" +#endif + output = val; +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + return true; + } + return false; +} + +/// Assign a value converted from a string in lexical cast to the output value directly +template ::value && std::is_assignable::value, + detail::enabler> = detail::dummy> +bool lexical_assign(const std::string &input, AssignTo &output) { + ConvertTo val{}; + bool parse_result = (!input.empty()) ? lexical_cast(input, val) : true; + if(parse_result) { + output = val; + } + return parse_result; +} + +/// Assign a value from a lexical cast through constructing a value and move assigning it +template < + typename AssignTo, + typename ConvertTo, + enable_if_t::value && !std::is_assignable::value && + std::is_move_assignable::value, + detail::enabler> = detail::dummy> +bool lexical_assign(const std::string &input, AssignTo &output) { + ConvertTo val{}; + bool parse_result = input.empty() ? true : lexical_cast(input, val); + if(parse_result) { + output = AssignTo(val); // use () form of constructor to allow some implicit conversions + } + return parse_result; +} + +/// primary lexical conversion operation, 1 string to 1 type of some kind +template ::value <= object_category::other && + classify_object::value <= object_category::wrapper_value, + detail::enabler> = detail::dummy> +bool lexical_conversion(const std::vector &strings, AssignTo &output) { + return lexical_assign(strings[0], output); +} + +/// Lexical conversion if there is only one element but the conversion type is for two, then call a two element +/// constructor +template ::value <= 2) && expected_count::value == 1 && + is_tuple_like::value && type_count_base::value == 2, + detail::enabler> = detail::dummy> +bool lexical_conversion(const std::vector &strings, AssignTo &output) { + // the remove const is to handle pair types coming from a container + using FirstType = typename std::remove_const::type>::type; + using SecondType = typename std::tuple_element<1, ConvertTo>::type; + FirstType v1; + SecondType v2{}; + bool retval = lexical_assign(strings[0], v1); + retval = retval && lexical_assign((strings.size() > 1) ? strings[1] : std::string{}, v2); + if(retval) { + output = AssignTo{v1, v2}; + } + return retval; +} + +/// Lexical conversion of a container types of single elements +template ::value && is_mutable_container::value && + type_count::value == 1, + detail::enabler> = detail::dummy> +bool lexical_conversion(const std::vector &strings, AssignTo &output) { + output.erase(output.begin(), output.end()); + if(strings.empty()) { + return true; + } + if(strings.size() == 1 && strings[0] == "{}") { + return true; + } + bool skip_remaining = false; + if(strings.size() == 2 && strings[0] == "{}" && is_separator(strings[1])) { + skip_remaining = true; + } + for(const auto &elem : strings) { + typename AssignTo::value_type out; + bool retval = lexical_assign(elem, out); + if(!retval) { + return false; + } + output.insert(output.end(), std::move(out)); + if(skip_remaining) { + break; + } + } + return (!output.empty()); +} + +/// Lexical conversion for complex types +template ::value, detail::enabler> = detail::dummy> +bool lexical_conversion(const std::vector &strings, AssignTo &output) { + + if(strings.size() >= 2 && !strings[1].empty()) { + using XC2 = typename wrapped_type::type; + XC2 x{0.0}, y{0.0}; + auto str1 = strings[1]; + if(str1.back() == 'i' || str1.back() == 'j') { + str1.pop_back(); + } + auto worked = lexical_cast(strings[0], x) && lexical_cast(str1, y); + if(worked) { + output = ConvertTo{x, y}; + } + return worked; + } + return lexical_assign(strings[0], output); +} + +/// Conversion to a vector type using a particular single type as the conversion type +template ::value && (expected_count::value == 1) && + (type_count::value == 1), + detail::enabler> = detail::dummy> +bool lexical_conversion(const std::vector &strings, AssignTo &output) { + bool retval = true; + output.clear(); + output.reserve(strings.size()); + for(const auto &elem : strings) { + + output.emplace_back(); + retval = retval && lexical_assign(elem, output.back()); + } + return (!output.empty()) && retval; +} + +// forward declaration + +/// Lexical conversion of a container types with conversion type of two elements +template ::value && is_mutable_container::value && + type_count_base::value == 2, + detail::enabler> = detail::dummy> +bool lexical_conversion(std::vector strings, AssignTo &output); + +/// Lexical conversion of a vector types with type_size >2 forward declaration +template ::value && is_mutable_container::value && + type_count_base::value != 2 && + ((type_count::value > 2) || + (type_count::value > type_count_base::value)), + detail::enabler> = detail::dummy> +bool lexical_conversion(const std::vector &strings, AssignTo &output); + +/// Conversion for tuples +template ::value && is_tuple_like::value && + (type_count_base::value != type_count::value || + type_count::value > 2), + detail::enabler> = detail::dummy> +bool lexical_conversion(const std::vector &strings, AssignTo &output); // forward declaration + +/// Conversion for operations where the assigned type is some class but the conversion is a mutable container or large +/// tuple +template ::value && !is_mutable_container::value && + classify_object::value != object_category::wrapper_value && + (is_mutable_container::value || type_count::value > 2), + detail::enabler> = detail::dummy> +bool lexical_conversion(const std::vector &strings, AssignTo &output) { + + if(strings.size() > 1 || (!strings.empty() && !(strings.front().empty()))) { + ConvertTo val; + auto retval = lexical_conversion(strings, val); + output = AssignTo{val}; + return retval; + } + output = AssignTo{}; + return true; +} + +/// function template for converting tuples if the static Index is greater than the tuple size +template +inline typename std::enable_if<(I >= type_count_base::value), bool>::type +tuple_conversion(const std::vector &, AssignTo &) { + return true; +} + +/// Conversion of a tuple element where the type size ==1 and not a mutable container +template +inline typename std::enable_if::value && type_count::value == 1, bool>::type +tuple_type_conversion(std::vector &strings, AssignTo &output) { + auto retval = lexical_assign(strings[0], output); + strings.erase(strings.begin()); + return retval; +} + +/// Conversion of a tuple element where the type size !=1 but the size is fixed and not a mutable container +template +inline typename std::enable_if::value && (type_count::value > 1) && + type_count::value == type_count_min::value, + bool>::type +tuple_type_conversion(std::vector &strings, AssignTo &output) { + auto retval = lexical_conversion(strings, output); + strings.erase(strings.begin(), strings.begin() + type_count::value); + return retval; +} + +/// Conversion of a tuple element where the type is a mutable container or a type with different min and max type sizes +template +inline typename std::enable_if::value || + type_count::value != type_count_min::value, + bool>::type +tuple_type_conversion(std::vector &strings, AssignTo &output) { + + std::size_t index{subtype_count_min::value}; + const std::size_t mx_count{subtype_count::value}; + const std::size_t mx{(std::min)(mx_count, strings.size() - 1)}; + + while(index < mx) { + if(is_separator(strings[index])) { + break; + } + ++index; + } + bool retval = lexical_conversion( + std::vector(strings.begin(), strings.begin() + static_cast(index)), output); + if(strings.size() > index) { + strings.erase(strings.begin(), strings.begin() + static_cast(index) + 1); + } else { + strings.clear(); + } + return retval; +} + +/// Tuple conversion operation +template +inline typename std::enable_if<(I < type_count_base::value), bool>::type +tuple_conversion(std::vector strings, AssignTo &output) { + bool retval = true; + using ConvertToElement = typename std:: + conditional::value, typename std::tuple_element::type, ConvertTo>::type; + if(!strings.empty()) { + retval = retval && tuple_type_conversion::type, ConvertToElement>( + strings, std::get(output)); + } + retval = retval && tuple_conversion(std::move(strings), output); + return retval; +} + +/// Lexical conversion of a container types with tuple elements of size 2 +template ::value && is_mutable_container::value && + type_count_base::value == 2, + detail::enabler>> +bool lexical_conversion(std::vector strings, AssignTo &output) { + output.clear(); + while(!strings.empty()) { + + typename std::remove_const::type>::type v1; + typename std::tuple_element<1, typename ConvertTo::value_type>::type v2; + bool retval = tuple_type_conversion(strings, v1); + if(!strings.empty()) { + retval = retval && tuple_type_conversion(strings, v2); + } + if(retval) { + output.insert(output.end(), typename AssignTo::value_type{v1, v2}); + } else { + return false; + } + } + return (!output.empty()); +} + +/// lexical conversion of tuples with type count>2 or tuples of types of some element with a type size>=2 +template ::value && is_tuple_like::value && + (type_count_base::value != type_count::value || + type_count::value > 2), + detail::enabler>> +bool lexical_conversion(const std::vector &strings, AssignTo &output) { + static_assert( + !is_tuple_like::value || type_count_base::value == type_count_base::value, + "if the conversion type is defined as a tuple it must be the same size as the type you are converting to"); + return tuple_conversion(strings, output); +} + +/// Lexical conversion of a vector types for everything but tuples of two elements and types of size 1 +template ::value && is_mutable_container::value && + type_count_base::value != 2 && + ((type_count::value > 2) || + (type_count::value > type_count_base::value)), + detail::enabler>> +bool lexical_conversion(const std::vector &strings, AssignTo &output) { + bool retval = true; + output.clear(); + std::vector temp; + std::size_t ii{0}; + std::size_t icount{0}; + std::size_t xcm{type_count::value}; + auto ii_max = strings.size(); + while(ii < ii_max) { + temp.push_back(strings[ii]); + ++ii; + ++icount; + if(icount == xcm || is_separator(temp.back()) || ii == ii_max) { + if(static_cast(xcm) > type_count_min::value && is_separator(temp.back())) { + temp.pop_back(); + } + typename AssignTo::value_type temp_out; + retval = retval && + lexical_conversion(temp, temp_out); + temp.clear(); + if(!retval) { + return false; + } + output.insert(output.end(), std::move(temp_out)); + icount = 0; + } + } + return retval; +} + +/// conversion for wrapper types +template ::value == object_category::wrapper_value && + std::is_assignable::value, + detail::enabler> = detail::dummy> +bool lexical_conversion(const std::vector &strings, AssignTo &output) { + if(strings.empty() || strings.front().empty()) { + output = ConvertTo{}; + return true; + } + typename ConvertTo::value_type val; + if(lexical_conversion(strings, val)) { + output = ConvertTo{val}; + return true; + } + return false; +} + +/// conversion for wrapper types +template ::value == object_category::wrapper_value && + !std::is_assignable::value, + detail::enabler> = detail::dummy> +bool lexical_conversion(const std::vector &strings, AssignTo &output) { + using ConvertType = typename ConvertTo::value_type; + if(strings.empty() || strings.front().empty()) { + output = ConvertType{}; + return true; + } + ConvertType val; + if(lexical_conversion(strings, val)) { + output = val; + return true; + } + return false; +} + +/// Sum a vector of strings +inline std::string sum_string_vector(const std::vector &values) { + double val{0.0}; + bool fail{false}; + std::string output; + for(const auto &arg : values) { + double tv{0.0}; + auto comp = lexical_cast(arg, tv); + if(!comp) { + errno = 0; + auto fv = detail::to_flag_value(arg); + fail = (errno != 0); + if(fail) { + break; + } + tv = static_cast(fv); + } + val += tv; + } + if(fail) { + for(const auto &arg : values) { + output.append(arg); + } + } else { + std::ostringstream out; + out.precision(16); + out << val; + output = out.str(); + } + return output; +} + +} // namespace detail + + + +namespace detail { + +// Returns false if not a short option. Otherwise, sets opt name and rest and returns true +CLI11_INLINE bool split_short(const std::string ¤t, std::string &name, std::string &rest); + +// Returns false if not a long option. Otherwise, sets opt name and other side of = and returns true +CLI11_INLINE bool split_long(const std::string ¤t, std::string &name, std::string &value); + +// Returns false if not a windows style option. Otherwise, sets opt name and value and returns true +CLI11_INLINE bool split_windows_style(const std::string ¤t, std::string &name, std::string &value); + +// Splits a string into multiple long and short names +CLI11_INLINE std::vector split_names(std::string current); + +/// extract default flag values either {def} or starting with a ! +CLI11_INLINE std::vector> get_default_flag_values(const std::string &str); + +/// Get a vector of short names, one of long names, and a single name +CLI11_INLINE std::tuple, std::vector, std::string> +get_names(const std::vector &input, bool allow_non_standard = false); + +} // namespace detail + + + +namespace detail { + +CLI11_INLINE bool split_short(const std::string ¤t, std::string &name, std::string &rest) { + if(current.size() > 1 && current[0] == '-' && valid_first_char(current[1])) { + name = current.substr(1, 1); + rest = current.substr(2); + return true; + } + return false; +} + +CLI11_INLINE bool split_long(const std::string ¤t, std::string &name, std::string &value) { + if(current.size() > 2 && current.compare(0, 2, "--") == 0 && valid_first_char(current[2])) { + auto loc = current.find_first_of('='); + if(loc != std::string::npos) { + name = current.substr(2, loc - 2); + value = current.substr(loc + 1); + } else { + name = current.substr(2); + value = ""; + } + return true; + } + return false; +} + +CLI11_INLINE bool split_windows_style(const std::string ¤t, std::string &name, std::string &value) { + if(current.size() > 1 && current[0] == '/' && valid_first_char(current[1])) { + auto loc = current.find_first_of(':'); + if(loc != std::string::npos) { + name = current.substr(1, loc - 1); + value = current.substr(loc + 1); + } else { + name = current.substr(1); + value = ""; + } + return true; + } + return false; +} + +CLI11_INLINE std::vector split_names(std::string current) { + std::vector output; + std::size_t val = 0; + while((val = current.find(',')) != std::string::npos) { + output.push_back(trim_copy(current.substr(0, val))); + current = current.substr(val + 1); + } + output.push_back(trim_copy(current)); + return output; +} + +CLI11_INLINE std::vector> get_default_flag_values(const std::string &str) { + std::vector flags = split_names(str); + flags.erase(std::remove_if(flags.begin(), + flags.end(), + [](const std::string &name) { + return ((name.empty()) || (!(((name.find_first_of('{') != std::string::npos) && + (name.back() == '}')) || + (name[0] == '!')))); + }), + flags.end()); + std::vector> output; + output.reserve(flags.size()); + for(auto &flag : flags) { + auto def_start = flag.find_first_of('{'); + std::string defval = "false"; + if((def_start != std::string::npos) && (flag.back() == '}')) { + defval = flag.substr(def_start + 1); + defval.pop_back(); + flag.erase(def_start, std::string::npos); // NOLINT(readability-suspicious-call-argument) + } + flag.erase(0, flag.find_first_not_of("-!")); + output.emplace_back(flag, defval); + } + return output; +} + +CLI11_INLINE std::tuple, std::vector, std::string> +get_names(const std::vector &input, bool allow_non_standard) { + + std::vector short_names; + std::vector long_names; + std::string pos_name; + for(std::string name : input) { + if(name.empty()) { + continue; + } + if(name.length() > 1 && name[0] == '-' && name[1] != '-') { + if(name.length() == 2 && valid_first_char(name[1])) { + short_names.emplace_back(1, name[1]); + } else if(name.length() > 2) { + if(allow_non_standard) { + name = name.substr(1); + if(valid_name_string(name)) { + short_names.push_back(name); + } else { + throw BadNameString::BadLongName(name); + } + } else { + throw BadNameString::MissingDash(name); + } + } else { + throw BadNameString::OneCharName(name); + } + } else if(name.length() > 2 && name.substr(0, 2) == "--") { + name = name.substr(2); + if(valid_name_string(name)) { + long_names.push_back(name); + } else { + throw BadNameString::BadLongName(name); + } + } else if(name == "-" || name == "--" || name == "++") { + throw BadNameString::ReservedName(name); + } else { + if(!pos_name.empty()) { + throw BadNameString::MultiPositionalNames(name); + } + if(valid_name_string(name)) { + pos_name = name; + } else { + throw BadNameString::BadPositionalName(name); + } + } + } + return std::make_tuple(short_names, long_names, pos_name); +} + +} // namespace detail + + + +class App; + +/// Holds values to load into Options +struct ConfigItem { + /// This is the list of parents + std::vector parents{}; + + /// This is the name + std::string name{}; + /// Listing of inputs + std::vector inputs{}; + /// @brief indicator if a multiline vector separator was inserted + bool multiline{false}; + /// The list of parents and name joined by "." + CLI11_NODISCARD std::string fullname() const { + std::vector tmp = parents; + tmp.emplace_back(name); + return detail::join(tmp, "."); + (void)multiline; // suppression for cppcheck false positive + } +}; + +/// This class provides a converter for configuration files. +class Config { + protected: + std::vector items{}; + + public: + /// Convert an app into a configuration + virtual std::string to_config(const App *, bool, bool, std::string) const = 0; + + /// Convert a configuration into an app + virtual std::vector from_config(std::istream &) const = 0; + + /// Get a flag value + CLI11_NODISCARD virtual std::string to_flag(const ConfigItem &item) const { + if(item.inputs.size() == 1) { + return item.inputs.at(0); + } + if(item.inputs.empty()) { + return "{}"; + } + throw ConversionError::TooManyInputsFlag(item.fullname()); // LCOV_EXCL_LINE + } + + /// Parse a config file, throw an error (ParseError:ConfigParseError or FileError) on failure + CLI11_NODISCARD std::vector from_file(const std::string &name) const { + std::ifstream input{name}; + if(!input.good()) + throw FileError::Missing(name); + + return from_config(input); + } + + /// Virtual destructor + virtual ~Config() = default; +}; + +/// This converter works with INI/TOML files; to write INI files use ConfigINI +class ConfigBase : public Config { + protected: + /// the character used for comments + char commentChar = '#'; + /// the character used to start an array '\0' is a default to not use + char arrayStart = '['; + /// the character used to end an array '\0' is a default to not use + char arrayEnd = ']'; + /// the character used to separate elements in an array + char arraySeparator = ','; + /// the character used separate the name from the value + char valueDelimiter = '='; + /// the character to use around strings + char stringQuote = '"'; + /// the character to use around single characters and literal strings + char literalQuote = '\''; + /// the maximum number of layers to allow + uint8_t maximumLayers{255}; + /// the separator used to separator parent layers + char parentSeparatorChar{'.'}; + /// comment default values + bool commentDefaultsBool = false; + /// specify the config reader should collapse repeated field names to a single vector + bool allowMultipleDuplicateFields{false}; + /// Specify the configuration index to use for arrayed sections + int16_t configIndex{-1}; + /// Specify the configuration section that should be used + std::string configSection{}; + + public: + std::string + to_config(const App * /*app*/, bool default_also, bool write_description, std::string prefix) const override; + + std::vector from_config(std::istream &input) const override; + /// Specify the configuration for comment characters + ConfigBase *comment(char cchar) { + commentChar = cchar; + return this; + } + /// Specify the start and end characters for an array + ConfigBase *arrayBounds(char aStart, char aEnd) { + arrayStart = aStart; + arrayEnd = aEnd; + return this; + } + /// Specify the delimiter character for an array + ConfigBase *arrayDelimiter(char aSep) { + arraySeparator = aSep; + return this; + } + /// Specify the delimiter between a name and value + ConfigBase *valueSeparator(char vSep) { + valueDelimiter = vSep; + return this; + } + /// Specify the quote characters used around strings and literal strings + ConfigBase *quoteCharacter(char qString, char literalChar) { + stringQuote = qString; + literalQuote = literalChar; + return this; + } + /// Specify the maximum number of parents + ConfigBase *maxLayers(uint8_t layers) { + maximumLayers = layers; + return this; + } + /// Specify the separator to use for parent layers + ConfigBase *parentSeparator(char sep) { + parentSeparatorChar = sep; + return this; + } + /// comment default value options + ConfigBase *commentDefaults(bool comDef = true) { + commentDefaultsBool = comDef; + return this; + } + /// get a reference to the configuration section + std::string §ionRef() { return configSection; } + /// get the section + CLI11_NODISCARD const std::string §ion() const { return configSection; } + /// specify a particular section of the configuration file to use + ConfigBase *section(const std::string §ionName) { + configSection = sectionName; + return this; + } + + /// get a reference to the configuration index + int16_t &indexRef() { return configIndex; } + /// get the section index + CLI11_NODISCARD int16_t index() const { return configIndex; } + /// specify a particular index in the section to use (-1) for all sections to use + ConfigBase *index(int16_t sectionIndex) { + configIndex = sectionIndex; + return this; + } + /// specify that multiple duplicate arguments should be merged even if not sequential + ConfigBase *allowDuplicateFields(bool value = true) { + allowMultipleDuplicateFields = value; + return this; + } +}; + +/// the default Config is the TOML file format +using ConfigTOML = ConfigBase; + +/// ConfigINI generates a "standard" INI compliant output +class ConfigINI : public ConfigTOML { + + public: + ConfigINI() { + commentChar = ';'; + arrayStart = '\0'; + arrayEnd = '\0'; + arraySeparator = ' '; + valueDelimiter = '='; + } +}; + + + +class Option; + +/// @defgroup validator_group Validators + +/// @brief Some validators that are provided +/// +/// These are simple `std::string(const std::string&)` validators that are useful. They return +/// a string if the validation fails. A custom struct is provided, as well, with the same user +/// semantics, but with the ability to provide a new type name. +/// @{ + +/// +class Validator { + protected: + /// This is the description function, if empty the description_ will be used + std::function desc_function_{[]() { return std::string{}; }}; + + /// This is the base function that is to be called. + /// Returns a string error message if validation fails. + std::function func_{[](std::string &) { return std::string{}; }}; + /// The name for search purposes of the Validator + std::string name_{}; + /// A Validator will only apply to an indexed value (-1 is all elements) + int application_index_ = -1; + /// Enable for Validator to allow it to be disabled if need be + bool active_{true}; + /// specify that a validator should not modify the input + bool non_modifying_{false}; + + Validator(std::string validator_desc, std::function func) + : desc_function_([validator_desc]() { return validator_desc; }), func_(std::move(func)) {} + + public: + Validator() = default; + /// Construct a Validator with just the description string + explicit Validator(std::string validator_desc) : desc_function_([validator_desc]() { return validator_desc; }) {} + /// Construct Validator from basic information + Validator(std::function op, std::string validator_desc, std::string validator_name = "") + : desc_function_([validator_desc]() { return validator_desc; }), func_(std::move(op)), + name_(std::move(validator_name)) {} + /// Set the Validator operation function + Validator &operation(std::function op) { + func_ = std::move(op); + return *this; + } + /// This is the required operator for a Validator - provided to help + /// users (CLI11 uses the member `func` directly) + std::string operator()(std::string &str) const; + + /// This is the required operator for a Validator - provided to help + /// users (CLI11 uses the member `func` directly) + std::string operator()(const std::string &str) const { + std::string value = str; + return (active_) ? func_(value) : std::string{}; + } + + /// Specify the type string + Validator &description(std::string validator_desc) { + desc_function_ = [validator_desc]() { return validator_desc; }; + return *this; + } + /// Specify the type string + CLI11_NODISCARD Validator description(std::string validator_desc) const; + + /// Generate type description information for the Validator + CLI11_NODISCARD std::string get_description() const { + if(active_) { + return desc_function_(); + } + return std::string{}; + } + /// Specify the type string + Validator &name(std::string validator_name) { + name_ = std::move(validator_name); + return *this; + } + /// Specify the type string + CLI11_NODISCARD Validator name(std::string validator_name) const { + Validator newval(*this); + newval.name_ = std::move(validator_name); + return newval; + } + /// Get the name of the Validator + CLI11_NODISCARD const std::string &get_name() const { return name_; } + /// Specify whether the Validator is active or not + Validator &active(bool active_val = true) { + active_ = active_val; + return *this; + } + /// Specify whether the Validator is active or not + CLI11_NODISCARD Validator active(bool active_val = true) const { + Validator newval(*this); + newval.active_ = active_val; + return newval; + } + + /// Specify whether the Validator can be modifying or not + Validator &non_modifying(bool no_modify = true) { + non_modifying_ = no_modify; + return *this; + } + /// Specify the application index of a validator + Validator &application_index(int app_index) { + application_index_ = app_index; + return *this; + } + /// Specify the application index of a validator + CLI11_NODISCARD Validator application_index(int app_index) const { + Validator newval(*this); + newval.application_index_ = app_index; + return newval; + } + /// Get the current value of the application index + CLI11_NODISCARD int get_application_index() const { return application_index_; } + /// Get a boolean if the validator is active + CLI11_NODISCARD bool get_active() const { return active_; } + + /// Get a boolean if the validator is allowed to modify the input returns true if it can modify the input + CLI11_NODISCARD bool get_modifying() const { return !non_modifying_; } + + /// Combining validators is a new validator. Type comes from left validator if function, otherwise only set if the + /// same. + Validator operator&(const Validator &other) const; + + /// Combining validators is a new validator. Type comes from left validator if function, otherwise only set if the + /// same. + Validator operator|(const Validator &other) const; + + /// Create a validator that fails when a given validator succeeds + Validator operator!() const; + + private: + void _merge_description(const Validator &val1, const Validator &val2, const std::string &merger); +}; + +/// Alias for Validator for custom Validator for clarity +using CustomValidator = Validator; + +// The implementation of the built in validators is using the Validator class; +// the user is only expected to use the const (static) versions (since there's no setup). +// Therefore, this is in detail. +namespace detail { + +/// CLI enumeration of different file types +enum class path_type : std::uint8_t { nonexistent, file, directory }; + +/// get the type of the path from a file name +CLI11_INLINE path_type check_path(const char *file) noexcept; + +// Static is not needed here, because global const implies static. + +/// Check for an existing file (returns error message if check fails) +class ExistingFileValidator : public Validator { + public: + ExistingFileValidator(); +}; + +/// Check for an existing directory (returns error message if check fails) +class ExistingDirectoryValidator : public Validator { + public: + ExistingDirectoryValidator(); +}; + +/// Check for an existing path +class ExistingPathValidator : public Validator { + public: + ExistingPathValidator(); +}; + +/// Check for an non-existing path +class NonexistentPathValidator : public Validator { + public: + NonexistentPathValidator(); +}; + +class EscapedStringTransformer : public Validator { + public: + EscapedStringTransformer(); +}; + +} // namespace detail + +/// Check for existing file (returns error message if check fails) +const detail::ExistingFileValidator ExistingFile; + +/// Check for an existing directory (returns error message if check fails) +const detail::ExistingDirectoryValidator ExistingDirectory; + +/// Check for an existing path +const detail::ExistingPathValidator ExistingPath; + +/// Check for an non-existing path +const detail::NonexistentPathValidator NonexistentPath; + +/// convert escaped characters into their associated values +const detail::EscapedStringTransformer EscapedString; + +/// Modify a path if the file is a particular default location, can be used as Check or transform +/// with the error return optionally disabled +class FileOnDefaultPath : public Validator { + public: + explicit FileOnDefaultPath(std::string default_path, bool enableErrorReturn = true); +}; + +/// Produce a range (factory). Min and max are inclusive. +class Range : public Validator { + public: + /// This produces a range with min and max inclusive. + /// + /// Note that the constructor is templated, but the struct is not, so C++17 is not + /// needed to provide nice syntax for Range(a,b). + template + Range(T min_val, T max_val, const std::string &validator_name = std::string{}) : Validator(validator_name) { + if(validator_name.empty()) { + std::stringstream out; + out << detail::type_name() << " in [" << min_val << " - " << max_val << "]"; + description(out.str()); + } + + func_ = [min_val, max_val](std::string &input) { + using CLI::detail::lexical_cast; + T val; + bool converted = lexical_cast(input, val); + if((!converted) || (val < min_val || val > max_val)) { + std::stringstream out; + out << "Value " << input << " not in range ["; + out << min_val << " - " << max_val << "]"; + return out.str(); + } + return std::string{}; + }; + } + + /// Range of one value is 0 to value + template + explicit Range(T max_val, const std::string &validator_name = std::string{}) + : Range(static_cast(0), max_val, validator_name) {} +}; + +/// Check for a non negative number +const Range NonNegativeNumber((std::numeric_limits::max)(), "NONNEGATIVE"); + +/// Check for a positive valued number (val>0.0), ::min here is the smallest positive number +const Range PositiveNumber((std::numeric_limits::min)(), (std::numeric_limits::max)(), "POSITIVE"); + +namespace detail { +// the following suggestion was made by Nikita Ofitserov(@himikof) +// done in templates to prevent compiler warnings on negation of unsigned numbers + +/// Do a check for overflow on signed numbers +template +inline typename std::enable_if::value, T>::type overflowCheck(const T &a, const T &b) { + if((a > 0) == (b > 0)) { + return ((std::numeric_limits::max)() / (std::abs)(a) < (std::abs)(b)); + } + return ((std::numeric_limits::min)() / (std::abs)(a) > -(std::abs)(b)); +} +/// Do a check for overflow on unsigned numbers +template +inline typename std::enable_if::value, T>::type overflowCheck(const T &a, const T &b) { + return ((std::numeric_limits::max)() / a < b); +} + +/// Performs a *= b; if it doesn't cause integer overflow. Returns false otherwise. +template typename std::enable_if::value, bool>::type checked_multiply(T &a, T b) { + if(a == 0 || b == 0 || a == 1 || b == 1) { + a *= b; + return true; + } + if(a == (std::numeric_limits::min)() || b == (std::numeric_limits::min)()) { + return false; + } + if(overflowCheck(a, b)) { + return false; + } + a *= b; + return true; +} + +/// Performs a *= b; if it doesn't equal infinity. Returns false otherwise. +template +typename std::enable_if::value, bool>::type checked_multiply(T &a, T b) { + T c = a * b; + if(std::isinf(c) && !std::isinf(a) && !std::isinf(b)) { + return false; + } + a = c; + return true; +} +/// Split a string into a program name and command line arguments +/// the string is assumed to contain a file name followed by other arguments +/// the return value contains is a pair with the first argument containing the program name and the second +/// everything else. +CLI11_INLINE std::pair split_program_name(std::string commandline); + +} // namespace detail +/// @} + + + + +CLI11_INLINE std::string Validator::operator()(std::string &str) const { + std::string retstring; + if(active_) { + if(non_modifying_) { + std::string value = str; + retstring = func_(value); + } else { + retstring = func_(str); + } + } + return retstring; +} + +CLI11_NODISCARD CLI11_INLINE Validator Validator::description(std::string validator_desc) const { + Validator newval(*this); + newval.desc_function_ = [validator_desc]() { return validator_desc; }; + return newval; +} + +CLI11_INLINE Validator Validator::operator&(const Validator &other) const { + Validator newval; + + newval._merge_description(*this, other, " AND "); + + // Give references (will make a copy in lambda function) + const std::function &f1 = func_; + const std::function &f2 = other.func_; + + newval.func_ = [f1, f2](std::string &input) { + std::string s1 = f1(input); + std::string s2 = f2(input); + if(!s1.empty() && !s2.empty()) + return std::string("(") + s1 + ") AND (" + s2 + ")"; + return s1 + s2; + }; + + newval.active_ = active_ && other.active_; + newval.application_index_ = application_index_; + return newval; +} + +CLI11_INLINE Validator Validator::operator|(const Validator &other) const { + Validator newval; + + newval._merge_description(*this, other, " OR "); + + // Give references (will make a copy in lambda function) + const std::function &f1 = func_; + const std::function &f2 = other.func_; + + newval.func_ = [f1, f2](std::string &input) { + std::string s1 = f1(input); + std::string s2 = f2(input); + if(s1.empty() || s2.empty()) + return std::string(); + + return std::string("(") + s1 + ") OR (" + s2 + ")"; + }; + newval.active_ = active_ && other.active_; + newval.application_index_ = application_index_; + return newval; +} + +CLI11_INLINE Validator Validator::operator!() const { + Validator newval; + const std::function &dfunc1 = desc_function_; + newval.desc_function_ = [dfunc1]() { + auto str = dfunc1(); + return (!str.empty()) ? std::string("NOT ") + str : std::string{}; + }; + // Give references (will make a copy in lambda function) + const std::function &f1 = func_; + + newval.func_ = [f1, dfunc1](std::string &test) -> std::string { + std::string s1 = f1(test); + if(s1.empty()) { + return std::string("check ") + dfunc1() + " succeeded improperly"; + } + return std::string{}; + }; + newval.active_ = active_; + newval.application_index_ = application_index_; + return newval; +} + +CLI11_INLINE void +Validator::_merge_description(const Validator &val1, const Validator &val2, const std::string &merger) { + + const std::function &dfunc1 = val1.desc_function_; + const std::function &dfunc2 = val2.desc_function_; + + desc_function_ = [=]() { + std::string f1 = dfunc1(); + std::string f2 = dfunc2(); + if((f1.empty()) || (f2.empty())) { + return f1 + f2; + } + return std::string(1, '(') + f1 + ')' + merger + '(' + f2 + ')'; + }; +} + +namespace detail { + +#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0 +CLI11_INLINE path_type check_path(const char *file) noexcept { + std::error_code ec; + auto stat = std::filesystem::status(to_path(file), ec); + if(ec) { + return path_type::nonexistent; + } + switch(stat.type()) { + case std::filesystem::file_type::none: // LCOV_EXCL_LINE + case std::filesystem::file_type::not_found: + return path_type::nonexistent; // LCOV_EXCL_LINE + case std::filesystem::file_type::directory: + return path_type::directory; + case std::filesystem::file_type::symlink: + case std::filesystem::file_type::block: + case std::filesystem::file_type::character: + case std::filesystem::file_type::fifo: + case std::filesystem::file_type::socket: + case std::filesystem::file_type::regular: + case std::filesystem::file_type::unknown: + default: + return path_type::file; + } +} +#else +CLI11_INLINE path_type check_path(const char *file) noexcept { +#if defined(_MSC_VER) + struct __stat64 buffer; + if(_stat64(file, &buffer) == 0) { + return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file; + } +#else + struct stat buffer; + if(stat(file, &buffer) == 0) { + return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file; + } +#endif + return path_type::nonexistent; +} +#endif + +CLI11_INLINE ExistingFileValidator::ExistingFileValidator() : Validator("FILE") { + func_ = [](std::string &filename) { + auto path_result = check_path(filename.c_str()); + if(path_result == path_type::nonexistent) { + return "File does not exist: " + filename; + } + if(path_result == path_type::directory) { + return "File is actually a directory: " + filename; + } + return std::string(); + }; +} + +CLI11_INLINE ExistingDirectoryValidator::ExistingDirectoryValidator() : Validator("DIR") { + func_ = [](std::string &filename) { + auto path_result = check_path(filename.c_str()); + if(path_result == path_type::nonexistent) { + return "Directory does not exist: " + filename; + } + if(path_result == path_type::file) { + return "Directory is actually a file: " + filename; + } + return std::string(); + }; +} + +CLI11_INLINE ExistingPathValidator::ExistingPathValidator() : Validator("PATH(existing)") { + func_ = [](std::string &filename) { + auto path_result = check_path(filename.c_str()); + if(path_result == path_type::nonexistent) { + return "Path does not exist: " + filename; + } + return std::string(); + }; +} + +CLI11_INLINE NonexistentPathValidator::NonexistentPathValidator() : Validator("PATH(non-existing)") { + func_ = [](std::string &filename) { + auto path_result = check_path(filename.c_str()); + if(path_result != path_type::nonexistent) { + return "Path already exists: " + filename; + } + return std::string(); + }; +} + +CLI11_INLINE EscapedStringTransformer::EscapedStringTransformer() { + func_ = [](std::string &str) { + try { + if(str.size() > 1 && (str.front() == '\"' || str.front() == '\'' || str.front() == '`') && + str.front() == str.back()) { + process_quoted_string(str); + } else if(str.find_first_of('\\') != std::string::npos) { + if(detail::is_binary_escaped_string(str)) { + str = detail::extract_binary_string(str); + } else { + str = remove_escaped_characters(str); + } + } + return std::string{}; + } catch(const std::invalid_argument &ia) { + return std::string(ia.what()); + } + }; +} +} // namespace detail + +CLI11_INLINE FileOnDefaultPath::FileOnDefaultPath(std::string default_path, bool enableErrorReturn) + : Validator("FILE") { + func_ = [default_path, enableErrorReturn](std::string &filename) { + auto path_result = detail::check_path(filename.c_str()); + if(path_result == detail::path_type::nonexistent) { + std::string test_file_path = default_path; + if(default_path.back() != '/' && default_path.back() != '\\') { + // Add folder separator + test_file_path += '/'; + } + test_file_path.append(filename); + path_result = detail::check_path(test_file_path.c_str()); + if(path_result == detail::path_type::file) { + filename = test_file_path; + } else { + if(enableErrorReturn) { + return "File does not exist: " + filename; + } + } + } + return std::string{}; + }; +} + +namespace detail { + +CLI11_INLINE std::pair split_program_name(std::string commandline) { + // try to determine the programName + std::pair vals; + trim(commandline); + auto esp = commandline.find_first_of(' ', 1); + while(detail::check_path(commandline.substr(0, esp).c_str()) != path_type::file) { + esp = commandline.find_first_of(' ', esp + 1); + if(esp == std::string::npos) { + // if we have reached the end and haven't found a valid file just assume the first argument is the + // program name + if(commandline[0] == '"' || commandline[0] == '\'' || commandline[0] == '`') { + bool embeddedQuote = false; + auto keyChar = commandline[0]; + auto end = commandline.find_first_of(keyChar, 1); + while((end != std::string::npos) && (commandline[end - 1] == '\\')) { // deal with escaped quotes + end = commandline.find_first_of(keyChar, end + 1); + embeddedQuote = true; + } + if(end != std::string::npos) { + vals.first = commandline.substr(1, end - 1); + esp = end + 1; + if(embeddedQuote) { + vals.first = find_and_replace(vals.first, std::string("\\") + keyChar, std::string(1, keyChar)); + } + } else { + esp = commandline.find_first_of(' ', 1); + } + } else { + esp = commandline.find_first_of(' ', 1); + } + + break; + } + } + if(vals.first.empty()) { + vals.first = commandline.substr(0, esp); + rtrim(vals.first); + } + + // strip the program name + vals.second = (esp < commandline.length() - 1) ? commandline.substr(esp + 1) : std::string{}; + ltrim(vals.second); + return vals; +} + +} // namespace detail +/// @} + + + + +// The implementation of the extra validators is using the Validator class; +// the user is only expected to use the const (static) versions (since there's no setup). +// Therefore, this is in detail. +namespace detail { + +/// Validate the given string is a legal ipv4 address +class IPV4Validator : public Validator { + public: + IPV4Validator(); +}; + +} // namespace detail + +/// Validate the input as a particular type +template class TypeValidator : public Validator { + public: + explicit TypeValidator(const std::string &validator_name) + : Validator(validator_name, [](std::string &input_string) { + using CLI::detail::lexical_cast; + auto val = DesiredType(); + if(!lexical_cast(input_string, val)) { + return std::string("Failed parsing ") + input_string + " as a " + detail::type_name(); + } + return std::string{}; + }) {} + TypeValidator() : TypeValidator(detail::type_name()) {} +}; + +/// Check for a number +const TypeValidator Number("NUMBER"); + +/// Produce a bounded range (factory). Min and max are inclusive. +class Bound : public Validator { + public: + /// This bounds a value with min and max inclusive. + /// + /// Note that the constructor is templated, but the struct is not, so C++17 is not + /// needed to provide nice syntax for Range(a,b). + template Bound(T min_val, T max_val) { + std::stringstream out; + out << detail::type_name() << " bounded to [" << min_val << " - " << max_val << "]"; + description(out.str()); + + func_ = [min_val, max_val](std::string &input) { + using CLI::detail::lexical_cast; + T val; + bool converted = lexical_cast(input, val); + if(!converted) { + return std::string("Value ") + input + " could not be converted"; + } + if(val < min_val) + input = detail::to_string(min_val); + else if(val > max_val) + input = detail::to_string(max_val); + + return std::string{}; + }; + } + + /// Range of one value is 0 to value + template explicit Bound(T max_val) : Bound(static_cast(0), max_val) {} +}; + +// Static is not needed here, because global const implies static. + +/// Check for an IP4 address +const detail::IPV4Validator ValidIPV4; + +namespace detail { +template ::type>::value, detail::enabler> = detail::dummy> +auto smart_deref(T value) -> decltype(*value) { + return *value; +} + +template < + typename T, + enable_if_t::type>::value, detail::enabler> = detail::dummy> +typename std::remove_reference::type &smart_deref(T &value) { + // NOLINTNEXTLINE + return value; +} +/// Generate a string representation of a set +template std::string generate_set(const T &set) { + using element_t = typename detail::element_type::type; + using iteration_type_t = typename detail::pair_adaptor::value_type; // the type of the object pair + std::string out(1, '{'); + out.append(detail::join( + detail::smart_deref(set), + [](const iteration_type_t &v) { return detail::pair_adaptor::first(v); }, + ",")); + out.push_back('}'); + return out; +} + +/// Generate a string representation of a map +template std::string generate_map(const T &map, bool key_only = false) { + using element_t = typename detail::element_type::type; + using iteration_type_t = typename detail::pair_adaptor::value_type; // the type of the object pair + std::string out(1, '{'); + out.append(detail::join( + detail::smart_deref(map), + [key_only](const iteration_type_t &v) { + std::string res{detail::to_string(detail::pair_adaptor::first(v))}; + + if(!key_only) { + res.append("->"); + res += detail::to_string(detail::pair_adaptor::second(v)); + } + return res; + }, + ",")); + out.push_back('}'); + return out; +} + +template struct has_find { + template + static auto test(int) -> decltype(std::declval().find(std::declval()), std::true_type()); + template static auto test(...) -> decltype(std::false_type()); + + static const auto value = decltype(test(0))::value; + using type = std::integral_constant; +}; + +/// A search function +template ::value, detail::enabler> = detail::dummy> +auto search(const T &set, const V &val) -> std::pair { + using element_t = typename detail::element_type::type; + auto &setref = detail::smart_deref(set); + auto it = std::find_if(std::begin(setref), std::end(setref), [&val](decltype(*std::begin(setref)) v) { + return (detail::pair_adaptor::first(v) == val); + }); + return {(it != std::end(setref)), it}; +} + +/// A search function that uses the built in find function +template ::value, detail::enabler> = detail::dummy> +auto search(const T &set, const V &val) -> std::pair { + auto &setref = detail::smart_deref(set); + auto it = setref.find(val); + return {(it != std::end(setref)), it}; +} + +/// A search function with a filter function +template +auto search(const T &set, const V &val, const std::function &filter_function) + -> std::pair { + using element_t = typename detail::element_type::type; + // do the potentially faster first search + auto res = search(set, val); + if((res.first) || (!(filter_function))) { + return res; + } + // if we haven't found it do the longer linear search with all the element translations + auto &setref = detail::smart_deref(set); + auto it = std::find_if(std::begin(setref), std::end(setref), [&](decltype(*std::begin(setref)) v) { + V a{detail::pair_adaptor::first(v)}; + a = filter_function(a); + return (a == val); + }); + return {(it != std::end(setref)), it}; +} + +} // namespace detail + /// Verify items are in a set +class IsMember : public Validator { + public: + using filter_fn_t = std::function; + + /// This allows in-place construction using an initializer list + template + IsMember(std::initializer_list values, Args &&...args) + : IsMember(std::vector(values), std::forward(args)...) {} + + /// This checks to see if an item is in a set (empty function) + template explicit IsMember(T &&set) : IsMember(std::forward(set), nullptr) {} + + /// This checks to see if an item is in a set: pointer or copy version. You can pass in a function that will filter + /// both sides of the comparison before computing the comparison. + template explicit IsMember(T set, F filter_function) { + + // Get the type of the contained item - requires a container have ::value_type + // if the type does not have first_type and second_type, these are both value_type + using element_t = typename detail::element_type::type; // Removes (smart) pointers if needed + using item_t = typename detail::pair_adaptor::first_type; // Is value_type if not a map + + using local_item_t = typename IsMemberType::type; // This will convert bad types to good ones + // (const char * to std::string) + + // Make a local copy of the filter function, using a std::function if not one already + std::function filter_fn = filter_function; + + // This is the type name for help, it will take the current version of the set contents + desc_function_ = [set]() { return detail::generate_set(detail::smart_deref(set)); }; + + // This is the function that validates + // It stores a copy of the set pointer-like, so shared_ptr will stay alive + func_ = [set, filter_fn](std::string &input) { + using CLI::detail::lexical_cast; + local_item_t b; + if(!lexical_cast(input, b)) { + throw ValidationError(input); // name is added later + } + if(filter_fn) { + b = filter_fn(b); + } + auto res = detail::search(set, b, filter_fn); + if(res.first) { + // Make sure the version in the input string is identical to the one in the set + if(filter_fn) { + input = detail::value_string(detail::pair_adaptor::first(*(res.second))); + } + + // Return empty error string (success) + return std::string{}; + } + + // If you reach this point, the result was not found + return input + " not in " + detail::generate_set(detail::smart_deref(set)); + }; + } + + /// You can pass in as many filter functions as you like, they nest (string only currently) + template + IsMember(T &&set, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other) + : IsMember( + std::forward(set), + [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); }, + other...) {} +}; + +/// definition of the default transformation object +template using TransformPairs = std::vector>; + +/// Translate named items to other or a value set +class Transformer : public Validator { + public: + using filter_fn_t = std::function; + + /// This allows in-place construction + template + Transformer(std::initializer_list> values, Args &&...args) + : Transformer(TransformPairs(values), std::forward(args)...) {} + + /// direct map of std::string to std::string + template explicit Transformer(T &&mapping) : Transformer(std::forward(mapping), nullptr) {} + + /// This checks to see if an item is in a set: pointer or copy version. You can pass in a function that will filter + /// both sides of the comparison before computing the comparison. + template explicit Transformer(T mapping, F filter_function) { + + static_assert(detail::pair_adaptor::type>::value, + "mapping must produce value pairs"); + // Get the type of the contained item - requires a container have ::value_type + // if the type does not have first_type and second_type, these are both value_type + using element_t = typename detail::element_type::type; // Removes (smart) pointers if needed + using item_t = typename detail::pair_adaptor::first_type; // Is value_type if not a map + using local_item_t = typename IsMemberType::type; // Will convert bad types to good ones + // (const char * to std::string) + + // Make a local copy of the filter function, using a std::function if not one already + std::function filter_fn = filter_function; + + // This is the type name for help, it will take the current version of the set contents + desc_function_ = [mapping]() { return detail::generate_map(detail::smart_deref(mapping)); }; + + func_ = [mapping, filter_fn](std::string &input) { + using CLI::detail::lexical_cast; + local_item_t b; + if(!lexical_cast(input, b)) { + return std::string(); + // there is no possible way we can match anything in the mapping if we can't convert so just return + } + if(filter_fn) { + b = filter_fn(b); + } + auto res = detail::search(mapping, b, filter_fn); + if(res.first) { + input = detail::value_string(detail::pair_adaptor::second(*res.second)); + } + return std::string{}; + }; + } + + /// You can pass in as many filter functions as you like, they nest + template + Transformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other) + : Transformer( + std::forward(mapping), + [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); }, + other...) {} +}; + +/// translate named items to other or a value set +class CheckedTransformer : public Validator { + public: + using filter_fn_t = std::function; + + /// This allows in-place construction + template + CheckedTransformer(std::initializer_list> values, Args &&...args) + : CheckedTransformer(TransformPairs(values), std::forward(args)...) {} + + /// direct map of std::string to std::string + template explicit CheckedTransformer(T mapping) : CheckedTransformer(std::move(mapping), nullptr) {} + + /// This checks to see if an item is in a set: pointer or copy version. You can pass in a function that will filter + /// both sides of the comparison before computing the comparison. + template explicit CheckedTransformer(T mapping, F filter_function) { + + static_assert(detail::pair_adaptor::type>::value, + "mapping must produce value pairs"); + // Get the type of the contained item - requires a container have ::value_type + // if the type does not have first_type and second_type, these are both value_type + using element_t = typename detail::element_type::type; // Removes (smart) pointers if needed + using item_t = typename detail::pair_adaptor::first_type; // Is value_type if not a map + using local_item_t = typename IsMemberType::type; // Will convert bad types to good ones + // (const char * to std::string) + using iteration_type_t = typename detail::pair_adaptor::value_type; // the type of the object pair + + // Make a local copy of the filter function, using a std::function if not one already + std::function filter_fn = filter_function; + + auto tfunc = [mapping]() { + std::string out("value in "); + out += detail::generate_map(detail::smart_deref(mapping)) + " OR {"; + out += detail::join( + detail::smart_deref(mapping), + [](const iteration_type_t &v) { return detail::to_string(detail::pair_adaptor::second(v)); }, + ","); + out.push_back('}'); + return out; + }; + + desc_function_ = tfunc; + + func_ = [mapping, tfunc, filter_fn](std::string &input) { + using CLI::detail::lexical_cast; + local_item_t b; + bool converted = lexical_cast(input, b); + if(converted) { + if(filter_fn) { + b = filter_fn(b); + } + auto res = detail::search(mapping, b, filter_fn); + if(res.first) { + input = detail::value_string(detail::pair_adaptor::second(*res.second)); + return std::string{}; + } + } + for(const auto &v : detail::smart_deref(mapping)) { + auto output_string = detail::value_string(detail::pair_adaptor::second(v)); + if(output_string == input) { + return std::string(); + } + } + + return "Check " + input + " " + tfunc() + " FAILED"; + }; + } + + /// You can pass in as many filter functions as you like, they nest + template + CheckedTransformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other) + : CheckedTransformer( + std::forward(mapping), + [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); }, + other...) {} +}; + +/// Helper function to allow ignore_case to be passed to IsMember or Transform +inline std::string ignore_case(std::string item) { return detail::to_lower(item); } + +/// Helper function to allow ignore_underscore to be passed to IsMember or Transform +inline std::string ignore_underscore(std::string item) { return detail::remove_underscore(item); } + +/// Helper function to allow checks to ignore spaces to be passed to IsMember or Transform +inline std::string ignore_space(std::string item) { + item.erase(std::remove(std::begin(item), std::end(item), ' '), std::end(item)); + item.erase(std::remove(std::begin(item), std::end(item), '\t'), std::end(item)); + return item; +} + +/// Multiply a number by a factor using given mapping. +/// Can be used to write transforms for SIZE or DURATION inputs. +/// +/// Example: +/// With mapping = `{"b"->1, "kb"->1024, "mb"->1024*1024}` +/// one can recognize inputs like "100", "12kb", "100 MB", +/// that will be automatically transformed to 100, 14448, 104857600. +/// +/// Output number type matches the type in the provided mapping. +/// Therefore, if it is required to interpret real inputs like "0.42 s", +/// the mapping should be of a type or . +class AsNumberWithUnit : public Validator { + public: + /// Adjust AsNumberWithUnit behavior. + /// CASE_SENSITIVE/CASE_INSENSITIVE controls how units are matched. + /// UNIT_OPTIONAL/UNIT_REQUIRED throws ValidationError + /// if UNIT_REQUIRED is set and unit literal is not found. + enum Options : std::uint8_t { + CASE_SENSITIVE = 0, + CASE_INSENSITIVE = 1, + UNIT_OPTIONAL = 0, + UNIT_REQUIRED = 2, + DEFAULT = CASE_INSENSITIVE | UNIT_OPTIONAL + }; + + template + explicit AsNumberWithUnit(std::map mapping, + Options opts = DEFAULT, + const std::string &unit_name = "UNIT") { + description(generate_description(unit_name, opts)); + validate_mapping(mapping, opts); + + // transform function + func_ = [mapping, opts](std::string &input) -> std::string { + Number num{}; + + detail::rtrim(input); + if(input.empty()) { + throw ValidationError("Input is empty"); + } + + // Find split position between number and prefix + auto unit_begin = input.end(); + while(unit_begin > input.begin() && std::isalpha(*(unit_begin - 1), std::locale())) { + --unit_begin; + } + + std::string unit{unit_begin, input.end()}; + input.resize(static_cast(std::distance(input.begin(), unit_begin))); + detail::trim(input); + + if(opts & UNIT_REQUIRED && unit.empty()) { + throw ValidationError("Missing mandatory unit"); + } + if(opts & CASE_INSENSITIVE) { + unit = detail::to_lower(unit); + } + if(unit.empty()) { + using CLI::detail::lexical_cast; + if(!lexical_cast(input, num)) { + throw ValidationError(std::string("Value ") + input + " could not be converted to " + + detail::type_name()); + } + // No need to modify input if no unit passed + return {}; + } + + // find corresponding factor + auto it = mapping.find(unit); + if(it == mapping.end()) { + throw ValidationError(unit + + " unit not recognized. " + "Allowed values: " + + detail::generate_map(mapping, true)); + } + + if(!input.empty()) { + using CLI::detail::lexical_cast; + bool converted = lexical_cast(input, num); + if(!converted) { + throw ValidationError(std::string("Value ") + input + " could not be converted to " + + detail::type_name()); + } + // perform safe multiplication + bool ok = detail::checked_multiply(num, it->second); + if(!ok) { + throw ValidationError(detail::to_string(num) + " multiplied by " + unit + + " factor would cause number overflow. Use smaller value."); + } + } else { + num = static_cast(it->second); + } + + input = detail::to_string(num); + + return {}; + }; + } + + private: + /// Check that mapping contains valid units. + /// Update mapping for CASE_INSENSITIVE mode. + template static void validate_mapping(std::map &mapping, Options opts) { + for(auto &kv : mapping) { + if(kv.first.empty()) { + throw ValidationError("Unit must not be empty."); + } + if(!detail::isalpha(kv.first)) { + throw ValidationError("Unit must contain only letters."); + } + } + + // make all units lowercase if CASE_INSENSITIVE + if(opts & CASE_INSENSITIVE) { + std::map lower_mapping; + for(auto &kv : mapping) { + auto s = detail::to_lower(kv.first); + if(lower_mapping.count(s)) { + throw ValidationError(std::string("Several matching lowercase unit representations are found: ") + + s); + } + lower_mapping[detail::to_lower(kv.first)] = kv.second; + } + mapping = std::move(lower_mapping); + } + } + + /// Generate description like this: NUMBER [UNIT] + template static std::string generate_description(const std::string &name, Options opts) { + std::stringstream out; + out << detail::type_name() << ' '; + if(opts & UNIT_REQUIRED) { + out << name; + } else { + out << '[' << name << ']'; + } + return out.str(); + } +}; + +inline AsNumberWithUnit::Options operator|(const AsNumberWithUnit::Options &a, const AsNumberWithUnit::Options &b) { + return static_cast(static_cast(a) | static_cast(b)); +} + +/// Converts a human-readable size string (with unit literal) to uin64_t size. +/// Example: +/// "100" => 100 +/// "1 b" => 100 +/// "10Kb" => 10240 // you can configure this to be interpreted as kilobyte (*1000) or kibibyte (*1024) +/// "10 KB" => 10240 +/// "10 kb" => 10240 +/// "10 kib" => 10240 // *i, *ib are always interpreted as *bibyte (*1024) +/// "10kb" => 10240 +/// "2 MB" => 2097152 +/// "2 EiB" => 2^61 // Units up to exibyte are supported +class AsSizeValue : public AsNumberWithUnit { + public: + using result_t = std::uint64_t; + + /// If kb_is_1000 is true, + /// interpret 'kb', 'k' as 1000 and 'kib', 'ki' as 1024 + /// (same applies to higher order units as well). + /// Otherwise, interpret all literals as factors of 1024. + /// The first option is formally correct, but + /// the second interpretation is more wide-spread + /// (see https://en.wikipedia.org/wiki/Binary_prefix). + explicit AsSizeValue(bool kb_is_1000); + + private: + /// Get mapping + static std::map init_mapping(bool kb_is_1000); + + /// Cache calculated mapping + static std::map get_mapping(bool kb_is_1000); +}; + +#if defined(CLI11_ENABLE_EXTRA_VALIDATORS) && CLI11_ENABLE_EXTRA_VALIDATORS != 0 +// new extra validators +#if CLI11_HAS_FILESYSTEM +namespace detail { +enum class Permission : std::uint8_t { none = 0, read = 1, write = 2, exec = 4 }; +class PermissionValidator : public Validator { + public: + explicit PermissionValidator(Permission permission); +}; +} // namespace detail + +/// Check that the file exist and available for read +const detail::PermissionValidator ReadPermissions(detail::Permission::read); + +/// Check that the file exist and available for write +const detail::PermissionValidator WritePermissions(detail::Permission::write); + +/// Check that the file exist and available for write +const detail::PermissionValidator ExecPermissions(detail::Permission::exec); +#endif + +#endif + + + +namespace detail { + +CLI11_INLINE IPV4Validator::IPV4Validator() : Validator("IPV4") { + func_ = [](std::string &ip_addr) { + auto cdot = std::count(ip_addr.begin(), ip_addr.end(), '.'); + if(cdot != 3u) { + return std::string("Invalid IPV4 address: must have 3 separators"); + } + auto result = CLI::detail::split(ip_addr, '.'); + if(result.size() != 4) { + return std::string("Invalid IPV4 address: must have four parts (") + ip_addr + ')'; + } + int num = 0; + for(const auto &var : result) { + using CLI::detail::lexical_cast; + bool retval = lexical_cast(var, num); + if(!retval) { + return std::string("Failed parsing number (") + var + ')'; + } + if(num < 0 || num > 255) { + return std::string("Each IP number must be between 0 and 255 ") + var; + } + } + return std::string{}; + }; +} + +} // namespace detail + +CLI11_INLINE AsSizeValue::AsSizeValue(bool kb_is_1000) : AsNumberWithUnit(get_mapping(kb_is_1000)) { + if(kb_is_1000) { + description("SIZE [b, kb(=1000b), kib(=1024b), ...]"); + } else { + description("SIZE [b, kb(=1024b), ...]"); + } +} + +CLI11_INLINE std::map AsSizeValue::init_mapping(bool kb_is_1000) { + std::map m; + result_t k_factor = kb_is_1000 ? 1000 : 1024; + result_t ki_factor = 1024; + result_t k = 1; + result_t ki = 1; + m["b"] = 1; + for(std::string p : {"k", "m", "g", "t", "p", "e"}) { + k *= k_factor; + ki *= ki_factor; + m[p] = k; + m[p + "b"] = k; + m[p + "i"] = ki; + m[p + "ib"] = ki; + } + return m; +} + +CLI11_INLINE std::map AsSizeValue::get_mapping(bool kb_is_1000) { + if(kb_is_1000) { + static auto m = init_mapping(true); + return m; + } + static auto m = init_mapping(false); + return m; +} + +namespace detail {} // namespace detail +/// @} + +#if defined(CLI11_ENABLE_EXTRA_VALIDATORS) && CLI11_ENABLE_EXTRA_VALIDATORS != 0 +// new extra validators +namespace detail { + +#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0 +CLI11_INLINE PermissionValidator::PermissionValidator(Permission permission) { + std::filesystem::perms permission_code = std::filesystem::perms::none; + std::string permission_name; + switch(permission) { + case Permission::read: + permission_code = std::filesystem::perms::owner_read | std::filesystem::perms::group_read | + std::filesystem::perms::others_read; + permission_name = "read"; + break; + case Permission::write: + permission_code = std::filesystem::perms::owner_write | std::filesystem::perms::group_write | + std::filesystem::perms::others_write; + permission_name = "write"; + break; + case Permission::exec: + permission_code = std::filesystem::perms::owner_exec | std::filesystem::perms::group_exec | + std::filesystem::perms::others_exec; + permission_name = "exec"; + break; + case Permission::none: + default: + permission_code = std::filesystem::perms::none; + break; + } + func_ = [permission_code](std::string &path) { + std::error_code ec; + auto p = std::filesystem::path(path); + if(!std::filesystem::exists(p, ec)) { + return std::string("Path does not exist: ") + path; + } + if(ec) { + return std::string("Error checking path: ") + ec.message(); // LCOV_EXCL_LINE + } + if(permission_code == std::filesystem::perms::none) { + return std::string{}; + } + auto perms = std::filesystem::status(p, ec).permissions(); + if(ec) { + return std::string("Error checking path status: ") + ec.message(); // LCOV_EXCL_LINE + } + if((perms & permission_code) == std::filesystem::perms::none) { + return std::string("Path does not have required permissions: ") + path; + } + return std::string{}; + }; + description("Path with " + permission_name + " permission"); +} +#endif + +} // namespace detail +#endif + + + +class Option; +class App; + +/// This enum signifies the type of help requested +/// +/// This is passed in by App; all user classes must accept this as +/// the second argument. + +enum class AppFormatMode : std::uint8_t { + Normal, ///< The normal, detailed help + All, ///< A fully expanded help + Sub, ///< Used when printed as part of expanded subcommand +}; + +/// This is the minimum requirements to run a formatter. +/// +/// A user can subclass this is if they do not care at all +/// about the structure in CLI::Formatter. +class FormatterBase { + protected: + /// @name Options + ///@{ + + /// The width of the left column (options/flags/subcommands) + std::size_t column_width_{30}; + + /// The alignment ratio for long options within the left column + float long_option_alignment_ratio_{1 / 3.f}; + + /// The width of the right column (description of options/flags/subcommands) + std::size_t right_column_width_{65}; + + /// The width of the description paragraph at the top of help + std::size_t description_paragraph_width_{80}; + + /// The width of the footer paragraph + std::size_t footer_paragraph_width_{80}; + + /// options controlling formatting for footer and descriptions + bool enable_description_formatting_{true}; + bool enable_footer_formatting_{true}; + + /// @brief The required help printout labels (user changeable) + /// Values are Needs, Excludes, etc. + std::map labels_{}; + + ///@} + /// @name Basic + ///@{ + + public: + FormatterBase() = default; + FormatterBase(const FormatterBase &) = default; + FormatterBase(FormatterBase &&) = default; + FormatterBase &operator=(const FormatterBase &) = default; + FormatterBase &operator=(FormatterBase &&) = default; + + /// Adding a destructor in this form to work around bug in GCC 4.7 + virtual ~FormatterBase() noexcept {} // NOLINT(modernize-use-equals-default) + + /// This is the key method that puts together help + virtual std::string make_help(const App *, std::string, AppFormatMode) const = 0; + + ///@} + /// @name Setters + ///@{ + + /// Set the "REQUIRED" or other labels + void label(std::string key, std::string val) { labels_[key] = val; } + + /// Set the left column width (options/flags/subcommands) + void column_width(std::size_t val) { column_width_ = val; } + + /// Set the alignment ratio for long options within the left column + /// The ratio is in [0;1] range (e.g. 0.2 = 20% of column width, 6.f/column_width = 6th character) + void long_option_alignment_ratio(float ratio) { long_option_alignment_ratio_ = ratio; } + + /// Set the right column width (description of options/flags/subcommands) + void right_column_width(std::size_t val) { right_column_width_ = val; } + + /// Set the description paragraph width at the top of help + void description_paragraph_width(std::size_t val) { description_paragraph_width_ = val; } + + /// Set the footer paragraph width + void footer_paragraph_width(std::size_t val) { footer_paragraph_width_ = val; } + /// enable formatting for description paragraph + void enable_description_formatting(bool value = true) { enable_description_formatting_ = value; } + /// disable formatting for footer paragraph + void enable_footer_formatting(bool value = true) { enable_footer_formatting_ = value; } + ///@} + /// @name Getters + ///@{ + + /// Get the current value of a name (REQUIRED, etc.) + CLI11_NODISCARD std::string get_label(std::string key) const { + if(labels_.find(key) == labels_.end()) + return key; + return labels_.at(key); + } + + /// Get the current left column width (options/flags/subcommands) + CLI11_NODISCARD std::size_t get_column_width() const { return column_width_; } + + /// Get the current right column width (description of options/flags/subcommands) + CLI11_NODISCARD std::size_t get_right_column_width() const { return right_column_width_; } + + /// Get the current description paragraph width at the top of help + CLI11_NODISCARD std::size_t get_description_paragraph_width() const { return description_paragraph_width_; } + + /// Get the current footer paragraph width + CLI11_NODISCARD std::size_t get_footer_paragraph_width() const { return footer_paragraph_width_; } + + /// Get the current status of description paragraph formatting + CLI11_NODISCARD bool is_description_paragraph_formatting_enabled() const { return enable_description_formatting_; } + + /// Get the current status of whether footer paragraph formatting is enabled + CLI11_NODISCARD bool is_footer_paragraph_formatting_enabled() const { return enable_footer_formatting_; } + + ///@} +}; + +/// This is a specialty override for lambda functions +class FormatterLambda final : public FormatterBase { + using funct_t = std::function; + + /// The lambda to hold and run + funct_t lambda_; + + public: + /// Create a FormatterLambda with a lambda function + explicit FormatterLambda(funct_t funct) : lambda_(std::move(funct)) {} + + /// Adding a destructor (mostly to make GCC 4.7 happy) + ~FormatterLambda() noexcept override {} // NOLINT(modernize-use-equals-default) + + /// This will simply call the lambda function + std::string make_help(const App *app, std::string name, AppFormatMode mode) const override { + return lambda_(app, name, mode); + } +}; + +/// This is the default Formatter for CLI11. It pretty prints help output, and is broken into quite a few +/// overridable methods, to be highly customizable with minimal effort. +class Formatter : public FormatterBase { + public: + Formatter() = default; + Formatter(const Formatter &) = default; + Formatter(Formatter &&) = default; + Formatter &operator=(const Formatter &) = default; + Formatter &operator=(Formatter &&) = default; + + /// @name Overridables + ///@{ + + /// This prints out a group of options with title + /// + CLI11_NODISCARD virtual std::string + make_group(std::string group, bool is_positional, std::vector opts) const; + + /// This prints out just the positionals "group" + virtual std::string make_positionals(const App *app) const; + + /// This prints out all the groups of options + std::string make_groups(const App *app, AppFormatMode mode) const; + + /// This prints out all the subcommands + virtual std::string make_subcommands(const App *app, AppFormatMode mode) const; + + /// This prints out a subcommand + virtual std::string make_subcommand(const App *sub) const; + + /// This prints out a subcommand in help-all + virtual std::string make_expanded(const App *sub, AppFormatMode mode) const; + + /// This prints out all the groups of options + virtual std::string make_footer(const App *app) const; + + /// This displays the description line + virtual std::string make_description(const App *app) const; + + /// This displays the usage line + virtual std::string make_usage(const App *app, std::string name) const; + + /// This puts everything together + std::string make_help(const App *app, std::string, AppFormatMode mode) const override; + + ///@} + /// @name Options + ///@{ + + /// This prints out an option help line, either positional or optional form + virtual std::string make_option(const Option *, bool) const; + + /// @brief This is the name part of an option, Default: left column + virtual std::string make_option_name(const Option *, bool) const; + + /// @brief This is the options part of the name, Default: combined into left column + virtual std::string make_option_opts(const Option *) const; + + /// @brief This is the description. Default: Right column, on new line if left column too large + virtual std::string make_option_desc(const Option *) const; + + /// @brief This is used to print the name on the USAGE line + virtual std::string make_option_usage(const Option *opt) const; + + ///@} +}; + + + + +using results_t = std::vector; +/// callback function definition +using callback_t = std::function; + +class Option; +class App; +class ConfigBase; + +using Option_p = std::unique_ptr