diff --git a/.clang-format b/.clang-format index 4c2e4efaf..db1fb17b6 100644 --- a/.clang-format +++ b/.clang-format @@ -4,6 +4,9 @@ AlignAfterOpenBracket: BlockIndent AlignEscapedNewlines: Left AlignOperands: Align AlignTrailingComments: false +AllowShortBlocksOnASingleLine: Empty +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty AlwaysBreakBeforeMultilineStrings: true AlwaysBreakTemplateDeclarations: Yes BreakBeforeBinaryOperators: NonAssignment diff --git a/.github/disabled_workflows/codeql-analysis.yml b/.github/disabled_workflows/codeql-analysis.yml deleted file mode 100644 index 205aee82c..000000000 --- a/.github/disabled_workflows/codeql-analysis.yml +++ /dev/null @@ -1,73 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: ${{ github.event_name == 'pull_request' }} - -on: - push: - branches: [ main ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ main ] - schedule: - - cron: '20 20 * * 4' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-22.04 - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'cpp' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - # Learn more: - # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Install dependencies - run: | - sudo apt-get -qq update - sudo apt-get install -y \ - ninja-build libboost-all-dev \ - libfmt-dev libarchive-dev libgit2-dev libspdlog-dev - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - - name: Run CMake - run: cmake -B build -G Ninja -DPOAC_CLANG_TIDY=OFF - - - name: Build Poac - run: ninja - working-directory: build - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 diff --git a/.github/disabled_workflows/linux.yml b/.github/disabled_workflows/linux.yml deleted file mode 100644 index 01be200f2..000000000 --- a/.github/disabled_workflows/linux.yml +++ /dev/null @@ -1,135 +0,0 @@ -name: Linux - -on: - push: - branches: [ main ] - pull_request: - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: ${{ github.event_name == 'pull_request' }} - -permissions: - contents: read - -jobs: - build-and-test: - name: "build & test" - runs-on: ubuntu-22.04 - strategy: - fail-fast: false - matrix: - build_type: [ Debug, Release ] - coverage: [ off ] - compiler: - - cc: clang-12 - cxx: clang++-12 - subpackage: lld-12 - - cc: clang-13 - cxx: clang++-13 - subpackage: lld-13 - - cc: clang-14 - cxx: clang++-14 - subpackage: lld-14 - - cc: gcc-11 - cxx: g++-11 - - cc: gcc-12 - cxx: g++-12 - include: - - build_type: Debug - coverage: on - compiler: - cc: gcc-12 - cxx: g++-12 - subpackage: lcov - env: - CC: ${{ matrix.compiler.cc }} - CXX: ${{ matrix.compiler.cxx }} - steps: - - uses: actions/checkout@v3 - - - name: Setup GCC - if: startsWith(matrix.compiler.cc, 'gcc') - run: sudo apt-get install -y ${{ matrix.compiler.cxx }} - - - name: Setup Clang - if: startsWith(matrix.compiler.cc, 'clang') - run: sudo apt-get install -y ${{ matrix.compiler.cc }} - - - name: Install dependencies - run: | - sudo apt-get -qq update - sudo apt-get install -y \ - ${{ matrix.compiler.subpackage }} \ - ninja-build libboost-all-dev \ - libfmt-dev libarchive-dev libgit2-dev libspdlog-dev - - - name: Run CMake - run: | - cmake -B build -G Ninja \ - -DPOAC_CLANG_TIDY=OFF \ - -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \ - -DPOAC_ENABLE_COVERAGE=${{ matrix.coverage }} - - - name: Build Poac - run: ninja - working-directory: build - - - name: Test Poac - run: ctest --output-on-failure --verbose - working-directory: build - - - name: Uninstall optional software for some commands - run: sudo apt-get purge -y clang-format - - - name: Test Poac more - run: ctest --output-on-failure --verbose - working-directory: build - - - name: Print info of the executable file - run: file ./poac - working-directory: build - - - name: Print help - run: ./poac --help - working-directory: build - - - name: Test binary - # FIXME: memory leak on Ninja - # https://github.com/poac-dev/poac/runs/6859118992?check_suite_focus=true#step:16:21 - if: matrix.build_type == 'Release' - run: | - ./poac create hello_world - cd hello_world - ../poac run - working-directory: build - - - name: Install Conan - id: conan - uses: turtlebrowser/get-conan@main - with: - version: 1.59.0 - - - name: Test conan dependency - # FIXME: memory leak on Ninja - # https://github.com/poacpm/poac/runs/6859118992?check_suite_focus=true#step:16:21 - if: matrix.build_type == 'Release' - run: | - git clone https://github.com/wx257osn2/poac-conan-demo.git - cd poac-conan-demo - ../build/poac build - - - name: Print coverage - if: success() && matrix.coverage == 'on' - run: | - lcov --directory . --capture --output-file coverage.info --gcov-tool "${CC_PATH/gcc/gcov}" - lcov --remove coverage.info '/usr/*' "${HOME}"'/.cache/*' --output-file coverage.info - lcov --list coverage.info - env: - CC_PATH: /usr/bin/${{ env.CC }} - - - name: Upload coverage to Codecov - if: success() && matrix.coverage == 'on' - uses: codecov/codecov-action@v3 - with: - files: coverage.info diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 000000000..31d36a8fc --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,80 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: ["main"] + pull_request: + branches: ["main"] + schedule: + - cron: "27 11 * * 2" + +jobs: + analyze: + name: Analyze + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners + # Consider using larger runners for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: ["c-cpp"] + # CodeQL supports [ 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' ] + # Use only 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use only 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/cpp.yml b/.github/workflows/cpp.yml index 29e4152c4..f641d7cbb 100644 --- a/.github/workflows/cpp.yml +++ b/.github/workflows/cpp.yml @@ -2,32 +2,32 @@ name: C++ on: push: - branches: [ main ] + branches: [main] pull_request: permissions: contents: read jobs: -# clang-tidy: -# runs-on: ubuntu-22.04 -# steps: -# - uses: actions/checkout@v4 -# -# - name: Install dependencies -# run: | -# sudo apt-get -qq update -# sudo apt-get install -y \ -# clang-14 lld-14 \ -# ninja-build libboost-all-dev \ -# libfmt-dev libarchive-dev libgit2-dev libspdlog-dev -# -# - name: Run CMake -# run: cmake -B build -G Ninja -# -# - name: Run clang-tidy -# run: ninja -# working-directory: build + # clang-tidy: + # runs-on: ubuntu-22.04 + # steps: + # - uses: actions/checkout@v4 + # + # - name: Install dependencies + # run: | + # sudo apt-get -qq update + # sudo apt-get install -y \ + # clang-14 lld-14 \ + # ninja-build libboost-all-dev \ + # libfmt-dev libarchive-dev libgit2-dev libspdlog-dev + # + # - name: Run CMake + # run: cmake -B build -G Ninja + # + # - name: Run clang-tidy + # run: ninja + # working-directory: build format: runs-on: ubuntu-22.04 @@ -46,21 +46,21 @@ jobs: eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" poac fmt --check --verbose - lint: - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v4 + # lint: + # runs-on: ubuntu-22.04 + # steps: + # - uses: actions/checkout@v4 - - name: Install Poac - run: | - eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" - brew update - brew install poac + # - name: Install Poac + # run: | + # eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + # brew update + # brew install poac - - name: Install cpplint - run: pip install cpplint + # - name: Install cpplint + # run: pip install cpplint - - name: Run lint - run: | - eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" - poac lint --verbose + # - name: Run lint + # run: | + # eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + # poac lint --verbose diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml new file mode 100644 index 000000000..8c4b97ac4 --- /dev/null +++ b/.github/workflows/linux.yml @@ -0,0 +1,79 @@ +name: Linux + +on: + push: + branches: [main] + pull_request: + +env: + POAC_TERM_COLOR: always + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +permissions: + contents: read + +jobs: + build-and-test: + name: "build & test" + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + compiler: + - cxx: clang++ + ver: 15 + - cxx: clang++ + ver: 16 + - cxx: clang++ + ver: 17 + - cxx: g++ + ver: 11 + - cxx: g++ + ver: 12 + - cxx: g++ + ver: 13 + env: + CXX: ${{ matrix.compiler.cxx }}-${{ matrix.compiler.ver }} + steps: + - uses: actions/checkout@v3 + + - name: Setup Clang + if: startsWith(matrix.compiler.cxx, 'clang') + run: | + wget https://apt.llvm.org/llvm.sh + chmod +x ./llvm.sh + sudo ./llvm.sh ${{ matrix.compiler.ver }} + + - name: First Generation Build + run: make + + - name: Test the first generation + run: make test + + - name: Second Generation Build + run: ./build-out/poac build --verbose + + - name: Test the second generation + run: ./poac-out/debug/poac test --verbose + + - name: Third Generation Build & Test + run: ./poac-out/debug/poac --verbose run --release test --verbose + + - name: Create a new project with the third generation + run: ./poac-out/debug/poac new hello_world + + - name: Run the new project + run: ../poac-out/debug/poac --verbose run + working-directory: hello_world + + # - name: Print coverage + # if: success() && matrix.coverage == 'on' + # run: | + # lcov --directory . --capture --output-file coverage.info --gcov-tool "${CC_PATH/gcc/gcov}" + # lcov --remove coverage.info '/usr/*' "${HOME}"'/.cache/*' --output-file coverage.info + # lcov --list coverage.info + # env: + # CC_PATH: /usr/bin/${{ env.CC }} diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index fe61611a0..b80a3dfa7 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -2,9 +2,12 @@ name: macOS on: push: - branches: [ main ] + branches: [main] pull_request: +env: + POAC_TERM_COLOR: always + concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} @@ -15,69 +18,36 @@ permissions: jobs: build-and-test: name: "build & test" - runs-on: ${{ matrix.os }} + runs-on: macos-${{ matrix.osver }} strategy: fail-fast: false matrix: - os: [ macos-11, macos-12, macos-13 ] - build_type: [ Debug, Release ] + osver: [11, 12, 13] steps: - uses: actions/checkout@v4 - - name: Install dependencies - run: | - brew install \ - llvm \ - ninja openssl boost \ - fmt libarchive libgit2 spdlog - - - name: Run CMake - run: | - cmake -B build -G Ninja \ - -DPOAC_CLANG_TIDY=OFF \ - -DPOAC_BUILD_TESTING=OFF \ - -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} - env: # TODO: Make POAC_BUILD_TESTING=ON - CXX: /usr/local/opt/llvm/bin/clang++ - - - name: Build Poac - run: ninja - working-directory: build - - - name: Test Poac - run: ctest --output-on-failure --verbose - working-directory: build + - name: First Generation Build + run: make - - name: Install optional software for some commands - run: brew install clang-format + - name: Test the first generation + run: make test - - name: Test Poac more - run: ctest --output-on-failure --verbose - working-directory: build + - name: Second Generation Build + run: ./build-out/poac build --verbose - - name: Show linked libraries - run: otool -L ./poac - working-directory: build + - name: Test the second generation + run: ./poac-out/debug/poac test --verbose - - name: Print help - run: ./poac --help - working-directory: build + - name: Third Generation Build & Test + run: ./poac-out/debug/poac --verbose run --release test --verbose - - name: Test binary - run: | - ./poac create hello_world - cd hello_world - ../poac run - working-directory: build + - name: Create a new project with the third generation + run: ./poac-out/debug/poac new hello_world - - name: Install Conan - id: conan - uses: turtlebrowser/get-conan@main - with: - version: 1.59.0 + - name: Run the new project + run: ../poac-out/debug/poac --verbose run + working-directory: hello_world - - name: Test conan dependency - run: | - git clone https://github.com/wx257osn2/poac-conan-demo.git - cd poac-conan-demo - ../build/poac build + # - name: Test Poac + # run: ctest --output-on-failure --verbose + # working-directory: build diff --git a/.gitignore b/.gitignore index 9965dc914..5250c30a0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ # CMake build/ +build-out/ # CLion .idea/ diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 0cea5b634..000000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,130 +0,0 @@ -# Reference: https://github.com/opencv/opencv/blob/e329c84d5e7cfa5965b5dbbe7aa94d377ede23cf/CMakeLists.txt#L9-L15 -# Disable in-source builds to prevent source tree corruption. -if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") - message(FATAL_ERROR " -FATAL: In-source builds are not allowed. - You should create a separate directory for build files. -") -endif () - -cmake_minimum_required(VERSION 3.26) -project(poac - VERSION 0.6.0 - LANGUAGES CXX -) -message(STATUS "CMake Version: ${CMAKE_VERSION}") -message(STATUS "Poac Version: ${CMAKE_PROJECT_VERSION}") -message(STATUS "Compiler Path: ${CMAKE_CXX_COMPILER}") - -# C++20 Modules -set(CMAKE_CXX_STANDARD 20) # turn on the dynamic depends for ninja -set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a") -set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1) -if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - # cf. https://gitlab.kitware.com/cmake/cmake/-/blob/master/.gitlab/ci/cxx_modules_rules_gcc.cmake?ref_type=heads - string(CONCAT CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE - " -E -x c++ " - " -MT -MD -MF " - " -fmodules-ts -fdep-file= -fdep-output= -fdep-format=trtbd" - " -o " - ) - set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FORMAT "gcc") - set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG - "-fmodules-ts -fmodule-mapper= -fdep-format=trtbd -x c++" - ) -endif() -if (APPLE) - # export CXX=/opt/homebrew/opt/llvm/bin/clang++ -endif () - -# Set the default build type to Debug -if (CMAKE_BUILD_TYPE STREQUAL "") - set(CMAKE_BUILD_TYPE "Debug") -endif () - -option(VERBOSE "Use verbose output" OFF) # -DVERBOSE=ON -option(CPM_USE_LOCAL_PACKAGES "Try to use local packages" ON) -option(POAC_BUILD_TESTING "Enable build tests" ON) - -include(CMakeDependentOption) -cmake_dependent_option( - POAC_CLANG_TIDY "Enable clang-tidy when Debug mode" ON - "CMAKE_BUILD_TYPE STREQUAL Debug" OFF -) -cmake_dependent_option( - POAC_ENABLE_COVERAGE "Enable coverage" OFF - "POAC_BUILD_TESTING" OFF -) - -# Option checks -if ((NOT POAC_BUILD_TESTING) AND POAC_ENABLE_COVERAGE) - message(FATAL_ERROR "POAC_ENABLE_COVERAGE cannot be enabled without POAC_BUILD_TESTING being on") -endif () - -set(CMAKE_VERBOSE_MAKEFILE ${VERBOSE}) -set(CMAKE_CXX_EXTENSIONS OFF) # without compiler extensions like gnu++11 -if (CPM_USE_LOCAL_PACKAGES) - set(CPM_SUPPORTED_LIBS LibArchive Libgit2 fmt spdlog) - message(STATUS "CPM_USE_LOCAL_PACKAGES is ON; `${CPM_SUPPORTED_LIBS}` on local will be used if found.") -endif () - -include(src/Mod.cmake) - -add_executable(poac src/main.cc) -target_compile_features(poac PUBLIC cxx_std_20) -target_link_libraries(poac PRIVATE - # Direct dependencies - - poac_cmd - poac_util_result_macros - poac_util_result - poac_util_levDistance - - structopt::structopt - termcolor2_literals_extra - mitama-cpp-result::mitama-cpp-result - toml11::toml11 -) - -include(cmake/PoacConfig.cmake) -target_link_libraries(poac PRIVATE ${STATIC_LINK_FLAG}) - -include(cmake/Helpers.cmake) -include(cmake/PoacDependencies.cmake) -if (NOT APPLE AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - list(APPEND POAC_DEPENDENCIES "-lstdc++fs") -endif () -target_link_libraries(poac PRIVATE - # Indirect dependencies - # TODO: should be derived from other deps? - - ${LIBGIT2_LIBRARY} - ${NINJA_LIBRARIES} -) - -set(CONFIG_VERSION_FILE ${CMAKE_CURRENT_BINARY_DIR}/poac-config-version.cmake) -include(CMakePackageConfigHelpers) -write_basic_package_version_file( - ${CONFIG_VERSION_FILE} COMPATIBILITY AnyNewerVersion -) - -include(GNUInstallDirs) -install(TARGETS poac - EXPORT poac-config -) -install(EXPORT poac-config - DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/poac - NAMESPACE poac:: -) -install(FILES ${CONFIG_VERSION_FILE} - DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/poac -) -install(TARGETS poac - DESTINATION bin -) - -include(CTest) -if (POAC_BUILD_TESTING AND ${CMAKE_SOURCE_DIR} STREQUAL ${PROJECT_SOURCE_DIR}) - enable_testing() - add_subdirectory(tests) -endif () diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..bce6789ed --- /dev/null +++ b/Makefile @@ -0,0 +1,132 @@ +# Compiler settings +CXX ?= clang++ +DEBUG_FLAGS = -g -O0 -DDEBUG +RELEASE_FLAGS = -O3 -DNDEBUG +CFLAGS = -Wall -Wextra -fdiagnostics-color -pedantic-errors -std=c++20 +ifeq ($(RELEASE), 1) + CFLAGS += $(RELEASE_FLAGS) +else + CFLAGS += $(DEBUG_FLAGS) +endif + +OUT_DIR = build-out +PROJ_NAME = $(OUT_DIR)/poac + + +.PHONY: all clean test + +all: $(OUT_DIR) $(OUT_DIR)/Cmd $(PROJ_NAME) + +clean: + rm -rf $(OUT_DIR) + +$(OUT_DIR)/DEPS/toml11: $(OUT_DIR)/DEPS + git clone https://github.com/ToruNiina/toml11.git $@ + git -C $@ reset --hard 846abd9a49082fe51440aa07005c360f13a67bbf + +$(OUT_DIR)/DEPS: + mkdir -p $@ + +$(OUT_DIR): + mkdir -p $@ + +$(OUT_DIR)/Cmd: + mkdir -p $@ + +$(PROJ_NAME): $(OUT_DIR)/Cmd/Help.o $(OUT_DIR)/Algos.o $(OUT_DIR)/Cmd/Build.o \ + $(OUT_DIR)/Cmd/Test.o $(OUT_DIR)/Cmd/Run.o $(OUT_DIR)/Cmd/New.o \ + $(OUT_DIR)/Cmd/Clean.o $(OUT_DIR)/Cmd/Init.o $(OUT_DIR)/Cmd/Version.o \ + $(OUT_DIR)/Cmd/Fmt.o $(OUT_DIR)/Cmd/Lint.o $(OUT_DIR)/BuildConfig.o \ + $(OUT_DIR)/Manifest.o $(OUT_DIR)/Logger.o $(OUT_DIR)/TermColor.o \ + $(OUT_DIR)/Cmd/Global.o $(OUT_DIR)/main.o + $(CXX) $(CFLAGS) $^ -o $@ + +$(OUT_DIR)/Algos.o: src/Algos.cc src/Algos.hpp + $(CXX) $(CFLAGS) -c $< -o $@ + +$(OUT_DIR)/TermColor.o: src/TermColor.cc src/TermColor.hpp + $(CXX) $(CFLAGS) -c $< -o $@ + +$(OUT_DIR)/Logger.o: src/Logger.cc src/Logger.hpp + $(CXX) $(CFLAGS) -c $< -o $@ + +$(OUT_DIR)/Cmd/Help.o: src/Cmd/Help.cc src/Cmd/Help.hpp src/Rustify.hpp \ + src/Algos.hpp src/Logger.hpp src/TermColor.hpp + $(CXX) $(CFLAGS) -c $< -o $@ + +$(OUT_DIR)/Cmd/Build.o: src/Cmd/Build.cc src/Cmd/Build.hpp src/Rustify.hpp \ + src/Algos.hpp src/Logger.hpp src/TermColor.hpp + $(CXX) $(CFLAGS) -c $< -o $@ + +$(OUT_DIR)/Cmd/Test.o: src/Cmd/Test.cc src/Cmd/Test.hpp src/Rustify.hpp \ + src/Algos.hpp src/Logger.hpp src/TermColor.hpp + $(CXX) $(CFLAGS) -c $< -o $@ + +$(OUT_DIR)/Cmd/Fmt.o: src/Cmd/Fmt.cc src/Cmd/Fmt.hpp src/Rustify.hpp \ + src/Algos.hpp src/Logger.hpp src/TermColor.hpp + $(CXX) $(CFLAGS) -c $< -o $@ + +$(OUT_DIR)/Cmd/Run.o: src/Cmd/Run.cc src/Cmd/Run.hpp src/Rustify.hpp \ + src/Algos.hpp src/Logger.hpp src/TermColor.hpp + $(CXX) $(CFLAGS) -c $< -o $@ + +$(OUT_DIR)/Cmd/New.o: src/Cmd/New.cc src/Cmd/New.hpp src/Rustify.hpp \ + src/Algos.hpp src/Logger.hpp src/TermColor.hpp + $(CXX) $(CFLAGS) -c $< -o $@ + +$(OUT_DIR)/Cmd/Clean.o: src/Cmd/Clean.cc src/Cmd/Clean.hpp src/Rustify.hpp \ + src/Algos.hpp src/Logger.hpp src/TermColor.hpp + $(CXX) $(CFLAGS) -c $< -o $@ + +$(OUT_DIR)/Cmd/Init.o: src/Cmd/Init.cc src/Cmd/Init.hpp src/Rustify.hpp \ + src/Algos.hpp src/Logger.hpp src/TermColor.hpp + $(CXX) $(CFLAGS) -c $< -o $@ + +$(OUT_DIR)/Cmd/Lint.o: src/Cmd/Lint.cc src/Cmd/Lint.hpp src/Rustify.hpp \ + src/Algos.hpp src/Logger.hpp src/TermColor.hpp + $(CXX) $(CFLAGS) -c $< -o $@ + +$(OUT_DIR)/Cmd/Version.o: src/Cmd/Version.cc src/Cmd/Version.hpp \ + src/Rustify.hpp src/Algos.hpp src/Logger.hpp src/TermColor.hpp + $(CXX) $(CFLAGS) -c $< -o $@ + +$(OUT_DIR)/Cmd/Global.o: src/Cmd/Global.cc src/Cmd/Global.hpp src/Rustify.hpp \ + src/Algos.hpp src/Logger.hpp src/TermColor.hpp + $(CXX) $(CFLAGS) -c $< -o $@ + +$(OUT_DIR)/BuildConfig.o: src/BuildConfig.cc src/BuildConfig.hpp + $(CXX) $(CFLAGS) -c $< -o $@ + +$(OUT_DIR)/Manifest.o: src/Manifest.cc src/Manifest.hpp $(OUT_DIR)/DEPS/toml11 + $(CXX) $(CFLAGS) -c $< -o $@ -I$(OUT_DIR)/DEPS/toml11 + +$(OUT_DIR)/main.o: src/main.cc src/Cmd/Build.hpp src/Cmd/Test.hpp \ + src/Cmd/Run.hpp src/Cmd/New.hpp src/Cmd/Clean.hpp src/Cmd/Init.hpp \ + src/Cmd/Version.hpp src/Rustify.hpp src/Algos.hpp src/Logger.hpp \ + src/TermColor.hpp src/Cmd/Global.hpp + $(CXX) $(CFLAGS) -c $< -o $@ + + +test: $(OUT_DIR)/tests $(OUT_DIR)/tests/test_BuildConfig \ + $(OUT_DIR)/tests/test_Algos + $(OUT_DIR)/tests/test_BuildConfig + $(OUT_DIR)/tests/test_Algos + +$(OUT_DIR)/tests: + mkdir -p $@ + +$(OUT_DIR)/tests/test_BuildConfig: $(OUT_DIR)/tests/test_BuildConfig.o \ + $(OUT_DIR)/Logger.o $(OUT_DIR)/TermColor.o $(OUT_DIR)/Manifest.o + $(CXX) $(CFLAGS) $^ -o $@ + +$(OUT_DIR)/tests/test_BuildConfig.o: src/BuildConfig.cc src/BuildConfig.hpp \ + src/Rustify.hpp src/Algos.hpp src/Logger.hpp src/TermColor.hpp + $(CXX) $(CFLAGS) -DPOAC_TEST -c $< -o $@ + +$(OUT_DIR)/tests/test_Algos: $(OUT_DIR)/tests/test_Algos.o $(OUT_DIR)/Logger.o \ + $(OUT_DIR)/TermColor.o + $(CXX) $(CFLAGS) $^ -o $@ + +$(OUT_DIR)/tests/test_Algos.o: src/Algos.cc src/Algos.hpp src/Logger.hpp \ + src/TermColor.hpp + $(CXX) $(CFLAGS) -DPOAC_TEST -c $< -o $@ diff --git a/README.md b/README.md index 140ac318b..83cd251b9 100644 --- a/README.md +++ b/README.md @@ -27,14 +27,14 @@ Please visit [poac.dev](https://poac.dev) and [The Poac Book](https://doc.poac.d By using Poac, you can create a C++ project, build sources, and execute an application: -![demo](https://user-images.githubusercontent.com/26405363/169694620-2e3f769e-c6c5-4e6a-a645-e5bae226a8cb.gif) +![demo](https://github.com/poac-dev/poac/assets/26405363/4486b424-e5a1-435e-a83e-fcd939bdaef0) ## Hello World You can get started with just a few commands as the demo shows. Let's create a new Poac project as follows: ```console -you:~$ poac create hello_world +you:~$ poac new hello_world Created binary (application) `hello_world` package ``` @@ -43,16 +43,17 @@ Then, you can use the `poac run` command to run your application: ```console you:~$ cd hello_world you:~/hello_world$ poac run - Compiling 1/1: hello_world v0.1.0 (/Users/you/hello_world) - Finished debug target(s) in 0.90s - Running `/Users/you/hello_world/poac-out/debug/hello_world` + Compiling src/main.cc + Linking hello_world + Finished debug target(s) in 0.45386s + Running poac-out/debug/hello_world Hello, world! ``` ## Supported Operating Systems -| Linux | macOS | -|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| +| Linux | macOS | +| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | [![GitHub Actions Linux Build](https://github.com/poac-dev/poac/workflows/Linux/badge.svg?branch=main)](https://github.com/poac-dev/poac/actions?query=workflow%3A%22Linux%22) | [![GitHub Actions macOS Build](https://github.com/poac-dev/poac/workflows/macOS/badge.svg?branch=main)](https://github.com/poac-dev/poac/actions?query=workflow%3A%22macOS%22) | ## Installation @@ -83,105 +84,52 @@ If your environment is not included in the released packages, you have to constr #### compilers -* Compilers which support [C++20](https://en.cppreference.com/w/cpp/20) and modules - - * `Clang`: `16` or later - +* Compilers which support [C++ 20](https://en.cppreference.com/w/cpp/20) + * `GCC`: `11` or later + * `Clang`: `15` or later + * `Apple Clang`: provided by `macOS Big Sur (11)` or later #### tools -* [`CMake`](https://gitlab.kitware.com/cmake/cmake): [`3.26`](https://cmake.org/cmake/help/latest/release/3.26.html) or later -* [`Ninja`](https://github.com/ninja-build/ninja): [`1.11`](https://github.com/ninja-build/ninja/releases/tag/v1.11.0) or later +* `Make` #### libraries -* [`boost`](https://github.com/boostorg): [`1.70.0`](https://github.com/boostorg/boost/releases/tag/boost-1.70.0) or later - * algorithm - * asio - * beast - * container_hash - * dynamic_bitset - * graph - * predef - * preprocessor - * property_tree - * range - * regex - * scope_exit - * uuid -* [`openssl`](https://github.com/openssl/openssl): [`3.0.0`](https://github.com/openssl/openssl/releases/tag/openssl-3.0.0) or later - * some `SHA256` functions are marked as [deprecated](https://github.com/openssl/openssl/blob/openssl-3.0.0/include/openssl/sha.h#L57-L79) since `3.0.0` - -
- - -> When configuring with CMake, the following libraries will be installed automatically. Therefore, there is usually no need to be concerned about them. (click here to view additional dependencies.) - +When running Make, the following libraries will be installed automatically. There is usually no need to be concerned about these. ---- - -**dependencies** - -* [`fmt`](https://github.com/fmtlib/fmt): [`9.0.0`](https://github.com/fmtlib/fmt/releases/tag/9.0.0) or later -* [`git2-cpp`](https://github.com/ken-matsui/git2-cpp): [`0.1.1`](https://github.com/ken-matsui/git2-cpp/releases/tag/0.1.1) or later -* [`glob`](https://github.com/p-ranav/glob): [`v0.0.1`](https://github.com/p-ranav/glob/releases/tag/v0.0.1) or later -* [`libarchive`](https://github.com/libarchive/libarchive): [`v3.6.1`](https://github.com/libarchive/libarchive/tree/master) or later - * requires [this commit](https://github.com/libarchive/libarchive/commit/a4c3c90bb828ab5f01589718266ac5d3fdccb854) -* [`libgit2`](https://github.com/libgit2/libgit2): [`v1.4.3`](https://github.com/libgit2/libgit2/releases/tag/v1.4.3) or later - * requires security updates -* [`mitama-cpp-result`](https://github.com/LoliGothick/mitama-cpp-result): [`v9.3.0`](https://github.com/LoliGothick/mitama-cpp-result/releases/tag/v9.3.0) or later - * requires [this commit](https://github.com/LoliGothick/mitama-cpp-result/commit/ec7f22ae921f750b0115681623d0c06223737819) -* [`ninja`](https://github.com/ninja-build/ninja): [`57b8fee`](https://github.com/ninja-build/ninja/commit/57b8fee639a4290176086f3839c78bfc0d02c42b) or later - * requires [this commit](https://github.com/ninja-build/ninja/commit/57b8fee639a4290176086f3839c78bfc0d02c42b) - * [`v1.11.1`](https://github.com/ninja-build/ninja/releases/tag/v1.11.1) does not include the commit -* [`spdlog`](https://github.com/gabime/spdlog): [`1.9.0`](https://github.com/gabime/spdlog/releases/tag/v1.9.0) or later -* [`structopt`](https://github.com/p-ranav/structopt): [`b1e1e16`](https://github.com/p-ranav/structopt/commit/b1e1e16867a5cf282664d392a18680cb5e3f6041) or later - * requires [this commit](https://github.com/p-ranav/structopt/commit/b1e1e16867a5cf282664d392a18680cb5e3f6041) - * awaiting the next release above [`v0.1.3`](https://github.com/p-ranav/structopt/releases/tag/v0.1.3) * [`toml11`](https://github.com/ToruNiina/toml11): [`9086b11`](https://github.com/ToruNiina/toml11/commit/9086b1114f39a8fb10d08ca704771c2f9f247d02) or later * requires [this commit](https://github.com/ToruNiina/toml11/commit/9086b1114f39a8fb10d08ca704771c2f9f247d02) * awaiting the next release above [`v3.7.1`](https://github.com/ToruNiina/toml11/releases/tag/v3.7.1) -**dev-dependencies** - -* [`μt`](https://github.com/boost-ext/ut): [`v1.1.9`](https://github.com/boost-ext/ut/releases/tag/v1.1.9) or later - ---- - -
- Once you have all the necessary requirements in place, you can proceed to build Poac by executing the following commands: ```bash git clone https://github.com/poac-dev/poac.git cd poac -cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DPOAC_BUILD_TESTING=OFF -cd build -ninja -ninja install +make ``` -Poac attempts to utilize locally installed dependencies by default. To bypass the use of local packages, you can specify `-DCPM_USE_LOCAL_PACKAGES=OFF` as an option for the `cmake` command. +Poac attempts to utilize locally installed dependencies by default. To bypass the use of local packages, you can download the required dependencies in `build-out/DEPS`. ## Usage ### Start a new project with Poac -The `poac create` command lets you start a new Poac project: +The `poac new` command lets you start a new Poac project: ```console -you:~$ poac create hello_world +you:~$ poac new hello_world Created binary (application) `hello_world` package ``` > [!TIP] > If you want to integrate your existing project with Poac, use the `init` command: -> +> > ```console > you:~/your-pj$ poac init > Created binary (application) `your-pj` package > ``` -> +> > This command just creates a `poac.toml` file not to break your project. ### Build the project @@ -190,148 +138,90 @@ In most cases, you will want to execute a binary as well as build the project— ```console you:~/hello_world$ poac run - Compiling 1/1: hello_world v0.1.0 (/Users/you/hello_world) - Finished debug target(s) in 0.90s - Running `/Users/you/hello_world/poac-out/debug/hello_world` + Compiling src/main.cc + Linking hello_world + Finished debug target(s) in 0.45386s + Running poac-out/debug/hello_world Hello, world! ``` -Should you just build it, run the `build` command: +If you just want to build it, run the `build` command: ```console you:~/hello_world$ poac build - Finished debug target(s) in 0.21s + Finished debug target(s) in 0.00866317s ``` Poac uses a cache since we executed the command with no changes. ### Install dependencies -Like Cargo for Rust does, Poac installs dependencies at build time. -However, Poac does not support [weired version specifiers](https://stackoverflow.com/q/22343224), such as `~` and `^`. -You can specify dependencies like: - -`poac.toml` - -```toml -[dependencies] -"boost/bind" = ">=1.64.0 and <2.0.0" -``` - -We regularly avoid auto updating packages to major versions which bring breaking changes, but minor and patch are acceptable. - -> [!TIP] -> If you would use a specific version, you can write the version like the following: -> -> ```toml -> [dependencies] -> "boost/bind" = "1.66.0" -> ``` - -#### Conan V1 Registry - -Poac also supports Conan V1 Registry. To use it: +Like Cargo for Rust does, Poac installs dependencies at build time. Poac currently only supports Git dependencies. You can specify dependencies like: `poac.toml` ```toml [dependencies] -fmt = { version = "9.1.0", registry = "conan-v1" } -spdlog = { version = "1.10.0", registry = "conan-v1" } -leveldb = { version = "1.23", registry = "conan-v1" } +"ToruNiina/toml11" = {git = "https://github.com/ToruNiina/toml11.git", rev = "846abd9a49082fe51440aa07005c360f13a67bbf"} ``` -*The demo is publised on [wx257osn2/poac-conan-demo](https://github.com/wx257osn2/poac-conan-demo)* - After editing `poac.toml`, executing the `build` command will install the package and its dependencies. ```console you:~/hello_world$ poac build - Resolving dependencies ... - Downloading packages ... - Downloaded boost/bind v1.66.0 - Downloaded boost/core v1.66.0 - Downloaded boost/assert v1.66.0 - Downloaded boost/config v1.66.0 - Compiling 1/1: hello_world v0.1.0 (/Users/you/hello_world) - Finished debug target(s) in 0.70s +Downloaded ToruNiina/toml11 846abd9a49082fe51440aa07005c360f13a67bbf + Compiling src/main.cc + Linking hello_world + Finished debug target(s) in 0.70s ``` -To use this dependency, update the `main.cpp` file. +> [!WARNING] +> Poac currently supports building a project with header-only dependencies. +> Building with build-required dependencies will be soon supported. -`src/main.cpp` +### Run tests -```cpp -#include -#include +You can write tests in any source files in the `src` directory. Create files like: -int f(int a, int b) { - return a + b; -} +`src/Lib.hpp` -int main(int argc, char** argv) { - std::cout << boost::bind(f, 5, _1)(10) << std::endl; -} -``` +```cpp +#ifndef HELLO_WORLD_LIB_HPP +#define HELLO_WORLD_LIB_HPP -You can now run this source code: +int add(int, int); -```console -you:~/hello_world$ poac run - Compiling 1/1: hello_world v0.1.0 (/Users/you/hello_world) - Finished debug target(s) in 0.50s - Running `/Users/you/hello_world/poac-out/debug/hello_world` -15 +#endif // HELLO_WORLD_LIB_HPP ``` -> [!WARNING] -> We currently support building a project with header-only dependencies. -> Building with build-required dependencies will be soon supported. - -### Create a dependency graph +`src/Lib.cc` -You can create a dependency graph by using the `graph` command: - -```console -you:~/hello_world$ poac graph -o out.png - Generated out.png -``` +```cpp +#include "Lib.hpp" -![Dependency Graph](https://user-images.githubusercontent.com/26405363/173274015-9fd4869d-94cf-4667-b07f-8e9fd94a02a6.png) +int add(int a, int b) { + return a + b; +} -Or you can export the graph as a `.dot` file: +#ifdef POAC_TEST -```console -you:~/hello_world$ poac graph -o out.dot - Generated out.dot -``` +# include -```dot -digraph G { -0[label="boost/bind: 1.66.0"]; -1[label="boost/config: 1.66.0"]; -2[label="boost/core: 1.66.0"]; -3[label="boost/assert: 1.66.0"]; -0->2 ; -0->1 ; -2->3 ; -2->1 ; -3->1 ; +int main() { + assert(add(1, 2) == 3); } -``` -> [!NOTE] -> When you want to export the graph as a `.png` file, please ensure `graphviz` is installed. +#endif +``` -If you omit specifying the output path, then Poac emits the graph to standard output: +Now, with the `test` command, you can run tests defined within `POAC_TEST`: ```console -you:~/hello_world$ poac graph -boost/bind -> boost/core -boost/bind -> boost/config -boost/core -> boost/assert -boost/core -> boost/config -boost/assert -> boost/config +you:~/hello_world$ poac test + Compiling src/Lib.cc + Linking tests/test_Lib + Testing Lib + Finished debug test(s) in 0.565934s ``` ### Run linter @@ -341,12 +231,11 @@ Poac supports linting it by a simple command with `cpplint`: ```console you:~/hello_world$ poac lint - Linting hello_world -src/main.cpp:0: No copyright message found. You should have a line: "Copyright [year] " [legal/copyright] [5] -Done processing src/main.cpp + Linting hello_world +src/main.cc:0: No copyright message found. You should have a line: "Copyright [year] " [legal/copyright] [5] +Done processing src/main.cc Total errors found: 1 - -Error: `cpplint` completed with exit code 1 +Error: `cpplint` exited with status 1 ``` > [!TIP] @@ -383,33 +272,6 @@ you:~/hello_world$ poac fmt To customize the format settings, try creating a [`.clang-format`](/.clang-format) file to the repository root. -### Search packages - -In case you would find what packages are provided, you can use the `search` command or visit [poac.dev](https://poac.dev). - -```console -$ poac search func -boost/function = "1.66.0" # Boost.org function module -boost/function_types = "1.66.0" # Boost.org function_types module -boost/functional = "1.66.0" # Boost.org functional module -``` - -### Publish packages - -WIP - -## Roadmap - -| Feature | Status | -|:---------------------------------------------------:|:------------------:| -| Install dependencies | :white_check_mark: | -| Build a project with header-only dependencies | :white_check_mark: | -| Support dev-dependencies | :white_check_mark: | -| Build a project including separated headers & impls | | -| Publish packages | WIP | -| Build a project with build-required dependencies | | -| Build a project with CMake | | - ## Why Poac? C++ is often considered a complex language and unconsciously avoided by many. The absence of a definitive package manager and the unfamiliar syntax of build systems like [CMake](https://cmake.org) make it seem difficult to set up a C++ environment, leaving people hesitant. @@ -435,14 +297,14 @@ https://dev.poac.dev ### Before submitting your PR Please make sure to follow these steps: -> [!IMPORTANT] -> I expect you to use the latest `clang-tidy` and `clang-format`. + -#### Run linter (`cpplint`) + #### Run formatter (`clang-format`) @@ -450,12 +312,12 @@ poac lint poac fmt ``` -#### Build with `clang-tidy` + --- @@ -473,19 +335,7 @@ Please see [LICENSE](LICENSE) for details. ### Third-party software -* boost - -* fmt - -* git2-cpp - -* glob - -* libarchive - -* libgit2 - -* mitama-cpp-result - -* ninja - -* openssl - -* spdlog - -* structopt - * toml11 - -* μt - [^1]: Amemiya, T., & Mizutani, S. (2006). On the Basic Affective Dimensions of Japanese Onomatopoeia and the Basic Level of Japanese Phonesthemes. 関西大学社会学部紀要, 37(2), 139–166. https://hdl.handle.net/10112/12311 diff --git a/cmake/AddBoost.cmake b/cmake/AddBoost.cmake deleted file mode 100644 index 08de1bb58..000000000 --- a/cmake/AddBoost.cmake +++ /dev/null @@ -1,49 +0,0 @@ -include_guard(GLOBAL) - -message(CHECK_START "Adding Boost") -list(APPEND CMAKE_MESSAGE_INDENT " ") - -set(Boost_DEBUG ${VERBOSE}) -if (DEFINED BOOST_ROOT) - set(BOOST_LIBRARYDIR "${BOOST_ROOT}/lib") -endif() - -find_package(Boost 1.70.0 REQUIRED COMPONENTS system regex) -if (Boost_FOUND) - message(CHECK_PASS "added") - message(STATUS "Boost include directories are ... ${Boost_INCLUDE_DIRS}") - message(STATUS "Boost library directories are ... ${Boost_LIBRARY_DIRS}") - message(STATUS "Boost libraries are ... ${Boost_LIBRARIES}") - - # TODO: Move this to the root CMakeLists.txt - target_include_directories(poac_util_rustify PRIVATE ${Boost_INCLUDE_DIRS}) - target_include_directories(poac_util_cfg PRIVATE ${Boost_INCLUDE_DIRS}) - target_include_directories(poac_util_misc PRIVATE ${Boost_INCLUDE_DIRS}) - target_include_directories(poac_util_pretty PRIVATE ${Boost_INCLUDE_DIRS}) - target_include_directories(poac_util_meta PRIVATE ${Boost_INCLUDE_DIRS}) - target_include_directories(poac_util_archive PRIVATE ${Boost_INCLUDE_DIRS}) - target_include_directories(poac_util_registry_conan_v1_manifest PRIVATE ${Boost_INCLUDE_DIRS}) - target_include_directories(poac_core_resolver_sat PRIVATE ${Boost_INCLUDE_DIRS}) - target_include_directories(poac_core_resolver_registry PRIVATE ${Boost_INCLUDE_DIRS}) - target_include_directories(poac_cmd_lint PRIVATE ${Boost_INCLUDE_DIRS}) - target_include_directories(poac_util_net PRIVATE ${Boost_INCLUDE_DIRS}) - target_include_directories(poac_util_registry_conan_v1_resolver PRIVATE ${Boost_INCLUDE_DIRS}) - target_include_directories(poac_core_resolver PRIVATE ${Boost_INCLUDE_DIRS}) - target_include_directories(poac_core_builder_syntax PRIVATE ${Boost_INCLUDE_DIRS}) - target_include_directories(poac_core_builder_manifest PRIVATE ${Boost_INCLUDE_DIRS}) - target_include_directories(poac_core_builder_build PRIVATE ${Boost_INCLUDE_DIRS}) - target_include_directories(poac_core_resolver_types PRIVATE ${Boost_INCLUDE_DIRS}) -# target_include_directories(poac_cmd_graph PRIVATE ${Boost_INCLUDE_DIRS}) - target_include_directories(poac_cmd_search PRIVATE ${Boost_INCLUDE_DIRS}) - # mitama-cpp-result depends on Boost internally - target_include_directories(poac_util_result_macros INTERFACE ${Boost_INCLUDE_DIRS}) - - target_include_directories(poac PRIVATE ${Boost_INCLUDE_DIRS}) - target_link_directories(poac PRIVATE ${Boost_LIBRARY_DIRS}) - list(APPEND POAC_DEPENDENCIES ${Boost_LIBRARIES}) -else () - message(CHECK_FAIL "not found") - list(APPEND missingDependencies boost) -endif () - -list(POP_BACK CMAKE_MESSAGE_INDENT) diff --git a/cmake/AddBoostUt.cmake b/cmake/AddBoostUt.cmake deleted file mode 100644 index 286e25827..000000000 --- a/cmake/AddBoostUt.cmake +++ /dev/null @@ -1,17 +0,0 @@ -include_guard(GLOBAL) - -message(CHECK_START "Adding Boost::ut") -list(APPEND CMAKE_MESSAGE_INDENT " ") - -FetchContent_Declare( - ut - GIT_REPOSITORY https://github.com/boost-ext/ut - GIT_TAG v1.1.9 -) - -FetchContent_MakeAvailable(ut) - -list(APPEND POAC_TEST_DEPENDENCIES Boost::ut) -message(CHECK_PASS "added") - -list(POP_BACK CMAKE_MESSAGE_INDENT) diff --git a/cmake/AddFmt.cmake b/cmake/AddFmt.cmake deleted file mode 100644 index a0e3a1032..000000000 --- a/cmake/AddFmt.cmake +++ /dev/null @@ -1,34 +0,0 @@ -include_guard(GLOBAL) - -message(CHECK_START "Adding fmt") -list(APPEND CMAKE_MESSAGE_INDENT " ") - -include(cmake/CPM.cmake) - -if (CMAKE_BUILD_TYPE STREQUAL Release) # -DCMAKE_BUILD_TYPE=Release - set(BUILD_SHARED_LIBS OFF) -else () - set(BUILD_SHARED_LIBS ON) -endif () -CPMAddPackage( - NAME fmt - VERSION 9.0.0 # minimum required version - GITHUB_REPOSITORY fmtlib/fmt - GIT_TAG 10.0.0 - OPTIONS - "BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS}" -) - -if (POAC_CLANG_TIDY AND fmt_ADDED) # If using downloaded package - # Disable clang-tidy - set_target_properties( - fmt - PROPERTIES - CXX_CLANG_TIDY "" - ) -endif () - -list(APPEND POAC_gDEPENDENCIES fmt::fmt) -message(CHECK_PASS "added") - -list(POP_BACK CMAKE_MESSAGE_INDENT) diff --git a/cmake/AddGit2Cpp.cmake b/cmake/AddGit2Cpp.cmake deleted file mode 100644 index 78d7f3f76..000000000 --- a/cmake/AddGit2Cpp.cmake +++ /dev/null @@ -1,19 +0,0 @@ -include_guard(GLOBAL) - -message(CHECK_START "Adding git2-cpp") -list(APPEND CMAKE_MESSAGE_INDENT " ") - -FetchContent_Declare( - git2-cpp - GIT_REPOSITORY https://github.com/ken-matsui/git2-cpp.git - GIT_TAG 0.1.1 -) - -set(BUILD_SHARED_LIBS OFF) -FetchContent_MakeAvailable(git2-cpp) -unset(BUILD_SHARED_LIBS) - -list(APPEND POAC_DEPENDENCIES git2-cpp::git2-cpp) -message(CHECK_PASS "added") - -list(POP_BACK CMAKE_MESSAGE_INDENT) diff --git a/cmake/AddGlob.cmake b/cmake/AddGlob.cmake deleted file mode 100644 index 182dc7ba4..000000000 --- a/cmake/AddGlob.cmake +++ /dev/null @@ -1,23 +0,0 @@ -include_guard(GLOBAL) - -message(CHECK_START "Adding Glob") -list(APPEND CMAKE_MESSAGE_INDENT " ") - -FetchContent_Declare( - Glob - GIT_REPOSITORY https://github.com/p-ranav/glob.git - GIT_TAG v0.0.1 -) -FetchContent_MakeAvailable(Glob) - -# Disable clang-tidy -set_target_properties( - Glob - PROPERTIES - CXX_CLANG_TIDY "" -) - -list(APPEND POAC_DEPENDENCIES Glob) -message(CHECK_PASS "added") - -list(POP_BACK CMAKE_MESSAGE_INDENT) diff --git a/cmake/AddLibArchive.cmake b/cmake/AddLibArchive.cmake deleted file mode 100644 index 0391fd314..000000000 --- a/cmake/AddLibArchive.cmake +++ /dev/null @@ -1,68 +0,0 @@ -include_guard(GLOBAL) - -message(CHECK_START "Adding LibArchive") -list(APPEND CMAKE_MESSAGE_INDENT " ") - -include(cmake/CPM.cmake) - -if (DEFINED LibArchive_INCLUDE_DIR) - message(STATUS "LibArchive_INCLUDE_DIR has been set manually: ${LibArchive_INCLUDE_DIR}") -else () - set(LIBARCHIVE_INCLUDE_DIR_TMP "${POAC_HOMEBREW_ROOT_PATH}/libarchive/include") - if (APPLE AND EXISTS "${LIBARCHIVE_INCLUDE_DIR_TMP}/archive.h") - # To support finding LibArchive on macOS - set(LibArchive_INCLUDE_DIR ${LIBARCHIVE_INCLUDE_DIR_TMP}) - message(STATUS "LibArchive_INCLUDE_DIR has been set automatically: ${LibArchive_INCLUDE_DIR}") - else () - message(STATUS "LibArchive_INCLUDE_DIR could not be set automatically") - endif () - unset(LIBARCHIVE_INCLUDE_DIR_TMP) -endif () - -set(CMAKE_PROJECT_libarchive_INCLUDE_BEFORE "${CMAKE_SOURCE_DIR}/cmake/LibArchivePoliciesFix.cmake") -CPMAddPackage( - NAME LibArchive - GITHUB_REPOSITORY libarchive/libarchive - VERSION 3.6.0 # minimum required version (but only when using local one) - GIT_TAG v3.6.2 # (3.6.1 or over is needed to build downloaded one) - OPTIONS - "ENABLE_OPENSSL OFF" - "ENABLE_LIBB2 OFF" - "ENABLE_LZMA OFF" - "ENABLE_ZSTD OFF" - "ENABLE_ZLIB OFF" - "ENABLE_BZip2 OFF" - "ENABLE_LIBXML2 OFF" - "ENABLE_EXPAT OFF" - "ENABLE_CAT OFF" - "ENABLE_CPIO OFF" - "ENABLE_TAR OFF" - "ENABLE_ACL OFF" - "ENABLE_ICONV OFF" - "ENABLE_TEST OFF" - "ENABLE_INSTALL OFF" -) - -if (LibArchive_ADDED) # If using downloaded package - set(LIBARCHIVE_INCLUDE_DIR "${LibArchive_SOURCE_DIR}/libarchive") - if (CMAKE_BUILD_TYPE STREQUAL Debug) # -DCMAKE_BUILD_TYPE=Debug - set(LIBARCHIVE_LIBRARY archive) - list(APPEND POAC_DEPENDENCIES archive) - else () - set(LIBARCHIVE_LIBRARY archive_static) - list(APPEND POAC_DEPENDENCIES archive_static) - endif () -else () # If using local package - if (APPLE) - set(LIBARCHIVE_INCLUDE_DIR ${LibArchive_INCLUDE_DIR}) - endif () - set(LIBARCHIVE_LIBRARY archive) - list(APPEND POAC_DEPENDENCIES archive) -endif () - -# TODO: Move this to the root CMakeLists.txt -target_include_directories(poac_util_archive PRIVATE ${LIBARCHIVE_INCLUDE_DIR}) -target_link_libraries(poac_util_archive PRIVATE ${LIBARCHIVE_LIBRARY}) - -message(CHECK_PASS "added") -list(POP_BACK CMAKE_MESSAGE_INDENT) diff --git a/cmake/AddLibGit2.cmake b/cmake/AddLibGit2.cmake deleted file mode 100644 index 2f407d424..000000000 --- a/cmake/AddLibGit2.cmake +++ /dev/null @@ -1,46 +0,0 @@ -include_guard(GLOBAL) - -message(CHECK_START "Adding libgit2") -list(APPEND CMAKE_MESSAGE_INDENT " ") - -include(cmake/CPM.cmake) - -list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") - -# Override cache string in libgit2/CMakeLists.txt -# ref: https://github.com/libgit2/libgit2/blob/43b5075df4c543fc8801ed4b829702d7f9f2c0ad/CMakeLists.txt#L57 -# ref2: https://github.com/libgit2/libgit2/blob/43b5075df4c543fc8801ed4b829702d7f9f2c0ad/src/CMakeLists.txt#L163 -# ref for how to do this: https://stackoverflow.com/a/62702897 -set(REGEX_BACKEND "builtin" CACHE INTERNAL "") - -set(CMAKE_PROJECT_libgit2_INCLUDE_BEFORE "${CMAKE_SOURCE_DIR}/cmake/CMP0077PolicyFix.cmake") -if (CMAKE_BUILD_TYPE STREQUAL Release) # -DCMAKE_BUILD_TYPE=Release - set(BUILD_SHARED_LIBS OFF) -else () - set(BUILD_SHARED_LIBS ON) -endif () -CPMAddPackage( - NAME libgit2 - GITHUB_REPOSITORY libgit2/libgit2 - VERSION 1.4.3 # minimum required version - GIT_TAG v1.6.1 - OPTIONS - "BUILD_TESTS OFF" - "USE_SSH OFF" - "USE_HTTPS OFF" - "USE_NTLMCLIENT OFF" - "USE_BUNDLED_ZLIB ON" - "BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS}" -) - -if (libgit2_ADDED) # If using downloaded package - set(LIBGIT2_INCLUDE_DIR ${libgit2_SOURCE_DIR}/include) - set(LIBGIT2_LIBRARY libgit2package) -else () # If using local package - set(LIBGIT2_LIBRARY ${LIBGIT2_LIBRARIES}) -endif () - -list(APPEND POAC_DEPENDENCIES ${LIBGIT2_LIBRARY}) -message(CHECK_PASS "added") - -list(POP_BACK CMAKE_MESSAGE_INDENT) diff --git a/cmake/AddMitamaCppResult.cmake b/cmake/AddMitamaCppResult.cmake deleted file mode 100644 index 792eb8712..000000000 --- a/cmake/AddMitamaCppResult.cmake +++ /dev/null @@ -1,15 +0,0 @@ -include_guard(GLOBAL) - -message(CHECK_START "Adding mitama-cpp-result") -list(APPEND CMAKE_MESSAGE_INDENT " ") - -FetchContent_Declare( - mitama-cpp-result - GIT_REPOSITORY https://github.com/LoliGothick/mitama-cpp-result.git - GIT_TAG v9.3.0 -) -FetchContent_MakeAvailable(mitama-cpp-result) -list(APPEND POAC_DEPENDENCIES mitama-cpp-result::mitama-cpp-result) -message(CHECK_PASS "added") - -list(POP_BACK CMAKE_MESSAGE_INDENT) diff --git a/cmake/AddNinja.cmake b/cmake/AddNinja.cmake deleted file mode 100644 index d4f597277..000000000 --- a/cmake/AddNinja.cmake +++ /dev/null @@ -1,44 +0,0 @@ -include_guard(GLOBAL) - -message(CHECK_START "Adding ninja") -list(APPEND CMAKE_MESSAGE_INDENT " ") - -FetchContent_Declare( - ninja - GIT_REPOSITORY https://github.com/ninja-build/ninja - GIT_TAG c6e002d86d6657f18dd772c8138454291becf885 -) - -set(BUILD_TESTING OFF) -set(NINJA_BUILD_BINARY OFF) -set(CMAKE_CXX_STANDARD 11) - -FetchContent_MakeAvailable(ninja) - -file(MAKE_DIRECTORY ${ninja_BINARY_DIR}/include) -file(CREATE_LINK ${ninja_SOURCE_DIR}/src ${ninja_BINARY_DIR}/include/ninja SYMBOLIC) - -set(NINJA_INCLUDE_DIR ${ninja_BINARY_DIR}/include) -set(NINJA_LIBRARIES libninja libninja-re2c) - -# TODO: Move this to the root CMakeLists.txt -target_include_directories(poac_core_builder_data PRIVATE ${NINJA_INCLUDE_DIR}) -target_link_libraries(poac_core_builder_data PRIVATE ${NINJA_LIBRARIES}) -target_include_directories(poac_core_builder_log PRIVATE ${NINJA_INCLUDE_DIR}) -target_link_libraries(poac_core_builder_log PRIVATE ${NINJA_LIBRARIES}) -target_include_directories(poac_core_builder_manifest PRIVATE ${NINJA_INCLUDE_DIR}) -target_link_libraries(poac_core_builder_manifest PRIVATE ${NINJA_LIBRARIES}) -target_include_directories(poac_core_builder_build PRIVATE ${NINJA_INCLUDE_DIR}) -target_link_libraries(poac_core_builder_build PRIVATE ${NINJA_LIBRARIES}) - -# Disable clang-tidy -set_target_properties( - libninja libninja-re2c - PROPERTIES - CXX_CLANG_TIDY "" -) - -list(APPEND POAC_DEPENDENCIES ${NINJA_LIBRARIES}) -message(CHECK_PASS "added") - -list(POP_BACK CMAKE_MESSAGE_INDENT) diff --git a/cmake/AddOpenSSL.cmake b/cmake/AddOpenSSL.cmake deleted file mode 100644 index c6af2a768..000000000 --- a/cmake/AddOpenSSL.cmake +++ /dev/null @@ -1,43 +0,0 @@ -include_guard(GLOBAL) - -message(CHECK_START "Adding OpenSSL") -list(APPEND CMAKE_MESSAGE_INDENT " ") - -if (APPLE) - set(OPENSSL_ROOT_DIR "${POAC_HOMEBREW_ROOT_PATH}/openssl") -endif () -if (DEFINED OPENSSL_ROOT_DIR) - set(OPENSSL_LIBRARIES ${OPENSSL_ROOT_DIR}/lib) -endif () - -find_package(OpenSSL REQUIRED) -if (OPENSSL_FOUND) - message(CHECK_PASS "added") - if (UNIX AND NOT APPLE) - list(APPEND OPENSSL_LIBRARIES ssl crypto dl) - elseif (APPLE) - list(APPEND OPENSSL_LIBRARIES dl) - elseif (WIN32) - list(APPEND OPENSSL_LIBRARIES bcrypt ws2_32) - endif () - message(STATUS "OpenSSL include directory is ... ${OPENSSL_INCLUDE_DIR}") - message(STATUS "OpenSSL libraries are ... ${OPENSSL_LIBRARIES}") - - # TODO: Move this to the root CMakeLists.txt - target_include_directories(poac_util_sha256 PRIVATE ${OPENSSL_INCLUDE_DIR}) - target_link_libraries(poac_util_sha256 PRIVATE ${OPENSSL_LIBRARIES}) - target_include_directories(poac_util_net PRIVATE ${OPENSSL_INCLUDE_DIR}) - target_link_libraries(poac_util_net PRIVATE ${OPENSSL_LIBRARIES}) - - target_include_directories(poac PRIVATE ${OPENSSL_INCLUDE_DIR}) - list(APPEND POAC_DEPENDENCIES ${OPENSSL_LIBRARIES}) -else () - message(CHECK_FAIL "not found") - list(APPEND missingDependencies openssl) - - if (APPLE) - message(FATAL_ERROR "OpenSSL not found. Please install it by `brew install openssl@3`") - endif () -endif () - -list(POP_BACK CMAKE_MESSAGE_INDENT) diff --git a/cmake/AddSpdlog.cmake b/cmake/AddSpdlog.cmake deleted file mode 100644 index eb7602a50..000000000 --- a/cmake/AddSpdlog.cmake +++ /dev/null @@ -1,26 +0,0 @@ -include_guard(GLOBAL) - -message(CHECK_START "Adding Spdlog") -list(APPEND CMAKE_MESSAGE_INDENT " ") - -include(cmake/CPM.cmake) - -if (CMAKE_BUILD_TYPE STREQUAL Release) # -DCMAKE_BUILD_TYPE=Release - set(SPDLOG_BUILD_SHARED OFF) -else () - set(SPDLOG_BUILD_SHARED ON) -endif () -CPMAddPackage( - NAME spdlog - GITHUB_REPOSITORY gabime/spdlog - VERSION 1.9.0 # minimum required version - GIT_TAG v1.11.0 - OPTIONS - "SPDLOG_FMT_EXTERNAL ON" - "SPDLOG_BUILD_SHARED ${SPDLOG_BUILD_SHARED}" -) - -list(APPEND POAC_DEPENDENCIES spdlog::spdlog) -message(CHECK_PASS "added") - -list(POP_BACK CMAKE_MESSAGE_INDENT) diff --git a/cmake/AddStructopt.cmake b/cmake/AddStructopt.cmake deleted file mode 100644 index c94a07f76..000000000 --- a/cmake/AddStructopt.cmake +++ /dev/null @@ -1,15 +0,0 @@ -include_guard(GLOBAL) - -message(CHECK_START "Adding structopt") -list(APPEND CMAKE_MESSAGE_INDENT " ") - -FetchContent_Declare( - structopt - GIT_REPOSITORY https://github.com/p-ranav/structopt.git - GIT_TAG 422c2e293702047b52e420651742f73581ad4677 -) -FetchContent_MakeAvailable(structopt) -list(APPEND POAC_DEPENDENCIES structopt::structopt) -message(CHECK_PASS "added") - -list(POP_BACK CMAKE_MESSAGE_INDENT) diff --git a/cmake/AddToml11.cmake b/cmake/AddToml11.cmake deleted file mode 100644 index 268dd8299..000000000 --- a/cmake/AddToml11.cmake +++ /dev/null @@ -1,19 +0,0 @@ -include_guard(GLOBAL) - -message(CHECK_START "Adding Toml11") -list(APPEND CMAKE_MESSAGE_INDENT " ") - -FetchContent_Declare( - toml11 - GIT_REPOSITORY https://github.com/ToruNiina/toml11.git - GIT_TAG 846abd9a49082fe51440aa07005c360f13a67bbf -) - -set(CMAKE_PROJECT_toml11_INCLUDE_BEFORE "${CMAKE_SOURCE_DIR}/cmake/CMP0077PolicyFix.cmake") -set(toml11_BUILD_TEST OFF) -FetchContent_MakeAvailable(toml11) - -list(APPEND POAC_DEPENDENCIES toml11::toml11) -message(CHECK_PASS "added") - -list(POP_BACK CMAKE_MESSAGE_INDENT) diff --git a/cmake/CMP0077PolicyFix.cmake b/cmake/CMP0077PolicyFix.cmake deleted file mode 100644 index 3cdff0123..000000000 --- a/cmake/CMP0077PolicyFix.cmake +++ /dev/null @@ -1,3 +0,0 @@ -# ref: https://gitlab.kitware.com/cmake/cmake/-/issues/19854 -# https://cmake.org/cmake/help/latest/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE_BEFORE.html#variable:CMAKE_PROJECT_%3CPROJECT-NAME%3E_INCLUDE_BEFORE -cmake_policy(SET CMP0077 NEW) diff --git a/cmake/CPM.cmake b/cmake/CPM.cmake deleted file mode 100644 index 9e5207994..000000000 --- a/cmake/CPM.cmake +++ /dev/null @@ -1,22 +0,0 @@ -include_guard(GLOBAL) -set(CPM_DOWNLOAD_VERSION 0.35.1) - -if(CPM_SOURCE_CACHE) - # Expand relative path. This is important if the provided path contains a tilde (~) - get_filename_component(CPM_SOURCE_CACHE ${CPM_SOURCE_CACHE} ABSOLUTE) - set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") -elseif(DEFINED ENV{CPM_SOURCE_CACHE}) - set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") -else() - set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") -endif() - -if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION})) - message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}") - file(DOWNLOAD - https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake - ${CPM_DOWNLOAD_LOCATION} - ) -endif() - -include(${CPM_DOWNLOAD_LOCATION}) diff --git a/cmake/ConfigDebug.cmake b/cmake/ConfigDebug.cmake deleted file mode 100644 index 2874b1363..000000000 --- a/cmake/ConfigDebug.cmake +++ /dev/null @@ -1,14 +0,0 @@ -include_guard(GLOBAL) - -# ref: https://github.com/google/sanitizers/wiki/AddressSanitizer#using-addresssanitizer -set(CMAKE_CXX_FLAGS_DEBUG "-g -O1 -fsanitize=address -fno-omit-frame-pointer") -# https://stackoverflow.com/a/38297422 -set(CMAKE_POSITION_INDEPENDENT_CODE ON) # -fPIC - -if (POAC_CLANG_TIDY) - # Enable clang-tidy - set(CMAKE_CXX_CLANG_TIDY clang-tidy) # -fix - # For header files: - # -export-fixes=out.yaml - # clang-apply-replacements . -endif () diff --git a/cmake/ConfigRelease.cmake b/cmake/ConfigRelease.cmake deleted file mode 100644 index a840bc372..000000000 --- a/cmake/ConfigRelease.cmake +++ /dev/null @@ -1,58 +0,0 @@ -include_guard(GLOBAL) - -function(enable_ipo) - include(CheckIPOSupported) - check_ipo_supported( - RESULT ipo_supported - OUTPUT ipo_check_output - LANGUAGES CXX - ) - if (ipo_supported) - set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) - else () - message(WARNING "IPO / LTO is not supported: ${ipo_check_output}") - endif () -endfunction() - -if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") - # ref: https://stackoverflow.com/a/3801032 - set(CMAKE_CXX_FLAGS_RELEASE "-O3 -flto -mtune=native") -elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(CMAKE_CXX_FLAGS_RELEASE "-O3") - # ref: https://stackoverflow.com/a/39256013 - SET(CMAKE_AR "gcc-ar") - SET(CMAKE_CXX_ARCHIVE_CREATE " qcs ") - SET(CMAKE_CXX_ARCHIVE_FINISH true) - enable_ipo() -elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - if (${CMAKE_CXX_COMPILER} MATCHES "-[0-9]+$") - string(REGEX REPLACE [[.*clang\+\+(-[0-9]+)$]] [[lld\1]] LINKER ${CMAKE_CXX_COMPILER}) - set(STATIC_LINK_FLAG "-fuse-ld=${LINKER}") - else () - find_program(lld_EXECUTABLE lld) - if (lld_EXECUTABLE) - set(STATIC_LINK_FLAG "-fuse-ld=lld") - else () - set(STATIC_LINK_FLAG "") # use `ld` - endif () - endif () - - # For nix, ref: https://github.com/NixOS/nixpkgs/issues/166205 - if (APPLE) - if (STATIC_LINK_FLAG STREQUAL "") - set(STATIC_LINK_FLAG "-lc++abi") - else () - set(STATIC_LINK_FLAG "${STATIC_LINK_FLAG} -lc++abi") - endif () - endif () - - set(CMAKE_CXX_FLAGS_RELEASE "-O3") - enable_ipo() -else () - set(CMAKE_CXX_FLAGS_RELEASE "-O3") - enable_ipo() -endif () - -if (UNIX AND NOT APPLE) - set(Boost_USE_STATIC_LIBS ON) -endif () diff --git a/cmake/ConfigStatic.cmake b/cmake/ConfigStatic.cmake deleted file mode 100644 index 5005a9f65..000000000 --- a/cmake/ConfigStatic.cmake +++ /dev/null @@ -1,19 +0,0 @@ -include_guard(GLOBAL) - -string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") -set(CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) -string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}") -set(CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_MINSIZEREL}) -string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") -set(CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) -string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}) - -string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") -set(CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG}) -string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") -set(CMAKE_C_FLAGS_MINSIZEREL ${CMAKE_C_FLAGS_MINSIZEREL}) -string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") -set(CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE}) -string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") -set(CMAKE_C_FLAGS_RELWITHDEBINFO ${CMAKE_C_FLAGS_RELWITHDEBINFO}) diff --git a/cmake/Findlibgit2.cmake b/cmake/Findlibgit2.cmake deleted file mode 100644 index 657acb765..000000000 --- a/cmake/Findlibgit2.cmake +++ /dev/null @@ -1,35 +0,0 @@ -# ref: https://github.com/libgit2/libgit2-backends/blob/b2b968fb97ea4e984dc9a6983a0dbbb44fb5f31a/CMake/FindLibgit2.cmake - -# - Try to find the libgit2 library -# Once done this will define -# -# LIBGIT2_FOUND - System has libgit2 -# LIBGIT2_INCLUDE_DIR - The libgit2 include directory -# LIBGIT2_LIBRARIES - The libraries needed to use libgit2 -# LIBGIT2_DEFINITIONS - Compiler switches required for using libgit2 - - -# use pkg-config to get the directories and then use these values -# in the FIND_PATH() and FIND_LIBRARY() calls -FIND_PACKAGE(PkgConfig) -PKG_SEARCH_MODULE(PC_LIBGIT2 libgit2) - -SET(LIBGIT2_DEFINITIONS ${PC_LIBGIT2_CFLAGS_OTHER}) - -FIND_PATH(LIBGIT2_INCLUDE_DIR NAMES git2.h - HINTS - ${PC_LIBGIT2_INCLUDEDIR} - ${PC_LIBGIT2_INCLUDE_DIRS} -) - -FIND_LIBRARY(LIBGIT2_LIBRARIES NAMES git2 - HINTS - ${PC_LIBGIT2_LIBDIR} - ${PC_LIBGIT2_LIBRARY_DIRS} -) - - -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(libgit2 DEFAULT_MSG LIBGIT2_LIBRARIES LIBGIT2_INCLUDE_DIR) - -MARK_AS_ADVANCED(LIBGIT2_INCLUDE_DIR LIBGIT2_LIBRARIES) diff --git a/cmake/Helpers.cmake b/cmake/Helpers.cmake deleted file mode 100644 index b012edb68..000000000 --- a/cmake/Helpers.cmake +++ /dev/null @@ -1,18 +0,0 @@ -# ref: https://stackoverflow.com/a/7788165 -macro (list_dir_items result curdir) - file(GLOB items RELATIVE ${curdir} ${curdir}/*) - set(${result} ${items}) -endmacro () - -macro (get_homebrew_prefix_path) - execute_process( - COMMAND brew --prefix - OUTPUT_VARIABLE POAC_HOMEBREW_PREFIX_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE - ) -endmacro () - -if (APPLE) - get_homebrew_prefix_path() - set(POAC_HOMEBREW_ROOT_PATH "${POAC_HOMEBREW_PREFIX_PATH}/opt") -endif() diff --git a/cmake/LibArchivePoliciesFix.cmake b/cmake/LibArchivePoliciesFix.cmake deleted file mode 100644 index 54ab14d52..000000000 --- a/cmake/LibArchivePoliciesFix.cmake +++ /dev/null @@ -1,2 +0,0 @@ -cmake_policy(SET CMP0048 NEW) -cmake_policy(SET CMP0077 NEW) diff --git a/cmake/PoacConfig.cmake b/cmake/PoacConfig.cmake deleted file mode 100644 index be99973b2..000000000 --- a/cmake/PoacConfig.cmake +++ /dev/null @@ -1,34 +0,0 @@ -include_guard(GLOBAL) - -target_compile_definitions(poac PRIVATE POAC_VERSION="${CMAKE_PROJECT_VERSION}") -if (NOT MSVC) - # undefined reference to symbol 'pthread_condattr_setclock@@GLIBC_2.3.3' - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") - if (APPLE) - target_compile_definitions(poac PRIVATE BOOST_BEAST_USE_STD_STRING_VIEW) - else () - target_compile_definitions(poac PRIVATE _GNU_SOURCE BOOST_ASIO_HAS_STD_STRING_VIEW) - endif () -endif () - -if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - target_compile_options(poac PRIVATE -fdiagnostics-color -Wall -Wextra) -elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - target_compile_options(poac PRIVATE /W4 /DBOOST_ASIO_HAS_STD_STRING_VIEW /bigobj /Zc:preprocessor) -else () - target_compile_options(poac PRIVATE -fdiagnostics-color -Wall -Wextra -pedantic-errors) - if (CMAKE_BUILD_TYPE STREQUAL Release) # -DCMAKE_BUILD_TYPE=Release - target_compile_options(poac PRIVATE -Werror) - endif () - if (CYGWIN OR MINGW) - target_compile_options(poac PRIVATE -O3 -Wa,-mbig-obj) - endif () -endif () - -if ((MSVC OR MINGW) AND ENABLE_STATIC) # -DENABLE_STATIC=ON - include(cmake/ConfigStatic.cmake) -elseif (CMAKE_BUILD_TYPE STREQUAL Debug) # -DCMAKE_BUILD_TYPE=Debug - include(cmake/ConfigDebug.cmake) -elseif (CMAKE_BUILD_TYPE STREQUAL Release) # -DCMAKE_BUILD_TYPE=Release - include(cmake/ConfigRelease.cmake) -endif () diff --git a/cmake/PoacDependencies.cmake b/cmake/PoacDependencies.cmake deleted file mode 100644 index fd04f8da6..000000000 --- a/cmake/PoacDependencies.cmake +++ /dev/null @@ -1,30 +0,0 @@ -include_guard(GLOBAL) -include(cmake/Helpers.cmake) - -message(CHECK_START "Adding Poac dependencies") -list(APPEND CMAKE_MESSAGE_INDENT " ") -unset(missingDependencies) - -include(FetchContent) -list_dir_items(DEPENDENCIES ${CMAKE_SOURCE_DIR}/cmake) -list(FILTER DEPENDENCIES INCLUDE REGEX "Add.*cmake") # Add files that match the regex - -# Dev-dependencies -if (NOT POAC_BUILD_TESTING) - list(REMOVE_ITEM DEPENDENCIES "AddBoostUt.cmake") -endif () - -# Include dependency cmake files -foreach (DEP IN LISTS DEPENDENCIES) - include(${CMAKE_SOURCE_DIR}/cmake/${DEP}) -endforeach () - -list(POP_BACK CMAKE_MESSAGE_INDENT) -if (missingDependencies) - message(CHECK_FAIL "missing dependencies: ${missingDependencies}") - message(FATAL_ERROR "missing dependencies found") -else () - message(CHECK_PASS "all dependencies are added") -endif () - -message(STATUS "dependencies are ... ${POAC_DEPENDENCIES}") diff --git a/etc/man/man1/poac.1 b/etc/man/man1/poac.1 deleted file mode 100644 index e69de29bb..000000000 diff --git a/etc/poac.bash b/etc/poac.bash deleted file mode 100644 index d4526ef4e..000000000 --- a/etc/poac.bash +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash - -if ! command -v poac >/dev/null 2>&1; then - return -fi - -__poac() { - local words=${COMP_WORDS} - local cword=${COMP_CWORD} - local cur=${COMP_WORDS[COMP_CWORD]} - local prev=${COMP_WORDS[COMP_CWORD-1]} - - case "${prev}" in - *) COMPREPLY=($__poac_commands) ;; - esac - - return 0 -} - -# complete is a bash builtin, but recent versions of ZSH come with a function -# called bashcompinit that will create a complete in ZSH. If the user is in -# ZSH, load and run bashcompinit before calling the complete function. -if [[ -n ${ZSH_VERSION-} ]]; then - autoload -U +X bashcompinit && bashcompinit - autoload -U +X compinit && compinit -fi - -complete -F __poac poac - -__poac_commands='build -create -fmt -init -lint -login -publish -run -search' diff --git a/poac.toml b/poac.toml index a3f3bed9b..4a9c7b2a4 100644 --- a/poac.toml +++ b/poac.toml @@ -1,85 +1,29 @@ [package] -name = "poac" -version = "0.6.0" -edition = 2020 authors = ["Ken Matsui <26405363+ken-matsui@users.noreply.github.com>"] -description = "Package Manager for C++" +description = "A package manager and build system for C++" +documentation = "https://doc.poac.dev" +edition = "20" +homepage = "https://poac.dev" license = "Apache-2.0" +name = "poac" readme = "README.md" repository = "https://github.com/poac-dev/poac" -homepage = "https://poac.dev" -documentation = "https://doc.poac.dev" +version = "0.6.0" [dependencies] -"ken-matsui/termcolor2" = ">=0.1.0 and <1.0.0" -#"ken-matsui/semver" = ">=0.1.0 and <1.0.0" -#"ken-matsui/git2-cpp" = ">=0.1.0 and <1.0.0" -#"ken-matsui/tar-cpp" = ">=0.1.0 and <1.0.0" -#"ken-matsui/url-cpp" = ">=0.1.0 and <1.0.0" -"boost/predef" = ">=1.64.0 and <2.0.0" -#"boost/property_tree" = ">=1.64.0 and <2.0.0" -#"boost/range" = ">=1.64.0 and <2.0.0" -#"boost/algorithm" = ">=1.64.0 and <2.0.0" -#"boost/foreach" = ">=1.64.0 and <2.0.0" -#"boost/dynamic_bitset" = ">=1.64.0 and <2.0.0" -#"boost/beast" = ">=1.64.0 and <2.0.0" -#"ToruNiina/toml11" = ">=3.0.0 and <4.0.0" - -#[dev-dependencies] -#"boost/test" = ">=1.64.0 and <2.0.0" - -[target.'cfg(os = "linux")'.profile] -definitions = ["_GNU_SOURCE", "BOOST_ASIO_HAS_STD_STRING_VIEW"] - -[target.'cfg(os = "unix")'.profile] -options = ["-fdiagnostics-color", "-Wall", "-Wextra", "-pthread"] -libraries = ["dl", "ssl", "crypt"] - -[target.'cfg(os = "macos")'.profile] -include-directories = ["/usr/local/opt/openssl/include"] -link-directories = ["/usr/local/opt/openssl/lib"] - -[target.'cfg(compiler = "msvc")'.profile] -definitions = ["BOOST_ASIO_HAS_STD_STRING_VIEW"] -options = ["/W4", "/bigobj"] - -[target.'cfg(any(os = "cygwin", platform = "mingw"))'.profile] -options = ["-Wa,-mbig-obj"] - -[target.'cfg(os = "windows")'.profile] -libraries = ["bcrypt", "ws2_32"] - -[target.'cfg(os = "unix")'.profile.dev] -options = ["-fsanitize=address"] - -[target.'cfg(os = "macos")'.profile.release] -options = ["-mtune=native", "-march=native"] - -[target.'cfg(all(os = "macos", os_version < "10.15"))'.profile] -compiler = "/usr/local/opt/llvm@7/bin/clang++" -include-directories = ["/usr/local/opt/llvm@7/include"] -link-directories = ["/usr/local/opt/llvm@7/lib"] - -[profile] -libraries = ["boost_sysytem", "git2"] +"ToruNiina/toml11" = {git = "https://github.com/ToruNiina/toml11.git", rev = "846abd9a49082fe51440aa07005c360f13a67bbf"} [profile.release] lto = true [lint.cpplint] filters = [ - "-legal/copyright", - "-whitespace", - "+whitespace/ending_newline", - "-build/c++11", - "-build/namespaces_literals", - # Didn't work correctly with inline namespaces - # `namespace termcolor2::inline color_literals::inline foreground_literals` - # suggested to `namespace termcolor2::inline` - "-readability/namespace", - # Unknown NOLINT error category: bugprone-branch-clone - # This is for clang-tidy - "-readability/nolint", - # I believe non-const reference would be much better than a pointer. - "-runtime/references", + "-legal/copyright", + "-whitespace", + "+whitespace/ending_newline", + "-build/c++11", + "-build/namespaces_literals", # Didn't work correctly with inline namespaces # `namespace termcolor2::inline color_literals::inline foreground_literals` # suggested to `namespace termcolor2::inline` + "-readability/namespace", # Unknown NOLINT error category: bugprone-branch-clone # This is for clang-tidy + "-readability/nolint", # I believe non-const reference would be much better than a pointer. + "-runtime/references", ] diff --git a/src/Algos.cc b/src/Algos.cc new file mode 100644 index 000000000..3a30e3747 --- /dev/null +++ b/src/Algos.cc @@ -0,0 +1,205 @@ +#include "Algos.hpp" + +#include "Rustify.hpp" + +#include + +// O(M) where M is the length of the word. +void trieInsert(TrieNode& root, StringRef word) { + TrieNode* node = &root; + for (char ch : word) { + if (!node->children.count(ch)) { + node->children[ch] = std::make_unique(); + } + node = node->children[ch].get(); + } + node->isEndOfWord = true; +} + +// O(M) where M is the length of the word. +bool trieSearch(const TrieNode& root, StringRef word) { + const TrieNode* node = &root; + for (char ch : word) { + if (!node->children.count(ch)) { + return false; + } + node = node->children.at(ch).get(); + if (node->isEndOfWord) { + return true; + } + } + return false; +} + +// O(M^2) where M is the length of the word. +bool trieSearchFromAnyPosition(const TrieNode& root, StringRef word) { + for (size_t i = 0; i < word.size(); ++i) { + const TrieNode* node = &root; + for (size_t j = i; j < word.size(); ++j) { + char ch = word[j]; + if (!node->children.count(ch)) { + break; + } + node = node->children.at(ch).get(); + if (node->isEndOfWord) { + return true; + } + } + } + return false; +} + +// ref: https://wandbox.org/permlink/zRjT41alOHdwcf00 +static usize levDistance(StringRef a, StringRef b) { + const usize asize = a.size(); + const usize bsize = b.size(); + + // for all i and j, d[i,j] will hold the Levenshtein distance between the + // first i characters of s and the first j characters of t + Vec> d(asize + 1, Vec(bsize + 1)); + d[0][0] = 0; + + // source prefixes can be transformed into empty string by dropping all + // characters + for (usize i = 1; i <= asize; ++i) { + d[i][0] = i; + } + + // target prefixes can be reached from empty source prefix by inserting every + // character + for (usize j = 1; j <= bsize; ++j) { + d[0][j] = j; + } + + for (usize i = 1; i <= asize; ++i) { + for (usize j = 1; j <= bsize; ++j) { + const usize subst_cost = a[i - 1] == b[j - 1] ? 0 : 1; + d[i][j] = std::min({ + d[i - 1][j] + 1, // deletion + d[i][j - 1] + 1, // insertion + d[i - 1][j - 1] + subst_cost // substitution + }); + } + } + + return d[asize][bsize]; +} + +static auto equalsInsensitive(StringRef a, StringRef b) -> bool { + return std::equal( + a.cbegin(), a.cend(), b.cbegin(), b.cend(), + [](char a, char b) { return std::tolower(a) == std::tolower(b); } + ); +} + +Option +findSimilarStr(StringRef lhs, std::span candidates) { + // We need to check if `Candidates` has the exact case-insensitive string + // because the Levenshtein distance match does not care about it. + for (StringRef c : candidates) { + if (equalsInsensitive(lhs, c)) { + return c; + } + } + + // Keep going with the Levenshtein distance match. + // If the LHS size is less than 3, use the LHS size minus 1 and if not, + // use the LHS size divided by 3. + const usize length = lhs.size(); + const usize max_dist = length < 3 ? length - 1 : length / 3; + + Option> similar_str = None; + for (const StringRef c : candidates) { + const usize cur_dist = levDistance(lhs, c); + if (cur_dist <= max_dist) { + // The first similar string found || More similar string found + if (!similar_str.has_value() || cur_dist < similar_str->second) { + similar_str = {c, cur_dist}; + } + } + } + + if (similar_str.has_value()) { + return similar_str->first; + } else { + return None; + } +} + +#ifdef POAC_TEST + +# include +# include + +void test_levDistance() { + // Test bytelength agnosticity + for (char c = 0; c < std::numeric_limits::max(); ++c) { + String str = String(1, c); + assert(levDistance(str, str) == 0); + } +} + +void test_levDistance2() { + constexpr StringRef A = "\nMäry häd ä little lämb\n\nLittle lämb\n"; + constexpr StringRef B = "\nMary häd ä little lämb\n\nLittle lämb\n"; + constexpr StringRef C = "Mary häd ä little lämb\n\nLittle lämb\n"; + + assert(levDistance(A, B) == 2); + assert(levDistance(B, A) == 2); + assert(levDistance(A, C) == 3); + assert(levDistance(C, A) == 3); + assert(levDistance(B, C) == 1); + assert(levDistance(C, B) == 1); + + assert(levDistance("b", "bc") == 1); + assert(levDistance("ab", "abc") == 1); + assert(levDistance("aab", "aabc") == 1); + assert(levDistance("aaab", "aaabc") == 1); + + assert(levDistance("a", "b") == 1); + assert(levDistance("ab", "ac") == 1); + assert(levDistance("aab", "aac") == 1); + assert(levDistance("aaab", "aaac") == 1); +} + +// ref: +// https://github.com/llvm/llvm-project/commit/a247ba9d15635d96225ef39c8c150c08f492e70a#diff-fd993637669817b267190e7de029b75af5a0328d43d9b70c2e8dd512512091a2 + +void test_findSimilarStr() { + constexpr Arr CANDIDATES{"if", "ifdef", "ifndef", + "elif", "else", "endif", + "elifdef", "elifndef"}; + + assert(findSimilarStr("id", CANDIDATES) == "if"sv); + assert(findSimilarStr("ifd", CANDIDATES) == "if"sv); + assert(findSimilarStr("ifde", CANDIDATES) == "ifdef"sv); + assert(findSimilarStr("elf", CANDIDATES) == "elif"sv); + assert(findSimilarStr("elsif", CANDIDATES) == "elif"sv); + assert(findSimilarStr("elseif", CANDIDATES) == "elif"sv); + assert(findSimilarStr("elfidef", CANDIDATES) == "elifdef"sv); + assert(findSimilarStr("elfindef", CANDIDATES) == "elifdef"sv); + assert(findSimilarStr("elfinndef", CANDIDATES) == "elifndef"sv); + assert(findSimilarStr("els", CANDIDATES) == "else"sv); + assert(findSimilarStr("endi", CANDIDATES) == "endif"sv); + + assert(findSimilarStr("i", CANDIDATES) == None); + assert(findSimilarStr("special_compiler_directive", CANDIDATES) == None); +} + +void test_findSimilarStr2() { + constexpr Arr CANDIDATES{"aaab", "aaabc"}; + assert(findSimilarStr("aaaa", CANDIDATES) == "aaab"sv); + assert(findSimilarStr("1111111111", CANDIDATES) == None); + + constexpr Arr CANDIDATES2{"AAAA"}; + assert(findSimilarStr("aaaa", CANDIDATES2) == "AAAA"sv); +} + +int main() { + test_levDistance(); + test_levDistance2(); + test_findSimilarStr(); + test_findSimilarStr2(); +} + +#endif diff --git a/src/Algos.hpp b/src/Algos.hpp new file mode 100644 index 000000000..60d10508b --- /dev/null +++ b/src/Algos.hpp @@ -0,0 +1,80 @@ +#pragma once + +#include "Rustify.hpp" + +#include +#include +#include +#include +#include + +struct TrieNode { + HashMap> children; + bool isEndOfWord = false; +}; +void trieInsert(TrieNode&, StringRef); +bool trieSearch(const TrieNode&, StringRef); +bool trieSearchFromAnyPosition(const TrieNode&, StringRef); + +template +Vec topoSort( + const HashMap& list, const HashMap>& adjList +) { + HashMap inDegree; + for (const auto& var : list) { + inDegree[var.first] = 0; + } + for (const auto& edge : adjList) { + if (!list.contains(edge.first)) { + continue; // Ignore nodes not in list + } + if (!inDegree.contains(edge.first)) { + inDegree[edge.first] = 0; + } + for (const auto& neighbor : edge.second) { + inDegree[neighbor]++; + } + } + + std::queue zeroInDegree; + for (const auto& var : inDegree) { + if (var.second == 0) { + zeroInDegree.push(var.first); + } + } + + Vec res; + while (!zeroInDegree.empty()) { + const String node = zeroInDegree.front(); + zeroInDegree.pop(); + res.push_back(node); + + if (!adjList.contains(node)) { + // No dependencies + continue; + } + for (const String& neighbor : adjList.at(node)) { + inDegree[neighbor]--; + if (inDegree[neighbor] == 0) { + zeroInDegree.push(neighbor); + } + } + } + + if (res.size() != list.size()) { + // Cycle detected + throw std::runtime_error("too complex build graph"); + } + return res; +} + +// ref: https://reviews.llvm.org/differential/changeset/?ref=3315514 +/// Find a similar string in `candidates`. +/// +/// \param lhs a string for a similar string in `Candidates` +/// +/// \param candidates the candidates to find a similar string. +/// +/// \returns a similar string if exists. If no similar string exists, +/// returns None. +Option findSimilarStr(StringRef, std::span); diff --git a/src/BuildConfig.cc b/src/BuildConfig.cc new file mode 100644 index 000000000..6a92c66c1 --- /dev/null +++ b/src/BuildConfig.cc @@ -0,0 +1,554 @@ +#include "BuildConfig.hpp" + +#include "Algos.hpp" +#include "Logger.hpp" +#include "Manifest.hpp" +#include "TermColor.hpp" + +#include +#include +#include +#include +#include +#include + +static String OUT_DIR = "poac-out/debug"; +static String CXX = "clang++"; +static String INCLUDES; + +struct Target { + Vec commands; + Vec dependsOn; +}; + +struct BuildConfig { + HashMap variables; + HashMap> varDeps; + HashMap targets; + HashMap> targetDeps; + + void + defineVariable(String name, String value, const Vec& dependsOn = {}); + void defineTarget( + String name, const Vec& commands, + const Vec& dependsOn = {} + ); + void emitMakefile(std::ostream& os = std::cout) const; +}; + +void BuildConfig::defineVariable( + String name, String value, const Vec& dependsOn +) { + variables[name] = value; + for (const String& dep : dependsOn) { + // reverse dependency + varDeps[dep].push_back(name); + } +} + +void BuildConfig::defineTarget( + String name, const Vec& commands, const Vec& dependsOn +) { + targets[name] = {commands, dependsOn}; + for (const String& dep : dependsOn) { + // reverse dependency + targetDeps[dep].push_back(name); + } +} + +static void emitTarget( + std::ostream& os, StringRef target, const Vec& dependsOn, + const Vec& commands = {} +) { + usize offset = 0; + + os << target << ":"; + offset += target.size() + 2; // : and space + + for (const String& dep : dependsOn) { + if (offset + dep.size() + 2 > 80) { // 2 for space and \. + // \ for line continuation. \ is the 80th character. + os << std::setw(83 - offset) << " \\\n "; + offset = 2; + } + os << " " << dep; + offset += dep.size() + 1; // space + } + os << '\n'; + + for (const String& cmd : commands) { + os << '\t' << cmd << '\n'; + } + os << '\n'; +} + +void BuildConfig::emitMakefile(std::ostream& os) const { + const Vec sortedVars = topoSort(variables, varDeps); + for (const String& var : sortedVars) { + if (var == "CXX") { + os << var << " ?= " << variables.at(var) << '\n'; + } else { + os << var << " = " << variables.at(var) << '\n'; + } + } + if (!sortedVars.empty() && !targets.empty()) { + os << '\n'; + } + + if (targets.contains(".PHONY")) { + emitTarget(os, ".PHONY", targets.at(".PHONY").dependsOn); + } + if (targets.contains("all")) { + emitTarget(os, "all", targets.at("all").dependsOn); + } + const Vec sortedTargets = topoSort(targets, targetDeps); + for (auto itr = sortedTargets.rbegin(); itr != sortedTargets.rend(); itr++) { + if (*itr == ".PHONY" || *itr == "all") { + continue; + } + emitTarget(os, *itr, targets.at(*itr).dependsOn, targets.at(*itr).commands); + } +} + +static Vec listSourceFiles(StringRef directory) { + Vec sourceFiles; + for (const auto& entry : fs::recursive_directory_iterator(directory)) { + if (!SOURCE_FILE_EXTS.contains(entry.path().extension())) { + continue; + } + sourceFiles.push_back(entry.path().string()); + } + return sourceFiles; +} + +static String exec(const char* cmd) { + std::array buffer; + String result; + std::unique_ptr pipe(popen(cmd, "r"), pclose); + if (!pipe) { + throw std::runtime_error("popen() failed!"); + } + while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { + result += buffer.data(); + } + return result; +} + +static String runMM(const String& sourceFile) { + const String command = + "cd " + OUT_DIR + " && " + CXX + INCLUDES + " -MM " + sourceFile; + return exec(command.c_str()); +} + +static void +parseMMOutput(const String& mmOutput, String& target, Vec& deps) { + std::istringstream iss(mmOutput); + std::getline(iss, target, ':'); + Logger::debug(target, ':'); + + String dependency; + while (std::getline(iss, dependency, ' ')) { + if (!dependency.empty() && dependency.front() != '\\') { + // Remove trailing newline if it exists + if (dependency.back() == '\n') { + dependency.pop_back(); + } + deps.push_back(dependency); + Logger::debug(" '", dependency, "'"); + } + } + Logger::debug(""); +} + +static bool isMakefileUpToDate(StringRef makefilePath) { + if (!fs::exists(makefilePath)) { + return false; + } + + const fs::file_time_type makefileTime = fs::last_write_time(makefilePath); + // Makefile depends on all files in ./src and poac.toml. + for (const auto& entry : fs::recursive_directory_iterator("src")) { + if (fs::last_write_time(entry.path()) > makefileTime) { + return false; + } + } + if (fs::last_write_time("poac.toml") > makefileTime) { + return false; + } + + return true; +} + +static bool containsTestCode(const String& sourceFile) { + std::ifstream ifs(sourceFile); + String line; + while (std::getline(ifs, line)) { + if (line.find("POAC_TEST") != String::npos) { + Logger::debug("contains test code: ", sourceFile); + return true; + } + } + Logger::debug("does not contain test code: ", sourceFile); + return false; +} + +static String buildCmd(const String& cmd) noexcept { + if (isVerbose()) { + return cmd; + } else { + return "@" + cmd; + } +} + +static void defineDirTarget(BuildConfig& config, const String& directory) { + config.defineTarget(directory, {buildCmd("mkdir -p $@")}); +} + +static void defineCompileTarget( + BuildConfig& config, const String& objTarget, const Vec& deps, + const bool isTest = false +) { + std::ostringstream oss; + Logger::log( + oss, LogLevel::info, "Compiling", deps[0].substr(6) // remove "../../" + ); + + Vec commands(2); + commands[0] = "@echo '" + oss.str() + "'"; + + const String compileCmd = "$(CXX) $(CFLAGS) $(INCLUDES)"; + if (isTest) { + commands[1] = buildCmd(compileCmd + " -DPOAC_TEST -c $< -o $@"); + } else { + commands[1] = buildCmd(compileCmd + " -c $< -o $@"); + } + config.defineTarget(objTarget, commands, deps); +} + +static void defineLinkTarget( + BuildConfig& config, const String& binTarget, const Vec& deps +) { + std::ostringstream oss; + Logger::log(oss, LogLevel::info, "Linking", binTarget); + + Vec commands(2); + commands[0] = "@echo '" + oss.str() + "'"; + commands[1] = buildCmd("$(CXX) $(CFLAGS) $^ -o $@"); + config.defineTarget(binTarget, commands, deps); +} + +struct ObjTargetInfo { + String name; + String baseDir; + Vec deps; +}; + +// Returns the directory where the Makefile is generated. +String emitMakefile(const bool debug) { + if (!fs::exists("src")) { + throw std::runtime_error("src directory not found"); + } + if (!fs::exists("src/main.cc")) { + throw std::runtime_error("src/main.cc not found"); + } + if (!fs::exists(OUT_DIR)) { + fs::create_directories(OUT_DIR); + } + if (const char* cxx = std::getenv("CXX")) { + CXX = cxx; + } + + const String makefilePath = OUT_DIR + "/Makefile"; + if (isMakefileUpToDate(makefilePath)) { + Logger::debug("Makefile is up to date"); + return OUT_DIR; + } + + const String projectName = getPackageName(); + const String pathFromOutDir = "../../"; + + BuildConfig config; + + // Compiler settings + config.defineVariable("CXX", CXX); + String cflags = + "-Wall -Wextra -pedantic-errors -std=c++" + getPackageEdition(); + if (shouldColor()) { + cflags += " -fdiagnostics-color"; + } + if (debug) { + cflags += " -g -O0 -DDEBUG"; + } else { + cflags += " -O3 -DNDEBUG"; + } + config.defineVariable("CFLAGS", cflags); + + const Vec deps = installGitDependencies(); + for (const Path& dep : deps) { + const Path includeDir = dep / "include"; + if (fs::exists(includeDir) && fs::is_directory(includeDir) + && !fs::is_empty(includeDir)) { + INCLUDES += " -I" + includeDir.string(); + } else { + INCLUDES += " -I" + dep.string(); + } + } + Logger::debug("INCLUDES: ", INCLUDES); + config.defineVariable("INCLUDES", INCLUDES); + + // Build rules + const String buildOutDir = projectName + ".d"; + defineDirTarget(config, buildOutDir); + + Vec phonies = {"all"}; + config.defineTarget("all", {}, {projectName}); + + const Vec sourceFiles = listSourceFiles("src"); + Vec buildObjTargets; + + // sourceFile.cc -> ObjTargetInfo + HashMap objTargetInfos; + for (const String& sourceFileName : sourceFiles) { + const String sourceFile = pathFromOutDir + sourceFileName; + const String mmOutput = runMM(sourceFile); + + String objTarget; // sourceFile.o + Vec objTargetDeps; + parseMMOutput(mmOutput, objTarget, objTargetDeps); + + const String targetBaseDir = + fs::relative(Path(sourceFile).parent_path(), pathFromOutDir + "src") + .string(); + objTargetInfos[sourceFileName] = {objTarget, targetBaseDir, objTargetDeps}; + + // Add a target to create the buildOutDir and buildTargetBaseDir. + Vec buildTargetDeps = objTargetDeps; + buildTargetDeps.push_back("|"); // order-only dependency + buildTargetDeps.push_back(buildOutDir); + String buildTargetBaseDir = buildOutDir; + if (targetBaseDir != ".") { + buildTargetBaseDir += "/" + targetBaseDir; + defineDirTarget(config, buildTargetBaseDir); + buildTargetDeps.push_back(buildTargetBaseDir); + } + + const String buildObjTarget = buildTargetBaseDir + "/" + objTarget; + buildObjTargets.push_back(buildObjTarget); + defineCompileTarget(config, buildObjTarget, buildTargetDeps); + } + defineLinkTarget(config, projectName, buildObjTargets); + + // Targets for testing. + bool enableTesting = false; + Vec testCommands; + Vec testTargets; + const HashSet buildObjTargetSet( + buildObjTargets.begin(), buildObjTargets.end() + ); + const String testOutDir = "tests"; + for (auto& [sourceFile, objTargetInfo] : objTargetInfos) { + if (containsTestCode(sourceFile)) { + enableTesting = true; + + // NOTE: Since we know that we don't use objTargetInfos for other + // targets, we can just update it here instead of creating a copy. + objTargetInfo.deps.push_back("|"); // order-only dependency + objTargetInfo.deps.push_back(testOutDir); + + // Add a target to create the testTargetBaseDir. + String testTargetBaseDir = testOutDir; + if (objTargetInfo.baseDir != ".") { + testTargetBaseDir += "/" + objTargetInfo.baseDir; + defineDirTarget(config, testTargetBaseDir); + objTargetInfo.deps.push_back(testTargetBaseDir); + } + + const String testObjTarget = + testTargetBaseDir + "/test_" + objTargetInfo.name; + const String testTargetName = Path(sourceFile).stem().string(); + const String testTarget = testTargetBaseDir + "/test_" + testTargetName; + + // Test object target. + defineCompileTarget(config, testObjTarget, objTargetInfo.deps, true); + + // Test binary target. + Vec testTargetDeps = {testObjTarget}; + // This test target depends on the object file corresponding to + // the header file included in this source file. + for (const String& header : objTargetInfo.deps) { + // We shouldn't depend on the original object file (e.g., + // poac.d/path/to/file.o). We should depend on the test object + // file (e.g., tests/path/to/test_file.o). + const Path headerPath(header); + if (Path(sourceFile).stem().string() == headerPath.stem().string()) { + continue; + } + if (!HEADER_FILE_EXTS.contains(headerPath.extension())) { + continue; + } + + // headerPath: src/path/to/header.h -> + // object target: poac.d/path/to/header.o + String headerObjTargetBaseDir = + fs::relative(headerPath.parent_path(), pathFromOutDir + "src") + .string(); + if (headerObjTargetBaseDir != ".") { + headerObjTargetBaseDir = buildOutDir + "/" + headerObjTargetBaseDir; + } else { + headerObjTargetBaseDir = buildOutDir; + } + const String headerObjTarget = + headerObjTargetBaseDir + "/" + headerPath.stem().string() + ".o"; + Logger::debug("headerObjTarget: ", headerObjTarget); + + auto itr = buildObjTargetSet.find(headerObjTarget); + if (itr == buildObjTargetSet.end()) { + continue; + } + testTargetDeps.push_back(*itr); + } + + defineLinkTarget(config, testTarget, testTargetDeps); + Logger::debug(testTarget, ':'); + for (const String& dep : testTargetDeps) { + Logger::debug(" '", dep, "'"); + } + + std::ostringstream oss; + Logger::log(oss, LogLevel::info, "Testing", testTargetName); + testCommands.push_back("@echo '" + oss.str() + "'"); + testCommands.push_back(buildCmd(testTarget)); + testTargets.push_back(testTarget); + } + } + if (enableTesting) { + // Target to create the tests directory. + defineDirTarget(config, testOutDir); + config.defineTarget("test", testCommands, testTargets); + phonies.push_back("test"); + } + + config.defineTarget(".PHONY", {}, phonies); + + std::ofstream ofs(makefilePath); + config.emitMakefile(ofs); + return OUT_DIR; +} + +String modeString(const bool debug) { + return debug ? "debug" : "release"; +} + +String getMakeCommand() { + if (isVerbose()) { + return "make"; + } else { + return "make -s --no-print-directory"; + } +} + +#ifdef POAC_TEST + +# include +# include +# include + +void test_cycle_vars() { + BuildConfig config; + config.defineVariable("a", "b", {"b"}); + config.defineVariable("b", "c", {"c"}); + config.defineVariable("c", "a", {"a"}); + + try { + std::stringstream ss; + config.emitMakefile(ss); + } catch (const std::runtime_error& e) { + assert(std::string(e.what()) == "too complex build graph"); + return; + } + + assert(false && "should not reach here"); +} + +void test_simple_vars() { + BuildConfig config; + config.defineVariable("c", "3", {"b"}); + config.defineVariable("b", "2", {"a"}); + config.defineVariable("a", "1"); + + std::stringstream ss; + config.emitMakefile(ss); + + assert(ss.str() == "a = 1\n" + "b = 2\n" + "c = 3\n"); +} + +void test_depend_on_unregistered_var() { + BuildConfig config; + config.defineVariable("a", "1", {"b"}); + + std::stringstream ss; + config.emitMakefile(ss); + + assert(ss.str() == "a = 1\n"); +} + +void test_cycle_targets() { + BuildConfig config; + config.defineTarget("a", {"echo a"}, {"b"}); + config.defineTarget("b", {"echo b"}, {"c"}); + config.defineTarget("c", {"echo c"}, {"a"}); + + try { + std::stringstream ss; + config.emitMakefile(ss); + } catch (const std::runtime_error& e) { + assert(std::string(e.what()) == "too complex build graph"); + return; + } + + assert(false && "should not reach here"); +} + +void test_simple_targets() { + BuildConfig config; + config.defineTarget("a", {"echo a"}); + config.defineTarget("b", {"echo b"}, {"a"}); + config.defineTarget("c", {"echo c"}, {"b"}); + + std::stringstream ss; + config.emitMakefile(ss); + + assert(ss.str() == "c: b\n" + "\techo c\n" + "\n" + "b: a\n" + "\techo b\n" + "\n" + "a:\n" + "\techo a\n" + "\n"); +} + +void test_depend_on_unregistered_target() { + BuildConfig config; + config.defineTarget("a", {"echo a"}, {"b"}); + + std::stringstream ss; + config.emitMakefile(ss); + + assert(ss.str() == "a: b\n" + "\techo a\n" + "\n"); +} + +int main() { + test_cycle_vars(); + test_simple_vars(); + test_depend_on_unregistered_var(); + test_cycle_targets(); + test_simple_targets(); + test_depend_on_unregistered_target(); +} +#endif diff --git a/src/BuildConfig.hpp b/src/BuildConfig.hpp new file mode 100644 index 000000000..ba2c788b1 --- /dev/null +++ b/src/BuildConfig.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "Rustify.hpp" + +static inline const HashSet SOURCE_FILE_EXTS{ + ".c", ".c++", ".cc", ".cpp", ".cxx" +}; +static inline const HashSet HEADER_FILE_EXTS{ + ".h", ".h++", ".hh", ".hpp", ".hxx" +}; + +String emitMakefile(const bool); +String modeString(const bool); +String getMakeCommand(); diff --git a/src/Cmd/Build.cc b/src/Cmd/Build.cc new file mode 100644 index 000000000..3b07959d6 --- /dev/null +++ b/src/Cmd/Build.cc @@ -0,0 +1,60 @@ +#include "Build.hpp" + +#include "../BuildConfig.hpp" +#include "../Logger.hpp" +#include "Global.hpp" + +#include +#include +#include + +int buildImpl(const bool isDebug, String& outDir) { + const auto start = std::chrono::steady_clock::now(); + + outDir = emitMakefile(isDebug); + const int status = std::system((getMakeCommand() + " -C " + outDir).c_str()); + const int exitCode = status >> 8; + + const auto end = std::chrono::steady_clock::now(); + const std::chrono::duration elapsed = end - start; + + if (exitCode == EXIT_SUCCESS) { + Logger::info( + "Finished", modeString(isDebug), " target(s) in ", elapsed.count(), "s" + ); + } + return exitCode; +} + +int buildMain(std::span args) { + bool isDebug = true; + // Parse args + for (StringRef arg : args) { + HANDLE_GLOBAL_OPTS({{"build"}}) // workaround for std::span until C++26 + + else if (arg == "-d" || arg == "--debug") { + isDebug = true; + } + else if (arg == "-r" || arg == "--release") { + isDebug = false; + } + else { + Logger::error("Unknown argument: ", arg); + return EXIT_FAILURE; + } + } + + String outDir; + return buildImpl(isDebug, outDir); +} + +void buildHelp() noexcept { + std::cout << buildDesc << '\n'; + std::cout << '\n'; + printUsage("build", "[OPTIONS]"); + std::cout << '\n'; + printHeader("Options:"); + printGlobalOpts(); + printOption("--debug", "-d", "Build with debug information [default]"); + printOption("--release", "-r", "Build with optimizations"); +} diff --git a/src/Cmd/Build.hpp b/src/Cmd/Build.hpp new file mode 100644 index 000000000..0bb0dc7d5 --- /dev/null +++ b/src/Cmd/Build.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "../Rustify.hpp" + +#include + +static inline constexpr StringRef buildDesc = + "Compile a local package and all of its dependencies"; + +int buildImpl(const bool, String&); +int buildMain(std::span); +void buildHelp() noexcept; diff --git a/src/Cmd/Clean.cc b/src/Cmd/Clean.cc new file mode 100644 index 000000000..17830d8be --- /dev/null +++ b/src/Cmd/Clean.cc @@ -0,0 +1,55 @@ +#include "Clean.hpp" + +#include "../Logger.hpp" +#include "Global.hpp" + +#include +#include + +int cleanMain(std::span args) noexcept { + Path outDir = "poac-out"; + + // Parse args + for (usize i = 0; i < args.size(); ++i) { + StringRef arg = args[i]; + HANDLE_GLOBAL_OPTS({{"clean"}}) + + else if (arg == "-p" || arg == "--profile") { + if (i + 1 >= args.size()) { + Logger::error("Missing argument for ", arg); + return EXIT_FAILURE; + } + + ++i; + + if (!(args[i] == "debug" || args[i] == "release")) { + Logger::error("Invalid argument for ", arg, ": ", args[i]); + return EXIT_FAILURE; + } + + outDir /= args[1]; + } + else { + Logger::error("Unknown argument: ", arg); + return EXIT_FAILURE; + } + } + + if (fs::exists(outDir)) { + Logger::info("Removing", fs::canonical(outDir).string()); + fs::remove_all(outDir); + } + return EXIT_SUCCESS; +} + +void cleanHelp() noexcept { + std::cout << cleanDesc << '\n'; + std::cout << '\n'; + printUsage("clean", "[OPTIONS]"); + std::cout << '\n'; + printHeader("Options:"); + printGlobalOpts(); + printOption( + "--profile", "-p", "Remove built artifacts in mode", "" + ); +} diff --git a/src/Cmd/Clean.hpp b/src/Cmd/Clean.hpp new file mode 100644 index 000000000..509729bf3 --- /dev/null +++ b/src/Cmd/Clean.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "../Rustify.hpp" + +#include + +static inline constexpr StringRef cleanDesc = "Remove the built directory"; + +int cleanMain(std::span) noexcept; +void cleanHelp() noexcept; diff --git a/src/Cmd/Fmt.cc b/src/Cmd/Fmt.cc new file mode 100644 index 000000000..5238469f6 --- /dev/null +++ b/src/Cmd/Fmt.cc @@ -0,0 +1,107 @@ +#include "Fmt.hpp" + +#include "../Algos.hpp" +#include "../BuildConfig.hpp" +#include "../Logger.hpp" +#include "../Manifest.hpp" +#include "../Rustify.hpp" +#include "Global.hpp" + +#include +#include +#include +#include + +int fmtMain(std::span args) { + bool isCheck = false; + // Parse args + for (StringRef arg : args) { + HANDLE_GLOBAL_OPTS({{"fmt"}}) + + else if (arg == "--check") { + isCheck = true; + } + else { + Logger::error("invalid argument: ", arg); + return EXIT_FAILURE; + } + } + + if (!commandExists("clang-format")) { + Logger::error( + "fmt command requires clang-format; try installing it by:\n" + " apt/brew install clang-format" + ); + return EXIT_FAILURE; + } + + const String packageName = getPackageName(); + String clangFormatArgs = "--style=file --fallback-style=LLVM -Werror"; + if (isVerbose()) { + clangFormatArgs += " --verbose"; + } + if (isCheck) { + clangFormatArgs += " --dry-run"; + } else { + clangFormatArgs += " -i"; + Logger::info("Formatting", packageName); + } + + // Read .gitignore if exists + TrieNode root; + if (fs::exists(".gitignore")) { + std::ifstream ifs(".gitignore"); + String line; + while (std::getline(ifs, line)) { + if (line.empty() || line[0] == '#') { + continue; + } + + trieInsert(root, line); + } + } + + // Automatically collects format-target files + for (auto entry = fs::recursive_directory_iterator("."); + entry != fs::recursive_directory_iterator(); ++entry) { + if (entry->is_directory()) { + const String path = entry->path().string(); + if (trieSearchFromAnyPosition(root, path)) { + Logger::debug("ignore: ", path); + entry.disable_recursion_pending(); + continue; + } + } else if (entry->is_regular_file()) { + const Path path = entry->path(); + if (trieSearchFromAnyPosition(root, path.string())) { + Logger::debug("Ignore: ", path.string()); + continue; + } + + const String ext = path.extension().string(); + if (SOURCE_FILE_EXTS.contains(ext) || HEADER_FILE_EXTS.contains(ext)) { + clangFormatArgs += " " + path.string(); + } + } + } + + const String clangFormat = "clang-format " + clangFormatArgs; + Logger::debug("Executing `", clangFormat, '`'); + const int code = std::system(clangFormat.c_str()); + const int exitCode = code >> 8; + if (exitCode != 0) { + Logger::error("clang-format exited with code ", exitCode); + return exitCode; + } + return EXIT_SUCCESS; +} + +void fmtHelp() noexcept { + std::cout << fmtDesc << '\n'; + std::cout << '\n'; + printUsage("fmt", "[OPTIONS]"); + std::cout << '\n'; + printHeader("Options:"); + printGlobalOpts(); + printOption("--check", "", "Run clang-format in check mode"); +} diff --git a/src/Cmd/Fmt.hpp b/src/Cmd/Fmt.hpp new file mode 100644 index 000000000..d0dc6354d --- /dev/null +++ b/src/Cmd/Fmt.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "../Rustify.hpp" + +#include + +static inline constexpr StringRef fmtDesc = "Format codes using clang-format"; + +int fmtMain(std::span); +void fmtHelp() noexcept; diff --git a/src/Cmd/Global.cc b/src/Cmd/Global.cc new file mode 100644 index 000000000..5a96971e6 --- /dev/null +++ b/src/Cmd/Global.cc @@ -0,0 +1,63 @@ +#include "Global.hpp" + +#include "../Rustify.hpp" +#include "../TermColor.hpp" + +#include +#include + +void printHeader(StringRef header) noexcept { + std::cout << bold(green(header)) << '\n'; +} + +void printUsage(StringRef cmd, StringRef usage) noexcept { + std::cout << bold(green("Usage: ")) << bold(cyan("poac ")); + if (!cmd.empty()) { + std::cout << bold(cyan(cmd)) << ' '; + } + std::cout << cyan(usage) << '\n'; +} + +void printOption( + StringRef lng, StringRef shrt, StringRef desc, StringRef placeholder +) noexcept { + String option; + if (!shrt.empty()) { + option += bold(cyan(shrt)); + option += ", "; + } else { + // This coloring is for the alignment with std::setw later. + option += bold(cyan(" ")); + } + option += bold(cyan(lng)); + option += ' '; + option += cyan(placeholder); + + if (shouldColor()) { + std::cout << " " << std::left << std::setw(69) << option << desc << '\n'; + } else { + std::cout << " " << std::left << std::setw(26) << option << desc << '\n'; + } +} + +void printCommand(StringRef name, StringRef desc) noexcept { + if (shouldColor()) { + std::cout << " " << std::left << std::setw(27) << bold(cyan(name)) << desc + << '\n'; + } else { + std::cout << " " << std::left << std::setw(10) << name << desc << '\n'; + } +} + +void printGlobalOpts() noexcept { + for (const auto& [lng, shrt, desc] : GLOBAL_OPT_HELPS) { + printOption(lng, shrt, desc); + } +} + +bool commandExists(StringRef cmd) noexcept { + String checkCmd = "command -v "; + checkCmd += cmd; + checkCmd += " >/dev/null 2>&1"; + return std::system(checkCmd.c_str()) == 0; +} diff --git a/src/Cmd/Global.hpp b/src/Cmd/Global.hpp new file mode 100644 index 000000000..3cf03e64a --- /dev/null +++ b/src/Cmd/Global.hpp @@ -0,0 +1,34 @@ +// Global options and helper functions for commands. + +#pragma once + +#include "../Logger.hpp" +#include "../Rustify.hpp" +#include "Help.hpp" + +#include + +#define HANDLE_GLOBAL_OPTS(HELP_ARGS) \ + if (arg == "-h" || arg == "--help") { \ + return helpMain(HELP_ARGS); \ + } else if (arg == "-v" || arg == "--verbose") { \ + Logger::setLevel(LogLevel::debug); \ + } else if (arg == "-q" || arg == "--quiet") { \ + Logger::setLevel(LogLevel::off); \ + } + +// long, short, description +static inline constexpr Arr, 3> + GLOBAL_OPT_HELPS{ + std::make_tuple("--verbose", "-v", "Use verbose output"), + {"--quiet", "-q", "Do not print poac log messages"}, + {"--help", "-h", "Print help"}, + }; + +void printHeader(StringRef) noexcept; +void printUsage(StringRef, StringRef) noexcept; +void printOption(StringRef, StringRef, StringRef, StringRef = "") noexcept; +void printCommand(StringRef, StringRef) noexcept; +void printGlobalOpts() noexcept; + +bool commandExists(StringRef) noexcept; diff --git a/src/Cmd/Help.cc b/src/Cmd/Help.cc new file mode 100644 index 000000000..22b5c07e5 --- /dev/null +++ b/src/Cmd/Help.cc @@ -0,0 +1,17 @@ +#include "Help.hpp" + +#include "Global.hpp" + +#include + +void helpHelp() noexcept { + std::cout << helpDesc << '\n'; + std::cout << '\n'; + printUsage("help", "[OPTIONS] [COMMAND]"); + std::cout << '\n'; + printHeader("Options:"); + printGlobalOpts(); + std::cout << '\n'; + printHeader("Arguments:"); + std::cout << " [COMMAND]" << '\n'; +} diff --git a/src/Cmd/Help.hpp b/src/Cmd/Help.hpp new file mode 100644 index 000000000..9bdcd762e --- /dev/null +++ b/src/Cmd/Help.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include "../Rustify.hpp" + +#include + +static inline constexpr StringRef helpDesc = + "Displays help for a poac subcommand"; + +int helpMain(std::span) noexcept; +void helpHelp() noexcept; diff --git a/src/Cmd/Init.cc b/src/Cmd/Init.cc new file mode 100644 index 000000000..8b5d20552 --- /dev/null +++ b/src/Cmd/Init.cc @@ -0,0 +1,58 @@ +#include "Init.hpp" + +#include "../Logger.hpp" +#include "Global.hpp" +#include "New.hpp" + +#include +#include +#include + +int initMain(std::span args) { + // Parse args + bool isBin = true; + for (StringRef arg : args) { + HANDLE_GLOBAL_OPTS({{"init"}}) + + else if (arg == "-b" || arg == "--bin") { + isBin = true; + } + else if (arg == "-l" || arg == "--lib") { + isBin = false; + } + else { + Logger::error("invalid argument: ", arg); + return EXIT_FAILURE; + } + } + + if (fs::exists("poac.toml")) { + Logger::error("cannot initialize an existing poac package"); + return EXIT_FAILURE; + } + + const String packageName = fs::current_path().stem().string(); + if (!verifyPackageName(packageName)) { + return EXIT_FAILURE; + } + + std::ofstream ofs("poac.toml"); + ofs << getPoacToml(packageName); + + Logger::info( + "Created", isBin ? "binary (application) `" : "library `", packageName, + "` package" + ); + return EXIT_SUCCESS; +} + +void initHelp() noexcept { + std::cout << initDesc << '\n'; + std::cout << '\n'; + printUsage("init", "[OPTIONS]"); + std::cout << '\n'; + printHeader("Options:"); + printGlobalOpts(); + printOption("--bin", "-b", "Use a binary (application) template [default]"); + printOption("--lib", "-l", "Use a library template"); +} diff --git a/src/Cmd/Init.hpp b/src/Cmd/Init.hpp new file mode 100644 index 000000000..5723381e1 --- /dev/null +++ b/src/Cmd/Init.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include "../Rustify.hpp" + +#include + +static inline constexpr StringRef initDesc = + "Create a new poac package in an existing directory"; + +int initMain(std::span); +void initHelp() noexcept; diff --git a/src/Cmd/Lint.cc b/src/Cmd/Lint.cc new file mode 100644 index 000000000..da8b6eadb --- /dev/null +++ b/src/Cmd/Lint.cc @@ -0,0 +1,98 @@ +#include "Lint.hpp" + +#include "../Logger.hpp" +#include "../Manifest.hpp" +#include "../Rustify.hpp" +#include "Global.hpp" + +#include +#include +#include +#include + +static int lint(StringRef name, StringRef cpplintArgs) { + Logger::info("Linting", name); + + String cpplintCmd = "cpplint --recursive ."; + cpplintCmd += cpplintArgs; + if (!isVerbose()) { + cpplintCmd += " --quiet"; + } + + // Read .gitignore if exists + if (fs::exists(".gitignore")) { + std::ifstream ifs(".gitignore"); + String line; + while (std::getline(ifs, line)) { + if (line.empty() || line[0] == '#') { + continue; + } + + cpplintCmd += " --exclude="; + cpplintCmd += line; + } + } + + Logger::debug("Executing ", cpplintCmd); + const int status = std::system(cpplintCmd.c_str()); + const int exitCode = status >> 8; + if (exitCode != 0) { + Logger::error("`cpplint` exited with status ", exitCode); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + +int lintMain(std::span args) { + // Parse args + for (StringRef arg : args) { + HANDLE_GLOBAL_OPTS({{"lint"}}) + + else { + Logger::error("invalid argument: ", arg); + return EXIT_FAILURE; + } + } + + if (!commandExists("cpplint")) { + Logger::error( + "lint command requires cpplint; try installing it by:\n" + " pip install cpplint" + ); + return EXIT_FAILURE; + } + + const String packageName = getPackageName(); + const Vec cpplintFilters = getLintCpplintFilters(); + if (!cpplintFilters.empty()) { + Logger::debug("Using Poac manifest file for lint ..."); + String cpplintArgs = " --root=include --filter="; + for (StringRef filter : cpplintFilters) { + cpplintArgs += filter; + cpplintArgs += ','; + } + return lint(packageName, cpplintArgs); + } else if (fs::exists("CPPLINT.cfg")) { + Logger::debug("Using CPPLINT.cfg for lint ..."); + return lint(packageName, ""); + } else { + Logger::debug("Using default arguments for lint ..."); + String cpplintArgs; + if (fs::exists("include")) { + cpplintArgs += " --root=include"; + } + if (2011 < editionToYear(getPackageEdition())) { + cpplintArgs += " --filter=-build/c++11"; + } + return lint(packageName, cpplintArgs); + } +} + +void lintHelp() noexcept { + std::cout << lintDesc << '\n'; + std::cout << '\n'; + printUsage("lint", "[OPTIONS]"); + std::cout << '\n'; + printHeader("Options:"); + printGlobalOpts(); +} diff --git a/src/Cmd/Lint.hpp b/src/Cmd/Lint.hpp new file mode 100644 index 000000000..5c5089fb1 --- /dev/null +++ b/src/Cmd/Lint.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "../Rustify.hpp" + +#include + +static inline constexpr StringRef lintDesc = "Lint codes using cpplint"; + +int lintMain(std::span); +void lintHelp() noexcept; diff --git a/src/Cmd/New.cc b/src/Cmd/New.cc new file mode 100644 index 000000000..da583fedb --- /dev/null +++ b/src/Cmd/New.cc @@ -0,0 +1,272 @@ +#include "New.hpp" + +#include "../Logger.hpp" +#include "../Rustify.hpp" +#include "Global.hpp" + +#include +#include +#include +#include +#include + +static inline constexpr StringRef mainCc = + "#include \n\n" + "int main([[maybe_unused]] int argc, [[maybe_unused]] char** argv) {\n" + " std::cout << \"Hello, world!\" << std::endl;\n" + "}\n"; + +String getPoacToml(StringRef projectName) noexcept { + String poacToml = + "[package]\n" + "name = \""; + poacToml += projectName; + poacToml += + "\"\n" + "version = \"0.1.0\"\n" + "authors = []\n" + "edition = \"20\"\n"; + return poacToml; +} + +static String getHeader(StringRef projectName) noexcept { + String projectNameUpper{}; + std::transform( + projectName.cbegin(), projectName.cend(), + std::back_inserter(projectNameUpper), ::toupper + ); + + String header = "#ifndef " + projectNameUpper + "_HPP\n" + "#define " + projectNameUpper + "_HPP\n\n" + "namespace "; + header += projectName; + header += + " {\n}\n\n" + "#endif // !" + + projectNameUpper + "_HPP\n"; + return header; +} + +static void writeToFile(std::ofstream& ofs, const Path& fpath, StringRef text) { + ofs.open(fpath); + if (ofs.is_open()) { + ofs << text; + } + ofs.close(); + + if (!ofs) { + throw std::runtime_error("writing `" + fpath.string() + "` failed"); + } + ofs.clear(); +} + +static void createTemplateFiles(const bool isBin, StringRef projectName) { + std::ofstream ofs; + + if (isBin) { + fs::create_directories(projectName / "src"_path); + writeToFile(ofs, projectName / "poac.toml"_path, getPoacToml(projectName)); + writeToFile(ofs, projectName / ".gitignore"_path, "/poac-out"); + writeToFile(ofs, projectName / "src"_path / "main.cc", mainCc); + + Logger::info("Created", "binary (application) `", projectName, "` package"); + } else { + fs::create_directories(projectName / "include"_path / projectName); + writeToFile(ofs, projectName / "poac.toml"_path, getPoacToml(projectName)); + writeToFile(ofs, projectName / ".gitignore"_path, "/poac-out\npoac.lock"); + writeToFile( + ofs, + (projectName / "include"_path / projectName / projectName).string() + + ".hpp", + getHeader(projectName) + ); + + Logger::info("Created", "library `", projectName, "` package"); + } +} + +bool verifyPackageName(StringRef name) noexcept { + // Empty + if (name.empty()) { + Logger::error("missing package name"); + return false; + } + + // Only one character + if (name.size() == 1) { + Logger::error("only one character in package name: ", name); + return false; + } + + // Only lowercase letters, numbers, dashes, and underscores + for (const char& c : name) { + if (!std::islower(c) && !std::isdigit(c) && c != '-' && c != '_') { + Logger::error("invalid character in package name: ", name); + return false; + } + } + + // Start with a letter + if (!std::isalpha(name[0])) { + Logger::error("package names must start with a letter: ", name); + return false; + } + + // End with a letter or digit + if (!std::isalnum(name[name.size() - 1])) { + Logger::error("package names must end with a letter or digit: ", name); + return false; + } + + // Using C++ keywords + const HashSet keywords = { + "alignas", + "alignof", + "and", + "and_eq", + "asm", + "atomic_cancel", + "atomic_commit", + "atomic_noexcept", + "auto", + "bitand", + "bitor", + "bool", + "break", + "case", + "catch", + "char", + "char8_t", + "char16_t", + "char32_t", + "class", + "compl", + "concept", + "const", + "consteval", + "constexpr", + "constinit", + "const_cast", + "continue", + "co_await", + "co_return", + "co_yield", + "decltype", + "default", + "delete", + "do", + "double", + "dynamic_cast", + "else", + "enum", + "explicit", + "export", + "extern", + "false", + "float", + "for", + "friend", + "goto", + "if", + "inline", + "int", + "long", + "mutable", + "namespace", + "new", + "noexcept", + "not", + "not_eq", + "nullptr", + "operator", + "or", + "or_eq", + "private", + "protected", + "public", + "reflexpr", + "register", + "reinterpret_cast", + "requires", + "return", + "short", + "signed", + "sizeof", + "static", + "static_assert", + "static_cast", + "struct", + "switch", + "synchronized", + "template", + "this", + "thread_local", + "throw", + "true", + "try", + "typedef", + "typeid", + "typename", + "union", + "unsigned", + "using", + "virtual", + "void", + "volatile", + "wchar_t", + "while", + "xor", + "xor_eq" + }; + if (keywords.contains(name)) { + Logger::error("package names cannot be a C++ keyword: ", name); + return false; + } + + return true; +} + +int newMain(std::span args) { + // Parse args + bool isBin = true; + String packageName; + for (usize i = 0; i < args.size(); ++i) { + StringRef arg = args[i]; + HANDLE_GLOBAL_OPTS({{"new"}}) + + else if (arg == "-b" || arg == "--bin") { + isBin = true; + } + else if (arg == "-l" || arg == "--lib") { + isBin = false; + } + else if (packageName.empty()) { + packageName = arg; + } + else { + Logger::error("too many arguments: ", arg); + return EXIT_FAILURE; + } + } + + if (!verifyPackageName(packageName)) { + return EXIT_FAILURE; + } + + createTemplateFiles(isBin, packageName); + return EXIT_SUCCESS; +} + +void newHelp() noexcept { + std::cout << newDesc << '\n'; + std::cout << '\n'; + printUsage("new", "[OPTIONS] "); + std::cout << '\n'; + printHeader("Options:"); + printGlobalOpts(); + printOption("--bin", "-b", "Use a binary (application) template [default]"); + printOption("--lib", "-l", "Use a library template"); + std::cout << '\n'; + printHeader("Arguments:"); + std::cout << " " << '\n'; +} diff --git a/src/Cmd/New.hpp b/src/Cmd/New.hpp new file mode 100644 index 000000000..ab67ace45 --- /dev/null +++ b/src/Cmd/New.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "../Rustify.hpp" + +#include + +static inline constexpr StringRef newDesc = "Create a new poac project"; + +String getPoacToml(StringRef) noexcept; +bool verifyPackageName(StringRef) noexcept; + +int newMain(std::span); +void newHelp() noexcept; diff --git a/src/Cmd/Run.cc b/src/Cmd/Run.cc new file mode 100644 index 000000000..bada4178f --- /dev/null +++ b/src/Cmd/Run.cc @@ -0,0 +1,57 @@ +#include "Run.hpp" + +#include "../BuildConfig.hpp" +#include "../Logger.hpp" +#include "../Manifest.hpp" +#include "Build.hpp" +#include "Global.hpp" + +#include +#include +#include + +int runMain(std::span args) { + // Parse args + bool isDebug = true; + String runArgs; + for (usize i = 0; i < args.size(); ++i) { + StringRef arg = args[i]; + HANDLE_GLOBAL_OPTS({{"run"}}) + + else if (arg == "-d" || arg == "--debug") { + isDebug = true; + } + else if (arg == "-r" || arg == "--release") { + isDebug = false; + } + else { + runArgs += " " + String(arg); + } + } + + String outDir; + if (buildImpl(isDebug, outDir) != EXIT_SUCCESS) { + return EXIT_FAILURE; + } + + const String projectName = getPackageName(); + const String command = outDir + "/" + projectName + runArgs; + Logger::info("Running", command); + const int status = std::system(command.c_str()); + const int exitCode = status >> 8; + return exitCode; +} + +void runHelp() noexcept { + std::cout << runDesc << '\n'; + std::cout << '\n'; + printUsage("run", "[OPTIONS] [args]..."); + std::cout << '\n'; + printHeader("Options:"); + printGlobalOpts(); + printOption("--debug", "-d", "Build with debug information [default]"); + printOption("--release", "-r", "Build with optimizations"); + std::cout << '\n'; + printHeader("Arguments:"); + std::cout << " [args]...\tArguments passed to the program" << '\n'; +} diff --git a/src/Cmd/Run.hpp b/src/Cmd/Run.hpp new file mode 100644 index 000000000..f8a5c9d33 --- /dev/null +++ b/src/Cmd/Run.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "../Rustify.hpp" + +#include + +static inline constexpr StringRef runDesc = "Build and execute src/main.cc"; + +int runMain(std::span); +void runHelp() noexcept; diff --git a/src/Cmd/Test.cc b/src/Cmd/Test.cc new file mode 100644 index 000000000..ea81c2bee --- /dev/null +++ b/src/Cmd/Test.cc @@ -0,0 +1,57 @@ +#include "Test.hpp" + +#include "../BuildConfig.hpp" +#include "../Logger.hpp" +#include "Global.hpp" + +#include +#include +#include + +int testMain(std::span args) { + // Parse args + bool isDebug = true; + for (StringRef arg : args) { + HANDLE_GLOBAL_OPTS({{"test"}}) + + else if (arg == "-d" || arg == "--debug") { + isDebug = true; + } + else if (arg == "-r" || arg == "--release") { + Logger::warn("The `--release` flag can disable assert macros."); + isDebug = false; + } + else { + Logger::error("invalid argument: ", arg); + return EXIT_FAILURE; + } + } + + const auto start = std::chrono::steady_clock::now(); + + const String outDir = emitMakefile(isDebug); + const int status = + std::system((getMakeCommand() + " -C " + outDir + " test").c_str()); + const int exitCode = status >> 8; + + const auto end = std::chrono::steady_clock::now(); + const std::chrono::duration elapsed = end - start; + + if (exitCode == EXIT_SUCCESS) { + Logger::info( + "Finished", modeString(isDebug), " test(s) in ", elapsed.count(), "s" + ); + } + return exitCode; +} + +void testHelp() noexcept { + std::cout << testDesc << '\n'; + std::cout << '\n'; + printUsage("test", "[OPTIONS]"); + std::cout << '\n'; + printHeader("Options:"); + printGlobalOpts(); + printOption("--debug", "-d", "Test with debug information [default]"); + printOption("--release", "-r", "Test with optimizations"); +} diff --git a/src/Cmd/Test.hpp b/src/Cmd/Test.hpp new file mode 100644 index 000000000..2b435491d --- /dev/null +++ b/src/Cmd/Test.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "../Rustify.hpp" + +#include + +static inline constexpr StringRef testDesc = "Run the tests of a local package"; + +int testMain(std::span); +void testHelp() noexcept; diff --git a/src/Cmd/Version.cc b/src/Cmd/Version.cc new file mode 100644 index 000000000..96aaaf418 --- /dev/null +++ b/src/Cmd/Version.cc @@ -0,0 +1,31 @@ +#include "Version.hpp" + +#include "../Logger.hpp" +#include "Global.hpp" + +#include +#include + +int versionMain(std::span args) noexcept { + // Parse args + for (StringRef arg : args) { + HANDLE_GLOBAL_OPTS({{"version"}}) + + else { + Logger::error("invalid argument: ", arg); + return EXIT_FAILURE; + } + } + + std::cout << "poac " << POAC_VERSION << '\n'; + return EXIT_SUCCESS; +} + +void versionHelp() noexcept { + std::cout << versionDesc << '\n'; + std::cout << '\n'; + printUsage("version", "[OPTIONS]"); + std::cout << '\n'; + printHeader("Options:"); + printGlobalOpts(); +} diff --git a/src/Cmd/Version.hpp b/src/Cmd/Version.hpp new file mode 100644 index 000000000..0c0a7e40c --- /dev/null +++ b/src/Cmd/Version.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "../Rustify.hpp" + +#include + +#define POAC_VERSION "0.6.0" + +static inline constexpr StringRef versionDesc = "Show version information"; + +int versionMain(std::span) noexcept; +void versionHelp() noexcept; diff --git a/src/Logger.cc b/src/Logger.cc new file mode 100644 index 000000000..f131bdc79 --- /dev/null +++ b/src/Logger.cc @@ -0,0 +1,22 @@ +#include "Logger.hpp" + +Logger& Logger::instance() noexcept { + static Logger instance; + return instance; +} + +void Logger::setLevel(LogLevel level) noexcept { + instance().level = level; +} + +LogLevel Logger::getLevel() noexcept { + return instance().level; +} + +bool isVerbose() noexcept { + return Logger::getLevel() == LogLevel::debug; +} + +bool isQuiet() noexcept { + return Logger::getLevel() == LogLevel::off; +} diff --git a/src/Logger.hpp b/src/Logger.hpp new file mode 100644 index 000000000..a07365c1c --- /dev/null +++ b/src/Logger.hpp @@ -0,0 +1,106 @@ +#pragma once + +#include "Rustify.hpp" +#include "TermColor.hpp" + +#include +#include +#include + +enum class LogLevel : u8 { + off = 0, // --quiet + error = 1, + warning = 2, + info = 3, // default + debug = 4 // --verbose +}; + +class Logger { +public: + static Logger& instance() noexcept; + static void setLevel(LogLevel) noexcept; + static LogLevel getLevel() noexcept; + + template + static void error(Args&&... message) noexcept { + logln(std::cerr, LogLevel::error, std::forward(message)...); + } + template + static void warn(Args&&... message) noexcept { + logln(std::cout, LogLevel::warning, std::forward(message)...); + } + template + static void info(T&& header, Args&&... message) noexcept { + logln( + std::cout, LogLevel::info, std::forward(header), + std::forward(message)... + ); + } + template + static void debug(Args&&... message) noexcept { + logln(std::cout, LogLevel::debug, std::forward(message)...); + } + + template + static void logln( + std::ostream& os, LogLevel messageLevel, T&& header, Args&&... message + ) noexcept { + log(os, messageLevel, std::forward(header), + std::forward(message)..., '\n'); + } + template + static void + log(std::ostream& os, LogLevel messageLevel, T&& header, + Args&&... message) noexcept { + instance().logImpl( + os, messageLevel, std::forward(header), + std::forward(message)... + ); + } + + template + void logImpl( + std::ostream& os, LogLevel messageLevel, T&& header, Args&&... message + ) noexcept { + // For other than `info`, header means just the first argument. For + // `info`, header means its header. + + if (messageLevel <= level) { + switch (messageLevel) { + case LogLevel::off: + return; + case LogLevel::error: + os << bold(red("Error: ")) << std::forward(header); + break; + case LogLevel::warning: + os << bold(yellow("Warning: ")) << std::forward(header); + break; + case LogLevel::info: + if (shouldColor()) { + os << std::right << std::setw(27) + << bold(green(std::forward(header))) << ' '; + } else { + os << std::right << std::setw(12) << std::forward(header) << ' '; + } + break; + case LogLevel::debug: + os << "[Poac] " << std::forward(header); + break; + } + (os << ... << std::forward(message)); + os << std::flush; + } + } + +private: + LogLevel level = LogLevel::info; + + Logger() noexcept = default; + + // Delete copy constructor and assignment operator to prevent copying + Logger(const Logger&) = delete; + Logger& operator=(const Logger&) = delete; +}; + +bool isVerbose() noexcept; +bool isQuiet() noexcept; diff --git a/src/Manifest.cc b/src/Manifest.cc new file mode 100644 index 000000000..cae0bbfbb --- /dev/null +++ b/src/Manifest.cc @@ -0,0 +1,194 @@ +#include "Manifest.hpp" + +#include "Logger.hpp" +#include "Rustify.hpp" +#include "TermColor.hpp" + +#include +#include +#include +#include + +#define TOML11_NO_ERROR_PREFIX +#include + +class Manifest { +public: + static Manifest& instance() noexcept { + static Manifest instance; + instance.load(); + return instance; + } + + void load() { + if (data.has_value()) { + return; + } + + if (shouldColor()) { + toml::color::enable(); + } else { + toml::color::disable(); + } + + data = toml::parse("poac.toml"); + } + + Option data = None; + Option packageName = None; + Option packageEdition = None; + +private: + Manifest() noexcept = default; + + // Delete copy constructor and assignment operator to prevent copying + Manifest(const Manifest&) = delete; + Manifest& operator=(const Manifest&) = delete; +}; + +String getPackageName() { + Manifest& manifest = Manifest::instance(); + if (manifest.packageName.has_value()) { + return manifest.packageName.value(); + } + + const String packageName = + toml::find(manifest.data.value(), "package", "name"); + if (packageName.empty()) { + throw std::runtime_error("package name is empty"); + } + manifest.packageName = packageName; + return packageName; +} + +String getPackageEdition() { + Manifest& manifest = Manifest::instance(); + if (manifest.packageEdition.has_value()) { + return manifest.packageEdition.value(); + } + + const String edition = + toml::find(manifest.data.value(), "package", "edition"); + if (edition.size() == 2 && isdigit(edition[0]) && isalnum(edition[1])) { + manifest.packageEdition = edition; + return edition; + } + throw std::runtime_error("invalid edition: " + edition); +} + +u16 editionToYear(StringRef edition) { + if (edition == "98") { + return 1998; + } else if (edition == "03") { + return 2003; + } else if (edition == "0x" || edition == "11") { + return 2011; + } else if (edition == "1y" || edition == "14") { + return 2014; + } else if (edition == "1z" || edition == "17") { + return 2017; + } else if (edition == "2a" || edition == "20") { + return 2020; + } else if (edition == "2b" || edition == "23") { + return 2023; + } else if (edition == "2c") { + return 2026; + } + throw std::runtime_error("invalid edition: " + String(edition)); +} + +Vec getLintCpplintFilters() { + Manifest& manifest = Manifest::instance(); + const auto& table = toml::get(*manifest.data); + if (!table.contains("lint")) { + return {}; + } + return toml::find_or>( + *manifest.data, "lint", "cpplint", "filters", Vec{} + ); +} + +static Path getXdgCacheHome() { + if (const char* env_p = std::getenv("XDG_CACHE_HOME")) { + return env_p; + } + const Path userDir = std::getenv("HOME"); + return userDir / ".cache"; +} + +static inline const Path CACHE_DIR(getXdgCacheHome() / "poac"); +static inline const Path GIT_DIR(CACHE_DIR / "git"); +static inline const Path GIT_SRC_DIR(GIT_DIR / "src"); + +/// @brief Install git dependencies. We do not need to resolve dependencies +/// (solve the SAT problem). +/// @return paths to the source files +Vec installGitDependencies() { + Manifest& manifest = Manifest::instance(); + const auto& table = toml::get(*manifest.data); + if (!table.contains("dependencies")) { + Logger::debug("no dependencies"); + return {}; + } + const auto deps = toml::find(*manifest.data, "dependencies"); + + Vec gitDeps; + for (const auto& dep : deps) { + if (dep.second.is_table()) { + const auto& info = dep.second.as_table(); + if (info.contains("git")) { + const auto& gitUrl = info.at("git"); + if (gitUrl.is_string()) { + // rev, tag, or branch + String target = "main"; + for (const String key : {"rev", "tag", "branch"}) { + if (info.contains(key)) { + const auto& value = info.at(key); + if (value.is_string()) { + target = value.as_string(); + break; + } + } + } + + const Path installDir = GIT_SRC_DIR / (dep.first + '-' + target); + if (fs::exists(installDir) && !fs::is_empty(installDir)) { + Logger::debug(dep.first, " is already installed"); + gitDeps.push_back(installDir); + continue; + } + + const String gitUrlStr = gitUrl.as_string(); + const String gitCloneCmd = + "git clone " + gitUrlStr + " " + installDir.string(); + if (std::system((gitCloneCmd + " >/dev/null 2>&1").c_str()) + != EXIT_SUCCESS) { + throw std::runtime_error( + "failed to clone " + gitUrlStr + " to " + installDir.string() + ); + } + + const String gitResetCmd = + "git -C " + installDir.string() + " reset --hard " + target; + if (std::system((gitResetCmd + " >/dev/null 2>&1").c_str()) + != EXIT_SUCCESS) { + throw std::runtime_error( + "failed to reset " + gitUrlStr + " to " + target + ); + } + + Logger::info( + "Downloaded", dep.first, ' ', target.empty() ? gitUrlStr : target + ); + gitDeps.push_back(installDir); + continue; + } + } + } + + throw std::runtime_error( + "non-git dependency is not supported yet: " + dep.first + ); + } + return gitDeps; +} diff --git a/src/Manifest.hpp b/src/Manifest.hpp new file mode 100644 index 000000000..a4572c4e3 --- /dev/null +++ b/src/Manifest.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "Rustify.hpp" + +String getPackageName(); +String getPackageEdition(); +u16 editionToYear(StringRef); +Vec getLintCpplintFilters(); +Vec installGitDependencies(); diff --git a/src/Mod.cmake b/src/Mod.cmake deleted file mode 100644 index 31ff9fd7f..000000000 --- a/src/Mod.cmake +++ /dev/null @@ -1,453 +0,0 @@ -include_guard(GLOBAL) - -include(src/util/Mod.cmake) - -add_library(poac_config) -target_sources(poac_config - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/config.ixx -) -target_link_libraries(poac_config PRIVATE - poac_util_misc - poac_util_rustify -) - - -add_library(poac_data_manifest) -target_sources(poac_data_manifest - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/data/manifest.ixx -) -target_link_libraries(poac_data_manifest PRIVATE - poac_util_rustify - - toml11::toml11 -) - - -add_library(poac_util_registry_conan_v1_manifest) -target_sources(poac_util_registry_conan_v1_manifest - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/registry/conan/v1/manifest.ixx -) -target_link_libraries(poac_util_registry_conan_v1_manifest PRIVATE - poac_config - poac_util_format - poac_util_rustify - poac_util_result -) - - -add_library(poac_util_validator) -target_sources(poac_util_validator - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/validator.ixx -) -target_link_libraries(poac_util_validator PRIVATE - poac_config - poac_data_manifest - poac_util_format - poac_util_log - poac_util_result_macros - poac_util_result - poac_util_rustify - - toml11::toml11 - spdlog::spdlog - semver -) - - -add_library(poac_core_resolver_sat) -target_sources(poac_core_resolver_sat - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/core/resolver/sat.ixx -) -target_link_libraries(poac_core_resolver_sat PRIVATE - poac_util_format - poac_util_log - poac_util_result - poac_util_rustify -) - -add_library(poac_core_resolver_registry) -target_sources(poac_core_resolver_registry - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/core/resolver/registry.ixx -) -target_link_libraries(poac_core_resolver_registry PRIVATE - poac_util_result - poac_util_rustify -) - - -add_library(poac_core_builder_compiler_lang) -target_sources(poac_core_builder_compiler_lang - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/core/builder/compiler/lang.ixx -) -target_link_libraries(poac_core_builder_compiler_lang PRIVATE - poac_util_cfg - poac_util_format - poac_util_log - poac_util_result - poac_util_rustify - - fmt::fmt -) - -add_library(poac_core_builder_compiler_error) -target_sources(poac_core_builder_compiler_error - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/core/builder/compiler/error.ixx -) -target_link_libraries(poac_core_builder_compiler_error PRIVATE - poac_core_builder_compiler_lang - poac_util_cfg - poac_util_format - poac_util_log - poac_util_result - poac_util_rustify - - fmt::fmt - semver_token -) - -add_library(poac_core_builder_compiler_cxx_apple_clang) -target_sources(poac_core_builder_compiler_cxx_apple_clang - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/core/builder/compiler/cxx/apple_clang.ixx -) -target_link_libraries(poac_core_builder_compiler_cxx_apple_clang PRIVATE - poac_core_builder_compiler_lang - poac_core_builder_compiler_error - - poac_util_cfg - poac_util_format - poac_util_log - poac_util_result_macros - poac_util_result - poac_util_rustify - poac_util_shell - - semver -) -add_library(poac_core_builder_compiler_cxx_clang) -target_sources(poac_core_builder_compiler_cxx_clang - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/core/builder/compiler/cxx/clang.ixx -) -target_link_libraries(poac_core_builder_compiler_cxx_clang PRIVATE - poac_core_builder_compiler_lang - poac_core_builder_compiler_error - - poac_util_cfg - poac_util_format - poac_util_log - poac_util_result_macros - poac_util_result - poac_util_rustify - poac_util_shell - - semver -) -add_library(poac_core_builder_compiler_cxx_gcc) -target_sources(poac_core_builder_compiler_cxx_gcc - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/core/builder/compiler/cxx/gcc.ixx -) -target_link_libraries(poac_core_builder_compiler_cxx_gcc PRIVATE - poac_core_builder_compiler_lang - poac_core_builder_compiler_error - - poac_util_cfg - poac_util_format - poac_util_log - poac_util_result_macros - poac_util_result - poac_util_rustify - poac_util_shell - - semver -) -add_library(poac_core_builder_compiler_cxx) -target_sources(poac_core_builder_compiler_cxx - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/core/builder/compiler/cxx.ixx -) -target_link_libraries(poac_core_builder_compiler_cxx PRIVATE - poac_core_builder_compiler_cxx_apple_clang - poac_core_builder_compiler_cxx_clang - poac_core_builder_compiler_cxx_gcc - poac_core_builder_compiler_error - - poac_util_misc - poac_util_cfg - poac_util_format - poac_util_log - poac_util_result_macros - poac_util_result - poac_util_rustify - poac_util_shell -) - -add_library(poac_core_builder_data) -target_sources(poac_core_builder_data - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/core/builder/data.ixx -) -target_link_libraries(poac_core_builder_data PRIVATE - poac_util_format - poac_util_log - poac_util_result - poac_util_rustify - - spdlog::spdlog -) - - -add_library(poac_core_resolver_types) -target_sources(poac_core_resolver_types - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/core/resolver/types.ixx -) -target_link_libraries(poac_core_resolver_types PRIVATE - poac_util_result - poac_util_rustify -) - - -add_library(poac_util_net) -target_sources(poac_util_net - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/net.ixx -) -target_link_libraries(poac_util_net PRIVATE - poac_core_resolver_types - poac_util_format - poac_util_log - poac_util_meta - poac_util_misc - poac_util_pretty - poac_util_result_macros - poac_util_result - poac_util_rustify - poac_util_verbosity - - spdlog::spdlog -) - - -add_library(poac_data_lockfile) -target_sources(poac_data_lockfile - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/data/lockfile.ixx -) -target_link_libraries(poac_data_lockfile PRIVATE - poac_config - poac_core_resolver_types - poac_data_manifest - poac_util_result_macros - poac_util_result - poac_util_rustify - - toml11::toml11 -) - - -add_library(poac_util_registry_conan_v1_resolver) -target_sources(poac_util_registry_conan_v1_resolver - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/registry/conan/v1/resolver.ixx -) -target_link_libraries(poac_util_registry_conan_v1_resolver PRIVATE - poac_config - poac_core_resolver_types - poac_data_lockfile - - poac_util_file - poac_util_format - poac_util_log - poac_util_rustify - poac_util_result_macros - poac_util_result - poac_util_shell -) - - -add_library(poac_core_resolver_resolve) -target_sources(poac_core_resolver_resolve - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/core/resolver/resolve.ixx -) -target_link_libraries(poac_core_resolver_resolve PRIVATE - poac_core_resolver_sat - poac_core_resolver_types - - poac_util_format - poac_util_log - poac_util_meta - poac_util_net - poac_util_registry_conan_v1_resolver - poac_util_result_macros - poac_util_result - poac_util_rustify - poac_util_verbosity - - semver -) - - -add_library(poac_core_resolver) -target_sources(poac_core_resolver - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/core/resolver.ixx -) -target_link_libraries(poac_core_resolver PRIVATE - poac_config - - poac_core_resolver_resolve - poac_core_resolver_types - poac_core_resolver_registry - - poac_data_manifest - poac_data_lockfile - - poac_util_archive - poac_util_file - poac_util_format - poac_util_log - poac_util_meta - poac_util_net - poac_util_registry_conan_v1_resolver - poac_util_result_macros - poac_util_result - poac_util_rustify - poac_util_sha256 - poac_util_shell - - toml11::toml11 - spdlog::spdlog -) - - -add_library(poac_core_builder_log) -target_sources(poac_core_builder_log - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/core/builder/log.ixx -) -target_link_libraries(poac_core_builder_log PRIVATE - poac_core_builder_data - poac_util_format - poac_util_log - poac_util_result - poac_util_rustify - - spdlog::spdlog -) - -add_library(poac_core_builder_syntax) -target_sources(poac_core_builder_syntax - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/core/builder/syntax.ixx -) -target_link_libraries(poac_core_builder_syntax PRIVATE - poac_util_format - poac_util_log - poac_util_pretty - poac_util_result - poac_util_rustify -) - -add_library(poac_core_builder_manifest) -target_sources(poac_core_builder_manifest - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/core/builder/manifest.ixx -) -target_link_libraries(poac_core_builder_manifest PRIVATE - poac_core_builder_data - poac_core_builder_compiler_cxx - poac_core_builder_syntax - poac_core_resolver - - poac_util_cfg - poac_util_format - poac_util_log - poac_util_registry_conan_v1_manifest - poac_util_result_macros - poac_util_result - poac_util_rustify - - toml11::toml11 -) - -add_library(poac_core_builder_build) -target_sources(poac_core_builder_build - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/core/builder/build.ixx -) -target_link_libraries(poac_core_builder_build PRIVATE - poac_config - poac_core_builder_data - poac_core_builder_log - poac_core_builder_manifest - poac_core_resolver_types - - poac_util_format - poac_util_log - poac_util_result_macros - poac_util_result - poac_util_rustify - poac_util_verbosity - - spdlog::spdlog - toml11::toml11 - termcolor2 - termcolor2_literals_extra -) - - -include(src/cmd/Mod.cmake) - -add_library(poac_cmd) -target_sources(poac_cmd - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/cmd.ixx -) -target_link_libraries(poac_cmd PRIVATE - poac_cmd_build - poac_cmd_clean - poac_cmd_create - poac_cmd_fmt - poac_cmd_graph - poac_cmd_init - poac_cmd_lint - poac_cmd_login - poac_cmd_publish - poac_cmd_run - poac_cmd_search -) diff --git a/src/util/rustify.ixx b/src/Rustify.hpp similarity index 53% rename from src/util/rustify.ixx rename to src/Rustify.hpp index 30f53c311..02a8b1e81 100644 --- a/src/util/rustify.ixx +++ b/src/Rustify.hpp @@ -1,36 +1,24 @@ -module; +#pragma once -// std #include -#include // std::size_t #include #include -#include // std::begin, std::end +#include #include #include +#include #include #include -#include +#include #include #include -#include // std::monostate +#include #include -// external -#include - -export module poac.util.rustify; - -export namespace poac { - -// -// Namespaces -// namespace fs = std::filesystem; +using namespace std::literals::string_literals; +using namespace std::literals::string_view_literals; -// -// Data types -// // NOLINTBEGIN(readability-identifier-naming) using u8 = std::uint8_t; using u16 = std::uint16_t; @@ -50,8 +38,6 @@ using f64 = double; using String = std::string; using StringRef = std::string_view; -// static_assert(String::npos == StringRef::npos, "npos should be the same"); - using Path = fs::path; template @@ -59,16 +45,34 @@ using Arr = std::array; template using Vec = std::vector; +template +using Map = std::map; +template +using HashMap = std::unordered_map; + +template +using Set = std::set; +template +using HashSet = std::unordered_set; + +template +using Fn = std::function; + template using Option = std::optional; +template +using Tuple = std::tuple; + struct NoneT : protected std::monostate { constexpr auto operator==(const usize rhs) const -> bool { return String::npos == rhs; } // NOLINTNEXTLINE(google-explicit-constructor) - constexpr operator std::nullopt_t() const { return std::nullopt; } + constexpr operator std::nullopt_t() const { + return std::nullopt; + } template constexpr operator Option() const { // NOLINT(google-explicit-constructor) @@ -77,39 +81,6 @@ struct NoneT : protected std::monostate { }; inline constexpr NoneT None; // NOLINT(readability-identifier-naming) -template -using Map = std::map; -template > -using HashMap = std::unordered_map; - -template -using HashSet = std::unordered_set>; - -// -// String literals -// -// using namespace std::literals::string_literals; -// using namespace std::literals::string_view_literals; - inline auto operator""_path(const char* str, usize /*unused*/) -> Path { return str; } - -// -// Utilities -// -template -inline void append(Vec& a, const Vec& b) { - a.insert(a.end(), b.cbegin(), b.cend()); -} -template -inline void append(HashMap& a, const HashMap& b) { - a.insert(b.cbegin(), b.cend()); -} - -template -constexpr auto contains(const Arr& a, const U& b) -> bool { - return std::find(std::begin(a), std::end(a), b) != std::end(a); -} - -} // namespace poac diff --git a/src/TermColor.cc b/src/TermColor.cc new file mode 100644 index 000000000..717c1e395 --- /dev/null +++ b/src/TermColor.cc @@ -0,0 +1,81 @@ +#include "TermColor.hpp" + +static bool isTerm() noexcept { + return std::getenv("TERM") != nullptr; +} + +class ColorState { +public: + void set(ColorMode mode) noexcept { + switch (mode) { + case ColorMode::always: + should_color_ = true; + return; + case ColorMode::automatic: + should_color_ = isTerm(); + return; + case ColorMode::never: + should_color_ = false; + return; + } + } + inline bool shouldColor() const noexcept { + return should_color_; + } + + static ColorState& instance() noexcept { + static ColorState instance; + return instance; + } + +private: + // default: automatic + bool should_color_ = isTerm(); + + ColorState() noexcept = default; + + // Delete copy constructor and assignment operator to prevent copying + ColorState(const ColorState&) = delete; + ColorState& operator=(const ColorState&) = delete; +}; + +void setColorMode(ColorMode cm) noexcept { + ColorState::instance().set(cm); +} + +bool shouldColor() noexcept { + return ColorState::instance().shouldColor(); +} + +static String colorize(StringRef str, StringRef color) noexcept { + if (!shouldColor()) { + return String(str); + } + return String(color) + String(str) + "\033[0m"; +} + +String gray(StringRef str) noexcept { + return colorize(str, "\033[30m"); +} +String red(StringRef str) noexcept { + return colorize(str, "\033[31m"); +} +String green(StringRef str) noexcept { + return colorize(str, "\033[32m"); +} +String yellow(StringRef str) noexcept { + return colorize(str, "\033[33m"); +} +String blue(StringRef str) noexcept { + return colorize(str, "\033[34m"); +} +String magenta(StringRef str) noexcept { + return colorize(str, "\033[35m"); +} +String cyan(StringRef str) noexcept { + return colorize(str, "\033[36m"); +} + +String bold(StringRef str) noexcept { + return colorize(str, "\033[1m"); +} diff --git a/src/TermColor.hpp b/src/TermColor.hpp new file mode 100644 index 000000000..0fb35a2c3 --- /dev/null +++ b/src/TermColor.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "Rustify.hpp" + +enum class ColorMode { + always, + automatic, + never, +}; + +void setColorMode(ColorMode) noexcept; +bool shouldColor() noexcept; + +String gray(StringRef) noexcept; +String red(StringRef) noexcept; +String green(StringRef) noexcept; +String yellow(StringRef) noexcept; +String blue(StringRef) noexcept; +String magenta(StringRef) noexcept; +String cyan(StringRef) noexcept; + +String bold(StringRef) noexcept; diff --git a/src/cmd.ixx b/src/cmd.ixx deleted file mode 100644 index 2493476e3..000000000 --- a/src/cmd.ixx +++ /dev/null @@ -1,13 +0,0 @@ -export module poac.cmd; - -export import poac.cmd.build; -export import poac.cmd.clean; -export import poac.cmd.create; -export import poac.cmd.fmt; -export import poac.cmd.graph; -export import poac.cmd.init; -export import poac.cmd.lint; -export import poac.cmd.login; -export import poac.cmd.publish; -export import poac.cmd.run; -export import poac.cmd.search; diff --git a/src/cmd/Mod.cmake b/src/cmd/Mod.cmake deleted file mode 100644 index b4bbb0d46..000000000 --- a/src/cmd/Mod.cmake +++ /dev/null @@ -1,249 +0,0 @@ -include_guard(GLOBAL) - -add_library(poac_cmd_build) -target_sources(poac_cmd_build - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/cmd/build.ixx -) -target_link_libraries(poac_cmd_build PRIVATE - poac_config - poac_core_builder_build - poac_core_resolver_types - poac_core_resolver - poac_data_manifest - - poac_util_log - poac_util_pretty - poac_util_result_macros - poac_util_result - poac_util_rustify - poac_util_validator - - structopt::structopt - toml11::toml11 - spdlog::spdlog -) - -add_library(poac_cmd_clean) -target_sources(poac_cmd_clean - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/cmd/clean.ixx -) -target_link_libraries(poac_cmd_clean PRIVATE - poac_config - poac_cmd_build - poac_data_manifest - - poac_util_format - poac_util_log - poac_util_result_macros - poac_util_result - poac_util_rustify - poac_util_validator - - structopt::structopt - spdlog::spdlog -) - -add_library(poac_cmd_create) -target_sources(poac_cmd_create - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/cmd/create.ixx -) -target_link_libraries(poac_cmd_create PRIVATE - poac_config - poac_data_manifest - poac_util_format - poac_util_log - poac_util_result_macros - poac_util_result - poac_util_rustify - poac_util_validator - - structopt::structopt - spdlog::spdlog - git2-cpp::git2-cpp -) - -add_library(poac_cmd_fmt) -target_sources(poac_cmd_fmt - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/cmd/fmt.ixx -) -target_link_libraries(poac_cmd_fmt PRIVATE - poac_config - poac_util_format - poac_util_log - poac_util_result_macros - poac_util_result - poac_util_rustify - poac_util_shell - poac_util_validator - poac_util_verbosity - - structopt::structopt - spdlog::spdlog - Glob - toml11::toml11 -) - -add_library(poac_cmd_graph) -target_sources(poac_cmd_graph - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/cmd/graph.ixx -) -target_link_libraries(poac_cmd_graph PRIVATE - poac_config - poac_cmd_build - poac_core_resolver_types - poac_core_resolver - poac_data_manifest - - poac_util_format - poac_util_log - poac_util_result_macros - poac_util_result - poac_util_rustify - poac_util_shell - - structopt::structopt - spdlog::spdlog - toml11::toml11 -) - -add_library(poac_cmd_init) -target_sources(poac_cmd_init - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/cmd/init.ixx -) -target_link_libraries(poac_cmd_init PRIVATE - poac_config - poac_cmd_create - poac_data_manifest - poac_util_format - poac_util_log - poac_util_result_macros - poac_util_result - poac_util_rustify - poac_util_validator - - structopt::structopt - spdlog::spdlog -) - -add_library(poac_cmd_lint) -target_sources(poac_cmd_lint - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/cmd/lint.ixx -) -target_link_libraries(poac_cmd_lint PRIVATE - poac_config - poac_cmd_fmt - poac_data_manifest - - poac_util_format - poac_util_log - poac_util_result_macros - poac_util_result - poac_util_rustify - poac_util_shell - poac_util_validator - poac_util_verbosity - - structopt::structopt - spdlog::spdlog - toml11::toml11 -) - -add_library(poac_cmd_login) -target_sources(poac_cmd_login - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/cmd/login.ixx -) -target_link_libraries(poac_cmd_login PRIVATE - poac_config - poac_util_format - poac_util_log - poac_util_net - poac_util_result_macros - poac_util_result - poac_util_rustify - - structopt::structopt - spdlog::spdlog -) - -add_library(poac_cmd_publish) -target_sources(poac_cmd_publish - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/cmd/publish.ixx -) -target_link_libraries(poac_cmd_publish PRIVATE - poac_config - poac_cmd_build - poac_cmd_login - poac_data_manifest - - poac_util_format - poac_util_log - poac_util_result_macros - poac_util_result - poac_util_rustify - poac_util_validator - - structopt::structopt - spdlog::spdlog - toml11::toml11 -) - -add_library(poac_cmd_run) -target_sources(poac_cmd_run - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/cmd/run.ixx -) -target_link_libraries(poac_cmd_run PRIVATE - poac_cmd_build - poac_data_manifest - - poac_util_format - poac_util_log - poac_util_result_macros - poac_util_result - poac_util_rustify - poac_util_shell - poac_util_validator - - structopt::structopt - spdlog::spdlog - toml11::toml11 -) - -add_library(poac_cmd_search) -target_sources(poac_cmd_search - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/cmd/search.ixx -) -target_link_libraries(poac_cmd_search PRIVATE - poac_util_format - poac_util_log - poac_util_net - poac_util_pretty - poac_util_result_macros - poac_util_result - poac_util_rustify - poac_util_verbosity - - structopt::structopt - spdlog::spdlog -) diff --git a/src/cmd/build.ixx b/src/cmd/build.ixx deleted file mode 100644 index 52cc8b9dc..000000000 --- a/src/cmd/build.ixx +++ /dev/null @@ -1,101 +0,0 @@ -module; - -// external -#include // NOLINT(build/include_order) -#include // NOLINT(build/include_order) -#include -#include - -// internal -#include "../util/result-macros.hpp" - -export module poac.cmd.build; - -import poac.config; -import poac.core.builder.build; -import poac.core.resolver.types; // ResolvedDeps -import poac.core.resolver; // install_deps -import poac.data.manifest; -import poac.util.log; -import poac.util.pretty; // to_time -import poac.util.result; -import poac.util.rustify; -import poac.util.validator; - -namespace poac::cmd::build { - -using core::builder::build::Mode; -using core::resolver::ResolvedDeps; - -export struct Options : structopt::sub_command { - /// Build artifacts in release mode, with optimizations - Option release = false; - /// Build artifacts with the specified profile - Option profile; -}; - -export using FailedToBuild = Error<"failed to build package `{}`", String>; -export using FailedToInstallDeps = Error<"failed to install dependencies">; -export using UnsupportedProfile = Error<"unsupported profile `{}`", String>; - -[[nodiscard]] auto build_impl( - const toml::value& manifest, const Mode& mode, - const ResolvedDeps& resolved_deps -) -> Result { - const spdlog::stopwatch sw; - const Path output_path = - Try(core::builder::build::start(manifest, mode, resolved_deps)); - - log::status( - "Finished", "{} target(s) in {}", to_string(mode), - util::pretty::to_time(sw.elapsed().count()) - ); - return Ok(output_path); -} - -export [[nodiscard]] auto -build(const Options& opts, const toml::value& manifest) - -> Result> { - const auto resolved_deps = - Try(core::resolver::install_deps(manifest).with_context([] { - return Err().get(); - })); - - // TODO(ken-matsui): We have to keep in mind a case of only dependencies - // require to be built, but this package does not. - if (!fs::exists(config::main_cpp_file)) { - log::status("Finished", "no build target(s) found"); - return Ok(None); - } - - const auto profile = - Try(util::validator::valid_profile(opts.profile, opts.release) - .map_err(to_anyhow)) - .value_or("debug"); - if (profile != "debug" && profile != "release") { - return Err(profile); - } - - const Mode mode = profile == "release" ? Mode::release : Mode::debug; - const Path output_path = Try(build_impl(manifest, mode, resolved_deps)); - return Ok(output_path); -} - -export [[nodiscard]] auto exec(const Options& opts) -> Result { - spdlog::trace("Checking if required config exists ..."); - Try(util::validator::required_config_exists().map_err(to_anyhow)); - - spdlog::trace("Parsing the manifest file ..."); - // TODO(ken-matsui): parse as a static type rather than toml::value - const toml::value manifest = toml::parse(data::manifest::NAME); - - Try(build(opts, manifest).with_context([&manifest] { - return Err(toml::find(manifest, "package", "name")) - .get(); - })); - return Ok(); -} - -} // namespace poac::cmd::build - -STRUCTOPT(poac::cmd::build::Options, release, profile); diff --git a/src/cmd/clean.ixx b/src/cmd/clean.ixx deleted file mode 100644 index 08af2d3eb..000000000 --- a/src/cmd/clean.ixx +++ /dev/null @@ -1,65 +0,0 @@ -module; - -// std -#include - -// external -#include // NOLINT(build/include_order) -#include - -// internal -#include "../util/result-macros.hpp" - -export module poac.cmd.clean; - -// internal -import poac.config; -import poac.cmd.build; -import poac.data.manifest; -import poac.util.format; -import poac.util.log; -import poac.util.result; -import poac.util.rustify; -import poac.util.validator; - -namespace poac::cmd::clean { - -export struct Options : structopt::sub_command { - /// Whether or not to clean release artifacts - Option release = false; - /// Clean artifacts of the specified profile - Option profile; -}; - -[[nodiscard]] auto clean(const Options& opts) -> Result { - const Option profile = - Try(util::validator::valid_profile(opts.profile, opts.release) - .map_err(to_anyhow)); - if (profile.has_value() && profile.value() != "debug" - && profile.value() != "release") { - return Err(profile.value()); - } - - const Path path = - profile.has_value() ? config::out_dir / profile.value() : config::out_dir; - - spdlog::trace("Removing ./{}", path); - - if (fs::exists(path)) { - log::status("Removing", fs::canonical(path).string()); - fs::remove_all(path); - } - - return Ok(); -} - -export [[nodiscard]] auto exec(const Options& opts) -> Result { - spdlog::trace("Checking if required config exists ..."); - Try(util::validator::required_config_exists().map_err(to_anyhow)); - - return clean(opts); -} - -} // namespace poac::cmd::clean - -STRUCTOPT(poac::cmd::clean::Options, release, profile); diff --git a/src/cmd/create.ixx b/src/cmd/create.ixx deleted file mode 100644 index 5d05128c8..000000000 --- a/src/cmd/create.ixx +++ /dev/null @@ -1,168 +0,0 @@ -module; - -// std -#include // transform -#include -#include -#include - -// external -#include -#include // NOLINT(build/include_order) -#include - -// internal -#include "../util/result-macros.hpp" - -export module poac.cmd.create; - -import poac.config; -import poac.data.manifest; -import poac.util.format; -import poac.util.log; -import poac.util.result; -import poac.util.rustify; -import poac.util.validator; - -namespace poac::cmd::create { - -export struct Options : structopt::sub_command { - /// Package name to create a new poac package - String package_name; - - /// Use a binary (application) template [default] - Option bin = false; - /// Use a library template - Option lib = false; -}; - -export using PassingBothBinAndLib = - Error<"cannot specify both lib and binary outputs">; - -export enum class ProjectType { - Bin, - Lib, -}; - -export auto to_string(ProjectType kind) -> String { - switch (kind) { - case ProjectType::Bin: - return "binary (application)"; - case ProjectType::Lib: - return "library"; - default: - __builtin_unreachable(); - } -} - -inline auto operator<<(std::ostream& os, ProjectType kind) -> std::ostream& { - return (os << to_string(kind)); -} - -export template -auto opts_to_project_type(T&& opts) -> ProjectType { - opts.bin.value(); // Just check if opts has a `.bin` member - return opts.lib.value() ? ProjectType::Lib : ProjectType::Bin; -} - -namespace files { - export inline auto poac_toml(StringRef project_name) -> String { - return format( - "[package]\n" - "name = \"{}\"\n" - "version = \"0.1.0\"\n" - "authors = []\n" - "edition = 2020\n", - project_name - ); - } - - inline constexpr StringRef MAIN_CPP = - "#include \n\n" - "int main(int argc, char** argv) {\n" - " std::cout << \"Hello, world!\" << std::endl;\n" - "}\n"; - - inline auto include_hpp(StringRef project_name) -> String { - String project_name_upper_cased{}; - std::transform( - project_name.cbegin(), project_name.cend(), - std::back_inserter(project_name_upper_cased), ::toupper - ); - - return format( - "#ifndef {0}_HPP\n" - "#define {0}_HPP\n\n" - "namespace {1} {{\n}}\n\n" - "#endif // !{0}_HPP\n", - project_name_upper_cased, project_name - ); - } -} // namespace files - -void write_to_file(std::ofstream& ofs, const String& fname, StringRef text) { - ofs.open(fname); - if (ofs.is_open()) { - ofs << text; - } - ofs.close(); - ofs.clear(); -} - -auto create_template_files(const ProjectType& type, const String& package_name) - -> Map { - switch (type) { - case ProjectType::Bin: - fs::create_directories(package_name / "src"_path); - return { - {".gitignore", format("/{}", config::POAC_OUT)}, - {data::manifest::NAME, files::poac_toml(package_name)}, - {"src"_path / "main.cpp", String(files::MAIN_CPP)}}; - case ProjectType::Lib: - fs::create_directories(package_name / "include"_path / package_name); - return { - {".gitignore", format("/{}\npoac.lock", config::POAC_OUT)}, - {data::manifest::NAME, files::poac_toml(package_name)}, - {"include"_path / package_name / (package_name + ".hpp"), - files::include_hpp(package_name)}, - }; - default: - __builtin_unreachable(); - } -} - -[[nodiscard]] auto create(const Options& opts) -> Result { - std::ofstream ofs; - const ProjectType type = opts_to_project_type(opts); - for (auto&& [name, text] : create_template_files(type, opts.package_name)) { - const String& file_path = (opts.package_name / name).string(); - spdlog::trace("Creating {}", file_path); - write_to_file(ofs, file_path, text); - } - - spdlog::trace("Initializing git repository at {}", opts.package_name); - git2::repository().init(opts.package_name); - - log::status("Created", "{} `{}` package", to_string(type), opts.package_name); - return Ok(); -} - -export [[nodiscard]] auto exec(const Options& opts) -> Result { - if (opts.bin.value() && opts.lib.value()) { - return Err(); - } - - namespace validator = util::validator; - - spdlog::trace("Validating the `{}` directory exists", opts.package_name); - Try(validator::can_create_directory(opts.package_name).map_err(to_anyhow)); - - spdlog::trace("Validating the package name `{}`", opts.package_name); - Try(validator::valid_package_name(opts.package_name).map_err(to_anyhow)); - - return create(opts); -} - -} // namespace poac::cmd::create - -STRUCTOPT(poac::cmd::create::Options, package_name, bin, lib); diff --git a/src/cmd/fmt.ixx b/src/cmd/fmt.ixx deleted file mode 100644 index c1fa852a5..000000000 --- a/src/cmd/fmt.ixx +++ /dev/null @@ -1,122 +0,0 @@ -module; - -// external -#include // NOLINT(build/include_order) -#include // NOLINT(build/include_order) -#include -#include - -// internal -#include "../util/result-macros.hpp" - -export module poac.cmd.fmt; - -import poac.config; -import poac.util.format; -import poac.util.log; -import poac.util.result; -import poac.util.rustify; -import poac.util.verbosity; -import poac.util.shell; -import poac.util.validator; - -namespace poac::cmd::fmt { - -export struct Options : structopt::sub_command { - /// Perform only checks - Option check = false; -}; - -using ClangFormatNotFound = Error< - "`fmt` command requires `clang-format`; try installing it by:\n" - " apt/brew install clang-format">; - -inline constexpr Arr EXTENSIONS{"c", "c++", "cc", "cpp", "cu", - "cuh", "cxx", "h", "h++", "hh", - "hpp", "hxx", "ixx", "cppm"}; -inline constexpr Arr PATTERNS{"{}/*.{}", "{}/**/*.{}"}; - -export inline constexpr Arr EXCLUDES{ - config::POAC_OUT, "build", "cmake-build-debug" // CLion -}; - -void fmt_impl(const Path& base_dir, Vec& targets) { - for (const auto& entry : fs::directory_iterator(base_dir)) { - if (entry.is_directory()) { - const String d = entry.path().filename().string(); - if (!d.starts_with('.') && !contains(EXCLUDES, d)) { - for (const StringRef e : EXTENSIONS) { - for (const StringRef p : PATTERNS) { - const String search = - format(::fmt::runtime((base_dir / p).string()), d, e); - const Vec search_glob = glob::rglob(search); - if (search_glob.empty()) { - spdlog::trace("Glob `{}` not found; skipping ...", search); - continue; - } - spdlog::trace("Glob `{}` found!", search); - append(targets, search_glob); - } - } - } - } - } -} - -[[nodiscard]] auto fmt(const Path& base_dir, StringRef args) -> Result { - Vec targets; - fmt_impl(base_dir, targets); - if (targets.empty()) { - spdlog::info("no targets found."); - return Ok(); - } - - const String clang_format = format( - "cd {} && clang-format {} {}", base_dir.string(), args, - ::fmt::join(targets, " ") - ); - spdlog::trace("Executing `{}`", clang_format); - if (const i32 code = util::shell::Cmd(clang_format).exec_no_capture(); - code != 0) { - spdlog::info(""); - return Err("clang-format", code); - } - return Ok(); -} - -export [[nodiscard]] auto exec(const Options& opts) -> Result { - spdlog::trace("Checking if `clang-format` command exists ..."); - if (!util::shell::has_command("clang-format")) { - return Err(); - } - - spdlog::trace("Checking if required config exists ..."); - const Path manifest_path = - Try(util::validator::required_config_exists().map_err(to_anyhow)); - - spdlog::trace("Parsing the manifest file: {} ...", manifest_path); - // TODO(ken-matsui): parse as a static type rather than toml::value - const toml::value manifest = - toml::parse(relative(manifest_path, config::cwd)); - String name = toml::find(manifest, "package", "name"); - if (name.empty()) { - log::warn("project name is empty; try setting anything you want."); - name = ""; - } - - String args = "--style=file --fallback-style=LLVM -Werror "; - if (util::verbosity::is_verbose()) { - args += "--verbose "; - } - if (opts.check.value()) { - args += "--dry-run"; - } else { - args += "-i"; - log::status("Formatting", name); - } - return fmt(manifest_path.parent_path(), args); -} - -} // namespace poac::cmd::fmt - -STRUCTOPT(poac::cmd::fmt::Options, check); diff --git a/src/cmd/init.ixx b/src/cmd/init.ixx deleted file mode 100644 index 2f3db596d..000000000 --- a/src/cmd/init.ixx +++ /dev/null @@ -1,66 +0,0 @@ -module; - -// std -#include -#include - -// external -#include // NOLINT(build/include_order) -#include - -// internal -#include "../util/result-macros.hpp" - -export module poac.cmd.init; - -import poac.cmd.create; -import poac.config; -import poac.data.manifest; -import poac.util.format; -import poac.util.log; -import poac.util.result; -import poac.util.rustify; -import poac.util.validator; - -namespace poac::cmd::init { - -export struct Options : structopt::sub_command { - /// Use a binary (application) template [default] - Option bin = false; - /// Use a library template - Option lib = false; -}; - -using AlreadyInitialized = Error<"cannot initialize an existing poac package">; - -[[nodiscard]] auto init(const Options& opts, StringRef package_name) - -> Result { - using create::ProjectType; - - spdlog::trace("Creating ./{}", data::manifest::NAME); - std::ofstream ofs_config(data::manifest::NAME); - - const ProjectType type = create::opts_to_project_type(opts); - ofs_config << create::files::poac_toml(package_name); - - log::status("Created", "{} `{}` package", to_string(type), package_name); - return Ok(); -} - -export [[nodiscard]] auto exec(const Options& opts) -> Result { - if (opts.bin.value() && opts.lib.value()) { - return Err(); - } else if (util::validator::required_config_exists(false).is_ok()) { - return Err(); - } - - const String package_name = config::cwd.stem().string(); - spdlog::trace("Validating the package name `{}`", package_name); - Try(util::validator::valid_package_name(package_name).map_err(to_anyhow)); - - return init(opts, package_name); -} - -} // namespace poac::cmd::init - -STRUCTOPT(poac::cmd::init::Options, bin, lib); diff --git a/src/cmd/lint.ixx b/src/cmd/lint.ixx deleted file mode 100644 index 032fc6178..000000000 --- a/src/cmd/lint.ixx +++ /dev/null @@ -1,116 +0,0 @@ -module; - -// std -#include - -// external -#include -#include // NOLINT(build/include_order) -#include -#include - -// internal -#include "../util/result-macros.hpp" - -export module poac.cmd.lint; - -import poac.config; -import poac.cmd.fmt; -import poac.data.manifest; -import poac.util.format; -import poac.util.log; -import poac.util.result; -import poac.util.rustify; -import poac.util.shell; -import poac.util.validator; -import poac.util.verbosity; - -namespace poac::cmd::lint { - -export struct Options : structopt::sub_command { - // Dummy option: DO NOT USE - Option dummy = false; - // FIXME(ken-matsui): this is structopt limitation; I'd remove this. -}; - -inline constexpr StringRef CONFIG_NAME = "CPPLINT.cfg"; - -using CppLintNotFound = Error< - "`lint` command requires `cpplint`; try:\n" - " pip install cpplint">; - -[[nodiscard]] auto -lint(StringRef name, const Path& base_dir, Option args) - -> Result { - log::status("Linting", name); - - String cpplint = format("cd {} && cpplint ", base_dir.string()); - if (!args.has_value()) { - spdlog::trace("Using cpplint config file: {} ...", base_dir / CONFIG_NAME); - } else { - spdlog::trace("Using pre-configured arguments ..."); - cpplint += format("{} ", args.value()); - } - if (!util::verbosity::is_verbose()) { - cpplint += "--quiet "; - } - cpplint += format("--exclude={} --recursive .", config::POAC_OUT); - - spdlog::trace("Executing `{}`", cpplint); - if (const i32 code = util::shell::Cmd(cpplint).exec_no_capture(); code != 0) { - spdlog::info(""); - return Err("cpplint", code); - } - return Ok(); -} - -export [[nodiscard]] auto exec([[maybe_unused]] const Options& opts) - -> Result { - spdlog::trace("Checking if `cpplint` command exists ..."); - if (!util::shell::has_command("cpplint")) { - return Err(); - } - - spdlog::trace("Checking if required config exists ..."); - const Path manifest_path = - Try(util::validator::required_config_exists().map_err(to_anyhow)); - const Path base_dir = manifest_path.parent_path(); - - spdlog::trace("Parsing the manifest file: {} ...", manifest_path); - // TODO(ken-matsui): parse as a static type rather than toml::value - const toml::value manifest = - toml::parse(relative(manifest_path, config::cwd)); - const String name = toml::find(manifest, "package", "name"); - const auto filters = toml::find_or>( - manifest, "lint", "cpplint", "filters", Vec{} - ); - if (!filters.empty()) { - spdlog::trace("Using Poac manifest file for lint ..."); - String args = "--root=include "; - for (const StringRef d : fmt::EXCLUDES) { - args += format("--exclude={} ", d); - } - args += "--filter=" + boost::join(filters, ","); - return lint(name, base_dir, args); - } - - const Path config_path = base_dir / CONFIG_NAME; - spdlog::trace("Checking if cpplint config exists: {} ...", config_path); - if (fs::exists(config_path)) { - spdlog::trace("Using cpplint config file: {} ...", config_path); - return lint(name, base_dir, None); - } - - String args; - if (fs::exists(config::include_dir)) { - args += "--root=include "; - } - if (2011 < toml::find(manifest, "package", "edition")) { - args += "--filter=-build/c++11 "; - } - return lint(name, base_dir, args); -} - -} // namespace poac::cmd::lint - -STRUCTOPT(poac::cmd::lint::Options, dummy); diff --git a/src/cmd/login.ixx b/src/cmd/login.ixx deleted file mode 100644 index 964216e2a..000000000 --- a/src/cmd/login.ixx +++ /dev/null @@ -1,59 +0,0 @@ -module; - -// std -#include - -// external -#include // NOLINT(build/include_order) -#include - -// internal -#include "../util/result-macros.hpp" - -export module poac.cmd.login; - -import poac.config; -import poac.util.format; -import poac.util.log; -import poac.util.net; -import poac.util.result; -import poac.util.rustify; - -namespace poac::cmd::login { - -export struct Options : structopt::sub_command { - /// API Token obtained on poac.dev - String api_token; -}; - -using InvalidAPIToken = Error<"invalid API token provided">; -using FailedToLogIn = Error<"failed to log in; API token might be incorrect">; - -export [[nodiscard]] auto check_token(StringRef api_token) -> Result { - spdlog::trace("Checking if api_token has 32 length"); - if (api_token.size() != 32) { - return Err(); - } - // TODO(ken-matsui): Implement login API - // spdlog::trace("Checking if api_token exists"); - // if (!util::net::api::login(api_token).unwrap_or(false)) { - // return Err(); - // } - return Ok(); -} - -export [[nodiscard]] auto exec(const Options& opts) -> Result { - Try(check_token(opts.api_token)); - - // Write API Token to `~/.poac/credentials` as TOML - spdlog::trace("Exporting the api_token to `{}`", config::cred_file); - std::ofstream ofs(config::cred_file, std::ofstream::trunc); - ofs << format("[registry]\ntoken = \"{}\"\n", opts.api_token); - - log::status("Login", "token for `{}` saved", "poac.dev"); - return Ok(); -} - -} // namespace poac::cmd::login - -STRUCTOPT(poac::cmd::login::Options, api_token); diff --git a/src/cmd/publish.ixx b/src/cmd/publish.ixx deleted file mode 100644 index 5547e70e7..000000000 --- a/src/cmd/publish.ixx +++ /dev/null @@ -1,120 +0,0 @@ -module; - -// std -#include -#include - -// external -#include // NOLINT(build/include_order) -#include -#include - -// internal -#include "../util/result-macros.hpp" - -export module poac.cmd.publish; - -import poac.config; -import poac.cmd.build; -import poac.cmd.login; -import poac.data.manifest; -import poac.util.format; -import poac.util.log; -import poac.util.result; -import poac.util.rustify; -import poac.util.validator; - -namespace poac::cmd::publish { - -export struct Options : structopt::sub_command { - /// API Token obtained on poac.dev - Option token; - - /// Perform all checks without uploading - Option dry_run = false; - - /// Allow dirty working directories to be packaged - Option allow_dirty = false; -}; - -using APITokenNotFound = Error< - "API token not found; please provide it through `--token " - "$YOUR_TOKEN` or `poac login $YOUR_TOKEN`. If you do not have " - "it yet, try signing up into poac.dev and generate a token at:\n" - " https://poac.dev/settings/tokens">; -using FailedToReadCred = Error< - "failed to read credentials from {0}; do not edit it manually " - "and use the `poac login` command.", - Path>; -using FailedToReadManifest = Error< - "failed to read a manifest file ({0}) for this package. Make " - "sure to the current directory was set up using Poac.", - Path>; - -using NotImplemented = Error< - "failed to publish; `publish` command is currently under development">; - -[[nodiscard]] auto get_manifest() -> Result { - spdlog::trace("Checking if required config exists ..."); - Try(util::validator::required_config_exists().map_err(to_anyhow)); - - spdlog::trace("Parsing the manifest file ..."); - // TODO(ken-matsui): parse as a static type rather than toml::value - return Ok(toml::parse(data::manifest::NAME)); -} - -[[nodiscard]] auto get_token(const Options& opts) -> Result { - if (opts.token.has_value()) { - Try(login::check_token(opts.token.value())); - return Ok(opts.token.value()); - } else { - // Retrieve a token from `~/.poac/credentials` - if (!fs::exists(config::cred_file)) { - return Err(); - } - - const toml::value cred = toml::parse(config::cred_file); - if (!cred.contains("registry")) { - return Err(config::cred_file); - } - const String token = toml::find(cred, "registry", "token"); - Try(login::check_token(token)); - return Ok(token); - } -} - -export [[nodiscard]] auto exec(const Options& opts) -> Result { - const String token = Try(get_token(opts)); - const toml::value manifest = Try(get_manifest()); - const data::manifest::PartialPackage package = - Try(util::validator::valid_manifest(manifest).map_err(to_anyhow)); - - // if readme is specified, readme exists (and read it) - - // if (allow-dirty is false) - // no changes from HEAD - // no changes from tag (using clone?) - - // The `repository` key should be installable - - // Check if all dependencies are using Poac's registry - // (to prevent unintentional errors) - - // Check buildablity - Try(cmd::build::build(cmd::build::Options{.release = true}, manifest) - .with_context([&manifest] { - return Err( - toml::find(manifest, "package", "name") - ) - .get(); - })); - - // download tar.gz and get hash - // Run publish - - return Err(); -} - -} // namespace poac::cmd::publish - -STRUCTOPT(poac::cmd::publish::Options, token, dry_run, allow_dirty); diff --git a/src/cmd/run.ixx b/src/cmd/run.ixx deleted file mode 100644 index 46891f187..000000000 --- a/src/cmd/run.ixx +++ /dev/null @@ -1,61 +0,0 @@ -module; - -// external -#include // NOLINT(build/include_order) -#include -#include - -// internal -#include "../util/result-macros.hpp" - -export module poac.cmd.run; - -import poac.cmd.build; -import poac.data.manifest; -import poac.util.format; -import poac.util.log; -import poac.util.result; -import poac.util.rustify; -import poac.util.shell; -import poac.util.validator; - -namespace poac::cmd::run { - -export struct Options : structopt::sub_command { - /// Build artifacts in release mode, with optimizations - Option release = false; - /// Build artifacts with the specified profile - Option profile; -}; - -export [[nodiscard]] auto exec(const Options& opts) -> Result { - spdlog::trace("Checking if required config exists ..."); - Try(util::validator::required_config_exists().map_err(to_anyhow)); - - spdlog::trace("Parsing the manifest file ..."); - // TODO(ken-matsui): parse as a static type rather than toml::value - const toml::value manifest = toml::parse(data::manifest::NAME); - const String name = toml::find(manifest, "package", "name"); - - const Option output = Try( - build::build({.release = opts.release, .profile = opts.profile}, manifest) - .with_context([&name] { - return Err(name).get(); - }) - ); - if (!output.has_value()) { - return Ok(); - } - - const Path executable = output.value() / name; - log::status("Running", executable); - if (const i32 code = util::shell::Cmd(executable).exec_no_capture(); - code != 0) { - return Err(executable, code); - } - return Ok(); -} - -} // namespace poac::cmd::run - -STRUCTOPT(poac::cmd::run::Options, release, profile); diff --git a/src/config.ixx b/src/config.ixx deleted file mode 100644 index af3f307e2..000000000 --- a/src/config.ixx +++ /dev/null @@ -1,50 +0,0 @@ -module; - -// std -#include -#include - -export module poac.config; - -import poac.util.misc; -import poac.util.rustify; - -namespace poac::config { - -export inline const Path user_dir = util::misc::expand_user(); - -// Ref: -// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html -inline const Path xdg_cache_home = - util::misc::getenv("XDG_CACHE_HOME", user_dir / ".cache"); -inline const Path xdg_data_home = - util::misc::getenv("XDG_DATA_HOME", user_dir / ".local" / "share"); -inline const Path xdg_state_home = - util::misc::getenv("XDG_STATE_HOME", user_dir / ".local" / "state"); - -export inline const Path data_dir(xdg_data_home / "poac"); -export inline const Path cred_file(data_dir / "credentials"); - -export inline const Path cache_dir(xdg_cache_home / "poac"); -export inline const Path registry_dir(cache_dir / "registry"); -export inline const Path registry_src_dir(registry_dir / "src"); -export inline const Path default_registry_dir(registry_src_dir / "poac.dev"); - -export inline const Path git_dir(cache_dir / "git"); -export inline const Path git_src_dir(git_dir / "src"); - -export inline const Path state_dir(xdg_state_home / "poac"); -export inline const Path log_file(state_dir / "log"); - -export inline const Path cwd = fs::current_path(); -export inline const Path src_dir(cwd / "src"); -export inline const Path include_dir(cwd / "include"); -export inline const Path tests_dir(cwd / "tests"); -export inline const Path main_cpp_file(src_dir / "main.cpp"); -export inline constexpr StringRef POAC_OUT = "poac-out"; -export inline const Path out_dir(cwd / POAC_OUT); - -export inline const Path conan_deps_dir(out_dir / ".conan"); -export inline const Path conan_deps_file(conan_deps_dir / "conan_poac.json"); - -} // namespace poac::config diff --git a/src/core/builder/build.ixx b/src/core/builder/build.ixx deleted file mode 100644 index 73692e8e6..000000000 --- a/src/core/builder/build.ixx +++ /dev/null @@ -1,201 +0,0 @@ -module; - -// std -#include // setenv -#include // ofstream -#include -#include - -// external -#include -#include -#include // NOLINT(build/include_order) -#include // NOLINT(build/include_order) -#include // NOLINT(build/include_order) -#include // StatusPrinter, Status // NOLINT(build/include_order) -#include // NOLINT(build/include_order) -#include - -// internal -#include "../../util/result-macros.hpp" - -export module poac.core.builder.build; - -import poac.config; -import poac.core.builder.data; -import poac.core.builder.log; -import poac.core.builder.manifest; -import poac.core.resolver.types; // ResolvedDeps -import poac.util.format; -import poac.util.log; -import poac.util.result; -import poac.util.rustify; -import poac.util.verbosity; -import termcolor2; -import termcolor2.literals_extra; - -namespace poac::core::builder::build { - -using GeneralError = - Error<"internal build system has been stopped with an error:\n{}", String>; - -export enum class Mode { - debug, - release, -}; - -export auto to_string(Mode mode) -> String { - switch (mode) { - case Mode::debug: - return "debug"; - case Mode::release: - return "release"; - default: - __builtin_unreachable(); - } -} - -auto operator<<(std::ostream& os, Mode mode) -> std::ostream& { - switch (mode) { - case Mode::debug: - return (os << "dev"); - case Mode::release: - return (os << "release"); - default: - __builtin_unreachable(); - } -} - -/// Build the targets listed on the command line. -[[nodiscard]] auto run(data::NinjaMain& ninja_main, Status& status) - -> Result { - String err; - const Vec targets = ninja_main.state.DefaultNodes(&err); - if (!err.empty()) { - return Err(err); - } - ninja_main.disk_interface.AllowStatCache(true); - - Builder builder( - &ninja_main.state, ninja_main.config, &ninja_main.build_log, - &ninja_main.deps_log, &ninja_main.disk_interface, &status, - ninja_main.start_time_millis - ); - for (Node* target : targets) { - if (!builder.AddTarget(target, &err)) { - if (!err.empty()) { - return Err(err); - } - // Added a target that is already up-to-date; not really an error. - } - } - // Make sure restat rules do not see stale timestamps. - ninja_main.disk_interface.AllowStatCache(false); - - if (builder.AlreadyUpToDate()) { - spdlog::trace("nothing to do."); - return Ok(); - } - if (!builder.Build(&err)) { - return Err(err); - } - return Ok(); -} - -auto get_ninja_verbosity() -> BuildConfig::Verbosity { - if (util::verbosity::is_verbose()) { - return BuildConfig::VERBOSE; - } else if (util::verbosity::is_quiet()) { - return BuildConfig::QUIET; - } else { - return BuildConfig::NORMAL; - } -} - -void write_comp_db(const data::NinjaMain& ninja_main, const Edge* const edge) { - boost::property_tree::ptree comp_db; - comp_db.put("directory", config::cwd); - comp_db.put("command", edge->EvaluateCommand()); - comp_db.put("file", edge->inputs_[0]->path()); - comp_db.put("output", edge->outputs_[0]->path()); - - if (util::verbosity::is_verbose()) { - boost::property_tree::write_json(std::cout, comp_db); - } - boost::property_tree::write_json( - ninja_main.build_dir / "compile_commands.json", comp_db - ); -} - -auto build_compilation_database(const data::NinjaMain& ninja_main) - -> Result { - for (Edge* e : ninja_main.state.edges_) { - if (e->inputs_.empty()) { - continue; - } - write_comp_db(ninja_main, e); - } - return Ok(); -} - -// Limit number of rebuilds, to prevent infinite loops. -inline constexpr i32 REBUILD_LIMIT = 100; - -export [[nodiscard]] auto start( - const toml::value& poac_manifest, const Mode& mode, - const resolver::ResolvedDeps& resolved_deps -) -> Result { - using namespace termcolor2::color_literals; - - const BuildConfig config; - - // ref: https://github.com/ninja-build/ninja/pull/2102#issuecomment-1147771497 - setenv("TERM", "dumb", true); - const String progress_status_format = - termcolor2::should_color() - ? format("{:>27} %f/%t: ", "Compiling"_bold_green) - : format("{:>12} %f/%t: ", "Compiling"); - setenv("NINJA_STATUS", progress_status_format.c_str(), true); - StatusPrinter status(config); - - const Path build_dir = config::out_dir / to_string(mode); - fs::create_directories(build_dir); - Try(manifest::create(build_dir, poac_manifest, resolved_deps)); - - for (i32 cycle = 1; cycle <= REBUILD_LIMIT; ++cycle) { - data::NinjaMain ninja_main(config, build_dir); - ManifestParserOptions parser_opts; - parser_opts.dupe_edge_action_ = kDupeEdgeActionError; - ManifestParser parser( - &ninja_main.state, &ninja_main.disk_interface, parser_opts - ); - String err; - if (!parser.Load( - (ninja_main.build_dir / manifest::MANIFEST_FILE_NAME).string(), &err - )) { - return Err(err); - } - - Try(build_compilation_database(ninja_main)); // RUN_AFTER_LOAD - - Try(log::load_build_log(ninja_main)); - Try(log::load_deps_log(ninja_main)); - - // Attempt to rebuild the manifest before building anything else - if (manifest::rebuild(ninja_main, status, err)) { - // Start the build over with the new manifest. - continue; - } else if (!err.empty()) { - return Err(err); - } - - Try(run(ninja_main, status)); - return Ok(config::out_dir / to_string(mode)); - } - return Err(format( - "internal manifest still dirty after {} tries, perhaps system time is not set", - REBUILD_LIMIT - )); -} - -} // namespace poac::core::builder::build diff --git a/src/core/builder/compiler/cxx.ixx b/src/core/builder/compiler/cxx.ixx deleted file mode 100644 index e2e88323a..000000000 --- a/src/core/builder/compiler/cxx.ixx +++ /dev/null @@ -1,98 +0,0 @@ -module; - -// internal -#include "../../../util/result-macros.hpp" - -export module poac.core.builder.compiler.cxx; - -import poac.core.builder.compiler.cxx.apple_clang; -import poac.core.builder.compiler.cxx.clang; -import poac.core.builder.compiler.cxx.gcc; -import poac.core.builder.compiler.error; - -import poac.util.cfg; -import poac.util.format; -import poac.util.log; -import poac.util.misc; -import poac.util.result; -import poac.util.rustify; -import poac.util.shell; - -namespace poac::core::builder::compiler::cxx { - -using CompilerCommandNotFound = Error< - "either general compilers or environment variable `POAC_CXX` was not found.\n" - "Please export it like `export POAC_CXX=g++-11`.">; -using UnknownCompilerCommand = - Error<"unknown compiler command found: {}", String>; -using UnsupportedCompiler = Error<"unsupported compiler found: {}", String>; - -[[nodiscard]] auto -get_compiler_ident(const String& compiler_command, bool is_macos) - -> Result { - if (is_macos) { - if (const auto res = util::shell::Cmd(compiler_command + " --version") - .stderr_to_stdout() - .exec()) { - if (res.output().find("Apple") != None) { - return Ok(util::cfg::Compiler::apple_clang); - } - } - } - - // `clang++` should be before `g++` because `g++` is a part of `clang++` - if (compiler_command.find("clang++") != None) { - return Ok(util::cfg::Compiler::clang); - } - if (compiler_command.find("g++") != None) { - return Ok(util::cfg::Compiler::gcc); - } - return Err(compiler_command); -} - -[[nodiscard]] auto get_std_flag( - util::cfg::Compiler compiler, const String& compiler_command, i64 edition, - bool use_gnu_extension -) -> Result { - switch (compiler) { - case util::cfg::Compiler::gcc: - return gcc::get_std_flag(compiler_command, edition, use_gnu_extension); - case util::cfg::Compiler::clang: - return clang::get_std_flag(compiler_command, edition, use_gnu_extension); - case util::cfg::Compiler::apple_clang: - return apple_clang::get_std_flag( - compiler_command, edition, use_gnu_extension - ); - default: - return Err(error::to_string(compiler)); - } -} - -[[nodiscard]] auto get_compiler_command() -> Result { - if (const auto cxx = util::misc::dupenv("CXX")) { - return Ok(cxx.value()); - } else if (util::shell::has_command("g++")) { - return Ok("g++"); - } else if (util::shell::has_command("clang++")) { - return Ok("clang++"); - } else { - return Err(); - } -} - -export [[nodiscard]] auto get_command(i64 edition, bool use_gnu_extension) - -> Result { - const String compiler_command = Try(get_compiler_command()); - const util::cfg::Compiler compiler = -#ifdef __APPLE__ - Try(get_compiler_ident(compiler_command, true)); -#else - Try(get_compiler_ident(compiler_command, false)); -#endif - - const String std_flag = - Try(get_std_flag(compiler, compiler_command, edition, use_gnu_extension)); - return Ok(format("{} {}", compiler_command, std_flag)); -} - -} // namespace poac::core::builder::compiler::cxx diff --git a/src/core/builder/compiler/cxx/apple_clang.ixx b/src/core/builder/compiler/cxx/apple_clang.ixx deleted file mode 100644 index 9f3dfd1f5..000000000 --- a/src/core/builder/compiler/cxx/apple_clang.ixx +++ /dev/null @@ -1,96 +0,0 @@ -module; - -// std -#include - -// internal -#include "../../../../util/result-macros.hpp" - -export module poac.core.builder.compiler.cxx.apple_clang; - -import poac.core.builder.compiler.error; -import poac.core.builder.compiler.lang; -import poac.util.cfg; -import poac.util.format; -import poac.util.log; -import poac.util.result; -import poac.util.rustify; -import poac.util.shell; -import semver; - -namespace poac::core::builder::compiler::cxx::apple_clang { - -inline constexpr util::cfg::Compiler COMPILER = - util::cfg::Compiler::apple_clang; - -[[nodiscard]] auto get_compiler_version_impl(const String& cmd_output) - -> Result { - // `Apple clang version 13.0.0 (...)` - String version; - for (usize i = 20; i < cmd_output.size(); ++i) { - if (cmd_output[i] == ' ') { // read until space - break; - } - version += cmd_output[i]; - } - return Ok(semver::parse(version)); -} - -[[nodiscard]] auto get_compiler_version(const String& compiler_command) - -> Result { - const auto res = - util::shell::Cmd(compiler_command + " --version").dump_stderr().exec(); - if (res.is_ok()) { - return get_compiler_version_impl(res.output()); - } - return Err(COMPILER); -} - -// thanks to: -// https://gitlab.kitware.com/cmake/cmake/-/blob/master/Modules/Compiler/AppleClang-CXX.cmake -export [[nodiscard]] auto get_std_flag( - const String& compiler_command, i64 edition, bool use_gnu_extension -) -> Result { - const semver::Version version = Try(get_compiler_version(compiler_command)); - const String specifier = use_gnu_extension ? "gnu" : "c"; - switch (edition) { - case 1998: - if (version >= "4.0.0") { - return Ok(format("-std={}++98", specifier)); - } - break; - case 2011: - if (version >= "4.0.0") { - return Ok(format("-std={}++11", specifier)); - } - break; - case 2014: - if (version >= "6.1.0") { - return Ok(format("-std={}++14", specifier)); - } else if (version >= "5.1.0") { - // AppleClang 5.0 knows this flag, but does not set a __cplusplus macro - // greater than 201103L - return Ok(format("-std={}++1y", specifier)); - } - break; - case 2017: - if (version >= "10.0.0") { - return Ok(format("-std={}++17", specifier)); - } else if (version >= "6.1.0") { - return Ok(format("-std={}++1z", specifier)); - } - break; - case 2020: - if (version >= "13.0.0") { - return Ok(format("-std={}++20", specifier)); - } else if (version >= "10.0.0") { - return Ok(format("-std={}++2a", specifier)); - } - break; - } - return Err( - COMPILER, version, lang::Lang::cxx, edition - ); -} - -} // namespace poac::core::builder::compiler::cxx::apple_clang diff --git a/src/core/builder/compiler/cxx/clang.ixx b/src/core/builder/compiler/cxx/clang.ixx deleted file mode 100644 index 5c442f6f6..000000000 --- a/src/core/builder/compiler/cxx/clang.ixx +++ /dev/null @@ -1,102 +0,0 @@ -module; - -// std -#include // std::isdigit -#include - -// internal -#include "../../../../util/result-macros.hpp" - -export module poac.core.builder.compiler.cxx.clang; - -import poac.core.builder.compiler.error; -import poac.core.builder.compiler.lang; -import poac.util.shell; -import poac.util.cfg; -import poac.util.format; -import poac.util.log; -import poac.util.result; -import poac.util.rustify; -import semver; - -namespace poac::core::builder::compiler::cxx::clang { - -inline constexpr util::cfg::Compiler COMPILER = util::cfg::Compiler::clang; - -[[nodiscard]] auto get_compiler_version_impl(const String& cmd_output) - -> Result { - // `clang version 12.0.0 (...)` - const String search = "version "; - usize i = cmd_output.find(search); - if (i == None) { - return Err(COMPILER); - } - - String version; - for (i += search.size(); i < cmd_output.size(); ++i) { - if (std::isdigit(cmd_output[i]) || cmd_output[i] == '.') { - version += cmd_output[i]; - } else { - break; - } - } - return Ok(semver::parse(version)); -} - -[[nodiscard]] auto get_compiler_version(const String& compiler_command) - -> Result { - const auto res = util::shell::Cmd(compiler_command + " --version").exec(); - if (res.is_ok()) { - return get_compiler_version_impl(res.output()); - } - return Err(COMPILER); -} - -// thanks to: -// https://gitlab.kitware.com/cmake/cmake/-/blob/master/Modules/Compiler/Clang.cmake -export [[nodiscard]] auto get_std_flag( - const String& compiler_command, i64 edition, bool use_gnu_extension -) -> Result { - const semver::Version version = Try(get_compiler_version(compiler_command)); - const String specifier = use_gnu_extension ? "gnu" : "c"; - switch (edition) { - case 1998: - if (version > "2.1.0") { - return Ok(format("-std={}++98", specifier)); - } - break; - case 2011: - if (version > "3.1.0") { - return Ok(format("-std={}++11", specifier)); - } else if (version > "2.1.0") { - return Ok(format("-std={}++0x", specifier)); - } - break; - case 2014: - if (version >= "3.5.0") { - return Ok(format("-std={}++14", specifier)); - } else if (version >= "3.4.0") { - return Ok(format("-std={}++1y", specifier)); - } - break; - case 2017: - if (version >= "5.0.0") { - return Ok(format("-std={}++17", specifier)); - } else if (version >= "3.5.0") { - return Ok(format("-std={}++1z", specifier)); - } - break; - case 2020: - if (version >= "11.0.0") { - return Ok(format("-std={}++20", specifier)); - } else if (version >= "5.0.0") { - return Ok(format("-std={}++2a", specifier)); - } - break; - } - return Err( - COMPILER, version, lang::Lang::cxx, edition - ); -} - -} // namespace poac::core::builder::compiler::cxx::clang diff --git a/src/core/builder/compiler/cxx/gcc.ixx b/src/core/builder/compiler/cxx/gcc.ixx deleted file mode 100644 index f4f0de666..000000000 --- a/src/core/builder/compiler/cxx/gcc.ixx +++ /dev/null @@ -1,102 +0,0 @@ -module; - -// std -#include // std::isdigit -#include - -// internal -#include "../../../../util/result-macros.hpp" - -export module poac.core.builder.compiler.cxx.gcc; - -import poac.core.builder.compiler.error; -import poac.core.builder.compiler.lang; -import poac.util.shell; -import poac.util.cfg; -import poac.util.format; -import poac.util.log; -import poac.util.result; -import poac.util.rustify; -import semver; - -namespace poac::core::builder::compiler::cxx::gcc { - -inline constexpr util::cfg::Compiler COMPILER = util::cfg::Compiler::gcc; - -[[nodiscard]] auto get_compiler_version_impl(const String& cmd_output) - -> Result { - // `g++ (GCC) 11.2.0\n` - usize itr = cmd_output.find('('); - if (itr == None) { - return Err(COMPILER); - } - itr = cmd_output.find(')', itr + 1); - - String version; - for (itr += 2; itr < cmd_output.size(); ++itr) { - if (std::isdigit(cmd_output[itr]) || cmd_output[itr] == '.') { - version += cmd_output[itr]; - } else { - break; - } - } - return Ok(semver::parse(version)); -} - -[[nodiscard]] auto get_compiler_version(const String& compiler_command) - -> Result { - const auto res = util::shell::Cmd(compiler_command + " --version").exec(); - if (res.is_ok()) { - return get_compiler_version_impl(res.output()); - } - return Err(COMPILER); -} - -// thanks to: -// https://gitlab.kitware.com/cmake/cmake/-/blob/master/Modules/Compiler/GNU-CXX.cmake -export [[nodiscard]] auto get_std_flag( - const String& compiler_command, i64 edition, bool use_gnu_extension -) -> Result { - const semver::Version version = Try(get_compiler_version(compiler_command)); - const String specifier = use_gnu_extension ? "gnu" : "c"; - switch (edition) { - case 1998: - if (version >= "3.4.0") { - return Ok(format("-std={}++98", specifier)); - } - break; - case 2011: - if (version >= "4.7.0") { - return Ok(format("-std={}++11", specifier)); - } else if (version >= "4.4.0") { - return Ok(format("-std={}++0x", specifier)); - } - break; - case 2014: - if (version >= "4.9.0") { - return Ok(format("-std={}++14", specifier)); - } else if (version >= "4.8.0") { - return Ok(format("-std={}++1y", specifier)); - } - break; - case 2017: - if (version >= "8.0.0") { - return Ok(format("-std={}++17", specifier)); - } else if (version >= "5.1.0") { - return Ok(format("-std={}++1z", specifier)); - } - break; - case 2020: - if (version >= "11.1.0") { - return Ok(format("-std={}++20", specifier)); - } else if (version >= "8.0.0") { - return Ok(format("-std={}++2a", specifier)); - } - break; - } - return Err( - COMPILER, version, lang::Lang::cxx, edition - ); -} - -} // namespace poac::core::builder::compiler::cxx::gcc diff --git a/src/core/builder/compiler/error.ixx b/src/core/builder/compiler/error.ixx deleted file mode 100644 index d5d475079..000000000 --- a/src/core/builder/compiler/error.ixx +++ /dev/null @@ -1,61 +0,0 @@ -module; - -// external -#include - -export module poac.core.builder.compiler.error; - -import semver.token; -import poac.core.builder.compiler.lang; -import poac.util.cfg; // compiler -import poac.util.format; -import poac.util.log; -import poac.util.result; -import poac.util.rustify; - -export namespace poac::core::builder::compiler::error { - -auto to_string(util::cfg::Compiler comp) -> String { - switch (comp) { - case util::cfg::Compiler::gcc: - return "GCC"; - case util::cfg::Compiler::clang: - return "Clang"; - case util::cfg::Compiler::apple_clang: - return "Apple Clang"; - case util::cfg::Compiler::msvc: - return "MSVC"; - case util::cfg::Compiler::icc: - return "Intel C++ Compiler"; - default: - __builtin_unreachable(); - } -} - -} // namespace poac::core::builder::compiler::error - -namespace fmt { - -template <> -struct formatter { - static constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } - - template - inline auto format(poac::util::cfg::Compiler c, FormatContext& ctx) { - return format_to( - ctx.out(), "{}", poac::core::builder::compiler::error::to_string(c) - ); - } -}; - -} // namespace fmt - -export namespace poac::core::builder::compiler::error { - -using UnsupportedLangVersion = Error< - "`{}` ({}) does not support {} edition: `{}`", util::cfg::Compiler, - semver::Version, poac::core::builder::compiler::lang::Lang, i64>; -using FailedToGetCompilerVersion = - Error<"failed to get version of compiler `{}`", util::cfg::Compiler>; - -} // namespace poac::core::builder::compiler::error diff --git a/src/core/builder/compiler/lang.ixx b/src/core/builder/compiler/lang.ixx deleted file mode 100644 index bda13e149..000000000 --- a/src/core/builder/compiler/lang.ixx +++ /dev/null @@ -1,49 +0,0 @@ -module; - -// external -#include - -export module poac.core.builder.compiler.lang; - -import poac.util.cfg; // compiler -import poac.util.format; -import poac.util.log; -import poac.util.result; -import poac.util.rustify; - -export namespace poac::core::builder::compiler::lang { - -enum class Lang { - c, - cxx, -}; - -auto to_string(Lang lang) -> String { - switch (lang) { - case Lang::c: - return "C"; - case Lang::cxx: - return "C++"; - default: - __builtin_unreachable(); - } -} - -} // namespace poac::core::builder::compiler::lang - -namespace fmt { - -template <> -struct formatter { - static constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } - - template - inline auto - format(poac::core::builder::compiler::lang::Lang l, FormatContext& ctx) { - return format_to( - ctx.out(), "{}", poac::core::builder::compiler::lang::to_string(l) - ); - } -}; - -} // namespace fmt diff --git a/src/core/builder/data.ixx b/src/core/builder/data.ixx deleted file mode 100644 index f9cecc803..000000000 --- a/src/core/builder/data.ixx +++ /dev/null @@ -1,71 +0,0 @@ -module; - -// std -#include - -// external -#include // BuildConfig // NOLINT(build/include_order) -#include // BuildLog, BuildLogUser // NOLINT(build/include_order) -#include // DepsLog // NOLINT(build/include_order) -#include // RealDiskInterface // NOLINT(build/include_order) -#include // Node // NOLINT(build/include_order) -#include // GetTimeMillis // NOLINT(build/include_order) -#include // State // NOLINT(build/include_order) -#include // StringPiece // NOLINT(build/include_order) -#include // TimeStamp // NOLINT(build/include_order) -#include // spdlog::error // NOLINT(build/include_order) - -export module poac.core.builder.data; - -import poac.util.format; -import poac.util.log; -import poac.util.result; -import poac.util.rustify; - -export namespace poac::core::builder::data { - -struct NinjaMain : public BuildLogUser { - NinjaMain(const BuildConfig& config, Path build_dir) - : config(config), build_dir(std::move(build_dir)) {} - - /// Build configuration set from flags (e.g. parallelism). - const BuildConfig& config; - - /// Loaded state (rules, nodes). - State state; - - /// Functions for accessing the disk. - RealDiskInterface disk_interface; - - /// The build directory, used for storing the build log etc. - Path build_dir; - - BuildLog build_log; - DepsLog deps_log; - - i64 start_time_millis = GetTimeMillis(); - - [[nodiscard]] auto IsPathDead(StringPiece s) const -> bool override { - Node* n = state.LookupNode(s); - if (n && n->in_edge()) { - return false; - } - // Just checking n isn't enough: If an old output is both in the build log - // and in the deps log, it will have a Node object in state_. (It will - // also have an in edge if one of its inputs is another output that's in - // the deps log, but having a deps edge product an output that's input to - // another deps edge is rare, and the first recompaction will delete all - // old outputs from the deps log, and then a second recompaction will - // clear the build log, which seems good enough for this corner case.) Do - // keep entries around for files which still exist on disk, for generators - // that want to use this information. - String err; - const TimeStamp mtime = disk_interface.Stat(s.AsString(), &err); - if (mtime == -1) { - spdlog::error(err); // Log and ignore Stat() errors. - } - return mtime == 0; - } -}; - -} // namespace poac::core::builder::data diff --git a/src/core/builder/log.ixx b/src/core/builder/log.ixx deleted file mode 100644 index 104c09a39..000000000 --- a/src/core/builder/log.ixx +++ /dev/null @@ -1,73 +0,0 @@ -module; - -// std -#include - -// external -#include // LoadStatus // NOLINT(build/include_order) -#include // NOLINT(build/include_order) - -export module poac.core.builder.log; - -// internal -import poac.core.builder.data; -import poac.util.format; -import poac.util.log; -import poac.util.result; -import poac.util.rustify; - -namespace poac::core::builder::log { - -using FailedToLoadBuildLog = - Error<"loading build log `{}`: {}", String, String>; -using FailedToOpenBuildLog = Error<"opening build log: {}", String>; -using FailedToLoadDepsLog = Error<"loading deps log `{}`: {}", String, String>; -using FailedToOpenDepsLog = Error<"opening deps log: {}", String>; - -inline constexpr StringRef BUILD_LOG_FILE_NAME = ".ninja_log"; -inline constexpr StringRef DEPS_LOG_FILE_NAME = ".ninja_deps"; - -export [[nodiscard]] auto load_build_log(data::NinjaMain& ninja_main) - -> Result { - const Path log_path = ninja_main.build_dir / BUILD_LOG_FILE_NAME; - - String err; - const LoadStatus status = ninja_main.build_log.Load(log_path, &err); - if (status == LOAD_ERROR) { - return Err(log_path.string(), err); - } - if (!err.empty()) { - // Hack: Load() can return a warning via err by returning LOAD_SUCCESS. - spdlog::warn(err); - err.clear(); - } - - if (!ninja_main.build_log.OpenForWrite(log_path, ninja_main, &err)) { - return Err(err); - } - return Ok(); -} - -export [[nodiscard]] auto load_deps_log(data::NinjaMain& ninja_main) - -> Result { - const Path log_path = ninja_main.build_dir / DEPS_LOG_FILE_NAME; - - String err; - const LoadStatus status = - ninja_main.deps_log.Load(log_path, &ninja_main.state, &err); - if (status == LOAD_ERROR) { - return Err(log_path.string(), err); - } - if (!err.empty()) { - // Hack: Load() can return a warning via err by returning LOAD_SUCCESS. - spdlog::warn(err); - err.clear(); - } - - if (!ninja_main.deps_log.OpenForWrite(log_path, &err)) { - return Err(err); - } - return Ok(); -} - -} // namespace poac::core::builder::log diff --git a/src/core/builder/manifest.ixx b/src/core/builder/manifest.ixx deleted file mode 100644 index 5c1229f17..000000000 --- a/src/core/builder/manifest.ixx +++ /dev/null @@ -1,234 +0,0 @@ -module; - -// std -#include -#include - -// external -#include // boost::algorithm::join -#include // Builder, Status // NOLINT(build/include_order) -#include // Node // NOLINT(build/include_order) -#include - -// internal -#include "../../util/result-macros.hpp" - -export module poac.core.builder.manifest; - -import poac.config; -import poac.core.builder.compiler.cxx; -import poac.core.builder.data; -import poac.core.builder.syntax; -import poac.core.resolver.types; // ResolvedDeps -import poac.core.resolver; // get_extracted_path -import poac.data.manifest; -import poac.util.cfg; -import poac.util.format; -import poac.util.log; -import poac.util.result; -import poac.util.rustify; -import poac.util.registry.conan.v1.manifest; - -namespace poac::core::builder::manifest { - -export inline constexpr StringRef MANIFEST_FILE_NAME = "build.ninja"; -inline constexpr Arr MANIFEST_HEADERS{ - "This file is automatically generated by Poac.", - "It is not intended for manual editing."}; - -inline auto ninja_manifest_last_modified(const Path& build_dir) - -> fs::file_time_type { - return fs::last_write_time(build_dir / MANIFEST_FILE_NAME); -} - -inline auto is_outdated(const Path& build_dir) -> bool { - if (!fs::exists(build_dir / MANIFEST_FILE_NAME)) { - return true; - } - using poac::data::manifest::poac_toml_last_modified; - return ninja_manifest_last_modified(build_dir) - < poac_toml_last_modified(config::cwd); -} - -export auto rebuild(data::NinjaMain& ninja_main, Status& status, String& err) - -> bool { - Node* node = ninja_main.state.LookupNode( - (ninja_main.build_dir / MANIFEST_FILE_NAME).string() - ); - if (!node) { - return false; - } - - Builder builder( - &ninja_main.state, ninja_main.config, &ninja_main.build_log, - &ninja_main.deps_log, &ninja_main.disk_interface, &status, - ninja_main.start_time_millis - ); - if (!builder.AddTarget(node, &err)) { - return false; - } - if (builder.AlreadyUpToDate()) { - return false; // Not an error, but we didn't rebuild. - } - if (!builder.Build(&err)) { - return false; - } - - // The manifest was only rebuilt if it is now dirty (it may have been cleaned - // by a restat). - if (!node->dirty()) { - // Reset the state to prevent problems like - // https://github.com/ninja-build/ninja/issues/874 - ninja_main.state.Reset(); - return false; - } - return true; -} - -auto construct_includes(Vec& includes) -> Vec { - Vec include_flags; - for (const Path& inc : includes) { - include_flags.emplace_back(format("-I{}", inc.string())); - } - return include_flags; -} - -auto gather_includes(const resolver::ResolvedDeps& resolved_deps) - -> Vec { - Vec includes; - if (fs::exists(config::include_dir)) { - includes.emplace_back(config::include_dir); - } - for (const auto& [package, inner_deps] : resolved_deps) { - static_cast(inner_deps); - - const Path include_path = resolver::get_extracted_path(package) / "include"; - if (fs::exists(include_path) && fs::is_directory(include_path)) { - includes.emplace_back(include_path); - } - } - return construct_includes(includes); -} - -auto get_cfg_profile(const toml::value& poac_manifest) -> Vec { - const auto target = - toml::find_or(poac_manifest, "target", toml::table{}); - Vec profiles; - for (const auto& [key, val] : target) { - if (key.find("cfg(") != None) { - if (util::cfg::parse(key).match()) { - const auto profile = - toml::find_or(val, "profile", toml::table{}); - profiles.emplace_back(profile); - } - } - } - return profiles; -} - -auto gather_flags( - const toml::value& poac_manifest, const String& name, - const Option& prefix = None -) -> Vec { - auto f = toml::find_or>( - poac_manifest, "target", "profile", name, Vec{} - ); - if (prefix.has_value()) { - std::transform( - f.begin(), f.end(), f.begin(), - [p = prefix.value()](const auto& s) { return p + s; } - ); - } - return f; -} - -[[nodiscard]] auto construct( - const Path& build_dir, const toml::value& poac_manifest, - const resolver::ResolvedDeps& resolved_deps -) -> Result { - syntax::Writer writer{std::ostringstream()}; - for (const StringRef header : MANIFEST_HEADERS) { - writer.comment(String(header)); - } - writer.newline(); - - const String name = toml::find(poac_manifest, "package", "name"); - const String version = - toml::find(poac_manifest, "package", "version"); - const i64 edition = toml::find(poac_manifest, "package", "edition"); - const String command = Try(compiler::cxx::get_command(edition, false)); - - writer.rule( - "compile", - format( - "{} $in -o $out $OPTIONS $DEFINES $INCLUDES $LIBDIRS $LIBRARIES", - command - ), - syntax::RuleSet{ - .description = "$PACKAGE_NAME v$PACKAGE_VERSION $PACKAGE_PATH", - } - ); - writer.newline(); - - const Path source_file = "src"_path / "main.cpp"; - Path output_file; - if (source_file == "src"_path / "main.cpp") { - // When building src/main.cpp, the output executable should be stored at - // poac-out/debug/name - output_file = build_dir / name; - } else { - output_file = (build_dir / source_file).string() + ".o"; - fs::create_directories(output_file.parent_path()); - } - - const Vec options = gather_flags(poac_manifest, "options"); - Vec includes = gather_includes(resolved_deps); - Vec defines = gather_flags(poac_manifest, "definitions", "-D"); - Vec libraries = gather_flags(poac_manifest, "libraries", "-l"); - Vec libdirs; - - auto conan_manifest = - Try(poac::util::registry::conan::v1::manifest::gather_conan_deps()); - append(includes, conan_manifest.includes); - append(defines, conan_manifest.defines); - append(libraries, conan_manifest.libraries); - append(libdirs, conan_manifest.libdirs); - - writer.build( - {output_file.string()}, "compile", - syntax::BuildSet{ - .inputs = std::vector{source_file.string()}, - .variables = - syntax::Variables{ - {"PACKAGE_NAME", name}, - {"PACKAGE_VERSION", version}, - {"PACKAGE_PATH", format("({})", config::cwd)}, - {"OPTIONS", boost::algorithm::join(options, " ")}, - {"DEFINES", boost::algorithm::join(defines, " ")}, - {"INCLUDES", boost::algorithm::join(includes, " ")}, - {"LIBDIRS", boost::algorithm::join(libdirs, " ")}, - {"LIBRARIES", boost::algorithm::join(libraries, " ")}, - }, - } - ); - writer.newline(); - - writer.defalt({output_file.string()}); - return Ok(writer.get_value()); -} - -export [[nodiscard]] auto create( - const Path& build_dir, const toml::value& poac_manifest, - const resolver::ResolvedDeps& resolved_deps -) -> Result { - // TODO(ken-matsui): `build.ninja` will be constructed from `poac.toml`, - // so if `poac.toml` has no change, - // then `build.ninja` is not needed to be updated. - // if (is_outdated(build_dir)) { - std::ofstream ofs(build_dir / MANIFEST_FILE_NAME, std::ios::out); - ofs << Try(construct(build_dir, poac_manifest, resolved_deps)); - // } - return Ok(); -} - -} // namespace poac::core::builder::manifest diff --git a/src/core/builder/syntax.ixx b/src/core/builder/syntax.ixx deleted file mode 100644 index 3f41c7973..000000000 --- a/src/core/builder/syntax.ixx +++ /dev/null @@ -1,299 +0,0 @@ -// C++ class to generate .ninja files. -// This file is based on ninja_syntax.py from: -// https://github.com/ninja-build/ninja/blob/master/misc/ninja_syntax.py - -module; - -// std -#include -#include -#include -#include // std::move - -// external -#include -#include -#include - -export module poac.core.builder.syntax; - -import poac.util.format; -import poac.util.log; -import poac.util.result; -import poac.util.rustify; -import poac.util.pretty; - -namespace poac::core::builder::syntax { - -export struct RuleSet { - Option description = None; - Option depfile = None; - bool generator = false; - Option pool = None; - bool restat = false; - Option rspfile = None; - Option rspfile_content = None; - Option deps = None; -}; - -export using Variables = HashMap; -export struct BuildSet { - Option> inputs = None; - Option> implicit = None; - Option order_only = None; - Option variables = None; - Option implicit_outputs = None; - Option pool = None; - Option dyndep = None; -}; - -inline auto escape_path(const Path& p) -> Path { - String s = p.string(); - boost::replace_all(s, "$ ", "$$ "); - boost::replace_all(s, " ", "$ "); - boost::replace_all(s, ":", "$:"); - return s; -} - -/// Escape a string such that it can be embedded into a Ninja file without -/// further interpretation. -inline void escape(String& s) { - assert(s.find('\n') == None); // Ninja syntax does not allow newlines - // We only have one special metacharacter: '$'. - boost::replace_all(s, "$", "$$"); -} - -/// Expand a string containing $vars as Ninja would. -/// -/// Note: doesn't handle the full Ninja variable syntax, but it's enough -/// to make configure.py's use of it work. -auto expand( - const String& text, const Variables& vars, const Variables& local_vars = {} -) -> String { - using namespace std::literals::string_literals; - - const auto exp = [&](const boost::smatch& m) { - const String var = m[1].str(); - if (var == "$") { - return "$"s; - } - return local_vars.contains(var) ? local_vars.at(var) - : vars.contains(var) ? vars.at(var) - : ""s; - }; - return boost::regex_replace(text, boost::regex(R"(\$(\$|\w*))"), exp); -} - -/// ref: https://stackoverflow.com/a/46379136 -auto operator*(const String& s, usize n) -> String { - String result; - result.reserve(s.size() * n); - for (usize i = 0; i < n; ++i) { - result += s; - } - return result; -} - -export class Writer { - std::ostringstream output; - usize width; - - /// Returns the number of '$' characters right in front of s[i]. - static auto count_dollars_before_index(StringRef s, usize i) -> usize { - usize dollar_count = 0; - usize dollar_index = i - 1; - while (dollar_index > 0 && s[dollar_index] == '$') { - dollar_count += 1; - dollar_index -= 1; - } - return dollar_count; - } - - // Export this function for testing -#if __has_include() -public: -#endif - /// Write 'text' word-wrapped at self.width characters. - void line(String text, usize indent = 0) { - String leading_space = String(" ") * indent; - - while (leading_space.length() + text.length() > width) { - // The text is too wide; wrap if possible. - - // Find the rightmost space that would obey our width constraint and - // that's not an escaped space. - const std::int32_t available_space = - width - leading_space.length() - 2; // " $".length() == 2 - std::int32_t space = available_space; - do { - space = text.rfind(' ', space); - // NOLINTNEXTLINE(readability-simplify-boolean-expr) - } while (!(space < 0 || count_dollars_before_index(text, space) % 2 == 0) - ); - - if (space < 0) { - // No such space; just use the first unescaped space we can find. - space = available_space - 1; - do { - space = text.find(' ', space + 1); - // NOLINTNEXTLINE(readability-simplify-boolean-expr) - } while ( - !(space < 0 || count_dollars_before_index(text, space) % 2 == 0) - ); - } - if (space < 0) { - // Give up on breaking. - break; - } - - output << leading_space + text.substr(0, space) + " $\n"; - text = text.substr(space + 1); - - // Subsequent lines are continuations, so indent them. - leading_space = String(" ") * (indent + 2); - } - output << leading_space + text + '\n'; - } - -#if !__has_include() -public: -#endif - explicit Writer(std::ostringstream&& o, usize w = 78) - : output(std::move(o)), width(w) {} - - inline auto get_value() const -> String { return output.str(); } - - inline void newline() { output << '\n'; } - - void comment(const String& text) { - for (const String& line : util::pretty::textwrap(text, width - 2)) { - output << "# " + line + '\n'; - } - } - - void variable(StringRef key, StringRef value, usize indent = 0) { - if (value.empty()) { - return; - } - line(format("{} = {}", key, value), indent); - } - - inline void - variable(StringRef key, const Vec& values, usize indent = 0) { - const String value = - boost::algorithm::join_if(values, " ", [](const auto& s) { - return !s.empty(); - }); - line(format("{} = {}", key, value), indent); - } - - inline void pool(StringRef name, StringRef depth) { - line(format("pool {}", name)); - variable("depth", depth, 1); - } - - void rule(StringRef name, StringRef command, const RuleSet& rule_set = {}) { - line(format("rule {}", name)); - variable("command", command, 1); - if (rule_set.description.has_value()) { - variable("description", rule_set.description.value(), 1); - } - if (rule_set.depfile.has_value()) { - variable("depfile", rule_set.depfile.value(), 1); - } - if (rule_set.generator) { - variable("generator", "1", 1); - } - if (rule_set.pool.has_value()) { - variable("pool", rule_set.pool.value(), 1); - } - if (rule_set.restat) { - variable("restat", "1", 1); - } - if (rule_set.rspfile.has_value()) { - variable("rspfile", rule_set.rspfile.value(), 1); - } - if (rule_set.rspfile_content.has_value()) { - variable("rspfile_content", rule_set.rspfile_content.value(), 1); - } - if (rule_set.deps.has_value()) { - variable("deps", rule_set.deps.value(), 1); - } - } - - auto build( - const Vec& outputs, StringRef rule, const BuildSet& build_set = {} - ) -> Vec { - Vec out_outputs; - for (const String& o : outputs) { - out_outputs.emplace_back(escape_path(o).string()); - } - - Vec all_inputs; - if (build_set.inputs.has_value()) { - for (const String& i : build_set.inputs.value()) { - all_inputs.emplace_back(escape_path(i).string()); - } - } - - if (build_set.implicit.has_value()) { - Vec implicit; - for (const Path& i : build_set.implicit.value()) { - implicit.emplace_back(escape_path(i).string()); - } - all_inputs.emplace_back("|"); - boost::push_back(all_inputs, implicit); - } - if (build_set.order_only.has_value()) { - Vec order_only; - for (const Path& o : build_set.order_only.value()) { - order_only.emplace_back(escape_path(o).string()); - } - all_inputs.emplace_back("||"); - boost::push_back(all_inputs, order_only); - } - if (build_set.implicit_outputs.has_value()) { - Vec implicit_outputs; - for (const Path& i : build_set.implicit_outputs.value()) { - implicit_outputs.emplace_back(escape_path(i).string()); - } - out_outputs.emplace_back("|"); - boost::push_back(out_outputs, implicit_outputs); - } - - line(format( - "build {}: {} {}", boost::algorithm::join(out_outputs, " "), rule, - boost::algorithm::join(all_inputs, " ") - )); - - if (build_set.pool.has_value()) { - line(format(" pool = {}", build_set.pool.value())); - } - if (build_set.dyndep.has_value()) { - line(format(" dyndep = {}", build_set.dyndep.value())); - } - - if (build_set.variables.has_value()) { - for (const auto& [key, val] : build_set.variables.value()) { - variable(key, val, 1); - } - } - - return outputs; - } - - inline void include(const Path& path) { line(format("include {}", path)); } - - inline void subninja(const Path& path) { line(format("subninja {}", path)); } - - inline void defalt(const Vec& paths) { - line(format("default {}", boost::algorithm::join(paths, " "))); - } - - inline friend auto operator<<(std::ostream& os, const Writer& w) - -> std::ostream& { - return os << w.get_value(); - } -}; - -} // namespace poac::core::builder::syntax diff --git a/src/main.cc b/src/main.cc index ce690552f..408461888 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,239 +1,141 @@ -// std +#include "Algos.hpp" +#include "Cmd/Build.hpp" +#include "Cmd/Clean.hpp" +#include "Cmd/Fmt.hpp" +#include "Cmd/Global.hpp" +#include "Cmd/Help.hpp" +#include "Cmd/Init.hpp" +#include "Cmd/Lint.hpp" +#include "Cmd/New.hpp" +#include "Cmd/Run.hpp" +#include "Cmd/Test.hpp" +#include "Cmd/Version.hpp" +#include "Logger.hpp" +#include "Rustify.hpp" +#include "TermColor.hpp" + #include -#include -#include - -// external -#include -#include -#include -#include -#include -#include // NOLINT(build/include_order) -#include // NOLINT(build/include_order) -#include -#include - -// internal -#include "util/result-macros.hpp" - -#ifndef POAC_VERSION -# error "POAC_VERSION is not defined" -#endif - -import poac.cmd; -import poac.util.format; -import poac.util.result; -import poac.util.rustify; -import poac.util.levDistance; -import poac.util.log; -import termcolor2.color_mode; -import termcolor2.literals; -import termcolor2.literals_extra; - -using namespace termcolor2::color_literals; // NOLINT(build/namespaces) -using namespace poac; // NOLINT(build/namespaces) -namespace anyhow = mitama::anyhow; - -struct Commands { - /// Use verbose output - Option verbose = false; - /// Do not print poac log messages - Option quiet = false; - /// Coloring: auto, always, never - Option color = "auto"; - - /// Compile a local package and all of its dependencies - cmd::build::Options build; - - /// Remove the output directory - cmd::clean::Options clean; - - /// Create a new poac package at - cmd::create::Options create; - - /// Format source code with clang-format (default `LLVM`) - cmd::fmt::Options fmt; - - /// Create graph of dependencies - cmd::graph::Options graph; - - /// Create a new poac package in an existing directory - cmd::init::Options init; - - /// Run cpplint - cmd::lint::Options lint; - - /// Log in to poac.dev - cmd::login::Options login; - - /// Publish a package to poac.dev - cmd::publish::Options publish; - - /// Build and run a binary - cmd::run::Options run; - - /// Search a package on poac.dev - cmd::search::Options search; +#include +#include +#include +#include + +struct Cmd { + Fn)> main; + Fn help; + StringRef desc; }; -#define STRINGIFY(r, data, elem) BOOST_PP_STRINGIZE(elem) , - -#define TO_STRINGS(...) \ - BOOST_PP_SEQ_FOR_EACH(STRINGIFY, hoge, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) - -#define DECL_CMDS(...) \ - inline constexpr StringRef command_list[] = {TO_STRINGS(__VA_ARGS__)} +#define DEFINE_CMD(name) \ + { \ + #name, { \ + name##Main, name##Help, name##Desc \ + } \ + } -#define structopt(...) \ - STRUCTOPT(Commands, verbose, quiet, color, __VA_ARGS__); \ - DECL_CMDS(__VA_ARGS__) +static inline const HashMap CMDS = { + DEFINE_CMD(help), DEFINE_CMD(build), DEFINE_CMD(test), DEFINE_CMD(run), + DEFINE_CMD(new), DEFINE_CMD(clean), DEFINE_CMD(init), DEFINE_CMD(version), + DEFINE_CMD(fmt), DEFINE_CMD(lint), +}; -structopt( - build, clean, create, fmt, /*graph,*/ init, lint, login, publish, run, - search -); +void noSuchCommand(StringRef arg) { + Vec candidates(CMDS.size()); + usize i = 0; + for (const auto& cmd : CMDS) { + candidates[i++] = cmd.first; + } -inline String colorize_structopt_error(String s) { - boost::replace_all(s, "Error:", "Error:"_bold_red); - return s; + String suggestion; + if (const auto similar = findSimilarStr(arg, candidates)) { + suggestion = " Did you mean `" + String(similar.value()) + "`?\n\n"; + } + Logger::error( + "no such command: `", arg, "`", "\n\n", suggestion, + " Run `poac help` for a list of commands" + ); } -inline String colorize_anyhow_error(String s) { - // `Caused by:` leaves a trailing newline - if (s.find("Caused by:") != None) { - boost::replace_all(s, "Caused by:", "Caused by:"_yellow); - boost::replace_last(s, "\n", ""); +int helpMain(std::span args) noexcept { + // Parse args + for (StringRef arg : args) { + HANDLE_GLOBAL_OPTS({{"help"}}) + + else if (CMDS.contains(arg)) { + CMDS.at(arg).help(); + return EXIT_SUCCESS; + } + else { + noSuchCommand(arg); + return EXIT_FAILURE; + } } - return s; -} -inline String colorize_help(String s) { - boost::replace_all(s, "USAGE:", "USAGE:"_yellow); - boost::replace_all(s, "FLAGS:", "FLAGS:"_yellow); - boost::replace_all(s, "OPTIONS:", "OPTIONS:"_yellow); - boost::replace_all(s, "SUBCOMMANDS:", "SUBCOMMANDS:"_yellow); - boost::replace_last(s, "\n", ""); - return s; -} + // Print help message for poac itself + std::cout << "A package manager and build system for C++" << '\n'; + std::cout << '\n'; + printUsage("", "[OPTIONS] [COMMAND]"); + std::cout << '\n'; -using ColorError = poac::Error< - "argument for --color must be `auto`, `always`, or `never`, but found `{}`", - StringRef>; + printHeader("Options:"); + printGlobalOpts(); + printOption("--version", "-V", "Print version info and exit"); + std::cout << '\n'; -[[nodiscard]] Result set_color_mode(StringRef color_mode) { - if (color_mode == "auto") { - termcolor2::set_color_mode(spdlog::color_mode::automatic); - if (termcolor2::should_color()) { - toml::color::enable(); - } else { - toml::color::disable(); - } - } else if (color_mode == "always") { - termcolor2::set_color_mode(spdlog::color_mode::always); - toml::color::enable(); - } else if (color_mode == "never") { - termcolor2::set_color_mode(spdlog::color_mode::never); - toml::color::disable(); - } else { - return Err(color_mode); + printHeader("Commands:"); + for (const auto& [name, cmd] : CMDS) { + printCommand(name, cmd.desc); } - return Ok(); + return EXIT_SUCCESS; } -[[nodiscard]] Result -exec(const structopt::app& app, const Commands& args) { - Try(set_color_mode(args.color.value())); - - if (args.build.has_value()) { - return cmd::build::exec(args.build); - } else if (args.clean.has_value()) { - return cmd::clean::exec(args.clean); - } else if (args.create.has_value()) { - return cmd::create::exec(args.create); - } else if (args.fmt.has_value()) { - return cmd::fmt::exec(args.fmt); - } else if (args.graph.has_value()) { - return cmd::graph::exec(args.graph); - } else if (args.init.has_value()) { - return cmd::init::exec(args.init); - } else if (args.lint.has_value()) { - return cmd::lint::exec(args.lint); - } else if (args.login.has_value()) { - return cmd::login::exec(args.login); - } else if (args.publish.has_value()) { - return cmd::publish::exec(args.publish); - } else if (args.run.has_value()) { - return cmd::run::exec(args.run); - } else if (args.search.has_value()) { - return cmd::search::exec(args.search); - } else { - spdlog::info("{}", colorize_help(app.help())); - return Ok(); +int main(int argc, char* argv[]) { + // Handle POAC_TERM_COLOR + if (const char* color_p = std::getenv("POAC_TERM_COLOR")) { + String color(color_p); + std::transform(color.begin(), color.end(), color.begin(), ::tolower); + + if (color == "always") { + setColorMode(ColorMode::always); + } else if (color == "auto") { + setColorMode(ColorMode::automatic); + } else if (color == "never") { + setColorMode(ColorMode::never); + } else { + Logger::error("invalid value for POAC_TERM_COLOR: ", color_p); + return EXIT_FAILURE; + } } -} -int main(const int argc, char* argv[]) { - spdlog::set_pattern("%v"); - auto err_logger = spdlog::stderr_logger_st("stderr"); + // Parse arguments (options should appear before the subcommand, as the help + // message shows intuitively) + for (int i = 1; i < argc; ++i) { + StringRef arg = argv[i]; - auto app = structopt::app("poac", POAC_VERSION); - try { - const auto args = app.parse(argc, argv); + // Global options (which are not command-specific) + HANDLE_GLOBAL_OPTS({}) - // Global options - if (args.verbose.value()) { - spdlog::set_level(spdlog::level::trace); - } else if (args.quiet.value()) { - spdlog::set_level(spdlog::level::off); + // Local options + else if (arg == "-V" || arg == "--version") { + return versionMain({}); } // Subcommands - return exec(app, args) - .map_err([err_logger](const auto& e) { - log::error( - err_logger, colorize_anyhow_error(format("{}", e->what())) - ); - }) - .is_err(); - } catch (const structopt::exception& e) { - if (argc > 1) { - i32 subcommand_index = 1; - for (; subcommand_index < argc; ++subcommand_index) { - if (argv[subcommand_index][0] != '-') { - break; - } - } - - // try to correct typo - if (const auto sugg = util::lev_distance::find_similar_str( - argv[subcommand_index], command_list - ); - sugg.has_value() && sugg.value() != argv[subcommand_index]) { - err_logger->error( - "{}\n" - " --> Did you mean `{}`?\n\n" - "For more information, try {}", - colorize_structopt_error(e.what()), sugg.value(), "--help"_green - ); + else if (CMDS.contains(arg)) { + try { + const Vec cmd_args(argv + i + 1, argv + argc); + return CMDS.at(arg).main(cmd_args); + } catch (const std::exception& e) { + Logger::error(e.what()); return EXIT_FAILURE; } } - err_logger->error( - "{}\n\nFor more information, try {}", - colorize_structopt_error(e.what()), "--help"_green - ); - return EXIT_FAILURE; - } catch (const std::exception& e) { - log::error(err_logger, e.what()); - return EXIT_FAILURE; - } catch (...) { - err_logger->error( - "{} Unknown error occurred\n\n" - "Please open an issue with reproducible information at:\n" - "https://github.com/poac-dev/poac/issues", - "Error:"_bold_red - ); - return EXIT_FAILURE; + else { + noSuchCommand(arg); + return EXIT_FAILURE; + } } + + helpMain({}); + return EXIT_SUCCESS; } diff --git a/src/util/Mod.cmake b/src/util/Mod.cmake deleted file mode 100644 index c8f79a8b2..000000000 --- a/src/util/Mod.cmake +++ /dev/null @@ -1,156 +0,0 @@ -include_guard(GLOBAL) - -include(src/util/termcolor2/Mod.cmake) -include(src/util/semver/Mod.cmake) - -add_library(poac_util_rustify) -target_sources(poac_util_rustify - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/rustify.ixx -) - -# When using result-macros.hpp, we need to link to this interface library. -add_library(poac_util_result_macros INTERFACE) -target_link_libraries(poac_util_result_macros INTERFACE - fmt::fmt # mitama-cpp-result depends on fmt internally - mitama-cpp-result::mitama-cpp-result -) -add_library(poac_util_result) -target_sources(poac_util_result - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/result.ixx -) -target_link_libraries(poac_util_result PRIVATE - poac_util_result_macros -) - -add_library(poac_util_cfg) -target_sources(poac_util_cfg - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/cfg.ixx -) -target_link_libraries(poac_util_cfg PRIVATE - poac_util_rustify -) - -add_library(poac_util_levDistance) -target_sources(poac_util_levDistance - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/levDistance.ixx -) -target_link_libraries(poac_util_levDistance PRIVATE - poac_util_rustify -) - -add_library(poac_util_misc) -target_sources(poac_util_misc - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/misc.ixx -) -target_link_libraries(poac_util_misc PRIVATE poac_util_rustify poac_util_result) - -add_library(poac_util_file) -target_sources(poac_util_file - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/file.ixx -) -target_link_libraries(poac_util_file PRIVATE - poac_util_result - poac_util_rustify -) - -add_library(poac_util_verbosity) -target_sources(poac_util_verbosity - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/verbosity.ixx -) -target_link_libraries(poac_util_verbosity PRIVATE - spdlog::spdlog -) - -add_library(poac_util_format) -target_sources(poac_util_format - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/format.ixx -) -target_link_libraries(poac_util_format PRIVATE - fmt::fmt -) - -add_library(poac_util_pretty) -target_sources(poac_util_pretty - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/pretty.ixx -) -target_link_libraries(poac_util_pretty PRIVATE - poac_util_format - poac_util_rustify -) - -add_library(poac_util_meta) -target_sources(poac_util_meta - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/meta.ixx -) -target_link_libraries(poac_util_meta PRIVATE - poac_util_rustify -) - -add_library(poac_util_shell) -target_sources(poac_util_shell - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/shell.ixx -) - -add_library(poac_util_log) -target_sources(poac_util_log - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/log.ixx -) -target_link_libraries(poac_util_log PRIVATE - poac_util_format - - spdlog::spdlog - termcolor2 - termcolor2_literals_extra - termcolor2_to_color_extra -) - -add_library(poac_util_sha256) -target_sources(poac_util_sha256 - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/sha256.ixx -) -target_link_libraries(poac_util_sha256 PRIVATE - poac_util_format - poac_util_log - poac_util_result - poac_util_rustify -) - -add_library(poac_util_archive) -target_sources(poac_util_archive - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/archive.ixx -) -target_link_libraries(poac_util_archive PRIVATE - poac_util_format - poac_util_log - poac_util_result_macros - poac_util_result - poac_util_rustify -) diff --git a/src/util/file.ixx b/src/util/file.ixx deleted file mode 100644 index 8d0d73379..000000000 --- a/src/util/file.ixx +++ /dev/null @@ -1,27 +0,0 @@ -module; - -// std -#include - -export module poac.util.file; - -import poac.util.result; -import poac.util.rustify; - -namespace poac::util::file { - -using WriteFileFailed = Error<"writing `{}` failed", String>; - -export auto write_file(const Path& p, StringRef content) -> Result { - std::ofstream ofs(p); - ofs << content; - ofs.close(); - - if (!ofs) { - return Err(p.string()); - } - - return Ok(); -} - -} // namespace poac::util::file diff --git a/src/util/format.ixx b/src/util/format.ixx deleted file mode 100644 index f76f2cd71..000000000 --- a/src/util/format.ixx +++ /dev/null @@ -1,14 +0,0 @@ -module; - -// external -#include // NOLINT(build/include_order) -#include // NOLINT(build/include_order) -#include // NOLINT(build/include_order) - -export module poac.util.format; - -export namespace poac { - -using fmt::format; - -} // namespace poac diff --git a/src/util/levDistance.ixx b/src/util/levDistance.ixx deleted file mode 100644 index 817b8914c..000000000 --- a/src/util/levDistance.ixx +++ /dev/null @@ -1,102 +0,0 @@ -module; - -// std -#include // std::min, std::equal -#include // std::tolower -#include // NOLINT(build/include_order) -#include // std::pair - -export module poac.util.levDistance; - -import poac.util.rustify; - -namespace poac::util::lev_distance { - -// ref: https://wandbox.org/permlink/zRjT41alOHdwcf00 -auto calc(StringRef a, StringRef b) -> usize { - const usize asize = a.size(); - const usize bsize = b.size(); - - // for all i and j, d[i,j] will hold the Levenshtein distance between the - // first i characters of s and the first j characters of t - Vec> d(asize + 1, Vec(bsize + 1)); - d[0][0] = 0; - - // source prefixes can be transformed into empty string by dropping all - // characters - for (usize i = 1; i <= asize; ++i) { - d[i][0] = i; - } - - // target prefixes can be reached from empty source prefix by inserting every - // character - for (usize j = 1; j <= bsize; ++j) { - d[0][j] = j; - } - - for (usize i = 1; i <= asize; ++i) { - for (usize j = 1; j <= bsize; ++j) { - const usize subst_cost = a[i - 1] == b[j - 1] ? 0 : 1; - d[i][j] = std::min({ - d[i - 1][j] + 1, // deletion - d[i][j - 1] + 1, // insertion - d[i - 1][j - 1] + subst_cost // substitution - }); - } - } - - return d[asize][bsize]; -} - -inline auto equals_insensitive(StringRef a, StringRef b) -> bool { - return std::equal( - a.cbegin(), a.cend(), b.cbegin(), b.cend(), - [](char a, char b) { return std::tolower(a) == std::tolower(b); } - ); -} - -// ref: https://reviews.llvm.org/differential/changeset/?ref=3315514 -/// Find a similar string in `candidates`. -/// -/// \param lhs a string for a similar string in `Candidates` -/// -/// \param candidates the candidates to find a similar string. -/// -/// \returns a similar string if exists. If no similar string exists, -/// returns None. -export auto -find_similar_str(StringRef lhs, std::span candidates) - -> Option { - // We need to check if `Candidates` has the exact case-insensitive string - // because the Levenshtein distance match does not care about it. - for (StringRef c : candidates) { - if (equals_insensitive(lhs, c)) { - return c; - } - } - - // Keep going with the Levenshtein distance match. - // If the LHS size is less than 3, use the LHS size minus 1 and if not, - // use the LHS size divided by 3. - const usize length = lhs.size(); - const usize max_dist = length < 3 ? length - 1 : length / 3; - - Option> similar_str = None; - for (const StringRef c : candidates) { - const usize cur_dist = calc(lhs, c); - if (cur_dist <= max_dist) { - // The first similar string found || More similar string found - if (!similar_str.has_value() || cur_dist < similar_str->second) { - similar_str = {c, cur_dist}; - } - } - } - - if (similar_str.has_value()) { - return similar_str->first; - } else { - return None; - } -} - -} // namespace poac::util::lev_distance diff --git a/src/util/log.ixx b/src/util/log.ixx deleted file mode 100644 index 245ca5174..000000000 --- a/src/util/log.ixx +++ /dev/null @@ -1,84 +0,0 @@ -module; - -// std -#include -#include -#include -#include - -// external -#include // NOLINT(build/include_order) - -export module poac.util.log; - -import poac.util.format; - -import termcolor2; -import termcolor2.literals_extra; -import termcolor2.to_color_extra; - -namespace poac { - -// -// String literals -// -using namespace termcolor2::color_literals; // NOLINT(build/namespaces) - -} // namespace poac - -export namespace poac::log { - -// -// Logs -// - -// Printed when `--verbose` -template -inline void debug(T&& msg) { - spdlog::debug("[poac] {}", std::forward(msg)); -} -template -inline void debug(fmt::format_string fmt, Args&&... args) { - debug(format(fmt, std::forward(args)...)); -} - -// Printed when `no option` & `--verbose` -template -inline void status(std::string_view header, T&& msg) { - if (termcolor2::should_color()) { - spdlog::info( - "{:>27} {}", termcolor2::to_bold_green(header), std::forward(msg) - ); - } else { - spdlog::info("{:>12} {}", header, std::forward(msg)); - } -} -template -inline void status( - std::string_view header, fmt::format_string fmt, Args&&... args -) { - status(header, format(fmt, std::forward(args)...)); -} - -template -inline void warn(T&& msg) { - spdlog::warn("{} {}", "Warning:"_bold_yellow, std::forward(msg)); -} -template -inline void warn(fmt::format_string fmt, Args&&... args) { - warn(format(fmt, std::forward(args)...)); -} - -template -inline void error(const std::shared_ptr& logger, T&& msg) { - logger->error("{} {}", "Error:"_bold_red, std::forward(msg)); -} -template -inline void error( - const std::shared_ptr& logger, - fmt::format_string fmt, Args&&... args -) { - error(logger, format(fmt, std::forward(args)...)); -} - -} // namespace poac::log diff --git a/src/util/misc.ixx b/src/util/misc.ixx deleted file mode 100644 index 4f0ef7d76..000000000 --- a/src/util/misc.ixx +++ /dev/null @@ -1,72 +0,0 @@ -module; - -// std -#include -#include - -// external -#include -#include // NOLINT(build/include_order) - -export module poac.util.misc; - -import poac.util.rustify; - -export namespace poac::util::misc { - -auto split(const String& raw, const String& delim) -> Vec { - Vec ret; - // Ref: https://github.com/llvm/llvm-project/issues/40486 - // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) - boost::split( - ret, raw, boost::is_any_of(delim), boost::algorithm::token_compress_on - ); - return ret; -} - -auto dupenv(const String& name) -> Option { -#if BOOST_COMP_MSVC - char* env; - usize len; - if (_dupenv_s(&env, &len, name.c_str())) { - return None; - } else { - String env_s(env); - std::free(env); - return env_s; - } -#else - if (const char* env = std::getenv(name.c_str())) { - return env; - } else { - return None; - } -#endif -} - -auto getenv(const String& name, const String& default_v) -> String { - if (const Option env = dupenv(name)) { - return env.value(); - } else { - return default_v; - } -} - -// Inspired by https://stackoverflow.com/q/4891006 -// Expand ~ to user home directory. -[[nodiscard]] auto expand_user() -> Path { - if (Option home = dupenv("HOME")) { - return home.value(); - } else if (Option user = dupenv("USERPROFILE")) { - return user.value(); - } else { - const auto home_drive = dupenv("HOMEDRIVE"); - const auto home_path = dupenv("HOMEPATH"); - if (home_drive && home_path) { - return home_drive.value() + home_path.value(); - } - throw std::runtime_error("could not get home directory"); - } -} - -} // namespace poac::util::misc diff --git a/src/util/pretty.ixx b/src/util/pretty.ixx deleted file mode 100644 index e5c237341..000000000 --- a/src/util/pretty.ixx +++ /dev/null @@ -1,91 +0,0 @@ -module; - -// std -#include -#include - -// external -#include - -export module poac.util.pretty; - -import poac.util.format; -import poac.util.rustify; - -export namespace poac::util::pretty { - -auto to_time(const f64& total_seconds) -> String { - if (total_seconds <= 1.0) { - return format("{:.2f}s", total_seconds); - } - - String res; - const u64 total_secs = static_cast(total_seconds); - if (const u64 days = total_secs / 60 / 60 / 24; days > 0) { - res += std::to_string(days) + "d "; - } - if (const u64 hours = (total_secs / 60 / 60) % 24; hours > 0) { - res += std::to_string(hours) + "h "; - } - if (const u64 minutes = (total_secs / 60) % 60; minutes > 0) { - res += std::to_string(minutes) + "m "; - } - const u64 seconds = total_secs % 60; - res += std::to_string(seconds) + "s"; - return res; -} - -inline auto to_time(const std::chrono::seconds& s) -> String { - return to_time(s.count()); -} - -inline auto to_time(const String& s) -> String { return to_time(std::stod(s)); } - -inline constexpr std::array SIZE_SUFFIXES = { - "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}; - -auto to_byte(f64 bytes) -> String { - int index = 0; - while (bytes >= 1000.0) { - bytes /= 1024.0; - ++index; - } - return format("{:.2f}{}", bytes, SIZE_SUFFIXES.at(index)); -} - -// If string size is over specified number of characters and it can be clipped, -// display an ellipsis (...). -inline auto clip_string(const String& s, const usize& n) -> String { - return s.size() <= n ? s : s.substr(0, n) + "..."; -} - -// This function does not break long words and break on hyphens. -// This assumes that space size is one (` `), not two (` `). -// textwrap(s, 15) => -// This function -// does not break -// long words and -// break on -// hyphens. -auto textwrap(const String& text, usize width) -> Vec { - Vec split_texts; - boost::split(split_texts, text, boost::is_space()); - - Vec wrapped_texts; - String consuming_text; - for (const auto& st : split_texts) { - if (consuming_text.size() + st.size() < width) { - consuming_text += - consuming_text.empty() ? st : " " + st; // assumes space size is one - } else { - wrapped_texts.emplace_back(consuming_text); - consuming_text = st; - } - } - if (!consuming_text.empty()) { - wrapped_texts.emplace_back(consuming_text); - } - return wrapped_texts; -} - -} // namespace poac::util::pretty diff --git a/src/util/result-macros.hpp b/src/util/result-macros.hpp deleted file mode 100644 index a8e57f182..000000000 --- a/src/util/result-macros.hpp +++ /dev/null @@ -1,14 +0,0 @@ -// -// NOTE: Do not include this unless you want to use Try. -// - -#pragma once - -// external -#include - -// -// Macros -// -// NOLINTNEXTLINE(readability-identifier-naming) -#define Try(...) MITAMA_TRY(__VA_ARGS__) diff --git a/src/util/result.ixx b/src/util/result.ixx deleted file mode 100644 index f43d1259a..000000000 --- a/src/util/result.ixx +++ /dev/null @@ -1,64 +0,0 @@ -module; - -// std -#include -#include - -// external -#include -#include -#include - -export module poac.util.result; - -export namespace poac { - -// -// Namespaces -// -namespace anyhow = mitama::anyhow; -namespace thiserror = mitama::thiserror; - -// -// Data types -// -template -using Result = std::conditional_t< - std::is_void_v, anyhow::result, mitama::result>; - -// alias_fn(Ok, mitama::success); // NOLINT(readability-identifier-naming) - -// NOLINT(readability-identifier-naming) -template -inline auto Ok(Args&&... args) - -> decltype(mitama::success(std::forward(args)...)) { - return mitama::success(std::forward(args)...); -} - -template -inline auto Err(Args&&... args) { // NOLINT(readability-identifier-naming) - if constexpr (std::is_void_v) { - return mitama::failure(std::forward(args)...); - } else { - return anyhow::failure(std::forward(args)...); - } -} - -// -// Errors -// -template -using Error = thiserror::error; - -using SubprocessFailed = - Error<"`{}` completed with exit code {}", std::string, std::int32_t>; - -// -// Utilities -// -// NOLINTNEXTLINE(readability-identifier-naming) -inline constexpr auto to_anyhow = [](const std::string& e) { - return anyhow::anyhow(e); -}; - -} // namespace poac diff --git a/src/util/semver/Mod.cmake b/src/util/semver/Mod.cmake deleted file mode 100644 index f3fbf1fea..000000000 --- a/src/util/semver/Mod.cmake +++ /dev/null @@ -1,102 +0,0 @@ -include_guard(GLOBAL) - -add_library(semver_exception) -target_sources(semver_exception - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/semver/exception.ixx -) - -add_library(semver_token) -target_sources(semver_token - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/semver/token.ixx -) - -add_library(semver_range) -target_sources(semver_range - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/semver/range.ixx -) -target_link_libraries(semver_range PRIVATE - semver_token -) - -add_library(semver_lexer) -target_sources(semver_lexer - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/semver/lexer.ixx -) -target_link_libraries(semver_lexer PRIVATE - semver_token -) - -add_library(semver_parser) -target_sources(semver_parser - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/semver/parser.ixx -) -target_link_libraries(semver_parser PRIVATE - semver_exception - semver_lexer - semver_token - semver_range -) - -add_library(semver_comparison) -target_sources(semver_comparison - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/semver/comparison.ixx -) -target_link_libraries(semver_comparison PRIVATE - semver_lexer - semver_parser - semver_token -) - -add_library(semver_interval) -target_sources(semver_interval - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/semver/interval.ixx -) -target_link_libraries(semver_interval PRIVATE - fmt::fmt - semver_comparison - semver_exception - semver_parser - semver_token -) - -add_library(semver_io) -target_sources(semver_io - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/semver/io.ixx -) -target_link_libraries(semver_io PRIVATE - fmt::fmt - semver_token -) - -add_library(semver) -target_sources(semver - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/semver/semver.ixx -) -target_link_libraries(semver PRIVATE - semver_comparison - semver_exception - semver_interval - semver_io - semver_lexer - semver_parser - semver_range - semver_token -) diff --git a/src/util/shell.ixx b/src/util/shell.ixx deleted file mode 100644 index b659607a5..000000000 --- a/src/util/shell.ixx +++ /dev/null @@ -1,142 +0,0 @@ -module; - -// std -#include -#include -#include -#include - -export module poac.util.shell; - -export namespace poac::util::shell { - -class Cmd { -public: - [[nodiscard]] inline auto string() const -> std::string { return cmd; } - - Cmd() = default; // NOLINT(bugprone-exception-escape) - explicit Cmd(std::string c) : cmd(std::move(c)) {} - - inline auto env(const std::string& name, const std::string& value) -> Cmd& { - cmd.insert(0, name + "=" + value + " "); - return *this; - } - inline auto stderr_to_stdout() -> Cmd& { - cmd += " 2>&1"; - return *this; - } - inline auto to_dev_null() -> Cmd& { - cmd += " >/dev/null"; - return *this; - } - inline auto dump_stdout() -> Cmd& { - cmd += " 1>/dev/null"; - return *this; - } - inline auto dump_stderr() -> Cmd& { - cmd += " 2>/dev/null"; - return *this; - } - - struct SimpleResult : std::pair { - SimpleResult(std::int32_t c, const std::string& r) - : std::pair({c, r}) {} - - [[nodiscard]] inline auto is_ok() const -> bool { return first == 0; } - [[nodiscard]] inline auto is_err() const -> bool { return !is_ok(); } - [[nodiscard]] inline auto output() const -> std::string { return second; } - explicit inline operator bool() const { return is_ok(); } - }; - - [[nodiscard]] inline auto exec() const -> SimpleResult { - std::array buffer{}; - std::string result; - FILE* pipe = popen(cmd.c_str(), "r"); // NOLINT(cert-env33-c) - if (!pipe) { - return {1, ""}; - } - while (std::fgets(buffer.data(), 128, pipe) != nullptr) { - result += buffer.data(); - } - - const std::int32_t code = pclose(pipe); - if (code != 0) { - return {code, result}; - } - return {0, result}; - } - - [[nodiscard]] inline auto exec_no_capture() const -> std::int32_t { - return std::system(cmd.c_str()); // NOLINT(cert-env33-c) - } - - inline friend auto operator<<(std::ostream& os, const Cmd& c) - -> std::ostream& { - return (os << c.cmd); - } - - inline auto operator==(const Cmd& rhs) const -> bool { - return this->cmd == rhs.cmd; - } - inline auto operator==(const std::string& rhs) const -> bool { - return this->cmd == rhs; - } - - inline auto operator&&(const Cmd& rhs) const -> Cmd { - return Cmd(this->cmd + " && " + rhs.cmd); - } - inline auto operator&&(const std::string& rhs) const -> Cmd { - return Cmd(this->cmd + " && " + rhs); - } - - inline auto operator&=(const Cmd& rhs) -> Cmd& { - this->cmd += " && " + rhs.cmd; - return *this; - } - inline auto operator&=(const std::string& rhs) -> Cmd& { - this->cmd += " && " + rhs; - return *this; - } - - inline auto operator||(const Cmd& rhs) const -> Cmd { - return Cmd(this->cmd + " || " + rhs.cmd); - } - inline auto operator||(const std::string& rhs) const -> Cmd { - return Cmd(this->cmd + " || " + rhs); - } - - inline auto operator|=(const Cmd& rhs) -> Cmd& { - this->cmd += " || " + rhs.cmd; - return *this; - } - inline auto operator|=(const std::string& rhs) -> Cmd& { - this->cmd += " || " + rhs; - return *this; - } - - // TODO(ken-matsui): should this be "; "? - inline auto operator+(const Cmd& rhs) const -> Cmd { - return Cmd(this->cmd + " " + rhs.cmd); - } - inline auto operator+(const std::string& rhs) const -> Cmd { - return Cmd(this->cmd + " " + rhs); - } - - inline auto operator+=(const Cmd& rhs) -> Cmd& { - this->cmd += " " + rhs.cmd; - return *this; - } - inline auto operator+=(const std::string& rhs) -> Cmd& { - this->cmd += " " + rhs; - return *this; - } - -private: - std::string cmd; -}; // NOLINT(readability/braces) - -inline auto has_command(const std::string& c) -> bool { - return Cmd("type " + c + " >/dev/null 2>&1").exec().is_ok(); -} - -} // namespace poac::util::shell diff --git a/src/util/termcolor2/Mod.cmake b/src/util/termcolor2/Mod.cmake deleted file mode 100644 index 1c183d054..000000000 --- a/src/util/termcolor2/Mod.cmake +++ /dev/null @@ -1,73 +0,0 @@ -include_guard(GLOBAL) - -add_library(termcolor2_color_mode) -target_sources(termcolor2_color_mode - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/termcolor2/color_mode.ixx -) -target_link_libraries(termcolor2_color_mode PRIVATE - spdlog::spdlog -) - -add_library(termcolor2_presets) -target_sources(termcolor2_presets - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/termcolor2/presets.ixx -) - -add_library(termcolor2_to_color) -target_sources(termcolor2_to_color - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/termcolor2/to_color.ixx -) -target_link_libraries(termcolor2_to_color PRIVATE - termcolor2_color_mode - termcolor2_presets -) - -add_library(termcolor2_to_color_extra) -target_sources(termcolor2_to_color_extra - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/termcolor2/to_color_extra.ixx -) -target_link_libraries(termcolor2_to_color_extra PRIVATE - termcolor2_color_mode - termcolor2_presets -) - -add_library(termcolor2_literals) -target_sources(termcolor2_literals - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/termcolor2/literals.ixx -) -target_link_libraries(termcolor2_literals PRIVATE - termcolor2_to_color -) - -add_library(termcolor2) -target_sources(termcolor2 - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/termcolor2/termcolor2.ixx -) -target_link_libraries(termcolor2 PRIVATE - termcolor2_color_mode - termcolor2_literals - termcolor2_presets - termcolor2_to_color -) - -add_library(termcolor2_literals_extra) -target_sources(termcolor2_literals_extra - PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES - src/util/termcolor2/literals_extra.ixx -) -target_link_libraries(termcolor2_literals_extra PRIVATE - termcolor2_to_color_extra -) diff --git a/src/util/termcolor2/color_mode.ixx b/src/util/termcolor2/color_mode.ixx deleted file mode 100644 index 24e52cc74..000000000 --- a/src/util/termcolor2/color_mode.ixx +++ /dev/null @@ -1,54 +0,0 @@ -module; - -// external -#include -#include - -export module termcolor2.color_mode; - -export namespace termcolor2::details { - -class ColorMode { -public: - inline void set(spdlog::color_mode mode) { - switch (mode) { - case spdlog::color_mode::always: - should_color_ = true; - return; - case spdlog::color_mode::automatic: - should_color_ = spdlog::details::os::is_color_terminal(); - return; - case spdlog::color_mode::never: - should_color_ = false; - return; - default: - __builtin_unreachable(); - } - } - [[nodiscard]] inline auto should_color() const -> bool { - return should_color_; - } - - static auto instance() -> ColorMode& { - static ColorMode INSTANCE; - return INSTANCE; - } - -private: - // default: automatic - bool should_color_ = spdlog::details::os::is_color_terminal(); -}; - -} // namespace termcolor2::details - -export namespace termcolor2 { - -inline void set_color_mode(spdlog::color_mode cm) { - details::ColorMode::instance().set(cm); -} - -inline auto should_color() -> bool { - return details::ColorMode::instance().should_color(); -} - -} // namespace termcolor2 diff --git a/src/util/termcolor2/literals.ixx b/src/util/termcolor2/literals.ixx deleted file mode 100644 index 8ea6c3704..000000000 --- a/src/util/termcolor2/literals.ixx +++ /dev/null @@ -1,496 +0,0 @@ -module; - -// std -#include // std::size_t -#include // std::basic_string - -export module termcolor2.literals; - -import termcolor2.to_color; - -export namespace termcolor2::inline color_literals::inline foreground_literals { - -inline auto operator"" _gray(const char* str, std::size_t len) - -> std::basic_string { - return to_gray(str, len); -} -inline auto operator"" _gray(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_gray(str, len); -} -inline auto operator"" _gray(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_gray(str, len); -} -inline auto operator"" _gray(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_gray(str, len); -} -inline auto operator"" _gray(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_gray(str, len); -} - -inline auto operator"" _red(const char* str, std::size_t len) - -> std::basic_string { - return to_red(str, len); -} -inline auto operator"" _red(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_red(str, len); -} -inline auto operator"" _red(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_red(str, len); -} -inline auto operator"" _red(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_red(str, len); -} -inline auto operator"" _red(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_red(str, len); -} - -inline auto operator"" _green(const char* str, std::size_t len) - -> std::basic_string { - return to_green(str, len); -} -inline auto operator"" _green(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_green(str, len); -} -inline auto operator"" _green(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_green(str, len); -} -inline auto operator"" _green(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_green(str, len); -} -inline auto operator"" _green(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_green(str, len); -} - -inline auto operator"" _yellow(const char* str, std::size_t len) - -> std::basic_string { - return to_yellow(str, len); -} -inline auto operator"" _yellow(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_yellow(str, len); -} -inline auto operator"" _yellow(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_yellow(str, len); -} -inline auto operator"" _yellow(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_yellow(str, len); -} -inline auto operator"" _yellow(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_yellow(str, len); -} - -inline auto operator"" _blue(const char* str, std::size_t len) - -> std::basic_string { - return to_blue(str, len); -} -inline auto operator"" _blue(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_blue(str, len); -} -inline auto operator"" _blue(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_blue(str, len); -} -inline auto operator"" _blue(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_blue(str, len); -} -inline auto operator"" _blue(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_blue(str, len); -} - -inline auto operator"" _magenta(const char* str, std::size_t len) - -> std::basic_string { - return to_magenta(str, len); -} -inline auto operator"" _magenta(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_magenta(str, len); -} -inline auto operator"" _magenta(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_magenta(str, len); -} -inline auto operator"" _magenta(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_magenta(str, len); -} -inline auto operator"" _magenta(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_magenta(str, len); -} - -inline auto operator"" _cyan(const char* str, std::size_t len) - -> std::basic_string { - return to_cyan(str, len); -} -inline auto operator"" _cyan(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_cyan(str, len); -} -inline auto operator"" _cyan(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_cyan(str, len); -} -inline auto operator"" _cyan(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_cyan(str, len); -} -inline auto operator"" _cyan(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_cyan(str, len); -} - -inline auto operator"" _white(const char* str, std::size_t len) - -> std::basic_string { - return to_white(str, len); -} -inline auto operator"" _white(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_white(str, len); -} -inline auto operator"" _white(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_white(str, len); -} -inline auto operator"" _white(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_white(str, len); -} -inline auto operator"" _white(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_white(str, len); -} - -// clang-format off -// to avoid reporting errors with inline namespace on only the dry-run mode. (IDK why) -} // namespace termcolor2::color_literals::foreground_literals -// clang-format on - -namespace termcolor2::inline color_literals::inline background_literals { -inline auto operator"" _on_gray(const char* str, std::size_t len) - -> std::basic_string { - return to_on_gray(str, len); -} -inline auto operator"" _on_gray(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_on_gray(str, len); -} -inline auto operator"" _on_gray(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_on_gray(str, len); -} -inline auto operator"" _on_gray(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_on_gray(str, len); -} -inline auto operator"" _on_gray(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_on_gray(str, len); -} - -inline auto operator"" _on_red(const char* str, std::size_t len) - -> std::basic_string { - return to_on_red(str, len); -} -inline auto operator"" _on_red(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_on_red(str, len); -} -inline auto operator"" _on_red(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_on_red(str, len); -} -inline auto operator"" _on_red(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_on_red(str, len); -} -inline auto operator"" _on_red(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_on_red(str, len); -} - -inline auto operator"" _on_green(const char* str, std::size_t len) - -> std::basic_string { - return to_on_green(str, len); -} -inline auto operator"" _on_green(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_on_green(str, len); -} -inline auto operator"" _on_green(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_on_green(str, len); -} -inline auto operator"" _on_green(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_on_green(str, len); -} -inline auto operator"" _on_green(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_on_green(str, len); -} - -inline auto operator"" _on_yellow(const char* str, std::size_t len) - -> std::basic_string { - return to_on_yellow(str, len); -} -inline auto operator"" _on_yellow(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_on_yellow(str, len); -} -inline auto operator"" _on_yellow(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_on_yellow(str, len); -} -inline auto operator"" _on_yellow(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_on_yellow(str, len); -} -inline auto operator"" _on_yellow(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_on_yellow(str, len); -} - -inline auto operator"" _on_blue(const char* str, std::size_t len) - -> std::basic_string { - return to_on_blue(str, len); -} -inline auto operator"" _on_blue(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_on_blue(str, len); -} -inline auto operator"" _on_blue(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_on_blue(str, len); -} -inline auto operator"" _on_blue(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_on_blue(str, len); -} -inline auto operator"" _on_blue(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_on_blue(str, len); -} - -inline auto operator"" _on_magenta(const char* str, std::size_t len) - -> std::basic_string { - return to_on_magenta(str, len); -} -inline auto operator"" _on_magenta(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_on_magenta(str, len); -} -inline auto operator"" _on_magenta(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_on_magenta(str, len); -} -inline auto operator"" _on_magenta(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_on_magenta(str, len); -} -inline auto operator"" _on_magenta(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_on_magenta(str, len); -} - -inline auto operator"" _on_cyan(const char* str, std::size_t len) - -> std::basic_string { - return to_on_cyan(str, len); -} -inline auto operator"" _on_cyan(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_on_cyan(str, len); -} -inline auto operator"" _on_cyan(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_on_cyan(str, len); -} -inline auto operator"" _on_cyan(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_on_cyan(str, len); -} -inline auto operator"" _on_cyan(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_on_cyan(str, len); -} - -inline auto operator"" _on_white(const char* str, std::size_t len) - -> std::basic_string { - return to_on_white(str, len); -} -inline auto operator"" _on_white(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_on_white(str, len); -} -inline auto operator"" _on_white(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_on_white(str, len); -} -inline auto operator"" _on_white(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_on_white(str, len); -} -inline auto operator"" _on_white(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_on_white(str, len); -} - -// clang-format off -// to avoid reporting errors with inline namespace on only the dry-run mode. (IDK why) -} // namespace termcolor2::color_literals::background_literals -// clang-format on - -namespace termcolor2::inline color_literals::inline attribute_literals { -inline auto operator"" _bold(const char* str, std::size_t len) - -> std::basic_string { - return to_bold(str, len); -} -inline auto operator"" _bold(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_bold(str, len); -} -inline auto operator"" _bold(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_bold(str, len); -} -inline auto operator"" _bold(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_bold(str, len); -} -inline auto operator"" _bold(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_bold(str, len); -} - -inline auto operator"" _dark(const char* str, std::size_t len) - -> std::basic_string { - return to_dark(str, len); -} -inline auto operator"" _dark(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_dark(str, len); -} -inline auto operator"" _dark(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_dark(str, len); -} -inline auto operator"" _dark(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_dark(str, len); -} -inline auto operator"" _dark(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_dark(str, len); -} - -inline auto operator"" _underline(const char* str, std::size_t len) - -> std::basic_string { - return to_underline(str, len); -} -inline auto operator"" _underline(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_underline(str, len); -} -inline auto operator"" _underline(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_underline(str, len); -} -inline auto operator"" _underline(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_underline(str, len); -} -inline auto operator"" _underline(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_underline(str, len); -} - -inline auto operator"" _blink(const char* str, std::size_t len) - -> std::basic_string { - return to_blink(str, len); -} -inline auto operator"" _blink(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_blink(str, len); -} -inline auto operator"" _blink(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_blink(str, len); -} -inline auto operator"" _blink(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_blink(str, len); -} -inline auto operator"" _blink(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_blink(str, len); -} - -inline auto operator"" _reverse(const char* str, std::size_t len) - -> std::basic_string { - return to_reverse(str, len); -} -inline auto operator"" _reverse(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_reverse(str, len); -} -inline auto operator"" _reverse(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_reverse(str, len); -} -inline auto operator"" _reverse(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_reverse(str, len); -} -inline auto operator"" _reverse(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_reverse(str, len); -} - -inline auto operator"" _concealed(const char* str, std::size_t len) - -> std::basic_string { - return to_concealed(str, len); -} -inline auto operator"" _concealed(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_concealed(str, len); -} -inline auto operator"" _concealed(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_concealed(str, len); -} -inline auto operator"" _concealed(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_concealed(str, len); -} -inline auto operator"" _concealed(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_concealed(str, len); -} - -// clang-format off -// to avoid reporting errors with inline namespace on only the dry-run mode. (IDK why) -} // namespace termcolor2::color_literals::attribute_literals -// clang-format on - -namespace termcolor2::inline control_literals { -// clang-format off -// to avoid reporting errors with inline namespace on only the dry-run mode. (IDK why) -} // namespace termcolor2::inline control_literals -// clang-format on diff --git a/src/util/termcolor2/literals_extra.ixx b/src/util/termcolor2/literals_extra.ixx deleted file mode 100644 index f3e895797..000000000 --- a/src/util/termcolor2/literals_extra.ixx +++ /dev/null @@ -1,184 +0,0 @@ -module; - -// std -#include // std::size_t -#include // std::basic_string - -export module termcolor2.literals_extra; - -import termcolor2.to_color_extra; - -export namespace termcolor2::inline color_literals::inline foreground_literals { - -inline auto operator"" _bold_gray(const char* str, std::size_t len) - -> std::basic_string { - return to_bold_gray(str, len); -} -inline auto operator"" _bold_gray(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_bold_gray(str, len); -} -inline auto operator"" _bold_gray(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_bold_gray(str, len); -} -inline auto operator"" _bold_gray(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_bold_gray(str, len); -} -inline auto operator"" _bold_gray(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_bold_gray(str, len); -} - -inline auto operator"" _bold_red(const char* str, std::size_t len) - -> std::basic_string { - return to_bold_red(str, len); -} -inline auto operator"" _bold_red(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_bold_red(str, len); -} -inline auto operator"" _bold_red(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_bold_red(str, len); -} -inline auto operator"" _bold_red(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_bold_red(str, len); -} -inline auto operator"" _bold_red(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_bold_red(str, len); -} - -inline auto operator"" _bold_green(const char* str, std::size_t len) - -> std::basic_string { - return to_bold_green(str, len); -} -inline auto operator"" _bold_green(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_bold_green(str, len); -} -inline auto operator"" _bold_green(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_bold_green(str, len); -} -inline auto operator"" _bold_green(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_bold_green(str, len); -} -inline auto operator"" _bold_green(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_bold_green(str, len); -} - -inline auto operator"" _bold_yellow(const char* str, std::size_t len) - -> std::basic_string { - return to_bold_yellow(str, len); -} -inline auto operator"" _bold_yellow(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_bold_yellow(str, len); -} -inline auto operator"" _bold_yellow(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_bold_yellow(str, len); -} -inline auto operator"" _bold_yellow(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_bold_yellow(str, len); -} -inline auto operator"" _bold_yellow(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_bold_yellow(str, len); -} - -inline auto operator"" _bold_blue(const char* str, std::size_t len) - -> std::basic_string { - return to_bold_blue(str, len); -} -inline auto operator"" _bold_blue(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_bold_blue(str, len); -} -inline auto operator"" _bold_blue(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_bold_blue(str, len); -} -inline auto operator"" _bold_blue(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_bold_blue(str, len); -} -inline auto operator"" _bold_blue(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_bold_blue(str, len); -} - -inline auto operator"" _bold_magenta(const char* str, std::size_t len) - -> std::basic_string { - return to_bold_magenta(str, len); -} -inline auto operator"" _bold_magenta(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_bold_magenta(str, len); -} -inline auto operator"" _bold_magenta(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_bold_magenta(str, len); -} -inline auto operator"" _bold_magenta(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_bold_magenta(str, len); -} -inline auto operator"" _bold_magenta(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_bold_magenta(str, len); -} - -inline auto operator"" _bold_cyan(const char* str, std::size_t len) - -> std::basic_string { - return to_bold_cyan(str, len); -} -inline auto operator"" _bold_cyan(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_bold_cyan(str, len); -} -inline auto operator"" _bold_cyan(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_bold_cyan(str, len); -} -inline auto operator"" _bold_cyan(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_bold_cyan(str, len); -} -inline auto operator"" _bold_cyan(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_bold_cyan(str, len); -} - -inline auto operator"" _bold_white(const char* str, std::size_t len) - -> std::basic_string { - return to_bold_white(str, len); -} -inline auto operator"" _bold_white(const wchar_t* str, std::size_t len) - -> std::basic_string { - return to_bold_white(str, len); -} -inline auto operator"" _bold_white(const char8_t* str, std::size_t len) - -> std::basic_string { - return to_bold_white(str, len); -} -inline auto operator"" _bold_white(const char16_t* str, std::size_t len) - -> std::basic_string { - return to_bold_white(str, len); -} -inline auto operator"" _bold_white(const char32_t* str, std::size_t len) - -> std::basic_string { - return to_bold_white(str, len); -} - -// clang-format off -// to avoid reporting errors with inline namespace on only the dry-run mode. (IDK why) -} // namespace termcolor2::color_literals::foreground_literals -// clang-format on diff --git a/src/util/termcolor2/presets.ixx b/src/util/termcolor2/presets.ixx deleted file mode 100644 index 0b8eb5736..000000000 --- a/src/util/termcolor2/presets.ixx +++ /dev/null @@ -1,217 +0,0 @@ -module; - -// std -#include -#include - -export module termcolor2.presets; - -export namespace termcolor2 { -namespace detail { - - // ref: https://zenn.dev/tetsurom/scraps/b6d81079559c91 -#define CHAR_LITERAL(t, x) \ - ::termcolor2::detail::select_type((x), (L##x), (u8##x), (u##x), (U##x)) - - template - [[nodiscard]] constexpr auto select_type( - // NOLINTNEXTLINE(modernize-avoid-c-arrays) - const char (&s1)[N], const wchar_t (&s2)[N], const char8_t (&s3)[N], - // NOLINTNEXTLINE(modernize-avoid-c-arrays) - const char16_t (&s4)[N], const char32_t (&s5)[N] - ) noexcept -> std::basic_string { - // C++23 > if consteval - try { - if constexpr (std::is_same_v) { - return s1; - } - if constexpr (std::is_same_v) { - return s2; - } - if constexpr (std::is_same_v) { - return s3; - } - if constexpr (std::is_same_v) { - return s4; - } - if constexpr (std::is_same_v) { - return s5; - } - } catch (...) { - __builtin_unreachable(); - } - } - -} // namespace detail - -// -// Foreground manipulators -// -template -inline constexpr auto gray_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[30m"); -} -inline const auto gray = gray_v(); - -template -inline constexpr auto red_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[31m"); -} -inline const auto red = red_v(); - -template -inline constexpr auto green_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[32m"); -} -inline const auto green = green_v(); - -template -inline constexpr auto yellow_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[33m"); -} -inline const auto yellow = yellow_v(); - -template -inline constexpr auto blue_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[34m"); -} -inline const auto blue = blue_v(); - -template -inline constexpr auto magenta_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[35m"); -} -inline const auto magenta = magenta_v(); - -template -inline constexpr auto cyan_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[36m"); -} -inline const auto cyan = cyan_v(); - -template -inline constexpr auto white_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[37m"); -} -inline const auto white = white_v(); - -// -// Background manipulators -// -template -inline constexpr auto on_gray_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[40m"); -} -inline const auto on_gray = on_gray_v(); - -template -inline constexpr auto on_red_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[41m"); -} -inline const auto on_red = on_red_v(); - -template -inline constexpr auto on_green_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[42m"); -} -inline const auto on_green = on_green_v(); - -template -inline constexpr auto on_yellow_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[43m"); -} -inline const auto on_yellow = on_yellow_v(); - -template -inline constexpr auto on_blue_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[44m"); -} -inline const auto on_blue = on_blue_v(); - -template -inline constexpr auto on_magenta_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[45m"); -} -inline const auto on_magenta = on_magenta_v(); - -template -inline constexpr auto on_cyan_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[46m"); -} -inline const auto on_cyan = on_cyan_v(); - -template -inline constexpr auto on_white_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[47m"); -} -inline const auto on_white = on_white_v(); - -// -// Attribute manipulators -// -template -inline constexpr auto bold_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[01m"); -} -inline const auto bold = bold_v(); - -template -inline constexpr auto dark_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[02m"); -} -inline const auto dark = dark_v(); - -template -inline constexpr auto underline_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[04m"); -} -inline const auto underline = underline_v(); - -template -inline constexpr auto blink_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[05m"); -} -inline const auto blink = blink_v(); - -template -inline constexpr auto reverse_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[07m"); -} -inline const auto reverse = reverse_v(); - -template -inline constexpr auto concealed_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[08m"); -} -inline const auto concealed = concealed_v(); - -template -inline constexpr auto reset_v() noexcept - -> std::basic_string { - return CHAR_LITERAL(CharT, "\033[00m"); -} -inline const auto reset = reset_v(); - -} // end namespace termcolor2 diff --git a/src/util/termcolor2/termcolor2.ixx b/src/util/termcolor2/termcolor2.ixx deleted file mode 100644 index ce401e2fe..000000000 --- a/src/util/termcolor2/termcolor2.ixx +++ /dev/null @@ -1,6 +0,0 @@ -export module termcolor2; - -export import termcolor2.color_mode; -export import termcolor2.literals; -export import termcolor2.presets; -export import termcolor2.to_color; diff --git a/src/util/termcolor2/to_color.ixx b/src/util/termcolor2/to_color.ixx deleted file mode 100644 index 176aa5fcd..000000000 --- a/src/util/termcolor2/to_color.ixx +++ /dev/null @@ -1,508 +0,0 @@ -module; - -// std -#include // std::size_t -#include // std::basic_string -#include // std::basic_string_view - -export module termcolor2.to_color; - -import termcolor2.color_mode; -import termcolor2.presets; - -export namespace termcolor2 { - -template -inline auto -to_color(Func&& fn, const std::basic_string& str) - -> std::basic_string { - if (should_color()) { - return fn() + str + reset_v(); - } else { - return str; - } -} - -// -// Foreground manipulators -// -template -inline auto to_gray(const CharT* str) - -> std::basic_string { - return to_color(gray_v, std::basic_string(str)); -} -template -inline auto -to_gray(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(gray_v, std::basic_string(str, len)); -} -template -inline auto -to_gray(const std::basic_string& str) -> std::basic_string { - return to_color(gray_v, str); -} -template -inline auto -to_gray(const std::basic_string_view str) -> std::basic_string { - return to_color(gray_v, std::basic_string(str)); -} - -template -inline auto to_red(const CharT* str) - -> std::basic_string { - return to_color(red_v, std::basic_string(str)); -} -template -inline auto to_red(const CharT* str, std::size_t len) - -> std::basic_string { - return to_color(red_v, std::basic_string(str, len)); -} -template -inline auto -to_red(const std::basic_string& str) -> std::basic_string { - return to_color(red_v, str); -} -template -inline auto -to_red(const std::basic_string_view str) -> std::basic_string { - return to_color(red_v, std::basic_string(str)); -} - -template -inline auto to_green(const CharT* str) - -> std::basic_string { - return to_color(green_v, std::basic_string(str)); -} -template -inline auto -to_green(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(green_v, std::basic_string(str, len)); -} -template -inline auto -to_green(const std::basic_string& str) -> std::basic_string { - return to_color(green_v, str); -} -template -inline auto -to_green(const std::basic_string_view str) -> std::basic_string { - return to_color(green_v, std::basic_string(str)); -} - -template -inline auto to_yellow(const CharT* str) - -> std::basic_string { - return to_color(yellow_v, std::basic_string(str)); -} -template -inline auto -to_yellow(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(yellow_v, std::basic_string(str, len)); -} -template -inline auto -to_yellow(const std::basic_string& str) -> std::basic_string { - return to_color(yellow_v, str); -} -template -inline auto -to_yellow(const std::basic_string_view str) -> std::basic_string { - return to_color(yellow_v, std::basic_string(str)); -} - -template -inline auto to_blue(const CharT* str) - -> std::basic_string { - return to_color(blue_v, std::basic_string(str)); -} -template -inline auto -to_blue(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(blue_v, std::basic_string(str, len)); -} -template -inline auto -to_blue(const std::basic_string& str) -> std::basic_string { - return to_color(blue_v, str); -} -template -inline auto -to_blue(const std::basic_string_view str) -> std::basic_string { - return to_color(blue_v, std::basic_string(str)); -} - -template -inline auto to_magenta(const CharT* str) - -> std::basic_string { - return to_color(magenta_v, std::basic_string(str)); -} -template -inline auto -to_magenta(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(magenta_v, std::basic_string(str, len)); -} -template -inline auto -to_magenta(const std::basic_string& str) -> std::basic_string { - return to_color(magenta_v, str); -} -template -inline auto -to_magenta(const std::basic_string_view str) - -> std::basic_string { - return to_color(magenta_v, std::basic_string(str)); -} - -template -inline auto to_cyan(const CharT* str) - -> std::basic_string { - return to_color(cyan_v, std::basic_string(str)); -} -template -inline auto -to_cyan(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(cyan_v, std::basic_string(str, len)); -} -template -inline auto -to_cyan(const std::basic_string& str) -> std::basic_string { - return to_color(cyan_v, str); -} -template -inline auto -to_cyan(const std::basic_string_view str) -> std::basic_string { - return to_color(cyan_v, std::basic_string(str)); -} - -template -inline auto to_white(const CharT* str) - -> std::basic_string { - return to_color(white_v, std::basic_string(str)); -} -template -inline auto -to_white(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(white_v, std::basic_string(str, len)); -} -template -inline auto -to_white(const std::basic_string& str) -> std::basic_string { - return to_color(white_v, str); -} -template -inline auto -to_white(const std::basic_string_view str) -> std::basic_string { - return to_color(white_v, std::basic_string(str)); -} - -// -// Background manipulators -// -template -inline auto to_on_gray(const CharT* str) - -> std::basic_string { - return to_color(on_gray_v, std::basic_string(str)); -} -template -inline auto -to_on_gray(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(on_gray_v, std::basic_string(str, len)); -} -template -inline auto -to_on_gray(const std::basic_string& str) -> std::basic_string { - return to_color(on_gray_v, str); -} -template -inline auto -to_on_gray(const std::basic_string_view str) - -> std::basic_string { - return to_color(on_gray_v, std::basic_string(str)); -} - -template -inline auto to_on_red(const CharT* str) - -> std::basic_string { - return to_color(on_red_v, std::basic_string(str)); -} -template -inline auto -to_on_red(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(on_red_v, std::basic_string(str, len)); -} -template -inline auto -to_on_red(const std::basic_string& str) -> std::basic_string { - return to_color(on_red_v, str); -} -template -inline auto -to_on_red(const std::basic_string_view str) -> std::basic_string { - return to_color(on_red_v, std::basic_string(str)); -} - -template -inline auto to_on_green(const CharT* str) - -> std::basic_string { - return to_color(on_green_v, std::basic_string(str)); -} -template -inline auto -to_on_green(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(on_green_v, std::basic_string(str, len)); -} -template -inline auto -to_on_green(const std::basic_string& str) -> std::basic_string { - return to_color(on_green_v, str); -} -template -inline auto -to_on_green(const std::basic_string_view str) - -> std::basic_string { - return to_color(on_green_v, std::basic_string(str)); -} - -template -inline auto to_on_yellow(const CharT* str) - -> std::basic_string { - return to_color(on_yellow_v, std::basic_string(str)); -} -template -inline auto -to_on_yellow(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(on_yellow_v, std::basic_string(str, len)); -} -template -inline auto -to_on_yellow(const std::basic_string& str) -> std::basic_string { - return to_color(on_yellow_v, str); -} -template -inline auto -to_on_yellow(const std::basic_string_view str) - -> std::basic_string { - return to_color(on_yellow_v, std::basic_string(str)); -} - -template -inline auto to_on_blue(const CharT* str) - -> std::basic_string { - return to_color(on_blue_v, std::basic_string(str)); -} -template -inline auto -to_on_blue(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(on_blue_v, std::basic_string(str, len)); -} -template -inline auto -to_on_blue(const std::basic_string& str) -> std::basic_string { - return to_color(on_blue_v, str); -} -template -inline auto -to_on_blue(const std::basic_string_view str) - -> std::basic_string { - return to_color(on_blue_v, std::basic_string(str)); -} - -template -inline auto to_on_magenta(const CharT* str) - -> std::basic_string { - return to_color(on_magenta_v, std::basic_string(str)); -} -template -inline auto -to_on_magenta(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(on_magenta_v, std::basic_string(str, len)); -} -template -inline auto -to_on_magenta(const std::basic_string& str) -> std::basic_string { - return to_color(on_magenta_v, str); -} -template -inline auto -to_on_magenta(const std::basic_string_view str) - -> std::basic_string { - return to_color(on_magenta_v, std::basic_string(str)); -} - -template -inline auto to_on_cyan(const CharT* str) - -> std::basic_string { - return to_color(on_cyan_v, std::basic_string(str)); -} -template -inline auto -to_on_cyan(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(on_cyan_v, std::basic_string(str, len)); -} -template -inline auto -to_on_cyan(const std::basic_string& str) -> std::basic_string { - return to_color(on_cyan_v, str); -} -template -inline auto -to_on_cyan(const std::basic_string_view str) - -> std::basic_string { - return to_color(on_cyan_v, std::basic_string(str)); -} - -template -inline auto to_on_white(const CharT* str) - -> std::basic_string { - return to_color(on_white_v, std::basic_string(str)); -} -template -inline auto -to_on_white(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(on_white_v, std::basic_string(str, len)); -} -template -inline auto -to_on_white(const std::basic_string& str) -> std::basic_string { - return to_color(on_white_v, str); -} -template -inline auto -to_on_white(const std::basic_string_view str) - -> std::basic_string { - return to_color(on_white_v, std::basic_string(str)); -} - -// -// Attribute manipulators -// -template -inline auto to_bold(const CharT* str) - -> std::basic_string { - return to_color(bold_v, std::basic_string(str)); -} -template -inline auto -to_bold(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(bold_v, std::basic_string(str, len)); -} -template -inline auto -to_bold(const std::basic_string& str) -> std::basic_string { - return to_color(bold_v, str); -} -template -inline auto -to_bold(const std::basic_string_view str) -> std::basic_string { - return to_color(bold_v, std::basic_string(str)); -} - -template -inline auto to_dark(const CharT* str) - -> std::basic_string { - return to_color(dark_v, std::basic_string(str)); -} -template -inline auto -to_dark(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(dark_v, std::basic_string(str, len)); -} -template -inline auto -to_dark(const std::basic_string& str) -> std::basic_string { - return to_color(dark_v, str); -} -template -inline auto -to_dark(const std::basic_string_view str) -> std::basic_string { - return to_color(dark_v, std::basic_string(str)); -} - -template -inline auto to_underline(const CharT* str) - -> std::basic_string { - return to_color(underline_v, std::basic_string(str)); -} -template -inline auto -to_underline(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(underline_v, std::basic_string(str, len)); -} -template -inline auto -to_underline(const std::basic_string& str) -> std::basic_string { - return to_color(underline_v, str); -} -template -inline auto -to_underline(const std::basic_string_view str) - -> std::basic_string { - return to_color(underline_v, std::basic_string(str)); -} - -template -inline auto to_blink(const CharT* str) - -> std::basic_string { - return to_color(blink_v, std::basic_string(str)); -} -template -inline auto -to_blink(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(blink_v, std::basic_string(str, len)); -} -template -inline auto -to_blink(const std::basic_string& str) -> std::basic_string { - return to_color(blink_v, str); -} -template -inline auto -to_blink(const std::basic_string_view str) -> std::basic_string { - return to_color(blink_v, std::basic_string(str)); -} - -template -inline auto to_reverse(const CharT* str) - -> std::basic_string { - return to_color(reverse_v, std::basic_string(str)); -} -template -inline auto -to_reverse(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(reverse_v, std::basic_string(str, len)); -} -template -inline auto -to_reverse(const std::basic_string& str) -> std::basic_string { - return to_color(reverse_v, str); -} -template -inline auto -to_reverse(const std::basic_string_view str) - -> std::basic_string { - return to_color(reverse_v, std::basic_string(str)); -} - -template -inline auto to_concealed(const CharT* str) - -> std::basic_string { - return to_color(concealed_v, std::basic_string(str)); -} -template -inline auto -to_concealed(const CharT* str, std::size_t len) -> std::basic_string { - return to_color(concealed_v, std::basic_string(str, len)); -} -template -inline auto -to_concealed(const std::basic_string& str) -> std::basic_string { - return to_color(concealed_v, str); -} -template -inline auto -to_concealed(const std::basic_string_view str) - -> std::basic_string { - return to_color(concealed_v, std::basic_string(str)); -} - -} // namespace termcolor2 diff --git a/src/util/termcolor2/to_color_extra.ixx b/src/util/termcolor2/to_color_extra.ixx deleted file mode 100644 index fa865e3af..000000000 --- a/src/util/termcolor2/to_color_extra.ixx +++ /dev/null @@ -1,207 +0,0 @@ -module; - -// std -#include // std::size_t -#include // std::basic_string -#include // std::basic_string_view - -export module termcolor2.to_color_extra; - -import termcolor2.color_mode; -import termcolor2.presets; - -export namespace termcolor2 { - -template -inline auto -to_bold_color(Func&& fn, const std::basic_string& str) - -> std::basic_string { - if (should_color()) { - return bold_v() + fn() + str + reset_v(); - } else { - return str; - } -} - -// -// Foreground manipulators -// -template -inline auto to_bold_gray(const CharT* str) - -> std::basic_string { - return to_bold_color(gray_v, std::basic_string(str)); -} -template -inline auto -to_bold_gray(const CharT* str, std::size_t len) -> std::basic_string { - return to_bold_color(gray_v, std::basic_string(str, len)); -} -template -inline auto -to_bold_gray(const std::basic_string& str) -> std::basic_string { - return to_bold_color(gray_v, str); -} -template -inline auto -to_bold_gray(const std::basic_string_view str) - -> std::basic_string { - return to_bold_color(gray_v, std::basic_string(str)); -} - -template -inline auto to_bold_red(const CharT* str) - -> std::basic_string { - return to_bold_color(red_v, std::basic_string(str)); -} -template -inline auto -to_bold_red(const CharT* str, std::size_t len) -> std::basic_string { - return to_bold_color(red_v, std::basic_string(str, len)); -} -template -inline auto -to_bold_red(const std::basic_string& str) -> std::basic_string { - return to_bold_color(red_v, str); -} -template -inline auto -to_bold_red(const std::basic_string_view str) - -> std::basic_string { - return to_bold_color(red_v, std::basic_string(str)); -} - -template -inline auto to_bold_green(const CharT* str) - -> std::basic_string { - return to_bold_color(green_v, std::basic_string(str)); -} -template -inline auto -to_bold_green(const CharT* str, std::size_t len) -> std::basic_string { - return to_bold_color(green_v, std::basic_string(str, len)); -} -template -inline auto -to_bold_green(const std::basic_string& str) -> std::basic_string { - return to_bold_color(green_v, str); -} -template -inline auto -to_bold_green(const std::basic_string_view str) - -> std::basic_string { - return to_bold_color(green_v, std::basic_string(str)); -} - -template -inline auto to_bold_yellow(const CharT* str) - -> std::basic_string { - return to_bold_color(yellow_v, std::basic_string(str)); -} -template -inline auto -to_bold_yellow(const CharT* str, std::size_t len) -> std::basic_string { - return to_bold_color(yellow_v, std::basic_string(str, len)); -} -template -inline auto -to_bold_yellow(const std::basic_string& str) - -> std::basic_string { - return to_bold_color(yellow_v, str); -} -template -inline auto -to_bold_yellow(const std::basic_string_view str) - -> std::basic_string { - return to_bold_color(yellow_v, std::basic_string(str)); -} - -template -inline auto to_bold_blue(const CharT* str) - -> std::basic_string { - return to_bold_color(blue_v, std::basic_string(str)); -} -template -inline auto -to_bold_blue(const CharT* str, std::size_t len) -> std::basic_string { - return to_bold_color(blue_v, std::basic_string(str, len)); -} -template -inline auto -to_bold_blue(const std::basic_string& str) -> std::basic_string { - return to_bold_color(blue_v, str); -} -template -inline auto -to_bold_blue(const std::basic_string_view str) - -> std::basic_string { - return to_bold_color(blue_v, std::basic_string(str)); -} - -template -inline auto to_bold_magenta(const CharT* str) - -> std::basic_string { - return to_bold_color(magenta_v, std::basic_string(str)); -} -template -inline auto -to_bold_magenta(const CharT* str, std::size_t len) -> std::basic_string { - return to_bold_color(magenta_v, std::basic_string(str, len)); -} -template -inline auto -to_bold_magenta(const std::basic_string& str) - -> std::basic_string { - return to_bold_color(magenta_v, str); -} -template -inline auto -to_bold_magenta(const std::basic_string_view str) - -> std::basic_string { - return to_bold_color(magenta_v, std::basic_string(str)); -} - -template -inline auto to_bold_cyan(const CharT* str) - -> std::basic_string { - return to_bold_color(cyan_v, std::basic_string(str)); -} -template -inline auto -to_bold_cyan(const CharT* str, std::size_t len) -> std::basic_string { - return to_bold_color(cyan_v, std::basic_string(str, len)); -} -template -inline auto -to_bold_cyan(const std::basic_string& str) -> std::basic_string { - return to_bold_color(cyan_v, str); -} -template -inline auto -to_bold_cyan(const std::basic_string_view str) - -> std::basic_string { - return to_bold_color(cyan_v, std::basic_string(str)); -} - -template -inline auto to_bold_white(const CharT* str) - -> std::basic_string { - return to_bold_color(white_v, std::basic_string(str)); -} -template -inline auto -to_bold_white(const CharT* str, std::size_t len) -> std::basic_string { - return to_bold_color(white_v, std::basic_string(str, len)); -} -template -inline auto -to_bold_white(const std::basic_string& str) -> std::basic_string { - return to_bold_color(white_v, str); -} -template -inline auto -to_bold_white(const std::basic_string_view str) - -> std::basic_string { - return to_bold_color(white_v, std::basic_string(str)); -} - -} // namespace termcolor2 diff --git a/src/util/verbosity.ixx b/src/util/verbosity.ixx deleted file mode 100644 index 41c118b44..000000000 --- a/src/util/verbosity.ixx +++ /dev/null @@ -1,18 +0,0 @@ -module; - -// external -#include - -export module poac.util.verbosity; - -export namespace poac::util::verbosity { - -inline auto is_verbose() -> bool { - return spdlog::should_log(spdlog::level::trace); -} - -inline auto is_quiet() -> bool { - return spdlog::level::off == spdlog::get_level(); -} - -} // namespace poac::util::verbosity diff --git a/src/cmd/graph.ixx b/srcOld/Cmd/Graph.cc similarity index 79% rename from src/cmd/graph.ixx rename to srcOld/Cmd/Graph.cc index 8ebb94f1a..0c40c2e46 100644 --- a/src/cmd/graph.ixx +++ b/srcOld/Cmd/Graph.cc @@ -1,4 +1,4 @@ -module; +#include "Graph.hpp" // std #include @@ -11,32 +11,20 @@ module; #include #include #include // NOLINT(build/include_order) -#include #include // internal -#include "../util/result-macros.hpp" - -export module poac.cmd.graph; - -// internal -import poac.cmd.build; -import poac.core.resolver.types; // ResolvedDeps -import poac.core.resolver; // install_deps -import poac.data.manifest; -import poac.util.format; -import poac.util.log; -import poac.util.result; -import poac.util.rustify; -import poac.util.shell; +#include "../Cmd/Build.hpp" +#include "../Core/Resolver.hpp" // install_deps +#include "../Core/Resolver.types.hpp" // ResolvedDeps +#include "../Data/Manifest.hpp" +#include "../Util/Format.hpp" +#include "../Util/Log.hpp" +#include "../Util/ResultMacros.hpp" +#include "../Util/Shell.hpp" namespace poac::cmd::graph { -export struct Options : structopt::sub_command { - // Perform only checks - Option output_file = None; -}; - using ExtError = Error<"The extension of the output file must be .dot or .png">; using GraphvizNotFound = Error< "`graph` command requires `graphviz`; try:\n" @@ -51,7 +39,7 @@ struct Vertex { using Graph = boost::adjacency_list; -auto create_resolved_deps() -> Result { +static auto create_resolved_deps() -> Result { spdlog::trace("Parsing the manifest file ..."); // TODO(ken-matsui): parse as a static type rather than toml::value const toml::value manifest = toml::parse(data::manifest::NAME); @@ -61,7 +49,7 @@ auto create_resolved_deps() -> Result { }); } -auto create_graph() -> Result>> { +static auto create_graph() -> Result>> { const core::resolver::ResolvedDeps resolved_deps = Try(create_resolved_deps()); Graph g; @@ -107,14 +95,16 @@ auto create_graph() -> Result>> { return Ok(std::make_pair(g, names)); } -[[nodiscard]] auto dot_file_output(const Path& output_path) -> Result { +[[nodiscard]] static auto dot_file_output(const Path& output_path) + -> Result { const auto [g, names] = Try(create_graph()); std::ofstream file(output_path); boost::write_graphviz(file, g, boost::make_label_writer(names.data())); return Ok(); } -[[nodiscard]] auto png_file_output(const Path& output_path) -> Result { +[[nodiscard]] static auto png_file_output(const Path& output_path) + -> Result { if (util::shell::has_command("dot")) { const auto [g, names] = Try(create_graph()); @@ -133,7 +123,7 @@ auto create_graph() -> Result>> { } } -[[nodiscard]] auto file_output(const Path& output_path) -> Result { +[[nodiscard]] static auto file_output(const Path& output_path) -> Result { if (output_path.extension() == ".png") { return png_file_output(output_path); } else if (output_path.extension() == ".dot") { @@ -143,7 +133,7 @@ auto create_graph() -> Result>> { } } -[[nodiscard]] auto console_output() -> Result { +[[nodiscard]] static auto console_output() -> Result { const auto [g, names] = Try(create_graph()); static_cast(names); // error: unused variable for (auto [itr, end] = edges(g); itr != end; ++itr) { @@ -155,7 +145,7 @@ auto create_graph() -> Result>> { return Ok(); } -export [[nodiscard]] auto exec(const Options& opts) -> Result { +[[nodiscard]] auto exec(const Options& opts) -> Result { if (opts.output_file.has_value()) { Try(file_output(opts.output_file.value())); log::status("Generated", opts.output_file.value()); @@ -166,5 +156,3 @@ export [[nodiscard]] auto exec(const Options& opts) -> Result { } } // namespace poac::cmd::graph - -STRUCTOPT(poac::cmd::graph::Options, output_file); diff --git a/srcOld/Cmd/Graph.hpp b/srcOld/Cmd/Graph.hpp new file mode 100644 index 000000000..6dc4f984a --- /dev/null +++ b/srcOld/Cmd/Graph.hpp @@ -0,0 +1,21 @@ +#pragma once + +// external +#include + +// internal +#include "../Util/Result.hpp" +#include "../Util/Rustify.hpp" + +namespace poac::cmd::graph { + +struct Options : structopt::sub_command { + // Perform only checks + Option output_file = None; +}; + +[[nodiscard]] auto exec(const Options& opts) -> Result; + +} // namespace poac::cmd::graph + +STRUCTOPT(poac::cmd::graph::Options, output_file); diff --git a/src/cmd/search.ixx b/srcOld/Cmd/Search.cc similarity index 72% rename from src/cmd/search.ixx rename to srcOld/Cmd/Search.cc index 9e37ac9e2..f9a6b70ab 100644 --- a/src/cmd/search.ixx +++ b/srcOld/Cmd/Search.cc @@ -1,4 +1,4 @@ -module; +#include "Search.hpp" // std #include // std::remove @@ -7,31 +7,20 @@ module; #include #include #include // NOLINT(build/include_order) -#include // internal -#include "../util/result-macros.hpp" - -export module poac.cmd.search; - -import poac.util.format; -import poac.util.log; -import poac.util.net; -import poac.util.pretty; -import poac.util.result; -import poac.util.rustify; -import poac.util.verbosity; +#include "../Util/Format.hpp" +#include "../Util/Log.hpp" +#include "../Util/Net.hpp" +#include "../Util/Pretty.hpp" +#include "../Util/ResultMacros.hpp" +#include "../Util/Verbosity.hpp" namespace poac::cmd::search { -export struct Options : structopt::sub_command { - /// Package name to search - String package_name; -}; - using PackageNotFound = Error<"No packages found for `{}`", String>; -[[nodiscard]] auto search(const Options& opts) -> Result { +[[nodiscard]] static auto search(const Options& opts) -> Result { const boost::property_tree::ptree pt = Try(util::net::api::search(opts.package_name, 20).map_err(to_anyhow)); if (util::verbosity::is_verbose()) { @@ -69,10 +58,8 @@ using PackageNotFound = Error<"No packages found for `{}`", String>; return Ok(); } -export [[nodiscard]] inline auto exec(const Options& opts) -> Result { +[[nodiscard]] auto exec(const Options& opts) -> Result { return search(opts); } } // namespace poac::cmd::search - -STRUCTOPT(poac::cmd::search::Options, package_name); diff --git a/srcOld/Cmd/Search.hpp b/srcOld/Cmd/Search.hpp new file mode 100644 index 000000000..5866a24de --- /dev/null +++ b/srcOld/Cmd/Search.hpp @@ -0,0 +1,21 @@ +#pragma once + +// external +#include + +// internal +#include "../Util/Result.hpp" +#include "../Util/Rustify.hpp" + +namespace poac::cmd::search { + +struct Options : structopt::sub_command { + /// Package name to search + String package_name; +}; + +[[nodiscard]] auto exec(const Options& opts) -> Result; + +} // namespace poac::cmd::search + +STRUCTOPT(poac::cmd::search::Options, package_name); diff --git a/srcOld/Config.hpp b/srcOld/Config.hpp new file mode 100644 index 000000000..58bf45f9f --- /dev/null +++ b/srcOld/Config.hpp @@ -0,0 +1,49 @@ +#pragma once + +// std +#include +#include + +// internal +#include "./Util/Misc.hpp" +#include "./Util/Rustify.hpp" + +namespace poac::config { + +inline const Path user_dir = util::misc::expand_user(); + +// Ref: +// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html +inline const Path xdg_cache_home = + util::misc::getenv("XDG_CACHE_HOME", user_dir / ".cache"); +inline const Path xdg_data_home = + util::misc::getenv("XDG_DATA_HOME", user_dir / ".local" / "share"); +inline const Path xdg_state_home = + util::misc::getenv("XDG_STATE_HOME", user_dir / ".local" / "state"); + +inline const Path data_dir(xdg_data_home / "poac"); +inline const Path cred_file(data_dir / "credentials"); + +inline const Path cache_dir(xdg_cache_home / "poac"); +inline const Path registry_dir(cache_dir / "registry"); +inline const Path registry_src_dir(registry_dir / "src"); +inline const Path default_registry_dir(registry_src_dir / "poac.dev"); + +inline const Path git_dir(cache_dir / "git"); +inline const Path git_src_dir(git_dir / "src"); + +inline const Path state_dir(xdg_state_home / "poac"); +inline const Path log_file(state_dir / "log"); + +inline const Path cwd = fs::current_path(); +inline const Path src_dir(cwd / "src"); +inline const Path include_dir(cwd / "include"); +inline const Path tests_dir(cwd / "tests"); +inline const Path main_cpp_file(src_dir / "main.cpp"); +inline constexpr StringRef POAC_OUT = "poac-out"; +inline const Path out_dir(cwd / POAC_OUT); + +inline const Path conan_deps_dir(out_dir / ".conan"); +inline const Path conan_deps_file(conan_deps_dir / "conan_poac.json"); + +} // namespace poac::config diff --git a/src/core/resolver.ixx b/srcOld/Core/Resolver.hpp similarity index 99% rename from src/core/resolver.ixx rename to srcOld/Core/Resolver.hpp index add43fc18..7bdb994a3 100644 --- a/src/core/resolver.ixx +++ b/srcOld/Core/Resolver.hpp @@ -250,7 +250,8 @@ do_resolve(const resolve::UniqDeps& deps) noexcept UniqDeps resolvable_deps{}; for (const auto& [name, table] : dependencies) { poac::core::resolver::resolve::DependencyInfo info = { - .index = "poac", .type = "poac"}; + .index = "poac", .type = "poac" + }; if (table.is_table()) { const toml::table& entries = table.as_table(); for (const auto& [n, v] : entries) { @@ -279,7 +280,8 @@ do_resolve(const resolve::UniqDeps& deps) noexcept -> Result { registry::Registries regs = { {"poac", {.index = "poac", .type = "poac"}}, - {"conan-v1", {.index = "conan", .type = "conan-v1"}}}; + {"conan-v1", {.index = "conan", .type = "conan-v1"}} + }; if (!manifest.contains("registries")) { return Ok(regs); } diff --git a/src/core/resolver/registry.ixx b/srcOld/Core/Resolver/Registry.hpp similarity index 100% rename from src/core/resolver/registry.ixx rename to srcOld/Core/Resolver/Registry.hpp diff --git a/src/core/resolver/resolve.ixx b/srcOld/Core/Resolver/Resolve.hpp similarity index 99% rename from src/core/resolver/resolve.ixx rename to srcOld/Core/Resolver/Resolve.hpp index ea6df8935..6d3523699 100644 --- a/src/core/resolver/resolve.ixx +++ b/srcOld/Core/Resolver/Resolve.hpp @@ -343,7 +343,8 @@ void gather_deps( gather_deps( Package{ package.name, - {version, package.dep_info.index, package.dep_info.type}}, + {version, package.dep_info.index, package.dep_info.type} + }, duplicate_deps, interval_cache ); } diff --git a/src/core/resolver/sat.ixx b/srcOld/Core/Resolver/Sat.hpp similarity index 98% rename from src/core/resolver/sat.ixx rename to srcOld/Core/Resolver/Sat.hpp index 0611e0a44..211055630 100644 --- a/src/core/resolver/sat.ixx +++ b/srcOld/Core/Resolver/Sat.hpp @@ -57,7 +57,9 @@ auto calc_literal_polarity(const TwoDim>& rng, const U& i) -> T { return acc; } -inline auto literal_to_index(i32 l) -> i32 { return std::abs(l) - 1; } +inline auto literal_to_index(i32 l) -> i32 { + return std::abs(l) - 1; +} // Find `1` or `-1` from whole clauses. Variables that have already been // assigned have been deleted from the clauses by the `delete_applied_literal` diff --git a/src/core/resolver/types.ixx b/srcOld/Core/Resolver/Types.hpp similarity index 100% rename from src/core/resolver/types.ixx rename to srcOld/Core/Resolver/Types.hpp diff --git a/src/data/lockfile.ixx b/srcOld/Data/Lockfile.hpp similarity index 100% rename from src/data/lockfile.ixx rename to srcOld/Data/Lockfile.hpp diff --git a/src/data/manifest.ixx b/srcOld/Data/Manifest.hpp similarity index 100% rename from src/data/manifest.ixx rename to srcOld/Data/Manifest.hpp diff --git a/src/util/archive.ixx b/srcOld/Util/Archive.hpp similarity index 97% rename from src/util/archive.ixx rename to srcOld/Util/Archive.hpp index da8d776aa..a95adf2b7 100644 --- a/src/util/archive.ixx +++ b/srcOld/Util/Archive.hpp @@ -151,7 +151,9 @@ extract(const Path& target_file_path, const Path& extract_path) if (!reader) { return Err("Cannot archive_read_new"); } - BOOST_SCOPE_EXIT_ALL(&reader) { archive_read_free(reader); }; + BOOST_SCOPE_EXIT_ALL(&reader) { + archive_read_free(reader); + }; read_as_targz(reader); const Writer writer(archive_write_disk_new()); @@ -163,7 +165,9 @@ extract(const Path& target_file_path, const Path& extract_path) archive_write_disk_set_standard_lookup(writer.get()); Try(archive_read_open_filename(reader, target_file_path, 10'240)); - BOOST_SCOPE_EXIT_ALL(&reader) { archive_read_close(reader); }; + BOOST_SCOPE_EXIT_ALL(&reader) { + archive_read_close(reader); + }; return extract_impl(reader, writer, extract_path); } diff --git a/src/util/cfg.ixx b/srcOld/Util/Cfg.hpp similarity index 99% rename from src/util/cfg.ixx rename to srcOld/Util/Cfg.hpp index a9e8a029a..0f93717c5 100644 --- a/src/util/cfg.ixx +++ b/srcOld/Util/Cfg.hpp @@ -847,6 +847,8 @@ void Parser::eat_right_paren() { } } -inline auto parse(StringRef s) -> CfgExpr { return Parser(s).expr(); } +inline auto parse(StringRef s) -> CfgExpr { + return Parser(s).expr(); +} } // end namespace poac::util::cfg diff --git a/src/util/meta.ixx b/srcOld/Util/Meta.hpp similarity index 100% rename from src/util/meta.ixx rename to srcOld/Util/Meta.hpp diff --git a/src/util/net.ixx b/srcOld/Util/Net.hpp similarity index 98% rename from src/util/net.ixx rename to srcOld/Util/Net.hpp index 889a3568f..48af2b249 100644 --- a/src/util/net.ixx +++ b/srcOld/Util/Net.hpp @@ -147,8 +147,12 @@ class MultiPartForm { : _boundary(boost::uuids::to_string(boost::uuids::random_generator{}())), _footer(format("{}--{}--{}", _crlf, _boundary, _crlf)) {} - [[nodiscard]] inline auto get_header() const -> String { return _header; } - [[nodiscard]] inline auto get_footer() const -> String { return _footer; } + [[nodiscard]] inline auto get_header() const -> String { + return _header; + } + [[nodiscard]] inline auto get_footer() const -> String { + return _footer; + } inline void set(const FileNameType& name, const String& value) { _form_param.emplace_back(format( @@ -198,7 +202,9 @@ class MultiPartForm { return file_info; } - inline auto body() noexcept -> SelfReference { return *this; } + inline auto body() noexcept -> SelfReference { + return *this; + } [[nodiscard]] inline auto body() const noexcept -> ConstSelfReference { return *this; } @@ -512,7 +518,8 @@ class Requests { )) { const boost::system::error_code error{ static_cast(::ERR_get_error()), - boost::asio::error::get_ssl_category()}; + boost::asio::error::get_ssl_category() + }; log::debug(error.message()); throw boost::system::system_error{error}; } @@ -541,7 +548,7 @@ export namespace poac::util::net::api { call(StringRef path, const Option& body = None) noexcept -> Result { try { - const Requests request{"api.poac.dev"}; + const Requests request{"poac-api.shuttleapp.rs"}; const String target = format("/v1{}", path); const auto response = Try(body.has_value() ? request.post(target, body.value()) diff --git a/src/util/registry/conan/v1/manifest.ixx b/srcOld/Util/Registry/Conan/V1/Manifest.hpp similarity index 97% rename from src/util/registry/conan/v1/manifest.ixx rename to srcOld/Util/Registry/Conan/V1/Manifest.hpp index a62e22e47..cea21420c 100644 --- a/src/util/registry/conan/v1/manifest.ixx +++ b/srcOld/Util/Registry/Conan/V1/Manifest.hpp @@ -70,7 +70,8 @@ auto gather_conan_deps() -> Result { .defines = gather_conan_defines(pt), .includes = gather_conan_includes(pt), .libdirs = gather_conan_libdirs(pt), - .libraries = gather_conan_libraries(pt)}); + .libraries = gather_conan_libraries(pt) + }); } } // namespace poac::util::registry::conan::v1::manifest diff --git a/src/util/registry/conan/v1/resolver.ixx b/srcOld/Util/Registry/Conan/V1/Resolver.hpp similarity index 98% rename from src/util/registry/conan/v1/resolver.ixx rename to srcOld/Util/Registry/Conan/V1/Resolver.hpp index aa4404920..75e4aa73d 100644 --- a/src/util/registry/conan/v1/resolver.ixx +++ b/srcOld/Util/Registry/Conan/V1/Resolver.hpp @@ -162,7 +162,9 @@ auto get_conan_config() -> String { auto install_conan_packages() -> Result { const Path cwd = fs::current_path(); - BOOST_SCOPE_EXIT_ALL(&cwd) { fs::current_path(cwd); }; + BOOST_SCOPE_EXIT_ALL(&cwd) { + fs::current_path(cwd); + }; fs::current_path(config::conan_deps_dir); util::shell::Cmd cmd( diff --git a/src/util/semver/comparison.ixx b/srcOld/Util/Semver/Comparison.hpp similarity index 100% rename from src/util/semver/comparison.ixx rename to srcOld/Util/Semver/Comparison.hpp diff --git a/src/util/semver/exception.ixx b/srcOld/Util/Semver/Exception.hpp similarity index 100% rename from src/util/semver/exception.ixx rename to srcOld/Util/Semver/Exception.hpp diff --git a/src/util/semver/interval.ixx b/srcOld/Util/Semver/Interval.hpp similarity index 100% rename from src/util/semver/interval.ixx rename to srcOld/Util/Semver/Interval.hpp diff --git a/src/util/semver/io.ixx b/srcOld/Util/Semver/Io.hpp similarity index 86% rename from src/util/semver/io.ixx rename to srcOld/Util/Semver/Io.hpp index 18a359501..f21cc4c19 100644 --- a/src/util/semver/io.ixx +++ b/srcOld/Util/Semver/Io.hpp @@ -23,7 +23,9 @@ namespace fmt { template <> struct formatter { - static constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } + static constexpr auto parse(format_parse_context& ctx) { + return ctx.begin(); + } template inline auto format(const semver::Version& v, FormatContext& ctx) { diff --git a/src/util/semver/lexer.ixx b/srcOld/Util/Semver/Lexer.hpp similarity index 99% rename from src/util/semver/lexer.ixx rename to srcOld/Util/Semver/Lexer.hpp index 4c8e58a08..4c2249fa6 100644 --- a/src/util/semver/lexer.ixx +++ b/srcOld/Util/Semver/Lexer.hpp @@ -141,7 +141,9 @@ export class Lexer { } private: - inline void step() noexcept { ++c1_index; } + inline void step() noexcept { + ++c1_index; + } void step_n(const SizeType& n) noexcept { for (SizeType i = 0; i < n; ++i) { diff --git a/src/util/semver/parser.ixx b/srcOld/Util/Semver/Parser.hpp similarity index 99% rename from src/util/semver/parser.ixx rename to srcOld/Util/Semver/Parser.hpp index 339b0d717..c6067b382 100644 --- a/src/util/semver/parser.ixx +++ b/srcOld/Util/Semver/Parser.hpp @@ -35,7 +35,9 @@ struct Parser { } /// Peek one token. - [[nodiscard]] inline auto peek() const noexcept -> Token { return this->c1; } + [[nodiscard]] inline auto peek() const noexcept -> Token { + return this->c1; + } /// Skip whitespace if present. void skip_whitespace() { diff --git a/src/util/semver/range.ixx b/srcOld/Util/Semver/Range.hpp similarity index 100% rename from src/util/semver/range.ixx rename to srcOld/Util/Semver/Range.hpp diff --git a/src/util/semver/semver.ixx b/srcOld/Util/Semver/Semver.hpp similarity index 100% rename from src/util/semver/semver.ixx rename to srcOld/Util/Semver/Semver.hpp diff --git a/src/util/semver/token.ixx b/srcOld/Util/Semver/Token.hpp similarity index 100% rename from src/util/semver/token.ixx rename to srcOld/Util/Semver/Token.hpp diff --git a/src/util/sha256.ixx b/srcOld/Util/Sha256.hpp similarity index 100% rename from src/util/sha256.ixx rename to srcOld/Util/Sha256.hpp diff --git a/src/util/validator.ixx b/srcOld/Util/Validator.hpp similarity index 100% rename from src/util/validator.ixx rename to srcOld/Util/Validator.hpp diff --git a/tests/CMakeLists.txt b/testsOld/CMakeLists.txt similarity index 100% rename from tests/CMakeLists.txt rename to testsOld/CMakeLists.txt diff --git a/tests/CPPLINT.cfg b/testsOld/CPPLINT.cfg similarity index 100% rename from tests/CPPLINT.cfg rename to testsOld/CPPLINT.cfg diff --git a/tests/ui/CMakeLists.txt b/testsOld/ui/CMakeLists.txt similarity index 100% rename from tests/ui/CMakeLists.txt rename to testsOld/ui/CMakeLists.txt diff --git a/tests/ui/create/CMakeLists.txt b/testsOld/ui/create/CMakeLists.txt similarity index 100% rename from tests/ui/create/CMakeLists.txt rename to testsOld/ui/create/CMakeLists.txt diff --git a/tests/ui/create/create-binary.cc b/testsOld/ui/create/create-binary.cc similarity index 100% rename from tests/ui/create/create-binary.cc rename to testsOld/ui/create/create-binary.cc diff --git a/tests/ui/create/create-binary.stdout b/testsOld/ui/create/create-binary.stdout similarity index 100% rename from tests/ui/create/create-binary.stdout rename to testsOld/ui/create/create-binary.stdout diff --git a/tests/ui/fmt/CMakeLists.txt b/testsOld/ui/fmt/CMakeLists.txt similarity index 100% rename from tests/ui/fmt/CMakeLists.txt rename to testsOld/ui/fmt/CMakeLists.txt diff --git a/tests/ui/fmt/empty-name.cc b/testsOld/ui/fmt/empty-name.cc similarity index 100% rename from tests/ui/fmt/empty-name.cc rename to testsOld/ui/fmt/empty-name.cc diff --git a/tests/ui/fmt/empty-name.stdout b/testsOld/ui/fmt/empty-name.stdout similarity index 100% rename from tests/ui/fmt/empty-name.stdout rename to testsOld/ui/fmt/empty-name.stdout diff --git a/tests/ui/fmt/invalid-manifest.cc b/testsOld/ui/fmt/invalid-manifest.cc similarity index 100% rename from tests/ui/fmt/invalid-manifest.cc rename to testsOld/ui/fmt/invalid-manifest.cc diff --git a/tests/ui/fmt/invalid-manifest.stderr b/testsOld/ui/fmt/invalid-manifest.stderr similarity index 100% rename from tests/ui/fmt/invalid-manifest.stderr rename to testsOld/ui/fmt/invalid-manifest.stderr diff --git a/tests/ui/fmt/no-clang-format.cc b/testsOld/ui/fmt/no-clang-format.cc similarity index 100% rename from tests/ui/fmt/no-clang-format.cc rename to testsOld/ui/fmt/no-clang-format.cc diff --git a/tests/ui/fmt/no-clang-format.stderr b/testsOld/ui/fmt/no-clang-format.stderr similarity index 100% rename from tests/ui/fmt/no-clang-format.stderr rename to testsOld/ui/fmt/no-clang-format.stderr diff --git a/tests/ui/fmt/no-manifest.cc b/testsOld/ui/fmt/no-manifest.cc similarity index 100% rename from tests/ui/fmt/no-manifest.cc rename to testsOld/ui/fmt/no-manifest.cc diff --git a/tests/ui/fmt/no-manifest.stderr b/testsOld/ui/fmt/no-manifest.stderr similarity index 100% rename from tests/ui/fmt/no-manifest.stderr rename to testsOld/ui/fmt/no-manifest.stderr diff --git a/tests/ui/fmt/no-targets.cc b/testsOld/ui/fmt/no-targets.cc similarity index 100% rename from tests/ui/fmt/no-targets.cc rename to testsOld/ui/fmt/no-targets.cc diff --git a/tests/ui/fmt/no-targets.stdout b/testsOld/ui/fmt/no-targets.stdout similarity index 100% rename from tests/ui/fmt/no-targets.stdout rename to testsOld/ui/fmt/no-targets.stdout diff --git a/tests/ui/init/CMakeLists.txt b/testsOld/ui/init/CMakeLists.txt similarity index 100% rename from tests/ui/init/CMakeLists.txt rename to testsOld/ui/init/CMakeLists.txt diff --git a/tests/ui/init/overwrite.cc b/testsOld/ui/init/overwrite.cc similarity index 100% rename from tests/ui/init/overwrite.cc rename to testsOld/ui/init/overwrite.cc diff --git a/tests/ui/init/overwrite.stderr b/testsOld/ui/init/overwrite.stderr similarity index 100% rename from tests/ui/init/overwrite.stderr rename to testsOld/ui/init/overwrite.stderr diff --git a/tests/ui/init/simple-init.cc b/testsOld/ui/init/simple-init.cc similarity index 100% rename from tests/ui/init/simple-init.cc rename to testsOld/ui/init/simple-init.cc diff --git a/tests/ui/init/simple-init.stdout b/testsOld/ui/init/simple-init.stdout similarity index 100% rename from tests/ui/init/simple-init.stdout rename to testsOld/ui/init/simple-init.stdout diff --git a/tests/ui/util/ui_test_util.hpp b/testsOld/ui/util/ui_test_util.hpp similarity index 97% rename from tests/ui/util/ui_test_util.hpp rename to testsOld/ui/util/ui_test_util.hpp index 688827ba4..1a2cc44d6 100644 --- a/tests/ui/util/ui_test_util.hpp +++ b/testsOld/ui/util/ui_test_util.hpp @@ -57,7 +57,9 @@ inline Cmd move_to_temp(const fs::path& temp_dir) { return Cmd("cd " + temp_dir.string()); } -inline void remove_temp(const fs::path& temp_dir) { fs::remove_all(temp_dir); } +inline void remove_temp(const fs::path& temp_dir) { + fs::remove_all(temp_dir); +} inline Cmd mk_cmd(const std::string& cmd, const fs::path& temp_dir) { return move_to_temp(temp_dir) && POAC_EXECUTABLE + cmd; diff --git a/tests/unit/CMakeLists.txt b/testsOld/unit/CMakeLists.txt similarity index 100% rename from tests/unit/CMakeLists.txt rename to testsOld/unit/CMakeLists.txt diff --git a/tests/unit/core/CMakeLists.txt b/testsOld/unit/core/CMakeLists.txt similarity index 100% rename from tests/unit/core/CMakeLists.txt rename to testsOld/unit/core/CMakeLists.txt diff --git a/tests/unit/core/builder/CMakeLists.txt b/testsOld/unit/core/builder/CMakeLists.txt similarity index 100% rename from tests/unit/core/builder/CMakeLists.txt rename to testsOld/unit/core/builder/CMakeLists.txt diff --git a/tests/unit/core/builder/compiler/CMakeLists.txt b/testsOld/unit/core/builder/compiler/CMakeLists.txt similarity index 100% rename from tests/unit/core/builder/compiler/CMakeLists.txt rename to testsOld/unit/core/builder/compiler/CMakeLists.txt diff --git a/tests/unit/core/builder/compiler/cxx/CMakeLists.txt b/testsOld/unit/core/builder/compiler/cxx/CMakeLists.txt similarity index 100% rename from tests/unit/core/builder/compiler/cxx/CMakeLists.txt rename to testsOld/unit/core/builder/compiler/cxx/CMakeLists.txt diff --git a/tests/unit/core/builder/compiler/cxx/apple_clang.cc b/testsOld/unit/core/builder/compiler/cxx/apple_clang.cc similarity index 100% rename from tests/unit/core/builder/compiler/cxx/apple_clang.cc rename to testsOld/unit/core/builder/compiler/cxx/apple_clang.cc diff --git a/tests/unit/core/builder/compiler/cxx/clang.cc b/testsOld/unit/core/builder/compiler/cxx/clang.cc similarity index 100% rename from tests/unit/core/builder/compiler/cxx/clang.cc rename to testsOld/unit/core/builder/compiler/cxx/clang.cc diff --git a/tests/unit/core/builder/compiler/cxx/cxx.cc b/testsOld/unit/core/builder/compiler/cxx/cxx.cc similarity index 100% rename from tests/unit/core/builder/compiler/cxx/cxx.cc rename to testsOld/unit/core/builder/compiler/cxx/cxx.cc diff --git a/tests/unit/core/builder/compiler/cxx/gcc.cc b/testsOld/unit/core/builder/compiler/cxx/gcc.cc similarity index 100% rename from tests/unit/core/builder/compiler/cxx/gcc.cc rename to testsOld/unit/core/builder/compiler/cxx/gcc.cc diff --git a/tests/unit/core/builder/syntax.cc b/testsOld/unit/core/builder/syntax.cc similarity index 100% rename from tests/unit/core/builder/syntax.cc rename to testsOld/unit/core/builder/syntax.cc diff --git a/tests/unit/core/resolver/CMakeLists.txt b/testsOld/unit/core/resolver/CMakeLists.txt similarity index 100% rename from tests/unit/core/resolver/CMakeLists.txt rename to testsOld/unit/core/resolver/CMakeLists.txt diff --git a/tests/unit/core/resolver/resolve.cc b/testsOld/unit/core/resolver/resolve.cc similarity index 100% rename from tests/unit/core/resolver/resolve.cc rename to testsOld/unit/core/resolver/resolve.cc diff --git a/tests/unit/core/resolver/sat.cc b/testsOld/unit/core/resolver/sat.cc similarity index 100% rename from tests/unit/core/resolver/sat.cc rename to testsOld/unit/core/resolver/sat.cc diff --git a/tests/unit/util/CMakeLists.txt b/testsOld/unit/util/CMakeLists.txt similarity index 100% rename from tests/unit/util/CMakeLists.txt rename to testsOld/unit/util/CMakeLists.txt diff --git a/tests/unit/util/cfg.cc b/testsOld/unit/util/cfg.cc similarity index 100% rename from tests/unit/util/cfg.cc rename to testsOld/unit/util/cfg.cc diff --git a/tests/unit/util/lev_distance.cc b/testsOld/unit/util/lev_distance.cc similarity index 100% rename from tests/unit/util/lev_distance.cc rename to testsOld/unit/util/lev_distance.cc diff --git a/tests/unit/util/meta.cc b/testsOld/unit/util/meta.cc similarity index 100% rename from tests/unit/util/meta.cc rename to testsOld/unit/util/meta.cc diff --git a/tests/unit/util/misc.cc b/testsOld/unit/util/misc.cc similarity index 100% rename from tests/unit/util/misc.cc rename to testsOld/unit/util/misc.cc diff --git a/tests/unit/util/net.cc b/testsOld/unit/util/net.cc similarity index 100% rename from tests/unit/util/net.cc rename to testsOld/unit/util/net.cc diff --git a/tests/unit/util/pretty.cc b/testsOld/unit/util/pretty.cc similarity index 100% rename from tests/unit/util/pretty.cc rename to testsOld/unit/util/pretty.cc diff --git a/tests/unit/util/semver/CMakeLists.txt b/testsOld/unit/util/semver/CMakeLists.txt similarity index 100% rename from tests/unit/util/semver/CMakeLists.txt rename to testsOld/unit/util/semver/CMakeLists.txt diff --git a/tests/unit/util/semver/interval.cc b/testsOld/unit/util/semver/interval.cc similarity index 100% rename from tests/unit/util/semver/interval.cc rename to testsOld/unit/util/semver/interval.cc diff --git a/tests/unit/util/semver/lexer.cc b/testsOld/unit/util/semver/lexer.cc similarity index 100% rename from tests/unit/util/semver/lexer.cc rename to testsOld/unit/util/semver/lexer.cc diff --git a/tests/unit/util/semver/parser.cc b/testsOld/unit/util/semver/parser.cc similarity index 100% rename from tests/unit/util/semver/parser.cc rename to testsOld/unit/util/semver/parser.cc diff --git a/tests/unit/util/semver/token.cc b/testsOld/unit/util/semver/token.cc similarity index 100% rename from tests/unit/util/semver/token.cc rename to testsOld/unit/util/semver/token.cc diff --git a/tests/unit/util/semver/version.cc b/testsOld/unit/util/semver/version.cc similarity index 100% rename from tests/unit/util/semver/version.cc rename to testsOld/unit/util/semver/version.cc diff --git a/tests/unit/util/sha256.cc b/testsOld/unit/util/sha256.cc similarity index 100% rename from tests/unit/util/sha256.cc rename to testsOld/unit/util/sha256.cc diff --git a/tests/unit/util/shell.cc b/testsOld/unit/util/shell.cc similarity index 100% rename from tests/unit/util/shell.cc rename to testsOld/unit/util/shell.cc diff --git a/tests/unit/util/termcolor2/CMakeLists.txt b/testsOld/unit/util/termcolor2/CMakeLists.txt similarity index 100% rename from tests/unit/util/termcolor2/CMakeLists.txt rename to testsOld/unit/util/termcolor2/CMakeLists.txt diff --git a/tests/unit/util/termcolor2/literals.cc b/testsOld/unit/util/termcolor2/literals.cc similarity index 100% rename from tests/unit/util/termcolor2/literals.cc rename to testsOld/unit/util/termcolor2/literals.cc diff --git a/tests/unit/util/termcolor2/to_color.cc b/testsOld/unit/util/termcolor2/to_color.cc similarity index 100% rename from tests/unit/util/termcolor2/to_color.cc rename to testsOld/unit/util/termcolor2/to_color.cc diff --git a/tests/unit/util/validator.cc b/testsOld/unit/util/validator.cc similarity index 100% rename from tests/unit/util/validator.cc rename to testsOld/unit/util/validator.cc diff --git a/tests/unit/util/verbosity.cc b/testsOld/unit/util/verbosity.cc similarity index 100% rename from tests/unit/util/verbosity.cc rename to testsOld/unit/util/verbosity.cc diff --git a/tests/util/ut_helpers/throws_with_msg.hpp b/testsOld/util/ut_helpers/throws_with_msg.hpp similarity index 100% rename from tests/util/ut_helpers/throws_with_msg.hpp rename to testsOld/util/ut_helpers/throws_with_msg.hpp