diff --git a/.circleci/config.yml b/.circleci/config.yml index 6dd292dd0..b2cea56ed 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,81 +1,66 @@ -aliases: - - &restore-poac-cache - keys: # restores saved poac cache - - v1-poac-cache-{{ checksum "poac.lock" }} - - v1-poac-cache-{{ checksum "poac.yml" }} - - v1-poac-cache-{{ .Branch }} - - v1-poac-cache - - &save-poac-cache1 - key: v1-poac-cache-{{ checksum "poac.lock" }} - paths: "deps" - - &save-poac-cache2 - key: v1-poac-cache-{{ checksum "poac.yml" }} - paths: "deps" - - &save-poac-cache3 - key: v1-poac-cache-{{ .Branch }} - paths: "deps" - - &save-poac-cache4 - key: v1-poac-cache - paths: "deps" - - - &restore-poac-build-cache - keys: # restores saved poac build cache - - v1-build-cache-{{ .Branch }} - - v1-build-cache - - &save-poac-build-cache1 - key: v1-build-cache-{{ .Branch }} - paths: "_build" - - &save-poac-build-cache2 - key: v1-build-cache - paths: "_build" - - - &at-current - at: . - - - &build-project - name: Build Project - command: mkdir build && cd build && cmake .. && make - - - &run-poac-test - name: Test Project - command: > - ./build/poac test --report -- - --output_format=XML - --log_level=all - --report_level=no - - &store-poac-test-result - path: _build/test/report +version: 2.1 + +executors: + x86_64: + parameters: + compiler: + description: "compiler-version" + type: string + docker: + - image: poacpm/x86_64-unknown-linux-gnu + environment: + CXX: << parameters.compiler >> - - &filter-ignore-gh-pages - branches: - ignore: gh-pages - - &defaults +commands: + poac-install: + steps: + - restore_cache: + keys: # restores saved poac cache + - v1-poac-cache-{{ checksum "poac.lock" }} + - v1-poac-cache-{{ checksum "poac.yml" }} + - v1-poac-cache-{{ .Branch }} + - v1-poac-cache + - run: poac install # source file only (no pre-built) + - save_cache: + key: v1-poac-cache-{{ checksum "poac.lock" }} + paths: "deps" + - save_cache: + key: v1-poac-cache-{{ checksum "poac.yml" }} + paths: "deps" + - save_cache: + key: v1-poac-cache-{{ .Branch }} + paths: "deps" + - save_cache: + key: v1-poac-cache + paths: "deps" + + default-build: steps: - - attach_workspace: *at-current - - run: uname -sm - - run: *build-project + - run: mkdir build && cd build && cmake .. && make - run: ./build/poac -h - run: file ./build/poac -# - run: *run-poac-test -# - store_test_results: *store-poac-test-result + default-test: + steps: + - run: + command: > + ./build/poac test --report -- + --output_format=XML + --log_level=all + --report_level=no + - store_test_results: + path: _build/test/report + -version: 2 jobs: checkout_code: docker: - image: poacpm/poac steps: - checkout - - - restore_cache: *restore-poac-cache -# - run: poac install # source file only (no pre-built) - - save_cache: *save-poac-cache1 - - save_cache: *save-poac-cache2 - - save_cache: *save-poac-cache3 - - save_cache: *save-poac-cache4 +# - poac-install - persist_to_workspace: root: . @@ -86,33 +71,37 @@ jobs: # - image: poacpm/x86_64-unknown-linux-gnu # environment: # CXX: g++-6 -# <<: *defaults +# steps: +# - default-build x86_64-unknown-linux-gnu_gcc-7: - docker: - - image: poacpm/x86_64-unknown-linux-gnu - environment: - CXX: g++-7 - <<: *defaults + parameters: + compiler: + description: "compiler-version" + type: string + executor: + name: x86_64 + compiler: << parameters.compiler >> + steps: + - attach_workspace: + at: . + - default-build +# - default-test x86_64-unknown-linux-gnu_gcc-8: - docker: - - image: poacpm/x86_64-unknown-linux-gnu - environment: - CXX: g++-8 + parameters: + compiler: + description: "compiler-version" + type: string + executor: + name: x86_64 + compiler: << parameters.compiler >> working_directory: /tmp/workspace/x86_64-unknown-linux-gnu steps: - attach_workspace: at: /tmp/workspace/x86_64-unknown-linux-gnu - - - run: uname -sm - - run: *build-project - - run: ./build/poac -h - - run: file ./build/poac - -# - run: *run-poac-test -# - store_test_results: *store-poac-test-result - + - default-build +# - default-test - persist_to_workspace: root: /tmp/workspace paths: x86_64-unknown-linux-gnu @@ -124,7 +113,8 @@ jobs: # CXX: /home/linuxbrew/.linuxbrew/opt/llvm@6/bin/clang++ # LDFLAGS: "-L/home/linuxbrew/.linuxbrew/opt/llvm@6/lib" # CPPFLAGS: "-I/home/linuxbrew/.linuxbrew/opt/llvm@6/include" -# <<: *defaults +# steps: +# - default-build # x86_64-unknown-linux-gnu_clang-7: # docker: @@ -132,118 +122,106 @@ jobs: # environment: # CXX: clang++ # LDFLAGS: "-L/home/linuxbrew/.linuxbrew/opt/llvm/lib -Wl,-rpath,/home/linuxbrew/.linuxbrew/opt/llvm/lib" -# <<: *defaults +# steps: +# - default-build # aarch64-unknown-linux-gnu: # docker: # - image: poacpm/aarch64-unknown-linux-gnu # environment: # CXX: g++-8 -# <<: *defaults +# steps: +# - default-build # powerpc-unknown-linux-gnu_gcc-4_8: # docker: # - image: poacpm/powerpc-unknown-linux-gnu # environment: # CXX: powerpc-linux-gnu-g++ -# <<: *defaults +# steps: +# - default-build # powerpc64-unknown-linux-gnu_gcc-5_4: # docker: # - image: poacpm/powerpc64-unknown-linux-gnu # environment: # CXX: powerpc64-linux-gnu-g++ -# <<: *defaults +# steps: +# - default-build # powerpc64le-unknown-linux-gnu: # docker: # - image: poacpm/powerpc64le-unknown-linux-gnu # environment: # CXX: g++-8 -# <<: *defaults +# steps: +# - default-build # s390x-unknown-linux-gnu: # docker: # - image: poacpm/s390x-unknown-linux-gnu # environment: # CXX: g++-8 -# <<: *defaults +# steps: +# - default-build # x86_64-pc-windows-gnu_gcc-6: # docker: # - image: poacpm/x86_64-pc-windows-gnu # environment: # CXX: x86_64-w64-mingw32-g++-posix -# <<: *defaults +# steps: +# - default-build # i686-pc-windows-gnu_gcc-6: # docker: # - image: poacpm/i686-pc-windows-gnu # environment: # CXX: i686-w64-mingw32-g++-posix -# <<: *defaults +# steps: +# - default-build release: docker: - image: circleci/golang:1.11 steps: - - attach_workspace: *at-current + - attach_workspace: + at: . - run: mkdir out - run: ARCH=x86_64-unknown-linux-gnu tar czf $ARCH out/$ARCH.tar.gz - run: go get github.com/tcnksm/ghr - run: ghr $CIRCLE_TAG out # - run: poac publish - gh_pages: - working_directory: ~/poac/docs - docker: - - image: node:10 - steps: - - checkout - - run: git config --global user.name $USERNAME - - run: git config --global user.email $EMAIL - - run: cp -r .circleci docs - - run: npm --prefix "$PWD/docs" install - - run: npm --prefix "$PWD/docs" run build - - run: cp docs/assets/robots.txt docs/_book - - run: npm --prefix "$PWD/docs" run publish - workflows: version: 2 builds: jobs: - - checkout_code: - filters: *filter-ignore-gh-pages + - checkout_code # - x86_64-unknown-linux-gnu_gcc-6: -# filters: *filter-ignore-gh-pages # requires: # - checkout_code - x86_64-unknown-linux-gnu_gcc-7: - filters: *filter-ignore-gh-pages + compiler: g++-7 requires: - checkout_code - x86_64-unknown-linux-gnu_gcc-8: - filters: *filter-ignore-gh-pages + compiler: g++-8 requires: - checkout_code # - x86_64-unknown-linux-gnu_clang-6: -# filters: *filter-ignore-gh-pages # requires: # - checkout_code # - x86_64-unknown-linux-gnu_clang-7: -# filters: *filter-ignore-gh-pages # requires: # - checkout_code # - aarch64-unknown-linux-gnu: -# filters: *filter-ignore-gh-pages # requires: # - checkout_code # - powerpc64le-unknown-linux-gnu: -# filters: *filter-ignore-gh-pages # requires: # - checkout_code # - s390x-unknown-linux-gnu: -# filters: *filter-ignore-gh-pages # requires: # - checkout_code - release: @@ -261,7 +239,3 @@ workflows: ignore: /.*/ tags: only: /^[0-9]+(\.[0-9]+){2}.*$/ - - gh_pages: - filters: - branches: - only: master diff --git a/CMakeLists.txt b/CMakeLists.txt index efeb48707..88042368a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ project(poac) # Preprocessor definitions add_definitions(-DPOAC_PROJECT_ROOT="${CMAKE_SOURCE_DIR}") -add_definitions(-DPOAC_VERSION="0.1.2") +add_definitions(-DPOAC_VERSION="0.2.0") if(CYGWIN) add_definitions(-D_GNU_SOURCE -DBOOST_ASIO_HAS_STD_STRING_VIEW -Wa,-mbig-obj) elseif(UNIX) @@ -58,6 +58,11 @@ if(APPLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I/usr/local/opt/llvm@7/include") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/local/opt/llvm@7/lib") endif() + + # -DCMAKE_BUILD_TYPE=Debug + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g -fsanitize=address") + # -DCMAKE_BUILD_TYPE=Release + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -mtune=native -march=native") else() if(WIN32 AND MSVC) link_directories(${BOOST_LIBRARYDIR}) @@ -77,6 +82,7 @@ else() 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}") diff --git a/README.md b/README.md index 1e2477cfc..f4c3bb416 100644 --- a/README.md +++ b/README.md @@ -5,18 +5,19 @@ Poac is a package manager for C++ users. Poac can download project's dependencies and compile project. -Please see [poac.pm](https://poac.io) for [installation instructions](https://poacpm.github.io/poac/en/getting-started/installation.html) and [other documentations](https://docs.poac.io). +Please see [poac.pm](https://poac.pm) for [installation instructions](https://doc.poac.pm/en/getting-started/installation.html) and [other documentations](https://doc.poac.pm). [![asciicast](https://asciinema.org/a/QwgRXsyeMYk62vwuZ6X6DZvcC.png)](https://asciinema.org/a/QwgRXsyeMYk62vwuZ6X6DZvcC) ## Supported Operating Systems -| Linux (= x86_64 GNU/Linux) | macOS (>= sierra) | Windows (= Windows Subsystem for Linux) | +| Linux (= x86-64 GNU/Linux) | macOS (>= sierra) | Windows (= MSVC >= 2017) | |:---:|:---:|:---:| |[![CircleCI](https://circleci.com/gh/poacpm/poac.svg?style=shield)](https://circleci.com/gh/poacpm/poac)|[![Travis CI](https://travis-ci.com/poacpm/poac.svg?branch=master)](https://travis-ci.com/poacpm/poac)|[![Build status](https://ci.appveyor.com/api/projects/status/6r7d0526he3nsq7l/branch/master?svg=true)](https://ci.appveyor.com/project/matken11235/poac/branch/master)| ## Code Status -[![GitHub](https://img.shields.io/github/license/poacpm/poac.svg)](https://github.com/awslabs/aws-c-common/blob/master/LICENSE) +[![GitHub License](https://img.shields.io/github/license/poacpm/poac.svg)](https://github.com/awslabs/aws-c-common/blob/master/LICENSE) +[![Github All Releases](https://img.shields.io/github/downloads/poacpm/poac/total.svg)]() [![Coverity Scan Build Status](https://scan.coverity.com/projects/17677/badge.svg)](https://scan.coverity.com/projects/poacpm-poac) [![Coverage Status](https://coveralls.io/repos/github/poacpm/poac/badge.svg?branch=master)](https://coveralls.io/github/poacpm/poac?branch=master) [![codecov](https://codecov.io/gh/poacpm/poac/branch/master/graph/badge.svg)](https://codecov.io/gh/poacpm/poac) @@ -26,7 +27,7 @@ Please see [poac.pm](https://poac.io) for [installation instructions](https://po ## Installation ### Easy install ```bash -curl -fsSL https://sh.poac.io | bash +curl -fsSL https://sh.poac.pm | bash ``` *When your OS is macOS, use [Homebrew](https://github.com/Homebrew/brew)* @@ -53,10 +54,11 @@ $ poac build ``` --> -## Requirements (runtime) +## Runtime requirements * compiler (gcc | clang | MSVC | ICC) * `tar`: in publish command * `dot(graphviz)`: in graph command +* `git`: in install command * `cmake`: optional * `make`: optional diff --git a/appveyor.yml b/appveyor.yml index 3c82bdfcd..8d36405c0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -16,6 +16,10 @@ platform: - x86 - x64 +artifacts: + - path: build\Release\poac.exe + name: Release + environment: matrix: - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 @@ -102,8 +106,7 @@ build_script: -DBOOST_ROOT=C:\Libraries\boost-1.69.0 ^ -DBOOST_LIBRARYDIR=C:\Libraries\boost-1.69.0\lib ^ -Dyaml-cpp_DIR=C:\Libraries\yaml-cpp\CMake && - cmake --build . --config %Configuration% && - cd .. + cmake --build . --config %Configuration% ) - if [%COMPILER%]==[cygwin64] ( diff --git a/docs/.bookignore b/docs/.bookignore deleted file mode 100644 index 9cf2ca785..000000000 --- a/docs/.bookignore +++ /dev/null @@ -1,3 +0,0 @@ -man/ -comp/ -img/ diff --git a/docs/CNAME b/docs/CNAME deleted file mode 100644 index 08d3e21a0..000000000 --- a/docs/CNAME +++ /dev/null @@ -1 +0,0 @@ -docs.poac.io diff --git a/docs/LANGS.md b/docs/LANGS.md deleted file mode 100644 index 5b267ba49..000000000 --- a/docs/LANGS.md +++ /dev/null @@ -1,4 +0,0 @@ -# Languages - -* [English](en/) -* [日本語](ja/) diff --git a/docs/assets/robots.txt b/docs/assets/robots.txt deleted file mode 100644 index 39607ffe8..000000000 --- a/docs/assets/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -User-agent: * -Disallow: -Sitemap: https://docs.poac.io/sitemap.xml diff --git a/docs/book.json b/docs/book.json deleted file mode 100644 index 6cddeddf5..000000000 --- a/docs/book.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "title": "The Poac Book", - "language": "en", - "plugins" : ["advanced-emoji", "github-buttons", "sitemap-general"], - "pluginsConfig": { - "github-buttons": { - "buttons": [ - { - "user": "poacpm", - "repo": "poac", - "type": "star", - "size": "small", - "width": "80", - "count": true - } - ] - }, - "sitemap-general": { - "prefix": "https://docs.poac.io/" - } - } -} diff --git a/docs/en/README.md b/docs/en/README.md deleted file mode 100644 index b3f5138fd..000000000 --- a/docs/en/README.md +++ /dev/null @@ -1,33 +0,0 @@ -## The Poac Book - -Poac is the C/C++ package manager. - -Poac can download project's dependencies and compile project, create package, and upload it to [poac.pm](https://poac.io). - -[poac.pm](https://poac.io) is the package registry, searching packages and management them, etc. can be done. - - -#### Sections -**[Getting Started](getting-started/README.md)** - -To get started with the poac system, install poac and create a project that outputs `Hello, world`. - - -**[Guide](guide/README.md)** - -The guide necessary for developing with poac - - -**[Reference](reference/README.md)** - -The reference covering more detailed features - - -**[Architecture](architecture/README.md)** - -A design concept and intention - - -**[Future](future/README.md)** - -Future development flow diff --git a/docs/en/SUMMARY.md b/docs/en/SUMMARY.md deleted file mode 100644 index 6ea18bfba..000000000 --- a/docs/en/SUMMARY.md +++ /dev/null @@ -1,25 +0,0 @@ -# Summary - -[Introduction](README.md) - -* [1. Getting Started](getting-started/README.md) - * [1.1. Installation](getting-started/installation.md) - * [1.2. Hello World](getting-started/hello-world.md) - -* [2. Guide](guide/README.md) - * [2.1. Creating a New Project](guide/creating-a-new-project.md) - * [2.2. Introduce to Existing Projects](guide/introduce-to-existing-projects.md) - * [2.3. Look Output of Help Option](guide/look-output-of-help-option.md) - -* [3. Reference](reference/README.md) - * [3.1. Specifying Dependencies](reference/specifying-dependencies.md) - * [3.1. Build Cpp Project](reference/build-cpp-project.md) - -* [4. Architecture](architecture/README.md) - * 4.1. Stable and Beta and Nightly - * 4.2. Dependency Management - * 4.3. About the poac.lock file - * 4.4. Why I Built poac - * 4.5. Detailed behavior until package publish - -* [5. Future](future/README.md) diff --git a/docs/en/architecture/README.md b/docs/en/architecture/README.md deleted file mode 100644 index e5f632f13..000000000 --- a/docs/en/architecture/README.md +++ /dev/null @@ -1,4 +0,0 @@ -## Architecture - -A design concept and intention. -* diff --git a/docs/en/architecture/cli.md b/docs/en/architecture/cli.md deleted file mode 100644 index 6d0f21111..000000000 --- a/docs/en/architecture/cli.md +++ /dev/null @@ -1 +0,0 @@ -## CLI diff --git a/docs/en/future/README.md b/docs/en/future/README.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/docs/en/getting-started/README.md b/docs/en/getting-started/README.md deleted file mode 100644 index 48e9bf3e5..000000000 --- a/docs/en/getting-started/README.md +++ /dev/null @@ -1,5 +0,0 @@ -## Getting Started - -To get started poac, install poac and create the project that outputs `Hello, world`. -* [1.1. Installation](installation.md) -* [1.2. Hello World](hello-world.md) diff --git a/docs/en/getting-started/hello-world.md b/docs/en/getting-started/hello-world.md deleted file mode 100644 index ecec18191..000000000 --- a/docs/en/getting-started/hello-world.md +++ /dev/null @@ -1,49 +0,0 @@ -## Hello World - -To start a new project with poac, use `poac new`: -```bash -$ poac new hello_world - -Your "hello_world" project was created successfully. - - -Go into your project by running: - $ cd hello_world - -Start your project with: - $ poac run -``` - -Check out to project directory. -```bash -$ cd hello_world -$ tree . -a -. -├── .gitignore -├── README.md -├── main.cpp -└── poac.yml - -0 directories, 4 files -``` - -`poac.yml` is the settings file. -Please refer to [setting-file](../guide/setting-file.md) for details on how to write the setting file. - - -Poac generates a “hello_world” binary for us, when you execute `poac build`: -```bash -$ poac build -Compiled: Output to `_build/bin/hello_world` - -$ ./_build/bin/hello_world -Hello, world! -``` - -We can also use `poac run` to compile and then run it, all in one step: -```bash -$ poac run -Compiled: Output to `_build/bin/hello_world` -Running: `_build/bin/hello_world` -Hello, world! -``` diff --git a/docs/en/getting-started/installation.md b/docs/en/getting-started/installation.md deleted file mode 100644 index de8276315..000000000 --- a/docs/en/getting-started/installation.md +++ /dev/null @@ -1,23 +0,0 @@ -## Installation - -### Easy install -```bash -curl -fsSL https://sh.poac.io | bash -``` -*When your OS is macOS, use [Homebrew](https://github.com/Homebrew/brew)* - -### Manual install (Build) -Poac requires the following tools and packages to build: -* [`boost`](https://github.com/boostorg): `1.66.0` or higher -* [`cmake`](https://github.com/Kitware/CMake): `3.0` or higher -* [`openssl`](https://github.com/openssl/openssl): as new as possible -* [`yaml-cpp`](https://github.com/jbeder/yaml-cpp): `0.6.0` or higher - -```bash -$ git clone https://github.com/poacpm/poac.git -$ cd poac -$ mkdir build && cd $_ -$ cmake .. -$ make -$ make install -``` diff --git a/docs/en/guide/README.md b/docs/en/guide/README.md deleted file mode 100644 index 26bf3e293..000000000 --- a/docs/en/guide/README.md +++ /dev/null @@ -1,6 +0,0 @@ -## Guide - -The guide necessary to develop with poac. -* [2.1. Creating a New Project](creating-a-new-project.md) -* [2.2. Introduce to Existing Projects](introduce-to-existing-projects.md) -* [2.3. Look Output of Help Option](look-output-of-help-option.md) diff --git a/docs/en/guide/creating-a-new-project.md b/docs/en/guide/creating-a-new-project.md deleted file mode 100644 index fbb7f7c29..000000000 --- a/docs/en/guide/creating-a-new-project.md +++ /dev/null @@ -1,53 +0,0 @@ - -```bash -$ poac new hello - -Your "hello" project was created successfully. - - -Go into your project by running: - $ cd hello - -Start your project with: - $ poac run -``` - -```bash -$ cd hello -$ vim poac.yml -``` - -```yaml -... -deps: - hello_world: 0.1.0 -... -``` - -```bash -$ poac install -Some new packages are needed. - - ✔ Installed! (from poac) hello_world: 0.1.0 - -Elapsed time: 0.106303s - ==> Installation finished successfully! - -$ vim main.cpp -``` - -```cpp -#include -#include - -int main(int argc, char** argv) { - hello_world::say(); -} -``` - -```bash -$ poac run -Compiled: Output to `_build/bin/hello` -Running: `_build/bin/hello` -Hello, world! -``` diff --git a/docs/en/guide/introduce-to-existing-projects.md b/docs/en/guide/introduce-to-existing-projects.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/docs/en/guide/look-output-of-help-option.md b/docs/en/guide/look-output-of-help-option.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/docs/en/reference/README.md b/docs/en/reference/README.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/docs/en/reference/build-cpp-project.md b/docs/en/reference/build-cpp-project.md deleted file mode 100644 index 8c4c91a64..000000000 --- a/docs/en/reference/build-cpp-project.md +++ /dev/null @@ -1,2 +0,0 @@ -## Sorry... -This feature is not yet implemented. \ No newline at end of file diff --git a/docs/en/reference/specifying-dependencies.md b/docs/en/reference/specifying-dependencies.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/docs/en/reference/test.md b/docs/en/reference/test.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/docs/img/demo1.gif b/docs/img/demo1.gif deleted file mode 100644 index 719c72f56..000000000 Binary files a/docs/img/demo1.gif and /dev/null differ diff --git a/docs/img/demo2.gif b/docs/img/demo2.gif deleted file mode 100644 index 6d9365f67..000000000 Binary files a/docs/img/demo2.gif and /dev/null differ diff --git a/docs/ja/README.md b/docs/ja/README.md deleted file mode 100644 index 84e54f913..000000000 --- a/docs/ja/README.md +++ /dev/null @@ -1,41 +0,0 @@ -## The Poac Book - -poac は C/C++ 言語向けのパッケージマネージャです。 - -poac はプロジェクトの依存関係を解決しつつパッケージをインストールしたり、それらをコンパイルしたり、パッケージを作成し、それを [poac.pm](https://poac.io) に公開したりすることができます。 - -[poac.pm](https://poac.io) はパッケージレジストリで、パッケージを検索することや、それらを管理することなどができます。 - -> Note: 本ソフトウェアはIPA未踏IT人材発掘・育成事業の2018年度採択プロジェクトとして開発されています。 -詳細は https://www.ipa.go.jp/jinzai/mitou/2018/gaiyou_t-2 をご覧下さい - - -#### 章 -**[入門](getting-started/README.md)** - -poac を使い始めるには、poac をインストールし `Hello, world` を出力するプロジェクトを作ってみましょう。 - - -**[ガイド](guide/README.md)** - -poac で開発していく上で必要なガイドです。 - - -**[リファレンス](reference/README.md)** - -より詳細な機能をカバーしたリファレンスです。 - - -**[アーキテクチャ](architecture/README.md)** - -設計におけるデザインコンセプトや意図、仕様などについて書かれています。 - - -**[貢献](contribution/README.md)** - -パッケージを公開する場合や poac に貢献する場合のガイドラインです。 - - -**[今後の行程](roadmap/README.md)** - -今後の開発の流れや追加する予定の機能について書かれています。 diff --git a/docs/ja/SUMMARY.md b/docs/ja/SUMMARY.md deleted file mode 100644 index 0b7e4f49c..000000000 --- a/docs/ja/SUMMARY.md +++ /dev/null @@ -1,25 +0,0 @@ -# Summary - -[Introduction](README.md) - -* [1. 入門](getting-started/README.md) - * [1.1. インストール](getting-started/installation.md) - * [1.2. Hello World](getting-started/hello-world.md) - -* [2. ガイド](guide/README.md) - * [2.1. 新しいプロジェクトの作成](guide/creating-a-new-project.md) - * [2.2. 既存のプロジェクトに使用する](guide/introduce-to-existing-projects.md) - * [2.3. 設定ファイル](guide/config-file.md) - -* [3. リファレンス](reference/README.md) - * [3.1. API](reference/api.md) - -* [4. アーキテクチャ](architecture/README.md) - * [4.1. コマンドの仕様](architecture/command-spec.md) - -* [5. 貢献する](contribution/README.md) - * [5.1. パッケージ開発者として貢献する](contribution/contribute-as-publisher.md) - -* [6. 今後](roadmap/README.md) - * [6.1. クライアントサイド](roadmap/client-side.md) - * [6.2. サーバーサイド](roadmap/server-side.md) diff --git a/docs/ja/architecture/README.md b/docs/ja/architecture/README.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/docs/ja/getting-started/README.md b/docs/ja/getting-started/README.md deleted file mode 100644 index 57ade7e4f..000000000 --- a/docs/ja/getting-started/README.md +++ /dev/null @@ -1,5 +0,0 @@ -## 入門 - -poac を使い始めるには、poac をインストールし `Hello, world` を出力するプロジェクトを作ってみましょう。 -* [1.1. インストール](installation.md) -* [1.2. Hello World](hello-world.md) diff --git a/docs/ja/getting-started/hello-world.md b/docs/ja/getting-started/hello-world.md deleted file mode 100644 index 18e5844b4..000000000 --- a/docs/ja/getting-started/hello-world.md +++ /dev/null @@ -1,53 +0,0 @@ -## Hello World - -poac で新しいプロジェクトを始めるには、`poac new`コマンドを使用します: -```bash -$ poac new hello_world - -Your "hello_world" project was created successfully. - - -Go into your project by running: - $ cd hello_world - -Start your project with: - $ poac run -``` - -プロジェクトディレクトリに移動します。 -```bash -$ cd hello_world -$ tree . -a -. -├── .gitignore -├── README.md -├── main.cpp -└── poac.yml - -0 directories, 4 files -``` - -`poac.yml` は設定ファイルです。(`poac.yaml`は無視されます.必ず`poac.yml`にしてください) - - -ここに依存関係やパッケージの情報を記載します。 - -設定ファイルの書き方の詳細に関しては [2.4. 設定ファイル](../guide/setting-file.md) を参照して下さい。 - - -`poac build`を実行すると、poac は “hello_world” バイナリを生成します: -```bash -$ poac build -Compiled: Output to `_build/bin/hello_world` - -$ ./_build/bin/hello_world -Hello, world! -``` - -また、`poac run`を使用してコンパイルと実行を行うことができます: -```bash -$ poac run -Compiled: Output to `_build/bin/hello_world` -Running: `_build/bin/hello_world` -Hello, world! -``` diff --git a/docs/ja/getting-started/installation.md b/docs/ja/getting-started/installation.md deleted file mode 100644 index 64a1683fb..000000000 --- a/docs/ja/getting-started/installation.md +++ /dev/null @@ -1,54 +0,0 @@ -## インストール - -### サポートしているOS -* macOS (>= sierra) -* Linux (= x86_64 GNU/Linux) -* Windows (= Windows Subsystem for Linux) - -### 簡単にインストールする -```bash -curl -fsSL https://sh.poac.io | bash -``` -*お使いのPCのOSがmacOSの時、内部では [Homebrew](https://github.com/Homebrew/brew) を使用します* - -### 手動でインストールする (ビルド) -poac はビルドするために以下のツールとパッケージが必要です: -* [`boost`](https://github.com/boostorg): `1.66.0` もしくはそれ以上 -* [`cmake`](https://github.com/Kitware/CMake): `3.0` もしくはそれ以上 -* [`openssl`](https://github.com/openssl/openssl): できるだけ最新のもの -* [`yaml-cpp`](https://github.com/jbeder/yaml-cpp): `0.6.0` もしくはそれ以上 - -```bash -$ git clone https://github.com/poacpm/poac.git -$ cd poac -$ mkdir build && cd $_ -$ cmake .. -$ make -$ make install -``` - - diff --git a/docs/ja/guide/README.md b/docs/ja/guide/README.md deleted file mode 100644 index b83012beb..000000000 --- a/docs/ja/guide/README.md +++ /dev/null @@ -1,6 +0,0 @@ -## ガイド - -poac で開発していく上で必要なガイドです。 -* [2.1. 新しいプロジェクトの作成](creating-a-new-project.md) -* [2.2. 既存のプロジェクトに使用する](introduce-to-existing-projects.md) -* [2.3. 設定ファイル](config-file.md) diff --git a/docs/ja/guide/config-file.md b/docs/ja/guide/config-file.md deleted file mode 100644 index 3cbb3e629..000000000 --- a/docs/ja/guide/config-file.md +++ /dev/null @@ -1,206 +0,0 @@ -## 設定ファイル - - -設定ファイルとは、poacが扱うpoac.ymlファイルのことで、 -設定ファイルが対応しているキーは以下に示す通りです。 - -```elm -name : String -version : String -cpp_version : Int (98, 03, 11(Include TR1), 14, 17, 20) -description : String -owners : List String -license : String -links: - github : Url - homepage : Url -deps : Deps -build : Build -test : Test -``` - -基本的に全て書く必要はありません。 -*これらの key 以外を記述してもエラーにはなりませんが、**JSONと違ってコメントが書ける**ため極力そちらを使用するのが良いでしょう* - -また、それぞれのコマンドが必要とする key は以下の通りです。 -そのコマンド実行時に必要とされていない場合は存在のチェックは行われません。 - -| | name | version | cpp_version | description | license | links | deps | build | test | -|:----------|:----:|:-------:|:-----------:|:-----------:|:-------:|:-----:|:----:|:-----:|:----:| -| build | ◯ | ◯ | ◯ | × | × | × | ◯ | ◯ | × | -| cache | × | × | × | × | × | × | × | × | × | -| cleanup | × | × | × | × | × | × | ◯ | × | × | -| graph | × | × | × | × | × | × | ◯ | × | × | -| init | × | × | × | × | × | × | × | × | × | -| install | × | × | × | × | × | × | ◯ | × | × | -| login | × | × | × | × | × | × | × | × | × | -| new | × | × | × | × | × | × | × | × | × | -| publish | ◯ | ◯ | ◯ | ◯ | △ | △ | △ | △ | △ | -| root | × | × | × | × | × | × | × | × | × | -| run | ◯ | ◯ | ◯ | × | × | × | ◯ | ◯ | × | -| search | × | × | × | × | × | × | × | × | × | -| test | ◯ | ◯ | ◯ | × | × | × | ◯ | ◯ | ◯ | -| uninstall | × | × | × | × | × | × | ◯ | × | × | -| update | × | × | × | × | × | × | ◯ | × | × | - -◯ ... 無ければエラー -△ ... あれば読み込む -× ... 完全に無視される - - -#### deps -depsは,dependenciesの略で依存関係という意味です。 -現在のプロジェクトで扱いたいパッケージを指定します。 -deps のバージョン指定には、以下の演算子が使用可能です。 - -等値: -* "0.1.0": 等しい - -不等価演算子(`!=`等)の提供がないのは,一つだけのバージョンを拒否することがまず無いからです。 -大概はあるバージョン以下を使用したく無い場合が多いため,それは以下の比較演算子で解決可能です。 - -比較演算子: -* ">=0.1.0": 以上 -* "<=0.1.0": 以下 -* ">0.1.0": より大きい -* "<0.1.0": より小さい - -上に示す演算子は,この後に示す演算子より**優先順位が高い**です。 -そして,比較演算子は必ずバージョンとの空白が無いようにする必要があります。 - -論理演算子: -* ">=0.1.0 and <0.3.0": 0.1.0以上でかつ0.3.0より小さい - -論理演算子の場合のみ。左右に空白がないとパースエラーになります。 - -`or`の提供はありません。 -なぜなら、`or`が必要になるような奇妙な依存性を持つ前に、もう一度見直すべきだからです。 -それに加え、等値式と比較演算式を論理演算子で結合できません。 -それもまた、必要のない依存性になるためです。 - -また、比較演算子を論理演算子で結合する場合、閉じた範囲にする必要があります。 -``` -←----┐ ┌-----→ ------◯-----------●------ - 1.0.0 3.0.0 -``` -などは許されないということです。 - -(この辺りの話がピンとこない場合でも、実際に適当なバージョンを指定して`poac install`を実行すると全て教えてくれます。) - -latest: -これを使用する時は最新のバージョンを使用したいがわからない時です. -```yaml -deps: - poac: latest -``` -poac installコマンド実行後に,自動的に存在するバージョンの範囲に置換されます. -```yaml -deps: - poac: latest -``` -置換規則は,command-specification.mdに示した,--outside option に書かれていることと同じです. - -以上が提供される演算子です. - - -実際には以下のように扱います. - -```yaml -deps: - poac: ">=0.1.0 and <0.3.0" -``` -以下のようにも書くことができます. -```yaml -deps: - poac: - version: ">=0.1.0 and <0.3.0" -``` -この書き方はその下にビルド手順を記載したい時に使用できます. -基本的にビルドが必要な(ヘッダーオンリーでない)ライブラリは,指定していなくても,提供者側のpoac.ymlに記載されているので, -そちらでビルドできます.しかし,セキュリティ的に信頼できなかったり,一時的に自分の方法でビルドしたい時は, -```yaml -deps: - boost/system: - version: ">=1.60.0 and <1.70.0" - build: poac -``` -のように書くと,提供者側でなく,プロジェクトルートディレクトリに配置したpoac.ymlのビルド方法が優先して選択されます. -system: manualが将来的に実装されるとshellコマンドを直接使用することができますが、セキュリティやその他雑多な理由により実装は先延ばしになっています。 - -一般的に大量の依存関係をもつパッケージにおいて、等値式を用いることは現実的ではありません。 -等値式を頻繁に用いると依存関係の解決に失敗する可能性があるからです。 - - -##### Dependency from GitHub -```yaml -deps: - github/:user/:package: - tag: "v0.1.2" - ... -``` -のようにします。 - -header-only libraryをgithubからインストールする場合,buildが不要なので以下のように書けると便利ですが,0.1.0では未対応です.じきに修正されます。 -```yaml -deps: - github/:user/:package: "v0.1.2" -``` - -*srcがgithubの時に範囲指定しても動作しません。* - - -##### Dependencies environment (現状未実装) - -dependenciesの種類の指定は, -```yaml -deps: -deps.dev: -deps.test: -``` -なにも指定しないdepsは,全ての環境を示します。 -内部的には,[ prod, dev, test ] の三つになります. -deps.prodは用意されていません.production時は,depsのみが選択されます.depsは,deps.prodのエイリアスではなく,全ての環境に置いてインストールされるdepsです. -deps.devは,開発時にのみインストールされます。つまり,基本的な開発時においては,depsとdeps.devがインストールされます. - - - - -下に幾つか例を挙げます. - -```bash -$ POAC_ENV=prod poac install -``` -とすると,depsのみがインストールされます. - -以下のは,poac installのみと同じ意味になります. -つまり,環境変数を指定せずに`poac install`とすると,自動でPOAC_ENVはdevに設定されます. -```bash -$ POAC_ENV=dev poac install # poac installのみと同じ意味(semantics)になります -``` -とすると,depsとdeps.devがインストールされます. - -POAC_ENVという環境変数を設定すると, -その環境に設定されます. -指定可能なのは,上記した三つの環境です. - -```bash -$ POAC_ENV=prod poac install -``` - - -#### cpp_version -cpp_versionは,98, 03, 11, 14, 17, 20以外を許容しません. -そのため,cpp_versionを使用するコマンドでそれ以外を指定すると,エラーになります. -11は,include TR1です. - -#### owners -ownersには,poac.pm にSignupしたのち,GitHubのUser IDを指定する必要があります. -publish時にtokenの所有者であるかどうかも検証されます. - - - - diff --git a/docs/ja/guide/creating-a-new-project.md b/docs/ja/guide/creating-a-new-project.md deleted file mode 100644 index 995fb83ab..000000000 --- a/docs/ja/guide/creating-a-new-project.md +++ /dev/null @@ -1,58 +0,0 @@ -## 新しいプロジェクトの作成 - - -まず、[1.2. Hello World](../getting-started/hello-world.md) と同じように`poac new`コマンドを実行してプロジェクトを作成します。 -```bash -$ poac new hello - -Your "hello" project was created successfully. - - -Go into your project by running: - $ cd hello - -Start your project with: - $ poac run -``` - -作成されたディレクトリに移動してファイルを見ると、`poac.yml`というファイルが作成されています。 -このファイルの最後に、以下の内容を加えてみます。 -depsは,dependenciesの略で依存関係という意味です。 -現在のhelloプロジェクトが使用するパッケージの一覧をdepsキーに示します。 -今回の場合は,hello_worldパッケージの0.1.0以上で1.0.0より小さいバージョンを使用するという意味になります。 -```yaml -deps: - hello_world: ">=0.1.0 and <1.0.0" -``` - -以上の編集をしたら、`poac install`を実行してインストールします。 -```bash -$ poac install -==> Resolving packages... -==> Resolving dependencies... -==> Fetching... - - ● hello_world 0.1.0 (from: poac) - -==> Done. -``` -*poac.ymlを編集しなくても、`poac install hello_world`でも自動でpoac.ymlを編集してインストール可能です* - - -今回インストールしたパッケージに合わせて、`main.cpp`を編集します。 -```cpp -#include -#include - -int main(int argc, char** argv) { - hello_world::say(); -} -``` - -そして、`poac run`を実行すると、同じように`Hello, world!`が表示され,外部パッケージを使用することができました! -```bash -$ poac run -Compiled: Output to `_build/bin/hello` -Running: `_build/bin/hello` -Hello, world! -``` diff --git a/docs/ja/guide/introduce-to-existing-projects.md b/docs/ja/guide/introduce-to-existing-projects.md deleted file mode 100644 index d1520a874..000000000 --- a/docs/ja/guide/introduce-to-existing-projects.md +++ /dev/null @@ -1,10 +0,0 @@ -## 既存のプロジェクトに使用する - -poacを既存のプロジェクトに使用する場合は、そのプロジェクトのディレクトリに移動して、`poac init`を実行します。 -``` -$ poac init -"./poac.yml" was created. -``` - -その後は、[2.1. 新しいプロジェクトの作成](creating-a-new-project.md)でしたように、 -`poac install hello_world`等を実行することで、poacを使用することができます。 diff --git a/docs/ja/reference/README.md b/docs/ja/reference/README.md deleted file mode 100644 index 26e96fa68..000000000 --- a/docs/ja/reference/README.md +++ /dev/null @@ -1,4 +0,0 @@ -## リファレンス - -より詳細な機能をカバーしたリファレンスです。 -* [3.1. API](api.md) diff --git a/docs/ja/reference/api.md b/docs/ja/reference/api.md deleted file mode 100644 index 5a1c17438..000000000 --- a/docs/ja/reference/api.md +++ /dev/null @@ -1,22 +0,0 @@ -### API - -##### `GET` /packages/:name/:version/deps -依存関係の取得 - -##### `GET` /packages/:org/:name/:version/deps -依存関係の取得 - -##### `GET` /packages/:name/versions -公開されているバージョンを取得 - -##### `GET` /packages/:org/:name/versions -公開されているバージョンを取得 - -##### `GET` /packages/:name/:version/exists -そのパッケージが存在するか検証 - -##### `GET` /packages/:org/:name/:version/exists -そのパッケージが存在するか検証 - -##### `POST` /tokens/validate -tokenの所有権等を検証 diff --git a/docs/ja/reference/build-cpp-project.md b/docs/ja/reference/build-cpp-project.md deleted file mode 100644 index 8c4c91a64..000000000 --- a/docs/ja/reference/build-cpp-project.md +++ /dev/null @@ -1,2 +0,0 @@ -## Sorry... -This feature is not yet implemented. \ No newline at end of file diff --git a/docs/ja/reference/specifying-dependencies.md b/docs/ja/reference/specifying-dependencies.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/docs/ja/roadmap/README.md b/docs/ja/roadmap/README.md deleted file mode 100644 index cee3dd296..000000000 --- a/docs/ja/roadmap/README.md +++ /dev/null @@ -1,5 +0,0 @@ -## 今後 - -今後の開発の流れや追加する予定の機能について書かれています。 -* [6.1. クライアントサイド](client-side.md) -* [6.2. サーバーサイド](server-side.md) diff --git a/docs/ja/roadmap/client-side.md b/docs/ja/roadmap/client-side.md deleted file mode 100644 index 523e337f8..000000000 --- a/docs/ja/roadmap/client-side.md +++ /dev/null @@ -1,21 +0,0 @@ -## Poac's roadmap (client side) - -### poac 0.2.0 -* devDependency, testDependency -* poac build using cmake -* enhance poac internal build system -* Support release(-O3) build, -O1, -O0 -> --release | -rのみO3のエイリアス -* Support Windows (MSVC, Cygwin, Mingw) -* 内部APIの改善 - -### それ以降 -* bench コマンド -* doc コマンド -* fmt コマンド -* watch コマンド -* Global install -* ビルド済みバイナリインストール -* Support x86_64以外 -* npm auditコマンドのようなもの -* npm linkコマンドのようなもの -* dependabot対応 diff --git a/docs/ja/roadmap/server-side.md b/docs/ja/roadmap/server-side.md deleted file mode 100644 index 6de94f486..000000000 --- a/docs/ja/roadmap/server-side.md +++ /dev/null @@ -1,8 +0,0 @@ -## Poac's roadmap (server side) - -* poac.ymlのサイト上編集 -* ファイルのサイト上編集 -* パッケージ名の動的変更 -* パッケージ名のname squatting policy -* パッケージバージョンの動的変更 -* パッケージ権限移譲 diff --git a/docs/package.json b/docs/package.json deleted file mode 100644 index 4ac498034..000000000 --- a/docs/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "docs", - "version": "1.0.0", - "description": "The Poac Book", - "main": "index.js", - "directories": { - "man": "man" - }, - "scripts": { - "build": "gitbook build", - "publish": "gh-pages -d _book -m ':books: Auto publish book'" - }, - "keywords": [], - "author": "matken11235", - "license": "ISC", - "dependencies": { - "gh-pages": "^2.0.1", - "gitbook-cli": "^2.3.2", - "gitbook-plugin-advanced-emoji": "^0.2.2", - "gitbook-plugin-github-buttons": "^3.0.0", - "gitbook-plugin-sitemap-general": "^0.1.1" - }, - "private": true -} diff --git a/include/poac/config.hpp b/include/poac/config.hpp index 40e052bf3..1a4e8f18f 100644 --- a/include/poac/config.hpp +++ b/include/poac/config.hpp @@ -10,33 +10,30 @@ //#define DEBUG namespace poac { - static constexpr char const* POAC_API_HOST = - "poac.io"; - static constexpr char const* POAC_PACKAGES_API = - "/api/packages/"; - static constexpr char const* POAC_TOKENS_VALIDATE_API = - "/api/tokens/validate"; - - static constexpr char const* POAC_UPLOAD_API_HOST = - "poac-pm.appspot.com"; - static constexpr char const* POAC_UPLOAD_API = + constexpr char const* POAC_API_HOST = + "api.poac.pm"; + constexpr char const* POAC_ARCHIVE_API = + "/packages/archive"; + constexpr char const* POAC_DEPS_API = + "/packages/deps"; + constexpr char const* POAC_EXISTS_API = + "/packages/exists"; + constexpr char const* POAC_VERSIONS_API = + "/packages/versions"; + constexpr char const* POAC_UPLOAD_API = "/packages/upload"; + constexpr char const* POAC_TOKENS_VALIDATE_API = + "/tokens/validate"; - static constexpr char const* POAC_STORAGE_HOST = - "storage.googleapis.com"; - - static constexpr char const* GITHUB_HOST = - "github.com"; - - static constexpr char const* ALGOLIA_APPLICATION_ID = + constexpr char const* ALGOLIA_APPLICATION_ID = "IOCVK5FECM"; - static constexpr char const* ALGOLIA_SEARCH_ONLY_KEY = + constexpr char const* ALGOLIA_SEARCH_ONLY_KEY = "9c0a76bacf692daa9e8eca2aaff4b2ab"; - static constexpr char const* ALGOLIA_INDEX_NAME = + constexpr char const* ALGOLIA_INDEX_NAME = "packages"; - static constexpr char const* ALGOLIA_SEARCH_INDEX_API_HOST = + constexpr char const* ALGOLIA_SEARCH_INDEX_API_HOST = "IOCVK5FECM-dsn.algolia.net"; - static constexpr char const* ALGOLIA_SEARCH_INDEX_API = + constexpr char const* ALGOLIA_SEARCH_INDEX_API = "/1/indexes/packages/query"; } #endif // !POAC_CONFIG_HPP diff --git a/include/poac/core.hpp b/include/poac/core.hpp index b5deb07e0..49503c3ac 100644 --- a/include/poac/core.hpp +++ b/include/poac/core.hpp @@ -1,12 +1,11 @@ #ifndef POAC_CORE_HPP #define POAC_CORE_HPP -#include "core/exception.hpp" -#include "core/inference.hpp" -#include "core/lock.hpp" +#include "core/abc.hpp" +#include "core/deper.hpp" +#include "core/except.hpp" +#include "core/infer.hpp" #include "core/naming.hpp" -#include "core/resolver.hpp" -#include "core/sat.hpp" -#include "core/semver.hpp" +#include "core/stroite.hpp" #endif // !POAC_CORE_HPP diff --git a/include/poac/core/abc.hpp b/include/poac/core/abc.hpp new file mode 100644 index 000000000..b7cb11db6 --- /dev/null +++ b/include/poac/core/abc.hpp @@ -0,0 +1,13 @@ +// provide ABstract Class +#ifndef POAC_CORE_ABC_HPP +#define POAC_CORE_ABC_HPP + +#include +#include + + +namespace poac::core::abc { + struct builder { + }; +} // end namespace +#endif // !POAC_CORE_ABC_HPP diff --git a/include/poac/core/deper.hpp b/include/poac/core/deper.hpp new file mode 100644 index 000000000..9b53c8f31 --- /dev/null +++ b/include/poac/core/deper.hpp @@ -0,0 +1,9 @@ +#ifndef POAC_CORE_DEPER_HPP +#define POAC_CORE_DEPER_HPP + +#include "deper/lock.hpp" +#include "deper/resolver.hpp" +#include "deper/sat.hpp" +#include "deper/semver.hpp" + +#endif // POAC_CORE_DEPER_HPP diff --git a/include/poac/core/lock.hpp b/include/poac/core/deper/lock.hpp similarity index 89% rename from include/poac/core/lock.hpp rename to include/poac/core/deper/lock.hpp index 43523879f..c5daeed27 100644 --- a/include/poac/core/lock.hpp +++ b/include/poac/core/deper/lock.hpp @@ -1,5 +1,5 @@ -#ifndef POAC_CORE_LOCK_HPP -#define POAC_CORE_LOCK_HPP +#ifndef POAC_CORE_DEPER_LOCK_HPP +#define POAC_CORE_DEPER_LOCK_HPP #include #include @@ -7,11 +7,11 @@ #include -#include "../io/file/yaml.hpp" #include "./resolver.hpp" +#include "../../io/file/yaml.hpp" -namespace poac::core::lock { +namespace poac::core::deper::lock { const std::string filename = "poac.lock"; std::optional @@ -38,7 +38,7 @@ namespace poac::core::lock { return std::nullopt; } - std::optional + std::optional load_deps_deps(const YAML::Node& node) { namespace yaml = io::file::yaml; // dependenciesも読む -> 順番に削除していく必要があるためと,対象でないパッケージが依存していることを防ぐため @@ -56,7 +56,7 @@ namespace poac::core::lock { } } - core::resolver::Resolved + resolver::Resolved create_resolved_deps(const std::map& locked_deps) { namespace yaml = io::file::yaml; @@ -77,10 +77,9 @@ namespace poac::core::lock { } // Ignore timestamp check - std::optional + std::optional load_ignore_timestamp() { namespace yaml = io::file::yaml; - namespace resolver = core::resolver; if (const auto lock = yaml::load(filename)) { if (const auto locked_deps = yaml::get>(*lock, "dependencies")) { @@ -90,10 +89,9 @@ namespace poac::core::lock { return std::nullopt; } - std::optional + std::optional load(const std::string& timestamp=io::file::yaml::get_timestamp()) { namespace yaml = io::file::yaml; - namespace resolver = core::resolver; if (const auto locked_deps = load_deps(timestamp)) { return create_resolved_deps(*locked_deps); @@ -103,4 +101,4 @@ namespace poac::core::lock { } } } // end namespace -#endif // !POAC_CORE_LOCK_HPP +#endif // !POAC_CORE_DEPER_LOCK_HPP diff --git a/include/poac/core/resolver.hpp b/include/poac/core/deper/resolver.hpp similarity index 63% rename from include/poac/core/resolver.hpp rename to include/poac/core/deper/resolver.hpp index 2c4d9f32d..75ec2e25a 100644 --- a/include/poac/core/resolver.hpp +++ b/include/poac/core/deper/resolver.hpp @@ -1,5 +1,5 @@ -#ifndef POAC_CORE_RESOLVER_HPP -#define POAC_CORE_RESOLVER_HPP +#ifndef POAC_CORE_DEPER_RESOLVER_HPP +#define POAC_CORE_DEPER_RESOLVER_HPP #include #include @@ -12,23 +12,23 @@ #include #include #include -#include // back_inserter +#include #include #include #include -#include "exception.hpp" -#include "naming.hpp" #include "sat.hpp" #include "semver.hpp" -#include "../io/file.hpp" -#include "../io/network.hpp" -#include "../config.hpp" -#include "../util/types.hpp" +#include "../except.hpp" +#include "../naming.hpp" +#include "../../io/file.hpp" +#include "../../io/net.hpp" +#include "../../config.hpp" +#include "../../util/types.hpp" -namespace poac::core::resolver { +namespace poac::core::deper::resolver { namespace cache { bool resolve(const std::string& package_name) { namespace path = io::file::path; @@ -44,12 +44,13 @@ namespace poac::core::resolver { } } namespace github { - std::string archive_url(const std::string& name, const std::string& tag) { - return "/" + name + "/archive/" + tag + ".tar.gz"; + std::string clone_command(const std::string& name, const std::string& tag) { + return "git clone -q https://github.com/" + name + ".git -b " + tag; } } std::string archive_url(const std::string& name, const std::string& version) { - return "/poac-pm.appspot.com/" + core::naming::to_cache("poac", name, version) + ".tar.gz"; + using namespace std::string_literals; + return POAC_ARCHIVE_API + "/"s + naming::hyphen_to_slash(name) + "/" + version; } @@ -59,6 +60,7 @@ namespace poac::core::resolver { struct Name { std::string name; }; struct Interval { std::string interval; }; struct Version { std::string version; }; + struct Versions { std::vector versions; }; struct Source { std::string source; }; struct InDeps { std::vector> deps; }; @@ -89,36 +91,6 @@ namespace poac::core::resolver { }; - // Interval to multiple versions - // `>=0.1.2 and <3.4.0` -> 2.5.0 - // `latest` -> 2.5.0 - // name is boost/config, no boost-config - std::vector - decide_versions(const std::string& name, const std::string& interval) { - // TODO: (`>1.2 and <=1.3.2` -> NG,`>1.2.0-alpha and <=1.3.2` -> OK) - if (const auto versions = io::network::api::versions(name)) { - if (interval == "latest") { - const auto latest = std::max_element((*versions).begin(), (*versions).end(), - [](auto a, auto b) { return semver::Version(a) > b; }); - return { *latest }; - } - else { // `2.0.0` specific version or `>=0.1.2 and <3.4.0` version interval - std::vector res; - semver::Interval i(name, interval); - copy_if((*versions).begin(), (*versions).end(), back_inserter(res), - [&](std::string s) { return i.satisfies(s); }); - if (res.empty()) { - throw exception::error("`" + name + ": " + interval + "` was not found."); - } - else { - return res; - } - } - } - else { - throw exception::error("`" + name + ": " + interval + "` was not found."); - } - } template inline std::string to_bin_str(T n, const std::size_t& digit_num) { @@ -139,40 +111,45 @@ namespace poac::core::resolver { // ¬A ∨ ¬B ∨ ¬C void multiple_versions_cnf(const std::vector& clause, std::vector>& clauses) { const int combinations = 1 << clause.size(); - for (int u = 0; u < combinations; ++u) { // index sequence - boost::dynamic_bitset<> bs(to_bin_str(u, clause.size())); + for (int i = 0; i < combinations; ++i) { // index sequence + boost::dynamic_bitset<> bs(to_bin_str(i, clause.size())); if (bs.count() == 1) { continue; } std::vector new_clause; for (std::size_t j = 0; j < bs.size(); ++j) { - if (bs[j] == 0) { - new_clause.push_back(clause[j]); + if (bs[j]) { + new_clause.emplace_back(clause[j] * -1); } else { - new_clause.push_back(clause[j] * -1); + new_clause.emplace_back(clause[j]); } } clauses.emplace_back(new_clause); } } + bool check_already_added(const std::vector& already_added, const int i) { + auto last = already_added.cend(); + return std::find(already_added.cbegin(), last, i + 1) != last; + } + std::vector> create_cnf(const Activated& activated) { std::vector> clauses; std::vector already_added; - const auto first = std::begin(activated); - const auto last = std::end(activated); + auto first = std::cbegin(activated); + auto last = std::cend(activated); for (int i = 0; i < static_cast(activated.size()); ++i) { - if (std::find(already_added.begin(), already_added.end(), i + 1) != already_added.end()) { + if (check_already_added(already_added, i)) { continue; } const auto name_lambda = [&](const auto& x){ return x.name == activated[i].name; }; - const auto count = std::count_if(first, last, name_lambda); - if (count == 1) { // 現在指すパッケージと同名の他のパッケージは存在しない + // 現在指すパッケージと同名の他のパッケージは存在しない + if (const auto count = std::count_if(first, last, name_lambda); count == 1) { std::vector clause; clause.emplace_back(i + 1); clauses.emplace_back(clause); @@ -182,8 +159,7 @@ namespace poac::core::resolver { clause[0] *= -1; for (const auto& dep : activated[i].deps) { // 必ず存在することが保証されている - const auto index = std::distance(first, std::find(first, last, dep)); - clause.emplace_back(index + 1); + clause.emplace_back(util::types::index_of(first, last, dep) + 1); } clauses.emplace_back(clause); } @@ -192,9 +168,9 @@ namespace poac::core::resolver { std::vector clause; for (auto found = first; found != last; found = std::find_if(found, last, name_lambda)) { - const auto index = std::distance(first, found) + 1; - clause.emplace_back(index); - already_added.emplace_back(index); + const auto index = std::distance(first, found); + clause.emplace_back(index + 1); + already_added.emplace_back(index + 1); // index ⇒ deps if (!found->deps.empty()) { @@ -202,8 +178,7 @@ namespace poac::core::resolver { new_clause.emplace_back(index); for (const auto& dep : found->deps) { // 必ず存在することが保証されている - const auto index2 = std::distance(first, std::find(first, last, dep)) + 1; - new_clause.emplace_back(index2); + new_clause.emplace_back(util::types::index_of(first, last, dep) + 1); } clauses.emplace_back(new_clause); } @@ -232,7 +207,7 @@ namespace poac::core::resolver { io::cli::debugln(0); } else { - throw exception::error("Could not solve in this dependencies."); + throw except::error("Could not solve in this dependencies."); } return resolved_deps; } @@ -273,8 +248,9 @@ namespace poac::core::resolver { const auto first = std::begin(rng); const auto last = std::end(rng); for (const auto& r : rng) { - long c = std::count_if(first, last, [&](const auto& x){ return x.name == r.name; }); - if (c > 1) { + if (std::count_if(first, last, [&](const auto& x) { + return x.name == r.name; + }) > 1) { return true; } } @@ -283,83 +259,110 @@ namespace poac::core::resolver { std::pair get_from_dep(const boost::property_tree::ptree& dep) { - const auto name = dep.get("name"); - const auto interval = dep.get("version"); - return { name, interval }; + return { dep.get("name"), dep.get("version") }; } - // delete name && version - void delete_duplicate(Activated& activated) { - for (auto itr = activated.begin(); itr != activated.end(); ++itr) { - const auto found = std::find_if(itr+1, activated.end(), - [&](auto x){ return itr->name == x.name && itr->version == x.version; }); - if (found != activated.end()) { - activated.erase(found); + + // Interval to multiple versions + // `>=0.1.2 and <3.4.0` -> 2.5.0 + // `latest` -> 2.5.0 + // name is boost/config, no boost-config + std::vector + decide_versions(const std::string& name, const std::string& interval) { +// io::cli::echo("[versions] ", name, ": ", interval); + + // TODO: (`>1.2 and <=1.3.2` -> NG,`>1.2.0-alpha and <=1.3.2` -> OK) + if (const auto versions = io::net::api::versions(name)) { + if (interval == "latest") { + const auto latest = std::max_element((*versions).begin(), (*versions).end(), + [](auto a, auto b) { return semver::Version(a) > b; }); + return { *latest }; + } + else { // `2.0.0` specific version or `>=0.1.2 and <3.4.0` version interval + std::vector res; + semver::Interval i(name, interval); + copy_if(versions->begin(), versions->end(), back_inserter(res), + [&](std::string s) { return i.satisfies(s); }); + if (res.empty()) { + throw except::error(except::msg::not_found("`" + name + ": " + interval + "`")); + } + else { + return res; + } } } + else { + throw except::error(except::msg::not_found("`" + name + ": " + interval + "`")); + } } - void activate(Resolved& new_deps, - Activated prev_activated_deps, - Activated& activated_deps, - const std::string& name, - const std::string& interval) + // BFS activator + void activate( + const std::string& name, + const std::string& version, + Activated& new_deps, + std::vector>& interval_cache) { - for (const auto& version : resolver::decide_versions(name, interval)) { - // {}なのは,依存先の依存先までは必要無く,依存先で十分なため - activated_deps.push_back({ {name}, {version}, {"poac"}, {} }); - - const auto lambda = [&](auto d) { return d.name == name && d.version == version; }; - // Circulating - auto result = std::find_if(prev_activated_deps.begin(), prev_activated_deps.end(), lambda); - if (result != prev_activated_deps.end()) { - break; - } - // Resolved - auto result2 = std::find_if(new_deps.activated.begin(), new_deps.activated.end(), lambda); - if (result2 != new_deps.activated.end()) { - break; - } - prev_activated_deps.push_back({ {name}, {version}, {"poac"}, {} }); + // Check if root package resolved dependency (by version), and Check circulating + if (auto last = new_deps.cend(); std::find_if(new_deps.cbegin(), last, + [&](auto d) { return d.name == name && d.version == version; }) != last) { + return; + } + + // Get dependency of dependency + if (const auto current_deps = io::net::api::deps(name, version)) { + Activated cur_deps_deps; - if (const auto current_deps = io::network::api::deps(name, version)) { - Activated activated_deps2; + for (const auto& current_dep : *current_deps) { + const auto [dep_name, dep_interval] = get_from_dep(current_dep.second); - for (const auto& current_dep : *current_deps) { - const auto[dep_name, dep_interval] = get_from_dep(current_dep.second); - activate(new_deps, prev_activated_deps, activated_deps2, dep_name, dep_interval); + // Check if node package is resolved dependency (by interval) + auto last = interval_cache.cend(); + const auto itr = std::find_if(interval_cache.cbegin(), last, + [&n=dep_name, &i=dep_interval](auto d) { return d.name == n && d.interval == i; }); + if (itr != last) { + for (const auto& dep_version : itr->versions) { + cur_deps_deps.push_back({ {dep_name}, {dep_version}, {"poac"}, {} }); + } + } + else { + const auto dep_versions = decide_versions(dep_name, dep_interval); + // Cache interval and versions pair + interval_cache.push_back({ {dep_name}, {dep_interval}, {dep_versions} }); + for (const auto& dep_version : dep_versions) { + cur_deps_deps.push_back({ {dep_name}, {dep_version}, {"poac"}, {} }); + } } - new_deps.activated.push_back({ {name}, {version}, {"poac"}, {activated_deps2} }); } - else { - new_deps.activated.push_back({ {name}, {version}, {"poac"}, {} }); + new_deps.push_back({ {name}, {version}, {"poac"}, {cur_deps_deps} }); + for (const auto& cur_dep : cur_deps_deps) { + activate(cur_dep.name, cur_dep.version, new_deps, interval_cache); } } + else { + new_deps.push_back({ {name}, {version}, {"poac"}, {} }); + } } Resolved activate_deps_loop(const Deps& deps) { - Resolved new_deps; - for (const auto& dep : deps) { - // Activate the top of dependencies - for (const auto& version : resolver::decide_versions(dep.name, dep.interval)) { - if (const auto current_deps = io::network::api::deps(dep.name, version)) { - Activated activated_deps; + Resolved new_deps{}; + std::vector> interval_cache; - for (const auto& current_dep : *current_deps) { - const auto [dep_name, dep_interval] = get_from_dep(current_dep.second); - - Activated prev_activated_deps; - prev_activated_deps.push_back({ {dep.name}, {version}, {"poac"}, {} }); // push top - activate(new_deps, prev_activated_deps, activated_deps, dep_name, dep_interval); - } - new_deps.activated.push_back({ {dep.name}, {version}, {"poac"}, {activated_deps} }); - } - else { - new_deps.activated.push_back({ {dep.name}, {version}, {"poac"}, {} }); - } + // Activate the root of dependencies + for (const auto& dep : deps) { + // Check if root package is resolved dependency (by interval) + if (auto last = interval_cache.cend(); std::find_if(interval_cache.cbegin(), last, + [&](auto d) { return d.name == dep.name && d.interval == dep.interval; }) != last) + { continue; } + + // Get versions using interval + const auto versions = decide_versions(dep.name, dep.interval); + // Cache interval and versions pair + interval_cache.push_back({ {dep.name}, {dep.interval}, {versions} }); + for (const auto& version : versions) { + activate(dep.name, version, new_deps.activated, interval_cache); } } - delete_duplicate(new_deps.activated); return new_deps; } @@ -378,8 +381,6 @@ namespace poac::core::resolver { } } - // 木の末端からpush_backされていくため,依存が無いものが一番最初の要素になる. - // つまり,配列のループのそのままの順番でインストールやビルドを行うと不具合は起きない const Resolved activated_deps = activate_deps_loop(poac_deps); Resolved resolved_deps; // 全ての依存関係が一つのパッケージ,一つのバージョンに依存する時はbacktrackが不要 @@ -398,4 +399,4 @@ namespace poac::core::resolver { return resolved_deps; } } // end namespace -#endif // !POAC_CORE_RESOLVER_HPP +#endif // !POAC_CORE_DEPER_RESOLVER_HPP diff --git a/include/poac/core/sat.hpp b/include/poac/core/deper/sat.hpp similarity index 98% rename from include/poac/core/sat.hpp rename to include/poac/core/deper/sat.hpp index 4c81b860a..e5b11e336 100644 --- a/include/poac/core/sat.hpp +++ b/include/poac/core/deper/sat.hpp @@ -1,5 +1,5 @@ -#ifndef POAC_CORE_SAT_HPP -#define POAC_CORE_SAT_HPP +#ifndef POAC_CORE_DEPER_SAT_HPP +#define POAC_CORE_DEPER_SAT_HPP #include #include @@ -13,7 +13,7 @@ #include -namespace poac::core::sat { +namespace poac::core::deper::sat { enum class Sat : int { satisfied, // found a satisfying assignment unsatisfied, // found no satisfying assignment @@ -188,4 +188,4 @@ namespace poac::core::sat { return dpll(clauses, literals); } } // end namespace -#endif // !POAC_CORE_SAT_HPP +#endif // !POAC_CORE_DEPER_SAT_HPP diff --git a/include/poac/core/semver.hpp b/include/poac/core/deper/semver.hpp similarity index 97% rename from include/poac/core/semver.hpp rename to include/poac/core/deper/semver.hpp index 4be4e0ccf..bcf3ac759 100644 --- a/include/poac/core/semver.hpp +++ b/include/poac/core/deper/semver.hpp @@ -2,8 +2,8 @@ // minimalistic and dedicated to poac // (A grammar not used by poac (or etc.) is not implemented) // Check if the package exists within the specified range -#ifndef POAC_CORE_SEMVER_HPP -#define POAC_CORE_SEMVER_HPP +#ifndef POAC_CORE_DEPER_SEMVER_HPP +#define POAC_CORE_DEPER_SEMVER_HPP #include #include @@ -14,11 +14,11 @@ #include #include -#include "../io/cli.hpp" -#include "./exception.hpp" +#include "../except.hpp" +#include "../../io/cli.hpp" -namespace poac::core::semver { +namespace poac::core::deper::semver { // The following Regular Expressions can be used for tokenizing, // validating, and parsing SemVer version strings. // A regular expression before binding is https://github.com/semver/semver/issues/232#issue-48635632 @@ -132,7 +132,7 @@ namespace poac::core::semver { io::cli::debugln(*this); } else { - throw exception::error("Invalid version"); + throw except::error("Invalid version"); } } @@ -450,7 +450,7 @@ namespace poac::core::semver { mode = 2; } else { - throw exception::error( + throw except::error( "`" + name + ": " + interval + "` is invalid expression.\n" "Comparison operators:\n" @@ -471,7 +471,7 @@ namespace poac::core::semver { case 2: return satisfies_bounded_interval(version); default: - throw exception::error("Unexcepted error"); + throw except::error("Unexcepted error"); } } @@ -500,12 +500,12 @@ namespace poac::core::semver { && (second_comp_op == "<" || second_comp_op == "<=")) { if (Version(first_version) > second_version) { // Prioritize the larger version - throw exception::error( + throw except::error( "`" + name + ": " + interval + "` is invalid expression.\n" "Did you mean " + first_comp_op + first_version + " ?"); } else { - throw exception::error( + throw except::error( "`" + name + ": " + interval + "` is invalid expression.\n" "Did you mean " + second_comp_op + second_version + " ?"); } @@ -514,12 +514,12 @@ namespace poac::core::semver { && (second_comp_op == ">" || second_comp_op == ">=")) { if (Version(first_version) < second_version) { // Prioritize the smaller version - throw exception::error( + throw except::error( "`" + name + ": " + interval + "` is invalid expression.\n" "Did you mean " + first_comp_op + first_version + " ?"); } else { - throw exception::error( + throw except::error( "`" + name + ": " + interval + "` is invalid expression.\n" "Did you mean " + second_comp_op + second_version + " ?"); } @@ -538,7 +538,7 @@ namespace poac::core::semver { if ((first_comp_op == "<" || first_comp_op == "<=") && (second_comp_op == ">" || second_comp_op == ">=")) { - throw exception::error( + throw except::error( "`" + name + ": " + interval + "` is strange.\n" "In this case of interval specification using `and`,\n" " it is necessary to be a bounded interval.\n" @@ -551,7 +551,7 @@ namespace poac::core::semver { if ((first_comp_op == ">" || first_comp_op == ">=") && (second_comp_op == "<" || second_comp_op == "<=")) { - throw exception::error( + throw except::error( "`" + name + ": " + interval + "` is strange.\n" "In this case of interval specification using `and`,\n" " it is necessary to be a bounded interval.\n" @@ -603,4 +603,4 @@ namespace poac::core::semver { return Interval(name, interval).satisfies(version); } } // end namespace -#endif // !POAC_CORE_SEMVER_HPP +#endif // !POAC_CORE_DEPER_SEMVER_HPP diff --git a/include/poac/core/except.hpp b/include/poac/core/except.hpp new file mode 100644 index 000000000..93f10a4e3 --- /dev/null +++ b/include/poac/core/except.hpp @@ -0,0 +1,86 @@ +#ifndef POAC_CORE_EXCEPT_HPP +#define POAC_CORE_EXCEPT_HPP + +#include +#include + + +namespace poac::core::except { + namespace msg { + std::string put_period(const std::string& str) { + if (*(str.end()) != '.') { + return str + "."; + } + return str; + } + + std::string not_found(const std::string& str) { + return put_period(str + " not found"); + } + std::string does_not_exist(const std::string& str) { + return put_period(str + " does not exist"); + } + std::string key_does_not_exist(const std::string& str) { + return put_period("Required key `" + str + "` does not exist in poac.yml"); + } + + std::string already_exist(const std::string& str) { + return put_period(str + " already exist"); + } + + std::string could_not(const std::string& str) { + return put_period("Could not " + str); + } + std::string could_not_load(const std::string& str) { + return put_period(could_not("load " + str)); + } + std::string could_not_read(const std::string& str) { + return put_period(could_not("read " + str)); + } + + std::string please(const std::string& str) { + return put_period("Please " + str); + } + std::string please_refer_docs(const std::string& str) { + // str <- /en/getting_started.html + return put_period(please("refer to https://doc.poac.pm" + str)); + } + std::string please_exec(const std::string& str) { + return put_period(please("Please execute " + str)); + } + } + + class invalid_first_arg : public std::invalid_argument + { + public: + explicit invalid_first_arg(const std::string& __s) : invalid_argument(__s) {} + explicit invalid_first_arg(const char* __s) : invalid_argument(__s) {} + + virtual ~invalid_first_arg() = default; + }; + class invalid_second_arg : public std::invalid_argument + { + public: + explicit invalid_second_arg(const std::string& __s) : invalid_argument(__s) {} + explicit invalid_second_arg(const char* __s) : invalid_argument(__s) {} + + virtual ~invalid_second_arg() = default; + }; + class error : public std::invalid_argument + { + public: + explicit error(const std::string& __s) : invalid_argument(__s) {} + explicit error(const char* __s) : invalid_argument(__s) {} + + virtual ~error() = default; + }; + class warn : public std::invalid_argument + { + public: + explicit warn(const std::string& __s) : invalid_argument(__s) {} + explicit warn(const char* __s) : invalid_argument(__s) {} + + virtual ~warn() = default; + }; +} // end namespace +#endif // !POAC_CORE_EXCEPT_HPP diff --git a/include/poac/core/exception.hpp b/include/poac/core/exception.hpp deleted file mode 100644 index ab5402dc8..000000000 --- a/include/poac/core/exception.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef POAC_CORE_EXCEPTION_HPP -#define POAC_CORE_EXCEPTION_HPP - -#include -#include - - -namespace poac::core::exception { -// namespace msg { -// static constexpr char const* COMPILE_ERR = -// "YAML directives must have exactly one argument"; -// } - - class invalid_first_arg : public std::invalid_argument - { - public: - explicit invalid_first_arg(const std::string& __s) : invalid_argument(__s) {} - explicit invalid_first_arg(const char* __s) : invalid_argument(__s) {} - - virtual ~invalid_first_arg() = default; - }; - class invalid_second_arg : public std::invalid_argument - { - public: - explicit invalid_second_arg(const std::string& __s) : invalid_argument(__s) {} - explicit invalid_second_arg(const char* __s) : invalid_argument(__s) {} - - virtual ~invalid_second_arg() = default; - }; - class error : public std::invalid_argument - { - public: - explicit error(const std::string& __s) : invalid_argument(__s) {} - explicit error(const char* __s) : invalid_argument(__s) {} - - virtual ~error() = default; - }; - class warn : public std::invalid_argument - { - public: - explicit warn(const std::string& __s) : invalid_argument(__s) {} - explicit warn(const char* __s) : invalid_argument(__s) {} - - virtual ~warn() = default; - }; -} // end namespace -#endif // !POAC_CORE_EXCEPTION_HPP diff --git a/include/poac/core/infer.hpp b/include/poac/core/infer.hpp new file mode 100644 index 000000000..2ae98112c --- /dev/null +++ b/include/poac/core/infer.hpp @@ -0,0 +1,165 @@ +#ifndef POAC_CORE_INFER_HPP +#define POAC_CORE_INFER_HPP + +#include +#include +#include +#include +#include + +#include + +#include "except.hpp" +#include "../option.hpp" +#include "../subcmd.hpp" +#include "../util/types.hpp" + + +namespace poac::core::infer { + using namespace util::types; + + // Index of T + // variable template partial specialization + template + static constexpr int index_of_v = non_type_conditional_v, I, index_of_v>; + template + static constexpr int index_of_v = non_type_conditional_v, I, -1>; + + // type in the index of I + template + struct at_impl { using type = std::conditional_t::type>; }; + template + struct at_impl { using type = std::conditional_t; }; + template + using at_impl_t = typename at_impl::type; + + // type list + template + struct type_list_t { + static constexpr std::size_t size() noexcept { return sizeof...(Ts); }; + template + static constexpr int index_of = index_of_v<0, remove_cvref_t, remove_cvref_t...>; + template + using at_t = at_impl_t; + }; + + using op_type_list_t = type_list_t< + subcmd::build, + subcmd::cache, + subcmd::cleanup, + subcmd::graph, + subcmd::init, + subcmd::install, + subcmd::login, + subcmd::new_, + subcmd::publish, + subcmd::root, + subcmd::run, + subcmd::search, + subcmd::test, + subcmd::uninstall, + subcmd::update, + option::help, + option::version + >; + const std::unordered_map subcmd_map { + { "build", op_type_list_t::index_of }, + { "cache", op_type_list_t::index_of }, + { "cleanup", op_type_list_t::index_of }, + { "graph", op_type_list_t::index_of }, + { "init", op_type_list_t::index_of }, + { "install", op_type_list_t::index_of }, + { "login", op_type_list_t::index_of }, + { "new", op_type_list_t::index_of }, + { "publish", op_type_list_t::index_of }, + { "root", op_type_list_t::index_of }, + { "run", op_type_list_t::index_of }, + { "search", op_type_list_t::index_of }, + { "test", op_type_list_t::index_of }, + { "uninstall", op_type_list_t::index_of }, + { "update", op_type_list_t::index_of } + }; + const std::unordered_map option_map { + { "--help", op_type_list_t::index_of }, + { "-h", op_type_list_t::index_of }, + { "--version", op_type_list_t::index_of }, + { "-v", op_type_list_t::index_of } + }; + +// GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47226 +#if BOOST_COMP_GNUC + template + auto execute2(VS&& vs) { return std::to_string(T()(std::forward(vs))); } + template + auto summary2() { return T::summary(); } + template + auto options2() { return T::options(); } + template + auto execute(std::index_sequence, int idx, VS&& vs) { + using func_t = decltype(&execute2, VS>); + static func_t func_table[] = { &execute2>... }; + return func_table[idx](std::forward(vs)); + } + template + auto summary(std::index_sequence, int idx) { + using func_t = decltype(&summary2>); + static func_t func_table[] = { &summary2>... }; + return func_table[idx](); + } + template + auto options(std::index_sequence, int idx) { + using func_t = decltype(&options2>); + static func_t func_table[] = { &options2>... }; + return func_table[idx](); + } +#else + // Create function pointer table: { &func<0>, &func<1>, ... } + // Execute function: &func[idx]() + template + auto execute(std::index_sequence, int idx, VS&& vs) { + // Return "0" or "1" (exit status) because match the type to the other two functions. + return std::vector({ +[](VS&& vs){ + return std::to_string(op_type_list_t::at_t()(std::forward(vs))); + }... })[idx](std::forward(vs)); + } + template + auto summary(std::index_sequence, int idx) { + return std::vector({ +[]{ return op_type_list_t::at_t::summary(); }... })[idx](); + } + template + auto options(std::index_sequence, int idx) { + return std::vector({ +[]{ return op_type_list_t::at_t::options(); }... })[idx](); + } +#endif + + // Execute function: execute or summary or options + template > + auto branch(S&& s, Index idx, VS&& vs) { + namespace except = core::except; + if (s == "exec") + return execute(Indices(), static_cast(idx), std::forward(vs)); + else if (s == "summary") + return summary(Indices(), static_cast(idx)); + else if (s == "options") + return options(Indices(), static_cast(idx)); + else + throw except::invalid_first_arg("Invalid argument"); + } + + template + auto _apply(S&& func, const OpTypeE& cmd, VS&& arg) { + return branch(std::forward(func), cmd, std::forward(arg)); + } + template + std::string apply(S&& func, S&& cmd, VS&& arg) { + namespace except = core::except; + if (auto itr = subcmd_map.find(cmd); itr != subcmd_map.end()) + return _apply(std::forward(func), itr->second, std::forward(arg)); + else if (itr = option_map.find(cmd); itr != option_map.end()) + return _apply(std::forward(func), itr->second, std::forward(arg)); + else + throw except::invalid_first_arg("Invalid argument"); + } +} +#endif // !POAC_CORE_INFER_HPP diff --git a/include/poac/core/inference.hpp b/include/poac/core/inference.hpp deleted file mode 100644 index acdc7e4e5..000000000 --- a/include/poac/core/inference.hpp +++ /dev/null @@ -1,191 +0,0 @@ -#ifndef POAC_CORE_INFERENCE_HPP -#define POAC_CORE_INFERENCE_HPP - -#include -#include -#include -#include - -#include - -#include "exception.hpp" -#include "../option.hpp" -#include "../subcmd.hpp" -#include "../util/types.hpp" - - -namespace poac::core::infer { - using namespace util::types; - - // Index of T - // variable template partial specialization - template - static constexpr int index_of_v = non_type_conditional_v, I, index_of_v>; - template - static constexpr int index_of_v = non_type_conditional_v, I, -1>; - - // type in the index of I - template - struct at_impl { using type = std::conditional_t::type>; }; - template - struct at_impl { using type = std::conditional_t; }; - template - using at_impl_t = typename at_impl::type; - - // std::initializer_list -> std::vector - template - static constexpr auto make_vector(std::initializer_list&& l) { - return std::vector{ l }; - } - - // type list - template - struct type_list_t { - static constexpr size_t size() noexcept { return sizeof...(Ts); }; - template - static constexpr int index_of = index_of_v<0, remove_cvref_t, remove_cvref_t...>; - template - using at_t = at_impl_t; - }; - - // TODO: 切り出す - using op_type_list_t = type_list_t< - subcmd::build, - subcmd::cache, - subcmd::cleanup, - subcmd::graph, - subcmd::init, - subcmd::install, - subcmd::login, - subcmd::new_, - subcmd::publish, - subcmd::root, - subcmd::run, - subcmd::search, - subcmd::test, - subcmd::uninstall, - subcmd::update, - option::help, - option::version - >; - enum class op_type_e : int { - build = op_type_list_t::index_of, - cache = op_type_list_t::index_of, - cleanup = op_type_list_t::index_of, - graph = op_type_list_t::index_of, - init = op_type_list_t::index_of, - install = op_type_list_t::index_of, - login = op_type_list_t::index_of, - new_ = op_type_list_t::index_of, - publish = op_type_list_t::index_of, - root = op_type_list_t::index_of, - run = op_type_list_t::index_of, - search = op_type_list_t::index_of, - test = op_type_list_t::index_of, - uninstall = op_type_list_t::index_of, - update = op_type_list_t::index_of, - help = op_type_list_t::index_of, - version = op_type_list_t::index_of - }; - const std::unordered_map subcmd_map { - { "build", op_type_e::build }, - { "cache", op_type_e::cache }, - { "cleanup", op_type_e::cleanup }, - { "graph", op_type_e::graph }, - { "init", op_type_e::init }, - { "install", op_type_e::install }, - { "login", op_type_e::login }, - { "new", op_type_e::new_ }, - { "publish", op_type_e::publish }, - { "root", op_type_e::root }, - { "run", op_type_e::run }, - { "search", op_type_e::search }, - { "test", op_type_e::test }, - { "uninstall", op_type_e::uninstall }, - { "update", op_type_e::update } - }; - const std::unordered_map option_map { - { "--help", op_type_e::help }, - { "-h", op_type_e::help }, - { "--version", op_type_e::version }, - { "-v", op_type_e::version } - }; - -// GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47226 -#if BOOST_COMP_GNUC - template >> - static auto execute2(VS&& vs) { return (T()(std::move(vs)), ""); } - template - static auto summary2() { return T::summary(); } - template - static auto options2() { return T::options(); } - template >> - static auto execute(std::index_sequence, int idx, VS&& vs) { - using func_t = decltype(&execute2, VS>); - static func_t func_table[] = { &execute2>... }; - return func_table[idx](std::move(vs)); - } - template - static auto summary(std::index_sequence, int idx) { - using func_t = decltype(&summary2>); - static func_t func_table[] = { &summary2>... }; - return func_table[idx](); - } - template - static auto options(std::index_sequence, int idx) { - using func_t = decltype(&options2>); - static func_t func_table[] = { &options2>... }; - return func_table[idx](); - } -#else - // Create function pointer table: { &func<0>, &func<1>, ... } - // Execute function: &func[idx]() - template >> - static auto execute(std::index_sequence, int idx, VS&& vs) { - // Return ""(empty string) because match the type to the other two functions. - return make_vector({ +[](VS&& vs){ - return std::to_string(op_type_list_t::at_t()(std::move(vs))); - }... })[idx](std::move(vs)); - } - template - static auto summary(std::index_sequence, int idx) { - return make_vector({ +[]{ return op_type_list_t::at_t::summary(); }... })[idx](); - } - template - static auto options(std::index_sequence, int idx) { - return make_vector({ +[]{ return op_type_list_t::at_t::options(); }... })[idx](); - } -#endif - - // Execute function: execute or summary or options - template , - typename = std::enable_if_t>> - static auto branch(S&& s, Index idx, VS&& vs) -> decltype(summary(Indices(), static_cast(idx))) { - namespace exception = core::exception; - if (s == "exec") - return execute(Indices(), static_cast(idx), std::move(vs)); - else if (s == "summary") - return summary(Indices(), static_cast(idx)); - else if (s == "options") - return options(Indices(), static_cast(idx)); - else - throw exception::invalid_first_arg("Invalid argument"); - } - - template - auto _apply(S&& func, const OpTypeE& cmd, VS&& arg) { - return branch(std::move(func), cmd, std::move(arg)); - } - template - std::string apply(S&& func, const S& cmd, VS&& arg) { - namespace exception = core::exception; - if (auto itr = subcmd_map.find(cmd); itr != subcmd_map.end()) - return _apply(std::move(func), itr->second, std::move(arg)); - else if (itr = option_map.find(cmd); itr != option_map.end()) - return _apply(std::move(func), itr->second, std::move(arg)); - else - throw exception::invalid_first_arg("Invalid argument"); - } -} -#endif // !POAC_CORE_INFERENCE_HPP diff --git a/include/poac/core/naming.hpp b/include/poac/core/naming.hpp index 422e45e41..5adb9f392 100644 --- a/include/poac/core/naming.hpp +++ b/include/poac/core/naming.hpp @@ -1,5 +1,4 @@ // Idempotent package naming library - #ifndef POAC_CORE_NAMING_HPP #define POAC_CORE_NAMING_HPP @@ -9,7 +8,7 @@ #include -#include "exception.hpp" +#include "except.hpp" #include "../io/file.hpp" @@ -44,6 +43,12 @@ namespace poac::core::naming { std::replace(name.begin(), name.end(), '/', '-'); return name; } + // boost-bind -> boost/bind + std::string hyphen_to_slash(std::string name) + { + std::replace(name.begin(), name.end(), '-', '/'); + return name; + } // 1. opencv/opencv, 3.4.2 -> opencv-3.4.2 @@ -104,7 +109,7 @@ namespace poac::core::naming { return to_cache_github(name, version); } else { - throw exception::error(err::source(src)); + throw except::error(err::source(src)); } } // boost/bind -> boost-bind @@ -121,7 +126,7 @@ namespace poac::core::naming { return cache_to_current(cache_name); } else { - throw exception::error(err::source(src)); + throw except::error(err::source(src)); } } @@ -146,7 +151,7 @@ namespace poac::core::naming { return *ver2; } } - throw exception::error(err::source(src)); + throw except::error(err::source(src)); } // github/curl/curl -> src = github, name = curl/curl @@ -172,42 +177,42 @@ namespace poac::core::naming { // only /, -, _, [0-9] if (std::regex_match(s, r1)) { - throw exception::error( + throw except::error( "Invalid name.\n" "It is prohibited to use / and -, _, number\n" " only string of the project name."); } // /name, -name, _name, 0name else if (std::regex_match(std::string(1, s[0]), r2)) { - throw exception::error( + throw except::error( "Invalid name.\n" "It is prohibited to use / and -, _\n" " at the begenning of the project name."); } // name/, name-, _name else if (std::regex_match(std::string(1, *(s.end()-1)), r2)) { - throw exception::error( + throw except::error( "Invalid name.\n" "It is prohibited to use / and -, _\n" " at the last of the project name."); } // na--me, n/-ame, nam_-e else if (std::regex_match(s, r3)) { - throw exception::error( + throw except::error( "Invalid name.\n" "It is prohibited to use / and -, _\n" " twice of the project name."); } // org/name/sub else if (std::count_if(s.begin(), s.end(), [](char c){ return c == '/'; }) > 1) { - throw exception::error( + throw except::error( "Invalid name.\n" "It is prohibited to use two\n" " /(slashes) in a project name."); } // use the other than [a-z], [0-9], -, _, / else if (!std::regex_match(s, r4)) { - throw exception::error( + throw except::error( "Invalid name.\n" "It is prohibited to use a character string" " that does not match ^([a-z|\\d|\\-|_|\\/]*)$\n" diff --git a/include/poac/core/stroite.hpp b/include/poac/core/stroite.hpp new file mode 100644 index 000000000..6e8fb6eec --- /dev/null +++ b/include/poac/core/stroite.hpp @@ -0,0 +1,8 @@ +#ifndef POAC_CORE_STROITE_HPP +#define POAC_CORE_STROITE_HPP + +#include "stroite/chain.hpp" +#include "stroite/core.hpp" +#include "stroite/utils.hpp" + +#endif // POAC_CORE_STROITE_HPP diff --git a/include/poac/core/stroite/chain.hpp b/include/poac/core/stroite/chain.hpp new file mode 100644 index 000000000..bc4fc4e0b --- /dev/null +++ b/include/poac/core/stroite/chain.hpp @@ -0,0 +1,6 @@ +#ifndef STROITE_CHAIN_HPP +#define STROITE_CHAIN_HPP + +#include "chain/cmake.hpp" + +#endif // STROITE_CHAIN_HPP diff --git a/include/poac/core/stroite/chain/cmake.hpp b/include/poac/core/stroite/chain/cmake.hpp new file mode 100644 index 000000000..46782ed28 --- /dev/null +++ b/include/poac/core/stroite/chain/cmake.hpp @@ -0,0 +1,49 @@ +#ifndef POAC_CORE_STROITE_CHAIN_CMAKE_HPP +#define POAC_CORE_STROITE_CHAIN_CMAKE_HPP + +#include +#include + +#include + +#include "../../except.hpp" +#include "../../../io/file/path.hpp" +#include "../../../util/command.hpp" + + +namespace poac::core::stroite::chain { + struct cmake { + boost::filesystem::path base_path; + + bool build() { // TODO: builderと同じinterfaceであるべき + namespace fs = boost::filesystem; + namespace path = io::file::path; + + util::command cmd("cd " + base_path.string()); + if (!fs::exists(base_path / "_build")) { + cmd &= "mkdir _build"; + } + cmd &= "cd _build"; + util::command cmake_cmd("cmake .."); +// for (const auto& [key, val] : cmake_args) { // TODO: -Dhoge 渡したい +// cmake_cmd.env(key, val); +// } + cmd &= cmake_cmd; + cmd &= util::command("make"); + + return cmd.exec_incontinent(); + } + + explicit cmake(const boost::filesystem::path& base_path = boost::filesystem::current_path()) + { + namespace fs = boost::filesystem; + + if (!fs::exists(base_path / "CMakeLists.txt")) { + throw except::error( + except::msg::does_not_exist((base_path / "CMakeLists.txt").string())); + } + this->base_path = base_path; + } + }; +} // end namespace +#endif // POAC_CORE_STROITE_CHAIN_CMAKE_HPP diff --git a/include/poac/util/stroite/core.hpp b/include/poac/core/stroite/core.hpp similarity index 63% rename from include/poac/util/stroite/core.hpp rename to include/poac/core/stroite/core.hpp index 083554263..fa5e433ac 100644 --- a/include/poac/util/stroite/core.hpp +++ b/include/poac/core/stroite/core.hpp @@ -2,7 +2,9 @@ #define STROITE_CORE_HPP #include "core/builder.hpp" +#include "core/cache.hpp" #include "core/compiler.hpp" #include "core/depends.hpp" +#include "core/search.hpp" -#endif // STROITE_CORE_HPP \ No newline at end of file +#endif // STROITE_CORE_HPP diff --git a/include/poac/core/stroite/core/builder.hpp b/include/poac/core/stroite/core/builder.hpp new file mode 100644 index 000000000..75a9b5714 --- /dev/null +++ b/include/poac/core/stroite/core/builder.hpp @@ -0,0 +1,249 @@ +#ifndef POAC_CORE_STROITE_CORE_BUILDER_HPP +#define POAC_CORE_STROITE_CORE_BUILDER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "./cache.hpp" +#include "./compiler.hpp" +#include "./depends.hpp" +#include "./search.hpp" +#include "../utils.hpp" +#include "../../except.hpp" +#include "../../naming.hpp" +#include "../../deper/lock.hpp" +#include "../../deper/semver.hpp" +#include "../../../io/file/path.hpp" +#include "../../../io/cli.hpp" +#include "../../../io/file/yaml.hpp" + + +namespace poac::core::stroite::core { + struct builder { + utils::options::compile compile_conf; + utils::options::link link_conf; + utils::options::static_lib static_lib_conf; + utils::options::dynamic_lib dynamic_lib_conf; + + std::string compiler; + std::string project_name; + boost::filesystem::path base_dir; + + std::map node; + std::map> depends_ts; + + bool verbose; // TODO: 一旦依存関係を集めて,一気に変換だとメモリが保たない.なので,インクリメンタルに変換するのが良い. + + + std::vector + hash_source_files( + std::vector&& source_files, + const bool usemain ) + { + namespace fs = boost::filesystem; + + if (usemain) { + if (!fs::exists("main.cpp")) { + throw except::error(except::msg::does_not_exist("main.cpp")); + } + else { + source_files.push_back("main.cpp"); + } + } + return core::cache::check_src_cpp(compile_conf, depends_ts, source_files, verbose); + } + + void make_include_search_path() { // TODO: hashチェック時の大量の文字列配列が恐らくキツイ. + namespace fs = boost::filesystem; + namespace lock = deper::lock; + namespace yaml = io::file::yaml; + namespace path = io::file::path; + + if (const auto locked_deps = lock::load_ignore_timestamp()) { + for (const auto& [name, dep] : locked_deps->backtracked) { + const std::string current_package_name = naming::to_current(dep.source, name, dep.version); + const fs::path include_dir = path::current_deps_dir / current_package_name / "include"; + + if (path::validate_dir(include_dir)) { + compile_conf.include_search_path.push_back(include_dir.string()); + } + else { + throw except::error( + name + " is not installed.\n" + "Please build after running `poac install`"); + } + } + } + else { + throw except::error( + "Could not load poac.lock.\n" + "Please build after running `poac install`"); + } + } + void configure_compile(const bool usemain) + { + namespace yaml = io::file::yaml; + namespace path = io::file::path; + + compile_conf.system = compiler; + compile_conf.version_prefix = utils::options::default_version_prefix(); + compile_conf.cpp_version = yaml::get_with_throw(node.at("cpp_version")); +// compile_conf.include_search_path = utils::options::make_include_search_path(exist_deps_key); + compile_conf.other_args = utils::options::make_compile_other_args(node); + compile_conf.source_files = hash_source_files(search::cpp(base_dir), usemain); + compile_conf.macro_defns = utils::options::make_macro_defns(node); + compile_conf.base_dir = base_dir; + compile_conf.output_root = path::current_build_cache_obj_dir; + } + std::optional> + compile() { + namespace fs = boost::filesystem; + + for (const auto& s : compile_conf.source_files) { + // sourceファイルを一つづつコンパイルする. + compile_conf.source_file = s; + if (const auto ret = core::compiler::compile(compile_conf, verbose)) { + // Since compile succeeded, save hash + std::ofstream ofs; + for (const auto& [hash_name, data] : depends_ts) { // TODO: ここまで持ち回るから落ちる? + std::string output_string; + for (const auto& [file_name, hash] : data) { + output_string += file_name + ": " + hash + "\n"; + } + fs::create_directories(fs::path(hash_name).parent_path()); + io::file::path::write_to_file(ofs, hash_name, output_string); + } + + } + else { + return std::nullopt; + } + } + + // Because it is excluded for the convenience of cache, + // ignore the return value of compiler.compile. + std::vector obj_files; + for (const auto& s : compile_conf.source_files) { + obj_files.push_back( + (compile_conf.output_root / fs::relative(s)) + .replace_extension("o") + .string() + ); + } + return obj_files; + } + + void make_link(const std::map& deps_node) { + namespace fs = boost::filesystem; + namespace yaml = io::file::yaml; + + for (const auto& [raw_name, next_node] : deps_node) { + const auto [src, name] = naming::get_source(raw_name); + const std::string version = naming::get_version(next_node, src); + + // FIXME: srcではなく,build systemを読む. + if (src != "poac") { + const std::string caching_name = naming::to_cache(src, name, version); // TODO: これ,なんで,cacheなのに, + const fs::path pkgpath = io::file::path::current_deps_dir / caching_name; // TODO: depsを読んでるん??? + + // TODO: できればlockファイルに書かれたパッケージの./depsディレクトリのpoac.ymlを読むのが好ましい + if (const fs::path lib_dir = pkgpath / "lib"; fs::exists(lib_dir)) { + link_conf.library_search_path.push_back(lib_dir.string()); + + if (const auto link = yaml::get>(next_node, "link", "include")) { + for (const auto& l : *link) { + link_conf.static_link_libs.push_back(l); + } + } + else { + link_conf.static_link_libs.push_back(caching_name); + } + } + } + } + } + void configure_link(const std::vector& obj_files_path) // TODO: obj_files_path以外は,インスタンス時に作れるからメモリの無駄遣いにならない. + { + namespace yaml = io::file::yaml; + + link_conf.obj_files_path = obj_files_path; + + link_conf.system = compiler; + link_conf.project_name = project_name; + link_conf.output_root = io::file::path::current_build_bin_dir; +// make_link(); +// link_conf.library_search_path = std::get<0>(links); +// link_conf.static_link_libs = std::get<1>(links); +// link_conf.library_path = std::get<2>(links); + if (const auto link_args = yaml::get>(node.at("build"), "link_args")) { + link_conf.other_args = *link_args; + } + } + auto link() + { + return core::compiler::link(link_conf, verbose); + } + + void configure_static_lib(const std::vector& obj_files_path) + { + static_lib_conf.project_name = project_name; + static_lib_conf.output_root = io::file::path::current_build_lib_dir; + static_lib_conf.obj_files_path = obj_files_path; + } + auto gen_static_lib() + { + return core::compiler::gen_static_lib(static_lib_conf, verbose); + } + + void configure_dynamic_lib(const std::vector& obj_files_path) + { + dynamic_lib_conf.system = compiler; + dynamic_lib_conf.project_name = project_name; + // outputを一箇所か分散か選べるように.boost::hoghoeみたいに,enumのオプションを渡すとOK + // 一箇所ってのは,./ poac build -> ./_buildだけど,depsも./_buildに配置されるやつ + dynamic_lib_conf.output_root = io::file::path::current_build_lib_dir; + dynamic_lib_conf.obj_files_path = obj_files_path; + } + auto gen_dynamic_lib() + { + return core::compiler::gen_dynamic_lib(dynamic_lib_conf, verbose); + } + + // TODO: poac.ymlのhashもcheck + // TODO: 自らのinclude,dirも,(存在するなら!) includeパスに渡してほしい.そうすると,poacでincludeできる + // TODO: この段階で,どこまでするのかが分かれば,コンパイルしないのに,コンパイル用の設定を生成した,とかが無くなって良さそう. + explicit builder(const bool verbose, const boost::filesystem::path& base_dir=boost::filesystem::current_path()) + { + namespace yaml = io::file::yaml; + + const auto config_file = yaml::load_config_by_dir_with_throw(base_dir); + node = yaml::get_by_width(config_file, "name", "version", "cpp_version", "build"); + + + // Create link configure and include search path + if (const auto deps_node = yaml::get>(config_file, "deps")) { + make_link(*deps_node); + make_include_search_path(); + } + + + compiler = utils::detect::compiler(); + project_name = naming::slash_to_hyphen(node.at("name").as()); + this->base_dir = base_dir; + this->verbose = verbose; + } + }; +} // end namespace +#endif // POAC_CORE_STROITE_CORE_BUILDER_HPP diff --git a/include/poac/core/stroite/core/cache.hpp b/include/poac/core/stroite/core/cache.hpp new file mode 100644 index 000000000..c6a871c8e --- /dev/null +++ b/include/poac/core/stroite/core/cache.hpp @@ -0,0 +1,124 @@ +#ifndef POAC_CORE_STROITE_CORE_CACHE_HPP +#define POAC_CORE_STROITE_CORE_CACHE_HPP + +#include +#include +#include +#include +#include + +#include + +#include "./depends.hpp" +#include "../utils/options.hpp" +#include "../../../io/file/path.hpp" + + +namespace poac::core::stroite::core::cache { + std::string to_cache_hash_path(const std::string& s) + { + namespace fs = boost::filesystem; + namespace path = io::file::path; + + const auto hash_path = path::current_build_cache_hash_dir / fs::relative(s); + return hash_path.string() + ".hash"; + } + + std::optional> + load_timestamps(const std::string& src_cpp_hash) + { + namespace fs = boost::filesystem; + namespace path = io::file::path; + + if (!fs::exists(src_cpp_hash)) { + return std::nullopt; + } + std::ifstream ifs(src_cpp_hash); + if (!ifs.is_open()) { + return std::nullopt; + } + + std::string buff; + std::map hash; + while (std::getline(ifs, buff)) { + const auto list_string = path::split(buff, ": \n"); + hash[list_string[0]] = list_string[1]; + } + return hash; + } + + void generate_timestamp( + const std::string& filename, + std::map& timestamp) + { + namespace fs = boost::filesystem; + + boost::system::error_code error; + const std::time_t last_time = fs::last_write_time(filename, error); + timestamp.emplace(filename, std::to_string(last_time)); + } + + // *.cpp -> hash + std::optional> + generate_timestamps( + const utils::options::compile& compile_conf, + const std::string& source_file, + const bool verbose) + { + if (const auto deps_headers = depends::gen(compile_conf, source_file, verbose)) + { + std::map hash; + for (const auto& name : *deps_headers) { + // Calculate the hash of the source dependent files. + generate_timestamp(name, hash); + } + // Calculate the hash of the source file itself. + generate_timestamp(source_file, hash); + return hash; + } + return std::nullopt; + } + + std::vector + check_src_cpp( + const utils::options::compile& compile_conf, + std::map>& depends_ts, + const std::vector& source_files, + const bool verbose) + { + std::vector required_source_files; // FIXME: コンパイルが必要な + for (const auto& sf : source_files) { + if (const auto previous_ts = load_timestamps(to_cache_hash_path(sf))) { + if (const auto current_ts = generate_timestamps(compile_conf, sf, verbose)) + { + // Since hash of already existing hash file + // does not match hash of current cpp file, + // it does not exclude it from compilation, + // and generates hash for overwriting. + if (*previous_ts != *current_ts) { + depends_ts[to_cache_hash_path(sf)] = *current_ts; // TODO: これも,メモリにおかず,どんどんストリームに流す? + required_source_files.push_back(sf); + } + } + } + else { + // Since hash file does not exist, generates hash and compiles source file. + if (const auto cur_hash = generate_timestamps(compile_conf, sf, verbose)) + { + depends_ts[to_cache_hash_path(sf)] = *cur_hash; + required_source_files.push_back(sf); + } + } + } + return required_source_files; + } + + + + + void is_required_compile() {} + + + // TODO: storeと,load, compare(check) => cacheのAPIをわかりやすくしたい.StoreとLoadのみで,わかりやすく +} // end namespace +#endif // POAC_CORE_STROITE_CORE_CACHE_HPP diff --git a/include/poac/util/stroite/core/compiler.hpp b/include/poac/core/stroite/core/compiler.hpp similarity index 51% rename from include/poac/util/stroite/core/compiler.hpp rename to include/poac/core/stroite/core/compiler.hpp index 16f1d7e0d..fe78aca1f 100644 --- a/include/poac/util/stroite/core/compiler.hpp +++ b/include/poac/core/stroite/core/compiler.hpp @@ -1,5 +1,5 @@ -#ifndef STROITE_CORE_COMPILER_HPP -#define STROITE_CORE_COMPILER_HPP +#ifndef POAC_CORE_STROITE_CORE_COMPILER_HPP +#define POAC_CORE_STROITE_CORE_COMPILER_HPP #include #include @@ -8,61 +8,57 @@ #include -#include "../../command.hpp" +#include "../utils/absorb.hpp" +#include "../../../util/command.hpp" -namespace stroite::core::compiler { +namespace poac::core::stroite::core::compiler { namespace fs = boost::filesystem; template - std::optional> - compile(const Opts& opts) + std::optional + compile(const Opts& opts, const bool verbose) { - poac::util::command cmd("cd " + opts.base_dir.string()); + util::command cmd("cd " + opts.base_dir.string()); cmd &= opts.system; cmd += opts.version_prefix + std::to_string(opts.cpp_version); cmd += "-c"; - for (const auto& s : opts.source_files) - cmd += s; + cmd += opts.source_file; for (const auto& isp : opts.include_search_path) cmd += "-I" + isp; for (const auto& oa : opts.other_args) cmd += oa; for (const auto& md : opts.macro_defns) cmd += md; - cmd += "-o"; - std::vector obj_files_path; - for (const auto& s : opts.source_files) { - auto obj_path = opts.output_root / fs::relative(s); - obj_path.replace_extension("o"); - fs::create_directories(obj_path.parent_path()); - const auto obj_path_str = obj_path.string(); - obj_files_path.push_back(obj_path_str); - cmd += obj_path_str; - } - if (opts.verbose) + cmd += "-o"; + auto obj_path = opts.output_root / fs::relative(opts.source_file); + obj_path.replace_extension("o"); + fs::create_directories(obj_path.parent_path()); + const auto obj_path_str = obj_path.string(); + std::string obj_files_path = obj_path_str; + cmd += obj_path_str; + + if (verbose) { std::cout << cmd << std::endl; + } - if (cmd.exec()) + if (cmd.exec()) { return obj_files_path; - else + } + else { return std::nullopt; + } } template std::optional - link(const Opts& opts) + link(const Opts& opts, const bool verbose) { -#ifdef _WIN32 - const std::string extension = ".exe"; -#else - const std::string extension = ""; -#endif const std::string bin_path = - (opts.output_root / opts.project_name).string() + extension; + (opts.output_root / opts.project_name).string() + utils::absorb::binary_extension; - poac::util::command cmd(opts.system); + util::command cmd(opts.system); for (const auto& o : opts.obj_files_path) cmd += o; for (const auto& lsp : opts.library_search_path) @@ -75,58 +71,67 @@ namespace stroite::core::compiler { cmd += oa; cmd += "-o " + bin_path; - if (opts.verbose) + if (verbose) { std::cout << cmd << std::endl; + } fs::create_directories(opts.output_root); - if (cmd.exec()) + if (cmd.exec()) { return bin_path; - else + } + else { return std::nullopt; + } } template std::optional - gen_static_lib(const Opts& opts) + gen_static_lib(const Opts& opts, const bool verbose) { - poac::util::command cmd("ar rcs"); - const std::string stlib_path = - (opts.output_root / opts.project_name).string() + ".a"; - cmd += stlib_path; + util::command cmd("ar rcs"); + const std::string lib_name = "lib" + opts.project_name + ".a"; + const std::string lib_path = (opts.output_root / lib_name).string(); + cmd += lib_path; for (const auto& o : opts.obj_files_path) cmd += o; - if (opts.verbose) + if (verbose) { std::cout << cmd << std::endl; + } fs::create_directories(opts.output_root); - if (cmd.exec()) - return stlib_path; - else + if (cmd.exec()) { + return lib_path; + } + else { return std::nullopt; + } } template std::optional - gen_dynamic_lib(const Opts& opts) + gen_dynamic_lib(const Opts& opts, const bool verbose) { - poac::util::command cmd(opts.system); - cmd += "-dynamiclib"; // -shared // FIXME: macosとlinux + util::command cmd(opts.system); + cmd += utils::absorb::dynamic_lib_option; for (const auto& o : opts.obj_files_path) cmd += o; cmd += "-o"; - const std::string dylib_path = - (opts.output_root / opts.project_name).string() + ".dylib"; // FIXME: macosとlinux - cmd += dylib_path; + const std::string lib_name = "lib" + opts.project_name + utils::absorb::dynamic_lib_extension; + const std::string lib_path = (opts.output_root / lib_name).string(); + cmd += lib_path; - if (opts.verbose) + if (verbose) { std::cout << cmd << std::endl; + } fs::create_directories(opts.output_root); - if (cmd.exec()) - return dylib_path; - else + if (cmd.exec()) { + return lib_path; + } + else { return std::nullopt; + } } } // end namespace -#endif // STROITE_CORE_COMPILER_HPP +#endif // POAC_CORE_STROITE_CORE_COMPILER_HPP diff --git a/include/poac/util/stroite/core/depends.hpp b/include/poac/core/stroite/core/depends.hpp similarity index 60% rename from include/poac/util/stroite/core/depends.hpp rename to include/poac/core/stroite/core/depends.hpp index 425f9c595..9db0358a2 100644 --- a/include/poac/util/stroite/core/depends.hpp +++ b/include/poac/core/stroite/core/depends.hpp @@ -1,5 +1,5 @@ -#ifndef STROITE_CORE_DEPENDS_HPP -#define STROITE_CORE_DEPENDS_HPP +#ifndef POAC_CORE_STROITE_CORE_DEPENDS_HPP +#define POAC_CORE_STROITE_CORE_DEPENDS_HPP #include #include @@ -7,20 +7,23 @@ #include #include "../utils.hpp" -#include "../../command.hpp" +#include "../../../util/command.hpp" +#include "../../../util/misc.hpp" -namespace stroite::core::depends { +namespace poac::core::stroite::core::depends { template std::optional - calc(const Opts& opts, const std::string& src_cpp) + calc(const Opts& opts, const std::string& src_cpp, const bool verbose) { - poac::util::command cmd(opts.system); + util::command cmd(opts.system); cmd += opts.version_prefix + std::to_string(opts.cpp_version); - for (const auto& isp : opts.include_search_path) + for (const auto& isp : opts.include_search_path) { cmd += "-I" + isp; - for (const auto& cta : opts.other_args) // TODO: other_argとして,include search pathを指定する可能性がある. + } + for (const auto& cta : opts.other_args) {// TODO: other_argとして,include search pathを指定する可能性がある. cmd += cta; + } // Like -M but do not mention header files that are found in system header directories, // nor header files that are included, directly or indirectly, from such a header. // This implies that the choice of angle brackets or double quotes in an ‘#include’ directive @@ -28,18 +31,18 @@ namespace stroite::core::depends { // (https://gcc.gnu.org/onlinedocs/gcc/Preprocessor-Options.html#Preprocessor-Options) cmd += "-MM " + src_cpp; - if (opts.verbose) + if (verbose) { std::cout << cmd << std::endl; - + } return cmd.exec(); } template std::optional> - gen(const Opts& opts, const std::string& src_cpp) + gen(const Opts& opts, const std::string& src_cpp, const bool verbose) { - if (const auto ret = calc(opts, src_cpp)) { - auto deps_headers = utils::misc::split(*ret, " \n\\"); + if (const auto ret = calc(opts, src_cpp, verbose)) { + auto deps_headers = util::misc::split(*ret, " \n\\"); deps_headers.erase(deps_headers.begin()); // main.o: deps_headers.erase(deps_headers.begin()); // main.cpp return deps_headers; @@ -49,4 +52,4 @@ namespace stroite::core::depends { } } } // end namespace -#endif // STROITE_CORE_DEPENDS_HPP +#endif // POAC_CORE_STROITE_CORE_DEPENDS_HPP diff --git a/include/poac/core/stroite/core/search.hpp b/include/poac/core/stroite/core/search.hpp new file mode 100644 index 000000000..98d76bef0 --- /dev/null +++ b/include/poac/core/stroite/core/search.hpp @@ -0,0 +1,40 @@ +#ifndef POAC_CORE_STROITE_CORE_SEARCH_HPP +#define POAC_CORE_STROITE_CORE_SEARCH_HPP + +#include +#include +#include + +#include + +#include "../../../io/file/path.hpp" + + +namespace poac::core::stroite::core::search { + bool is_cpp_file(const boost::filesystem::path& p) { + namespace fs = boost::filesystem; + return !fs::is_directory(p) + && (p.extension().string() == ".cpp" + || p.extension().string() == ".cxx" + || p.extension().string() == ".cc" + || p.extension().string() == ".cp"); + } + + std::vector + cpp(const boost::filesystem::path& base_dir) { + namespace fs = boost::filesystem; + namespace path = io::file::path; + + std::vector source_files; + const auto source_dir = base_dir / "src"; + if (path::validate_dir(source_dir)) { + for (const fs::path& p : fs::recursive_directory_iterator(source_dir)) { + if (is_cpp_file(p)) { + source_files.push_back(p.string()); + } + } + } + return source_files; + } +} // end namespace +#endif // POAC_CORE_STROITE_CORE_SEARCH_HPP diff --git a/include/poac/core/stroite/utils.hpp b/include/poac/core/stroite/utils.hpp new file mode 100644 index 000000000..f9b5c89a3 --- /dev/null +++ b/include/poac/core/stroite/utils.hpp @@ -0,0 +1,8 @@ +#ifndef STROITE_UTILS_HPP +#define STROITE_UTILS_HPP + +#include "utils/absorb.hpp" +#include "utils/detect.hpp" +#include "utils/options.hpp" + +#endif // STROITE_UTILS_HPP diff --git a/include/poac/core/stroite/utils/absorb.hpp b/include/poac/core/stroite/utils/absorb.hpp new file mode 100644 index 000000000..c815ce43f --- /dev/null +++ b/include/poac/core/stroite/utils/absorb.hpp @@ -0,0 +1,20 @@ +#ifndef POAC_CORE_STROITE_UTILS_ABSORB_HPP +#define POAC_CORE_STROITE_UTILS_ABSORB_HPP + + +namespace poac::core::stroite::utils::absorb { +#ifdef __APPLE__ + const std::string binary_extension = ""; + const std::string dynamic_lib_extension = ".dylib"; + const std::string dynamic_lib_option = "-dynamiclib"; +#elif defined(_WIN32) + const std::string binary_extension = ".exe"; + const std::string dynamic_lib_extension = ".dll"; + const std::string dynamic_lib_option = "-shared -fPIC"; +#else + const std::string binary_extension = ""; + const std::string dynamic_lib_extension = ".so"; + const std::string dynamic_lib_option = "-shared -fPIC"; +#endif +} // end namespace +#endif // POAC_CORE_STROITE_UTILS_ABSORB_HPP diff --git a/include/poac/core/stroite/utils/detect.hpp b/include/poac/core/stroite/utils/detect.hpp new file mode 100644 index 000000000..3ce5e4c12 --- /dev/null +++ b/include/poac/core/stroite/utils/detect.hpp @@ -0,0 +1,69 @@ +#ifndef POAC_CORE_STROITE_UTILS_DETECT_HPP +#define POAC_CORE_STROITE_UTILS_DETECT_HPP + +#include +#include +#include +#include + +#include + +#include "../../except.hpp" +#include "../../../util/command.hpp" + + +namespace poac::core::stroite::utils::detect { + // Automatic selection of compiler + auto compiler() { + namespace command = util::_command; + + if (const char* cxx = std::getenv("CXX")) { + return cxx; + } + else if (command::has_command("g++")) { + return "g++"; + } + else if (command::has_command("clang++")) { + return "clang++"; + } + else { + throw except::error( + "Environment variable \"CXX\" was not found.\n" + "Select the compiler and export it."); + } + } + + + std::string check_support_build_system(const std::string& system) { + if (system != "poac" && system != "cmake") { + throw except::error("Unknown build system " + system); + } + return system; + } + + std::optional + build_system(const YAML::Node &node) + { + namespace yaml = io::file::yaml; + + if (const auto system = yaml::get(node, "build")) { + return check_support_build_system(*system); + } + else if (const auto build_node = yaml::get>(node, "build")) { + YAML::Node build_node2; + try { + build_node2 = (*build_node).at("system"); + } + catch(std::out_of_range&) { + return std::nullopt; + } + + if (const auto system2 = yaml::get(build_node2)) { + return check_support_build_system(*system2); + } + } + // No build required + return std::nullopt; + } +} // end namespace +#endif // POAC_CORE_STROITE_UTILS_DETECT_HPP diff --git a/include/poac/util/stroite/utils/options.hpp b/include/poac/core/stroite/utils/options.hpp similarity index 51% rename from include/poac/util/stroite/utils/options.hpp rename to include/poac/core/stroite/utils/options.hpp index 46643652d..75807502e 100644 --- a/include/poac/util/stroite/utils/options.hpp +++ b/include/poac/core/stroite/utils/options.hpp @@ -1,32 +1,42 @@ -#ifndef STROITE_UTILS_OPTIONS_HPP -#define STROITE_UTILS_OPTIONS_HPP +#ifndef POAC_CORE_STROITE_UTILS_OPTIONS_HPP +#define POAC_CORE_STROITE_UTILS_OPTIONS_HPP #include +#include #include #include #include +#include -#include "../../command.hpp" +#include "./absorb.hpp" +#include "../../except.hpp" +#include "../../naming.hpp" +#include "../../deper/lock.hpp" +#include "../../deper/semver.hpp" +#include "../../../io/file/path.hpp" +#include "../../../io/cli.hpp" +#include "../../../io/file/yaml.hpp" +#include "../../../util/command.hpp" -namespace stroite::utils::options { - namespace fs = boost::filesystem; - using command = poac::util::command; - +namespace poac::core::stroite::utils::options { struct compile { std::string system; // TODO: systemだけ別の管理にして,compiler.hppに,system, std::string optsとして渡したい. std::string version_prefix; unsigned int cpp_version; std::vector source_files; + std::string source_file; std::vector include_search_path; std::vector other_args; std::vector macro_defns; boost::filesystem::path base_dir; boost::filesystem::path output_root; - bool verbose; // TODO: これ,別で渡せない??? }; std::string to_string(const compile& c) { + namespace fs = boost::filesystem; + using command = util::command; + command opts; opts += c.version_prefix + std::to_string(c.cpp_version); opts += "-c"; @@ -42,7 +52,7 @@ namespace stroite::utils::options { fs::create_directories(obj_path.parent_path()); opts += obj_path.string(); } - return opts.data(); + return opts.string(); } struct link { @@ -54,9 +64,10 @@ namespace stroite::utils::options { std::vector static_link_libs; std::vector library_path; std::vector other_args; - bool verbose; }; std::string to_string(const link& l) { + using command = util::command; + command opts; opts += accumulate(begin(l.obj_files_path), end(l.obj_files_path), command()); opts += accumulate(begin(l.library_search_path), end(l.library_search_path), command(), @@ -66,20 +77,21 @@ namespace stroite::utils::options { opts += accumulate(begin(l.library_path), end(l.library_path), command()); opts += accumulate(begin(l.other_args), end(l.other_args), command()); opts += "-o " + (l.output_root / l.project_name).string(); - return opts.data(); + return opts.string(); } struct static_lib { std::string project_name; boost::filesystem::path output_root; std::vector obj_files_path; - bool verbose; }; std::string to_string(const static_lib& s) { + using command = util::command; + command opts; opts += (s.output_root / s.project_name).string() + ".a"; opts += accumulate(begin(s.obj_files_path), end(s.obj_files_path), command()); - return opts.data(); + return opts.string(); } struct dynamic_lib { @@ -87,21 +99,70 @@ namespace stroite::utils::options { std::string project_name; boost::filesystem::path output_root; std::vector obj_files_path; - bool verbose; }; std::string to_string(const dynamic_lib& d) { + using command = util::command; + command opts; -#ifdef __APPLE__ - opts += "-dynamiclib"; - const std::string extension = ".dylib"; -#else - opts += "-shared -fPIC"; - const std::string extension = ".so"; -#endif + opts += absorb::dynamic_lib_option; + const std::string extension = absorb::dynamic_lib_extension; opts += accumulate(begin(d.obj_files_path), end(d.obj_files_path), command()); opts += "-o"; opts += (d.output_root / d.project_name).string() + extension; - return opts.data(); + return opts.string(); + } + + + template + void enable_gnu(Opts& opts) { // TODO: + opts.version_prefix = "-std=gnu++"; + } + + // TODO: できれば,implに, + std::string default_version_prefix() { + return "-std=c++"; + } + template + std::string make_macro_defn(const std::string& first, const T& second) { + return make_macro_defn(first, std::to_string(second)); + } + template <> + std::string make_macro_defn(const std::string& first, const std::string& second) { + return "-D" + first + "=" + R"(\")" + second + R"(\")"; + } + template <> + std::string make_macro_defn(const std::string& first, const std::uint64_t& second) { + std::ostringstream oss; + oss << second; + return make_macro_defn(first, oss.str()); + } + + std::vector + make_macro_defns(const std::map& node) { + namespace fs = boost::filesystem; + namespace yaml = io::file::yaml; + + std::vector macro_defns; + // poac automatically define the absolute path of the project's root directory. + // TODO: これ,依存関係もこれ使ってたら,それも,ルートのにならへん?header-only libの時 + macro_defns.emplace_back(make_macro_defn("POAC_PROJECT_ROOT", fs::current_path().string())); + const auto version = deper::semver::Version(yaml::get_with_throw(node.at("version"))); + macro_defns.emplace_back(make_macro_defn("POAC_VERSION", version.get_full())); + macro_defns.emplace_back(make_macro_defn("POAC_MAJOR_VERSION", version.major)); + macro_defns.emplace_back(make_macro_defn("POAC_MINOR_VERSION", version.minor)); + macro_defns.emplace_back(make_macro_defn("POAC_PATCH_VERSION", version.patch)); + return macro_defns; + } + + std::vector + make_compile_other_args(const std::map& node) { + namespace yaml = io::file::yaml; + if (const auto compile_args = yaml::get>(node.at("build"), "compile_args")) { + return *compile_args; + } + else { + return {}; + } } } // end namespace -#endif // STROITE_UTILS_OPTIONS_HPP +#endif // POAC_CORE_STROITE_UTILS_OPTIONS_HPP diff --git a/include/poac/io.hpp b/include/poac/io.hpp index fcee47f7e..851899d14 100644 --- a/include/poac/io.hpp +++ b/include/poac/io.hpp @@ -3,6 +3,6 @@ #include "io/cli.hpp" #include "io/file.hpp" -#include "io/network.hpp" +#include "io/net.hpp" #endif // !POAC_IO_HPP diff --git a/include/poac/io/cli.hpp b/include/poac/io/cli.hpp index 8616f057b..2d543c84f 100644 --- a/include/poac/io/cli.hpp +++ b/include/poac/io/cli.hpp @@ -7,6 +7,8 @@ #include #include +#include "../util/pretty.hpp" + namespace poac::io::cli { // Clear screen @@ -46,27 +48,13 @@ namespace poac::io::cli { } } - template - inline void echo(const T&... s) { - (std::cout << ... << s) << std::endl; - } - template - inline void debugln([[maybe_unused]] const T&... s) { -#ifdef DEBUG - echo(s...); -#endif - } - template - inline void debug([[maybe_unused]] const T &... s) { -#ifdef DEBUG - (std::cout << ... << s); -#endif - } - const std::string red = "\x1b[31m"; const std::string green = "\x1b[32m"; const std::string yellow = "\x1b[33m"; const std::string blue = "\x1b[34m"; + const std::string pink = "\x1b[35m"; + const std::string lightblue = "\x1b[36m"; + const std::string gray = "\x1b[90m"; const std::string bold = "\x1b[1m"; const std::string underline = "\x1b[4m"; const std::string reset = "\x1b[0m"; @@ -75,6 +63,9 @@ namespace poac::io::cli { inline std::string to_green(const std::string& s) { return green+s+reset; } inline std::string to_yellow(const std::string& s) { return yellow+s+reset; } inline std::string to_blue(const std::string& s) { return blue+s+reset; } + inline std::string to_pink(const std::string& s) { return pink+s+reset; } + inline std::string to_lightblue(const std::string& s) { return lightblue+s+reset; } + inline std::string to_gray(const std::string& s) { return gray+s+reset; } inline std::string to_bold(const std::string& s) { return bold+s+reset; } inline std::string to_underline(const std::string& s) { return underline+s+reset; } @@ -82,16 +73,19 @@ namespace poac::io::cli { const std::string status = to_green("==> "); const std::string fetched = to_green(" ● "); const std::string fetch_failed = to_red(" ● "); + const std::string warning = to_yellow("WARN: "); const std::string error = to_red("ERROR: "); - const std::string info = to_underline("INFO:") + " "; + const std::string info = to_blue("info: "); + const std::string debug_m = to_gray("[debug] "); inline std::string to_status(const std::string& s) { return status+s; } inline std::string to_fetched(const std::string& s) { return fetched+s; } inline std::string to_fetch_failed(const std::string& s) { return fetch_failed+s; } + + inline std::string to_info(const std::string& s) { return info+s; } inline std::string to_warning(const std::string& s) { return warning+s; } inline std::string to_error(const std::string& s) { return error+s; } - inline std::string to_info(const std::string& s) { return info+s; } inline std::string status_done() { return to_status("Done."); } @@ -99,14 +93,89 @@ namespace poac::io::cli { const std::vector spinners{ "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏" }; - std::string at_spinner(const size_t& index) { + std::string to_spinner(const size_t& index) { return spinners[index % spinners.size()]; } const std::vector pointers{ ". ", ".. ", "..." }; - std::string at_pointer(const size_t& index) { + std::string to_pointer(const size_t& index) { if (index <= 2) return pointers[0]; else if (index <= 5) return pointers[1]; else return pointers[2]; } + + // Create progress bar, [====> ] + std::string to_progress(const int& max_count, int now_count) { + if (now_count > max_count) { + now_count = max_count; + } + + const int bar_size = 50; + const int percent = (now_count * 100) / max_count; + const int bar_pos = percent / 2; + + std::string bar = "["; + if (now_count >= max_count) { + for (int i = 0; i < (bar_size - 1); ++i) { + bar += "="; + } + bar += ">]"; + } + else if ((bar_pos - 1) > 0) { + for (int i = 0; i < (bar_pos - 1); ++i) { + bar += "="; + } + bar += ">"; + for (int i = 0; i < (bar_size - bar_pos); ++i) { + bar += " "; + } + bar += "]"; + } + else if (bar_pos == 1) { + bar += ">"; + for (int i = 0; i < (bar_size - 1); ++i) { + bar += " "; + } + bar += "]"; + } + else { + for (int i = 0; i < bar_size; ++i) { + bar += " "; + } + bar += "]"; + } + return bar; + } + // Print byte progress bar, [====> ] 10.21B/21.28KB + void echo_byte_progress(const int& max_count, const int& now_count) { + const auto [ parsed_max_byte, max_byte_unit ] = util::pretty::to_byte(max_count); + const auto [ parsed_now_byte, now_byte_unit ] = util::pretty::to_byte(now_count); + std::cout << cli::to_progress(max_count, now_count) << " "; + std::cout << std::fixed; + std::cout << std::setprecision(2) << parsed_now_byte << now_byte_unit << "/"; + std::cout << std::setprecision(2) << parsed_max_byte << max_byte_unit << std::flush; + } + + + template + inline void echo(const T&... s) { + (std::cout << ... << s) << std::endl; + } + template + inline void echo_noln(const T&... s) { + (std::cout << ... << s); + } + + template + inline void debugln([[maybe_unused]] const T&... s) { +#ifdef DEBUG + echo(debug_m, s...); +#endif + } + template + inline void debug([[maybe_unused]] const T &... s) { +#ifdef DEBUG + echo_noln(debug_m, s...); +#endif + } } // end namespace #endif // !POAC_IO_CLI_HPP diff --git a/include/poac/io/file/path.hpp b/include/poac/io/file/path.hpp index a38e89ec4..3e8a5f9be 100644 --- a/include/poac/io/file/path.hpp +++ b/include/poac/io/file/path.hpp @@ -9,13 +9,15 @@ #include #include -#include "../../core/exception.hpp" +#include "../../core/except.hpp" #include "../../util/command.hpp" namespace poac::io::file::path { // Inspired by https://stackoverflow.com/q/4891006 std::string expand_user(std::string path) { + namespace except = core::except; + if (!path.empty() && path[0] == '~') { assert(path.size() == 1 || path[1] == '/'); const char* home = std::getenv("HOME"); @@ -28,11 +30,13 @@ namespace poac::io::file::path { path.replace(0, 1, std::string(hdrive) + hpath); } else { - throw core::exception::error("Could not read environment variable HOMEPATH."); + throw except::error( + except::msg::could_not_read("environment variable HOMEPATH")); } } else { - throw core::exception::error("Could not read environment variable HOMEDRIVE."); + throw except::error( + except::msg::could_not_read("environment variable HOMEDRIVE")); } } } @@ -63,7 +67,7 @@ namespace poac::io::file::path { const boost::filesystem::path current_build_cache_obj_dir( current_build_cache_dir / "obj" ); - const boost::filesystem::path current_build_cache_hash_dir( + const boost::filesystem::path current_build_cache_hash_dir( // FIXME: hashでなく,timestamp current_build_cache_dir / "_hash" ); const boost::filesystem::path current_build_bin_dir( diff --git a/include/poac/io/file/tarball.hpp b/include/poac/io/file/tarball.hpp index d7fb660e1..17e5b3db0 100644 --- a/include/poac/io/file/tarball.hpp +++ b/include/poac/io/file/tarball.hpp @@ -12,7 +12,7 @@ namespace poac::io::file::tarball { namespace fs = boost::filesystem; bool extract(const fs::path& filename, const std::string& options = "") { - const std::string cmd = "tar -zxf " + filename.string() + " " + options; + const std::string cmd = "tar zxf " + filename.string() + " " + options; return static_cast(std::system(cmd.data())); } // ~/.poac/cache/package.tar.gz -> ~/.poac/cache/username-repository-tag/... @@ -24,7 +24,7 @@ namespace poac::io::file::tarball { // It is almost the same behavior as --remove-files, // but deleted in fs::remove because there is a possibility // that it is not compatible with --remove-files. - bool extract_spec_rm(const fs::path &input, const fs::path &output) { + bool extract_spec_rm(const fs::path& input, const fs::path& output) { // true == error // TODO: install.hpp用のエラー判定とfsのboolean値が逆 return !(extract_spec(input, output) || fs::remove(input)); } @@ -36,7 +36,7 @@ namespace poac::io::file::tarball { } const std::string filepath = fs::relative(input.parent_path()).string(); const std::string filename = input.filename().string(); - const std::string cmd = "cd " + filepath + " && " + "tar -zcf " + output.string() + " " + exclude + filename; + const std::string cmd = "cd " + filepath + " && " + "tar zcf " + output.string() + " " + exclude + filename; return static_cast(std::system(cmd.data())); } } // end namespace diff --git a/include/poac/io/file/yaml.hpp b/include/poac/io/file/yaml.hpp index 0bed70c3e..4c284f181 100644 --- a/include/poac/io/file/yaml.hpp +++ b/include/poac/io/file/yaml.hpp @@ -11,7 +11,7 @@ #include #include -#include "../../core/exception.hpp" +#include "../../core/except.hpp" namespace poac::io::file::yaml { @@ -36,100 +36,112 @@ namespace poac::io::file::yaml { T get(const YAML::Node& node, Keys&&... keys) { return get((wrapper(node) ->* ... ->* keys).node); } + + + // Private member accessor + using YAML_Node_t = bool YAML::Node::*; +#if BOOST_COMP_MSVC + template + struct accessor { + static T m_isValid; + static T get() { return m_isValid; } + }; + template + T accessor::m_isValid; + + template + struct bastion { + bastion() { accessor::m_isValid = V; } + }; + + template struct bastion; + using access = accessor; +#else + template + struct accessor { + static constexpr T m_isValid = V; + static T get() { return m_isValid; } + }; + template + using bastion = accessor; + using access = bastion; +#endif + + template + std::optional + read(const YAML::Node& node, Head&& head) { + if (!(node[head].*access::get())) { + return head; + } + else { + return std::nullopt; + } + } + template + std::optional + read(const YAML::Node& node, Head&& head, Tail&&... tail) { + if (!(node[head].*access::get())) { + return head; + } + else { + return read(node, tail...); + } + } } template std::optional - get(const YAML::Node& node) { + get(const YAML::Node& node) noexcept { try { return detail::get(node); } - catch (const YAML::BadConversion& e) { + catch (...) { return std::nullopt; } } template std::optional - get(const YAML::Node& node, Args&&... args) { + get(const YAML::Node& node, Args&&... args) noexcept { try { return detail::get(node, args...); } - catch (const YAML::BadConversion& e) { + catch (...) { return std::nullopt; } } template - bool get(const YAML::Node& node, Args&&... args) { + bool get(const YAML::Node& node, Args&&... args) noexcept { try { return detail::get(node, args...); } - catch (const YAML::BadConversion& e) { + catch (...) { return false; } } template - T get_with_throw(const YAML::Node& node, const std::string& arg) { - namespace exception = core::exception; + T get_with_throw(const YAML::Node& node) { + namespace except = core::except; try { - return detail::get(node, arg); + return detail::get(node); } - catch (const YAML::BadConversion& e) { - throw exception::error( - "Required key `" + arg + "` does not exist in poac.yml.\n" - "Please refer to https://docs.poac.io"); + catch (...) { + throw except::error( + except::msg::key_does_not_exist("") + "\n" + + except::msg::please_refer_docs("")); } } - - - // Private member accessor - using YAML_Node_t = bool YAML::Node::*; -#if BOOST_COMP_MSVC - template - struct accessor { - static T m_isValid; - static T get() { return m_isValid; } - }; - template - T accessor::m_isValid; - - template - struct bastion { - bastion() { accessor::m_isValid = V; } - }; - - template struct bastion; - using access = accessor; -#else - template - struct accessor { - static constexpr T m_isValid = V; - static T get() { return m_isValid; } - }; template - using bastion = accessor; - using access = bastion; -#endif - - template - std::optional - read(const YAML::Node& node, Head&& head) { - if (!(node[head].*access::get())) { - return head; - } - else { - return std::nullopt; - } - } - template - std::optional - read(const YAML::Node& node, Head&& head, Tail&&... tail) { - if (!(node[head].*access::get())) { - return head; + T get_with_throw(const YAML::Node& node, const std::string& arg) { + namespace except = core::except; + try { + return detail::get(node, arg); } - else { - return read(node, tail...); + catch (...) { + throw except::error( + except::msg::key_does_not_exist(arg) + "\n" + + except::msg::please_refer_docs("")); } } @@ -137,12 +149,11 @@ namespace poac::io::file::yaml { template static std::map get_by_width(const YAML::Node& node, const Args&... args) { - namespace exception = core::exception; - if (const auto result = read(node, args...)) { - throw exception::error( - "Required key `" + std::string(*result) + - "` does not exist in poac.yml.\n" - "Please refer to https://docs.poac.io"); + namespace except = core::except; + if (const auto result = detail::read(node, args...)) { + throw except::error( + except::msg::key_does_not_exist(std::string(*result)) + "\n" + + except::msg::please_refer_docs("")); } else { std::map mp; @@ -153,7 +164,7 @@ namespace poac::io::file::yaml { template static std::optional> get_by_width_opt(const YAML::Node& node, const Args&... args) { - if (read(node, args...)) { + if (detail::read(node, args...)) { return std::nullopt; } else { @@ -188,19 +199,19 @@ namespace poac::io::file::yaml { YAML::Node load_config() { - namespace exception = core::exception; + namespace except = core::except; if (const auto op_filename = exists_config()) { if (const auto op_node = load(*op_filename)) { return *op_node; } else { - throw exception::error("Could not load poac.yml"); + throw except::error(except::msg::could_not_load("poac.yml")); } } else { - throw exception::error( - "poac.yml does not exists.\n" - "Please execute `poac init` or `poac new $PROJNAME`."); + throw except::error( + except::msg::does_not_exist("poac.yml") + "\n" + + except::msg::please_exec("`poac init` or `poac new $PROJNAME`")); } } template @@ -212,26 +223,40 @@ namespace poac::io::file::yaml { return get_by_width_opt(load_config(), args...); } - YAML::Node load_config_by_dir(const boost::filesystem::path& base) { - namespace exception = core::exception; + std::optional + load_config_by_dir(const boost::filesystem::path& base) { + if (const auto op_filename = exists_config(base)) { + if (const auto op_node = load(*op_filename)) { + return op_node; + } + else { + return std::nullopt; + } + } + else { + return std::nullopt; + } + } + YAML::Node load_config_by_dir_with_throw(const boost::filesystem::path& base) { + namespace except = core::except; if (const auto op_filename = exists_config(base)) { if (const auto op_node = load(*op_filename)) { return *op_node; } else { - throw exception::error("Could not load poac.yml"); + throw except::error(except::msg::could_not_load("poac.yml")); } } else { - throw exception::error( - "poac.yml does not exists.\n" - "Please execute $ poac init or $ poac new $PROJNAME."); + throw except::error( + except::msg::does_not_exist("poac.yml") + "\n" + + except::msg::please_exec("`poac init` or `poac new $PROJNAME`")); } } std::string get_timestamp() { namespace fs = boost::filesystem; - namespace exception = core::exception; + namespace except = core::except; if (const auto op_filename = exists_config()) { boost::system::error_code error; @@ -239,9 +264,9 @@ namespace poac::io::file::yaml { return std::to_string(last_time); } else { - throw exception::error( - "poac.yml does not exists.\n" - "Please execute `poac init` or `poac new $PROJNAME`."); + throw except::error( + except::msg::does_not_exist("poac.yml") + "\n" + + except::msg::please_exec("`poac init` or `poac new $PROJNAME`")); } } } // end namespace diff --git a/include/poac/io/net.hpp b/include/poac/io/net.hpp new file mode 100644 index 000000000..eb00753ca --- /dev/null +++ b/include/poac/io/net.hpp @@ -0,0 +1,479 @@ +#ifndef POAC_IO_NET_HPP +#define POAC_IO_NET_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../core/except.hpp" +#include "./cli.hpp" +#include "../util/misc.hpp" +#include "../util/types.hpp" +#include "../util/pretty.hpp" + + +namespace poac::io::net { + namespace http = boost::beast::http; + namespace ssl = boost::asio::ssl; + using Headers = std::map, std::string>; + + template + http::request + create_request( + http::verb method, + std::string_view target, + std::string_view host=POAC_API_HOST, + const Headers& headers={}) + { + // Set up an HTTP request message, 10 -> HTTP/1.0, 11 -> HTTP/1.1 + http::request req{ method, std::string(target), 11 }; + req.set(http::field::host, host); + req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING); + for (const auto& [field, string_param] : headers) { + std::visit([&, s=string_param](auto f) { req.set(f, s); }, field); + } + return req; + } + + std::pair + parse_url(const std::string& url) { + // https://api.poac.pm/packages/deps -> api.poac.pm + const std::string host = util::misc::split(url, "://")[1]; + // https://api.poac.pm/packages/deps -> /packages/deps + const std::string target(url, url.find(host) + host.size()); + return { host, target }; + } + + + class multiPartForm { + public: + multiPartForm() + : boundary(boost::lexical_cast(boost::uuids::random_generator{}())) + , footer_(CRLF + "--" + boundary + "--" + CRLF) + {} + + std::string header() const noexcept { + return header_; + } + std::string footer() const noexcept { + return footer_; + } + + void set(const std::string& name, const std::string& value) { + form_param.emplace_back( + "--" + boundary + CRLF + content_disposition + + "name=\"" + name + "\"" + CRLF + CRLF + value); + gen_header(); // re-generate + } + void set(const std::string& name, const boost::filesystem::path& value, const std::map& h={}) { + file_param.emplace_back(name, value, h); + gen_header(); // re-generate + } + template + void set_req(const Request& req) { + std::stringstream ss; + ss << req; + form_param.insert(form_param.begin(), ss.str()); + gen_header(); // re-generate + } + + std::string content_type() const { + return "multipart/form-data; boundary=" + boundary; + } + std::size_t content_length() const { + namespace fs = boost::filesystem; + + std::size_t filesize = 0; + for (const auto& [name, filename, h] : file_param) { + (void)name; (void)h; + filesize += static_cast(fs::file_size(filename)); + } + return header_.size() + filesize + footer_.size(); + } + + struct fileInfo { + std::string path; + std::size_t size; + }; + std::vector + file() const { + namespace fs = boost::filesystem; + + std::vector file_info; + for (const auto& [name, filename, h] : file_param) { + (void)name; (void)h; + file_info.push_back({filename.string(), static_cast(fs::file_size(filename))}); + } + return file_info; + } + +// multiPartForm* body() { return this; } +// const multiPartForm* body() const { return this; } + multiPartForm& body() { return *this; } + const multiPartForm& body() const { return *this; } +// multiPartForm body() const { return *this; } + + private: + const std::string CRLF = "\r\n"; + std::string header_; + std::string boundary; + std::string footer_; + const std::string content_disposition = "Content-Disposition: form-data; "; + std::vector form_param; + std::vector>> file_param; + + void gen_header() { + std::string r; + if (form_param.size() > 0) { + r = form_param[0]; + if (form_param.size() != 1) { + for (auto itr = form_param.cbegin()+1; itr != form_param.cend(); ++itr) { + r += CRLF + (*itr); + } + } + } + for (const auto& [name, filename, h] : file_param) { + std::string h_ = + "--" + boundary + CRLF + content_disposition + + "name=\"" + name + "\"; filename=\"" + filename.filename().string() + "\""; + if (!h.empty()) { + for (const auto& [field, content] : h) { + h_ += CRLF; + h_ += std::string(http::to_string(field)) + ": " + content; + } + } + r += CRLF + h_; + } + r += CRLF + CRLF; + header_ = r; + } + }; + + + // Only SSL usage + class requests { + public: + explicit requests(std::string_view host_=POAC_API_HOST) : host(host_) { + // The io_context is required for all I/O + ioc = std::make_unique(); + // The SSL context is required, and holds certificates + ctx = std::make_unique(ssl::context::sslv23); + // These objects perform our I/O + resolver = std::make_unique(*ioc); + stream = std::make_unique>(*ioc, *ctx); + } + + template + typename ResponseBody::value_type + do_(Request&& req, Ofstream&& ofs) const + { + ssl_prepare(); + write_request(req); + return read_response(std::forward(req), std::forward(ofs)); + } + + template , std::ofstream>, + http::vector_body, http::string_body>> + typename ResponseBody::value_type + get(std::string_view target, const Headers& headers={}, Ofstream&& ofs=nullptr) const + { + const auto req = create_request(http::verb::get, target, host, headers); + cli::debugln(req); + return do_(std::move(req), std::forward(ofs)); + } + + template , multiPartForm>, + http::empty_body, http::string_body>, + typename ResponseBody=std::conditional_t< + std::is_same_v, std::ofstream>, + http::vector_body, http::string_body>> + typename ResponseBody::value_type + post(std::string_view target, BodyType&& body, const Headers& headers={}, Ofstream&& ofs=nullptr) const + { + auto req = create_request(http::verb::post, target, host, headers); + if constexpr (!std::is_same_v, multiPartForm>) { + req.set(http::field::content_type, "application/json"); + body.erase(std::remove(body.begin(), body.end(), '\n'), body.end()); + req.body() = body; + req.prepare_payload(); + return do_( + std::forward(req), std::forward(ofs)); + } + else { + req.set(http::field::accept, "*/*"); + req.set(http::field::content_type, body.content_type()); + req.set(http::field::content_length, body.content_length()); + body.set_req(req); + return do_( + std::forward(body), std::forward(ofs)); + } + } + + private: + std::string_view port = "443"; + std::string_view host; + std::unique_ptr ioc; + std::unique_ptr ctx; + std::unique_ptr resolver; + std::unique_ptr> stream; + + template + void write_request(const Request& req) const + { + if constexpr (!std::is_same_v, multiPartForm>) { + simple_write(req); + } + else { + progress_write(req); + } + } + + template + void simple_write(const Request& req) const + { + cli::debugln("Write type: string"); + // Send the HTTP request to the remote host + http::write(*stream, req); + } + + template + void progress_write(const Request& req) const + { + cli::debugln("Write type: multipart/form-data"); + + // Send the HTTP request to the remote host + stream->write_some(boost::asio::buffer(req.header())); + // Read file and write to stream + // FIXME: 複数のファイル送信を想定していない. + // FIXME: -> 複数ファイルだと,req.headerをちょびちょびで送る必要がある. + for (const auto& file : req.file()) { + std::ifstream ifs(file.path, std::ios::in | std::ios::binary); + char buf[512]; + unsigned long cur_file_size = 0; + while (!ifs.eof()) { + ifs.read(buf, 512); + stream->write_some(boost::asio::buffer(buf, ifs.gcount())); + + // Print progress bar + std::cout << '\r' << cli::to_info("Uploading "); + cli::echo_byte_progress(file.size, cur_file_size += 512); + std::cout << " "; + } + std::cout << '\r' << cli::clr_line << cli::to_info("Uploaded.") << std::endl; + } + // Send footer to stream + stream->write_some(boost::asio::buffer(req.footer())); + cli::echo(cli::to_info("Waiting for server response...")); + } + + + template + typename ResponseBody::value_type + read_response(Request&& old_req, Ofstream&& ofs) const + { + // This buffer is used for reading and must be persisted + boost::beast::flat_buffer buffer; + // Declare a container to hold the response + http::response res; + // Receive the HTTP response + http::read(*stream, buffer, res); + // Handle HTTP status code + return handle_status( + std::forward(old_req), + std::move(res), + std::forward(ofs)); + } + + template + typename ResponseBody::value_type + handle_status(Request&& old_req, Response&& res, Ofstream&& ofs) const + { + close_stream(); + switch (res.base().result_int() / 100) { + case 2: + return parse_response( + std::forward(res), + std::forward(ofs)); + case 3: + return redirect( + std::forward(old_req), + std::forward(res), + std::forward(ofs)); + default: // 500 + // TODO: handle error + return parse_response( + std::forward(res), + std::forward(ofs)); + } + } + + template + typename ResponseBody::value_type + parse_response(Response&& res, Ofstream&& ofs) const + { + if constexpr (!std::is_same_v, std::ofstream>) { + cli::debugln("Read type: string"); + return res.body(); + } + else { + cli::debugln("Read type: file with progress"); + const typename ResponseBody::value_type response_body = res.body(); + const auto content_length = response_body.size(); + if (content_length < 100'000 /* 100KB */) { + for (const auto& r : response_body) { ofs << r; } + } + else { + int acc = 0; + for (const auto& r : response_body) { + ofs << r; + if (++acc % 100 == 0) { + // To be accurate, not downloading. + std::cout << '\r' << cli::to_info("Downloading "); + cli::echo_byte_progress(content_length, acc); + std::cout << " "; + } + } + } + return {}; + } + } + + template + typename ResponseBody::value_type + redirect(Request&& old_req, Response&& res, Ofstream&& ofs) const + { + const std::string new_location = res.base()["Location"].to_string(); + const auto [new_host, new_target] = parse_url(new_location); + cli::debugln("Redirect to ", new_location, '\n'); + + // FIXME: header information is gone. + const requests req(new_host); + if constexpr (method == http::verb::get) { + return req.get(new_target, {}, std::forward(ofs)); + } + else if (method == http::verb::post) { + return req.post(new_target, old_req.body(), {}, std::forward(ofs)); + } + else { // verb error + return {}; + } + } + + void close_stream() const + { + // Gracefully close the stream + boost::system::error_code ec; + stream->shutdown(ec); + if (ec == boost::asio::error::eof) { + // Rationale: https://stackoverflow.com/q/25587403 + ec.assign(0, ec.category()); + } + } + + // Prepare ssl connection + void ssl_prepare() const + { + ssl_set_tlsext(); + lookup(); + ssl_handshake(); + } + void ssl_set_tlsext() const + { + // Set SNI Hostname (many hosts need this to handshake successfully) + if(!SSL_set_tlsext_host_name(stream->native_handle(), std::string(host).c_str())) + { + boost::system::error_code ec{ + static_cast(::ERR_get_error()), boost::asio::error::get_ssl_category() + }; + cli::debugln(ec.message()); + throw boost::system::system_error{ ec }; + } + } + void lookup() const + { + // Look up the domain name + const auto results = resolver->resolve(host, port); + // Make the connection on the IP address we get from a lookup + boost::asio::connect(stream->next_layer(), results.begin(), results.end()); + } + void ssl_handshake() const + { + // Perform the SSL handshake + stream->handshake(ssl::stream_base::client); + } + }; + + + namespace api { + std::optional> + versions(const std::string& name) { + using namespace std::string_literals; + boost::property_tree::ptree pt; + { + std::stringstream ss; + { + requests req{}; + const auto res = req.get(POAC_VERSIONS_API + "/"s + name); // TODO: /演算子が欲しい + ss << res.data(); + } + cli::debugln(name, ": ", ss.str()); + if (ss.str() == "null") { + return std::nullopt; + } + boost::property_tree::json_parser::read_json(ss, pt); + } + return util::types::ptree_to_vector(pt); + } + + std::optional + deps(const std::string& name, const std::string& version) { +// io::cli::echo("[deps] ", name, ": ", version); + + using namespace std::string_literals; + std::stringstream ss; + { + requests req{}; + const auto res = req.get(POAC_DEPS_API + "/"s + name + "/" + version); + ss << res.data(); + } + if (ss.str() == "null") { + return std::nullopt; + } + else { + boost::property_tree::ptree pt; + boost::property_tree::json_parser::read_json(ss, pt); + return pt; + } + } + } +} // end namespace +#endif // !POAC_IO_NET_HPP diff --git a/include/poac/io/network.hpp b/include/poac/io/network.hpp deleted file mode 100644 index 4cddb3210..000000000 --- a/include/poac/io/network.hpp +++ /dev/null @@ -1,270 +0,0 @@ -#ifndef POAC_IO_NETWORK_HPP -#define POAC_IO_NETWORK_HPP - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../core/exception.hpp" -#include "./cli.hpp" -#include "../util/types.hpp" - - -namespace poac::io::network { - namespace ssl = boost::asio::ssl; - namespace http = boost::beast::http; - - using Headers = std::map, std::string>; - - template - typename ResponseBody::value_type - request(const http::request& req, std::string_view host) - { - // The io_context is required for all I/O - boost::asio::io_context ioc; - // The SSL context is required, and holds certificates - ssl::context ctx{ ssl::context::sslv23 }; - // These objects perform our I/O - boost::asio::ip::tcp::resolver resolver{ ioc }; - ssl::stream stream{ ioc, ctx }; - - // Set SNI Hostname (many hosts need this to handshake successfully) - if(!SSL_set_tlsext_host_name(stream.native_handle(), std::string(host).c_str())) - { - boost::system::error_code ec{ - static_cast(::ERR_get_error()), boost::asio::error::get_ssl_category() - }; - throw boost::system::system_error{ ec }; - } - // Look up the domain name - const auto port = "443"; - const auto results = resolver.resolve(host, port); - // Make the connection on the IP address we get from a lookup - boost::asio::connect(stream.next_layer(), results.begin(), results.end()); - // Perform the SSL handshake - stream.handshake(ssl::stream_base::client); - - // Send the HTTP request to the remote host - http::write(stream, req); - - // This buffer is used for reading and must be persisted - boost::beast::flat_buffer buffer; - // Declare a container to hold the response - http::response res; - // Receive the HTTP response - http::read(stream, buffer, res); - - // Gracefully close the stream - boost::system::error_code ec; - stream.shutdown(ec); - if (ec == boost::asio::error::eof) { - // Rationale: https://stackoverflow.com/q/25587403 - ec.assign(0, ec.category()); - } - return res.body(); - } - - - template - http::request - create_request( - http::verb method, - std::string_view target, - std::string_view host=POAC_API_HOST, - const Headers& headers={}) - { - // Set up an HTTP request message, 10 -> HTTP/1.0, 11 -> HTTP/1.1 - http::request req{ method, std::string(target), 11 }; - req.set(http::field::host, host); - req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING); - for (const auto& [field, string_param] : headers) { - std::visit([&, s=string_param](auto f) { req.set(f, s); }, field); - } - return req; - } - - std::string get( - std::string_view target, - std::string_view host=POAC_API_HOST, - const Headers& headers={}) - { - const auto req = create_request(http::verb::get, target, host, headers); - const auto res = request(req, host); - return res.data(); - } - void get( - std::string_view target, - const boost::filesystem::path& out, - std::string_view host=POAC_API_HOST, - const Headers& headers={}) - { - const auto req = create_request(http::verb::get, target, host, headers); - const auto res = request>(req, host); - std::ofstream output_file(out.string(), std::ios::out | std::ios::binary); - for (const auto& r : res) { - output_file << r; - } - } - - std::string post( - std::string_view target, - std::string body, - std::string_view host=POAC_API_HOST, - const Headers& headers={}) - { - auto req = create_request(http::verb::post, target, host, headers); - req.set(http::field::content_type, "application/json"); - body.erase(std::remove(body.begin(), body.end(), '\n'), body.end()); - req.body() = body; - req.prepare_payload(); - - const auto res = request(req, host); - return res.data(); - } - - - std::string post_file( - const std::string& token, - const boost::filesystem::path& file_path, - std::string_view target=POAC_UPLOAD_API, - std::string_view host=POAC_UPLOAD_API_HOST) - { - namespace fs = boost::filesystem; - - const std::string CRLF = "\r\n"; - const std::string boundary = boost::lexical_cast(boost::uuids::random_generator{}()); - const std::string boundary_footer = CRLF + "--" + boundary + "--" + CRLF; // footer - const std::string content_disposition = "Content-Disposition: form-data; "; - - std::stringstream token_stream; - token_stream << "--" << boundary << CRLF - << content_disposition << "name=\"token\"" << CRLF << CRLF - << token; - - std::stringstream file_stream; - file_stream << CRLF << "--" << boundary << CRLF - << content_disposition << "name=\"file\"; filename=\"" << file_path.filename().string() << "\"" << CRLF - << "Content-Type: application/x-gzip" << CRLF - << "Content-Transfer-Encoding: binary" << CRLF << CRLF; - - auto req = create_request(http::verb::post, target, host); - req.set(http::field::accept, "*/*"); - req.set(http::field::content_type, "multipart/form-data; boundary=" + boundary); - const auto content_length = token_stream.str().size() + file_stream.str().size() + fs::file_size(file_path) + boundary_footer.size(); - req.set(http::field::content_length, content_length); - - - // The io_context is required for all I/O - boost::asio::io_context ioc; - // The SSL context is required, and holds certificates - ssl::context ctx{ ssl::context::sslv23 }; - // These objects perform our I/O - boost::asio::ip::tcp::resolver resolver{ ioc }; - ssl::stream stream{ ioc, ctx }; - - // Set SNI Hostname (many hosts need this to handshake successfully) - if(!SSL_set_tlsext_host_name(stream.native_handle(), std::string(host).c_str())) - { - boost::system::error_code ec{ - static_cast(::ERR_get_error()), boost::asio::error::get_ssl_category() - }; - throw boost::system::system_error{ ec }; - } - // Look up the domain name - const auto port = "443"; - const auto results = resolver.resolve(host, port); - // Make the connection on the IP address we get from a lookup - boost::asio::connect(stream.next_layer(), results.begin(), results.end()); - // Perform the SSL handshake - stream.handshake(ssl::stream_base::client); - - // Convert request to string - std::stringstream reqss; - reqss << req; - // Send the HTTP request to the remote host - stream.write_some(boost::asio::buffer(reqss.str())); - stream.write_some(boost::asio::buffer(token_stream.str())); - stream.write_some(boost::asio::buffer(file_stream.str())); - // Read file and write to stream - { - std::ifstream file(file_path.string(), std::ios::in | std::ios::binary); - char buf[512]; - while (!file.eof()) { - file.read(buf, 512); - stream.write_some(boost::asio::buffer(buf, file.gcount())); - } - } - // Write footer to stream - stream.write_some(boost::asio::buffer(boundary_footer)); - - // This buffer is used for reading and must be persisted - boost::beast::flat_buffer buffer; - // Declare a container to hold the response - http::response res; - // Receive the HTTP response - http::read(stream, buffer, res); - - // Gracefully close the stream - boost::system::error_code ec; - stream.shutdown(ec); - if (ec == boost::asio::error::eof) { - // Rationale: https://stackoverflow.com/q/25587403 - ec.assign(0, ec.category()); - } - - return res.body().data(); - } - - - namespace api { - std::optional> - versions(const std::string& name) { - boost::property_tree::ptree pt; - { - std::stringstream ss; - ss << io::network::get(POAC_PACKAGES_API + name + "/versions"); - if (ss.str() == "null") { - return std::nullopt; - } - boost::property_tree::json_parser::read_json(ss, pt); - } - return util::types::ptree_to_vector(pt); - } - - std::optional - deps(const std::string& name, const std::string& version) { - std::stringstream ss; - ss << io::network::get(POAC_PACKAGES_API + name + "/" + version + "/deps"); - if (ss.str() == "null") { - return std::nullopt; - } - else { - boost::property_tree::ptree pt; - boost::property_tree::json_parser::read_json(ss, pt); - return pt; - } - } - } -} // end namespace -#endif // !POAC_IO_NETWORK_HPP diff --git a/include/poac/option/help.hpp b/include/poac/option/help.hpp index 42fdbb787..3e77032b2 100644 --- a/include/poac/option/help.hpp +++ b/include/poac/option/help.hpp @@ -7,22 +7,20 @@ #include #include -#include "../core/exception.hpp" -#include "../core/inference.hpp" +#include "../core/except.hpp" +#include "../core/infer.hpp" #include "../io/cli.hpp" // Forward-declaration namespace poac::core::infer { - enum class op_type_e : int; - - template >> + template auto _apply(S&& func, const OpTypeE& cmd, VS&& arg); - template >> - std::string apply(S&& func, const S& cmd, VS&& arg); + template + std::string apply(S&& func, S&& cmd, VS&& arg); - extern const std::unordered_map subcmd_map; - extern const std::unordered_map option_map; + extern const std::unordered_map subcmd_map; + extern const std::unordered_map option_map; } // TODO: help文を,コンパイル時に一つの文字列として変換する. @@ -31,20 +29,24 @@ namespace poac::core::infer { // TODO: さらに,versionを,poacの部分に埋め込めば(もう一段階抽象化後),optionを管理する必要がなくなる. namespace poac::option { namespace _help { - void echo_option(const std::string& arg) { - namespace exception = core::exception; + template + void echo_option(S&& arg) { + namespace except = core::except; + using namespace std::string_literals; + try { std::cout << "Usage: poac " << arg << " " - << core::infer::apply(std::string("options"), arg, std::vector()) + << core::infer::apply("options"s, std::forward(arg), std::vector()) << std::endl; } - catch (const exception::invalid_first_arg& e) { - throw exception::invalid_second_arg("--help"); + catch (const except::invalid_first_arg& e) { + throw except::invalid_second_arg("--help"); } } template void show(const T& key, const U& value) { + using namespace std::string_literals; // Eliminate -h and -v // It assumes two characters because the regular expression is slow. if (key.size() != 2) { @@ -53,7 +55,7 @@ namespace poac::option { << io::cli::reset; std::cout << io::cli::yellow - << _apply(std::string("summary"), value, std::vector()) + << core::infer::_apply("summary"s, value, std::vector()) << io::cli::reset << std::endl; } @@ -66,49 +68,51 @@ namespace poac::option { << "Available subcommands:" << io::cli::reset << std::endl; - for (const auto&[name, value] : core::infer::subcmd_map) + for (const auto& [name, value] : core::infer::subcmd_map) { show(name, value); + } std::cout << io::cli::bold << "Available options:" << io::cli::reset << std::endl; - for (const auto&[name, value] : core::infer::option_map) + for (const auto& [name, value] : core::infer::option_map) { show(name, value); + } std::cout << std::endl << "See `poac --help` for information on a specific command.\n" "For full documentation, see: https://github.com/poacpm/poac#readme\n"; } - template>> + template int _main(VS&& vs) { - namespace exception = core::exception; + namespace except = core::except; if (vs.size() == 0) { exec_help(); return EXIT_SUCCESS; } else if (vs.size() == 1) { - echo_option(vs[0]); + echo_option(std::move(vs[0])); return EXIT_SUCCESS; } else { - throw exception::invalid_second_arg("--help"); + throw except::invalid_second_arg("--help"); } // show only --help's option } } struct help { - static const std::string summary() { + static std::string summary() { return "Display help for a command"; } - static const std::string options() { + static std::string options() { return ""; } - template>> + template int operator()(VS&& argv) { - return _help::_main(std::move(argv)); + return _help::_main(std::forward(argv)); } }; } // end namespace diff --git a/include/poac/option/version.hpp b/include/poac/option/version.hpp index ec8751c69..9b097e4ae 100644 --- a/include/poac/option/version.hpp +++ b/include/poac/option/version.hpp @@ -7,17 +7,17 @@ namespace poac::option { struct version { - static const std::string summary() { + static std::string summary() { return "Show the current poac version"; } - static const std::string options() { + static std::string options() { return ""; } - template>> + template int operator()([[maybe_unused]] VS&& argv) { std::cout << POAC_VERSION << std::endl; return EXIT_SUCCESS; } }; } // end namespace -#endif // !POAC_OPTION_VERSION_HPP \ No newline at end of file +#endif // !POAC_OPTION_VERSION_HPP diff --git a/include/poac/subcmd/build.hpp b/include/poac/subcmd/build.hpp index 257bb8b82..8c202bee4 100644 --- a/include/poac/subcmd/build.hpp +++ b/include/poac/subcmd/build.hpp @@ -10,17 +10,18 @@ #include #include -#include "../core/exception.hpp" -#include "../core/lock.hpp" +#include "../core/except.hpp" +#include "../core/stroite/utils/absorb.hpp" +#include "../core/stroite/utils/detect.hpp" +#include "../core/deper/lock.hpp" #include "../io/file.hpp" #include "../io/cli.hpp" -#include "../util/stroite.hpp" +#include "../core/stroite.hpp" #include "../core/naming.hpp" #include "../util/argparse.hpp" -// TODO: --release, --no-cache, --example, --backend cmake -// TODO: --check-std(標準では標準ライブラリをチェックしないため,標準ライブラリを書き換えてもリビルドしない) +// TODO: --release, --no-cache (build systemにpoacを使用する時のみ), --example namespace poac::subcmd { namespace _build { std::optional @@ -42,57 +43,62 @@ namespace poac::subcmd { } } - auto handle_compile_message(const std::optional& output) { + std::optional + handle_compile_message(const std::optional& output) { return handle_message("Compiled", output); } - auto handle_generate_message(const std::optional& output) { + std::optional + handle_generate_message(const std::optional& output) { return handle_message("Generated", output); } - auto handle_link( - stroite::builder& bs, + std::optional + handle_link( + core::stroite::core::builder& bs, const std::vector& obj_files_path, - const bool verbose) + const std::vector& library_path) // depsのlibや,自分自身のlib { - bs.configure_link(obj_files_path, verbose); - return handle_compile_message(bs._link()); + bs.configure_link(obj_files_path); + for (const auto& l : library_path) { + bs.link_conf.library_path.push_back(l); + } + return handle_compile_message(bs.link()); } std::optional handle_compile( - stroite::builder& bs, - const bool verbose) + core::stroite::core::builder& bs, + const std::vector& library_path) { - if (const auto obj_files_path = bs._compile()) { - return handle_link(bs, *obj_files_path, verbose); + if (const auto obj_files_path = bs.compile()) { + return handle_link(bs, *obj_files_path, library_path); } else { // Compile failure return std::nullopt; } } - auto handle_generate_static_lib( - stroite::builder& bs, - const std::vector& obj_files_path, - const bool verbose) + std::optional + handle_generate_static_lib( + core::stroite::core::builder& bs, + const std::vector& obj_files_path) { - bs.configure_static_lib(obj_files_path, verbose); - return handle_generate_message(bs._gen_static_lib()); + bs.configure_static_lib(obj_files_path); + return handle_generate_message(bs.gen_static_lib()); } - auto handle_generate_dynamic_lib( - stroite::builder& bs, - const std::vector& obj_files_path, - const bool verbose) + std::optional + handle_generate_dynamic_lib( + core::stroite::core::builder& bs, + const std::vector& obj_files_path) { - bs.configure_dynamic_lib(obj_files_path, verbose); - return handle_generate_message(bs._gen_dynamic_lib()); + bs.configure_dynamic_lib(obj_files_path); + return handle_generate_message(bs.gen_dynamic_lib()); } void handle_generate_lib( - stroite::builder& bs, - const std::vector& obj_files_path, - const bool verbose) + core::stroite::core::builder& bs, + const std::vector& obj_files_path) { - handle_generate_static_lib(bs, obj_files_path, verbose); - handle_generate_dynamic_lib(bs, obj_files_path, verbose); + handle_generate_static_lib(bs, obj_files_path); + handle_generate_dynamic_lib(bs, obj_files_path); } void handle_exist_message( @@ -113,13 +119,7 @@ namespace poac::subcmd { handle_exist_message(lib_path, ".a", "Static link library"); } void is_exist_dynamic_lib(const std::string& lib_path) { -#ifdef __APPLE__ - const std::string extension = ".dylib"; -#elif defined(_WIN32) - const std::string extension = ".dll"; -#else - const std::string extension = ".so"; -#endif + const std::string extension = core::stroite::utils::absorb::dynamic_lib_extension; handle_exist_message(lib_path, extension, "Dynamic link library"); } std::string is_exist_lib(const std::string& project_name) { @@ -131,39 +131,42 @@ namespace poac::subcmd { } - std::optional - build_bin(stroite::builder& bs, const bool verbose) + std::optional // TODO: このあたり,builder.hppへ移動できる -> bs.build()のみで,binのビルドとかlibとかを意識せずに使いたい + build_bin( + core::stroite::core::builder& bs, + const std::vector& library_path) { - bs.configure_compile(true, verbose); + bs.configure_compile(true); // Since the obj file already exists and has not been changed as a result // of verification of the hash file, return only the list of existing obj_files // and do not compile. // There is no necessity of linking that there is no change completely. if (bs.compile_conf.source_files.empty()) { // No need for compile and link -#ifdef _WIN32 - const std::string extension = ".exe"; -#else - const std::string extension = ""; -#endif + const std::string extension = core::stroite::utils::absorb::binary_extension; const std::string bin_path = (io::file::path::current_build_bin_dir / bs.project_name).string(); handle_exist_message(bin_path, extension, "Binary"); return bin_path; } else { - return handle_compile(bs, verbose); + return handle_compile(bs, library_path); } } std::optional - build_link_libs(stroite::builder& bs, const bool verbose) + build_link_libs( + core::stroite::core::builder& bs, + std::vector& deps_obj_files_path) { - bs.configure_compile(false, verbose); + bs.configure_compile(false); if (bs.compile_conf.source_files.empty()) { // No need for compile and link return is_exist_lib(bs.project_name); } - if (const auto obj_files_path = bs._compile()) { - handle_generate_lib(bs, *obj_files_path, verbose); + if (auto obj_files_path = bs.compile()) { + for (const auto o : *obj_files_path) { + deps_obj_files_path.push_back(o); + } + handle_generate_lib(bs, deps_obj_files_path); return std::nullopt; } else { // Compile failure @@ -172,85 +175,133 @@ namespace poac::subcmd { } - bool compile_deps( + std::optional> + compile_deps( const YAML::Node& node, const std::string& name, const boost::filesystem::path& deps_path, const bool verbose) { - namespace exception = core::exception; + namespace except = core::except; + namespace stroite = core::stroite; - // depsのビルド時はbinaryは不要.必要になる可能性があるのはlibraryのみ - if (io::file::yaml::get(node, "build", "lib")) { - stroite::builder bs(deps_path); + if (const auto system = stroite::utils::detect::build_system(node)) { + if (*system == "poac") { + // depsのビルド時はbinaryは不要.必要になる可能性があるのはlibraryのみ + if (io::file::yaml::get(node, "build", "lib")) { + stroite::core::builder bs(verbose, deps_path); - bs.configure_compile(false, verbose); - if (!bs.compile_conf.source_files.empty()) { - std::cout << io::cli::to_status(name) << std::endl; + bs.configure_compile(false); + if (!bs.compile_conf.source_files.empty()) { + io::cli::echo(io::cli::to_status(name)); - if (const auto obj_files_path = bs._compile()) { - handle_generate_lib(bs, *obj_files_path, verbose); - } - else { // Compile failure - throw exception::error("\nCompile error."); + if (const auto obj_files_path = bs.compile()) { + handle_generate_lib(bs, *obj_files_path); + io::cli::echo(); + return *obj_files_path; + } + else { // Compile failure + throw except::error("\nCompile error."); + } + } } - std::cout << std::endl; } - - return true; + else if (*system == "cmake") { + stroite::chain::cmake bs(deps_path); + io::cli::echo(io::cli::to_status(name)); + bs.build(); + io::cli::echo(); + return {}; + } } - return false; + return std::nullopt; // 結局compileしていない } - void build_deps(const YAML::Node& node, const bool verbose) { + // TODO: depends.hppで処理させる? -> であれば,ビルド自体はすべきでない? + std::optional> + build_deps(const YAML::Node& node, std::vector& obj_files_path, const bool verbose) { namespace fs = boost::filesystem; - namespace exception = core::exception; - namespace lock = core::lock; + namespace except = core::except; + namespace stroite = core::stroite; + namespace lock = core::deper::lock; namespace naming = core::naming; namespace yaml = io::file::yaml; - if (!yaml::get(node, "deps")) { - return; // depsが存在しない - } - // TODO: ビルド順序 - if (const auto locked_deps = lock::load_ignore_timestamp()) { - for (const auto& [name, dep] : (*locked_deps).backtracked) { - const std::string current_package_name = naming::to_current(dep.source, name, dep.version); - const auto deps_path = fs::current_path() / "deps" / current_package_name; + std::vector library_path; + if (const auto deps_node = yaml::get>(node, "deps")) { + // TODO: ビルド順序 + if (const auto locked_deps = lock::load_ignore_timestamp()) { + for (const auto& [name, dep] : (*locked_deps).backtracked) { + const std::string current_package_name = naming::to_current(dep.source, name, dep.version); + const auto deps_path = fs::current_path() / "deps" / current_package_name; - if (fs::exists(deps_path)) { - // IF dep.source == "github" - // ./deps/pack/poac.yml は存在しないと見做す (TODO: poac projectなのにgithubをsourceとしている場合がある) - // 現状は,./poac.ymlから,buildキーを読み込む -> 無いなら header-onlyと見做す. + if (fs::exists(deps_path)) { + bool exist_build_key = true; + try { // 依存の依存は,poac.ymlに書かれていないため,buildキーは存在しない + (*deps_node).at(name); + } + catch(std::out_of_range&) { + exist_build_key = false; + } - // IF dep.source == "poac" - // プロジェクトルートの方に,buildキーがあるならそちらを - // -> 無いなら,提供者->deps_pathの方を選ぶ - // -> 無いなら,header-onlyと見做す. - if (!compile_deps(node, name, deps_path, verbose) && dep.source == "poac") { - const auto deps_config_node = yaml::load_config_by_dir(deps_path); - compile_deps(deps_config_node, name, deps_path, verbose); + if (exist_build_key) { + if (const auto system = stroite::utils::detect::build_system((*deps_node).at(name))) { + if (const auto obj_files_path_opt = compile_deps((*deps_node).at(name), name, deps_path, verbose)) { + for (const auto& o : *obj_files_path_opt) { + obj_files_path.push_back(o); + } + library_path.push_back((io::file::path::current_build_lib_dir / current_package_name).string() + ".a"); // TODO: 可変にしたい / dylibかa + } + } + else if (const auto deps_config_node = yaml::load_config_by_dir(deps_path)) { + if (const auto obj_files_path_opt = compile_deps(*deps_config_node, name, deps_path, verbose)) { + for (const auto& o : *obj_files_path_opt) { + obj_files_path.push_back(o); + } + library_path.push_back((io::file::path::current_build_lib_dir / current_package_name).string() + ".a"); // TODO: 可変にしたい + } + } + // header-only + } + else { + if (const auto deps_config_node = yaml::load_config_by_dir(deps_path)) { + if (const auto obj_files_path_opt = compile_deps(*deps_config_node, name, deps_path, verbose)) { + for (const auto& o : *obj_files_path_opt) { + obj_files_path.push_back(o); + } + library_path.push_back((io::file::path::current_build_lib_dir / current_package_name).string() + ".a"); // TODO: 可変にしたい + } + } + // header-only + } + } + else { + throw except::error( + name + " is not installed.\n" + "Please build after running `poac install`"); } - } - else { - throw exception::error( - name + " is not installed.\n" - "Please build after running `poac install`"); } } + else { + throw except::error( + "Could not load poac.lock.\n" + "Please build after running `poac install`"); + } + } + if (library_path.empty()) { + return std::nullopt; } else { - throw exception::error( - "Could not load poac.lock.\n" - "Please build after running `poac install`"); + return library_path; } } - template>> + template int _main(VS&& argv) { namespace fs = boost::filesystem; - namespace exception = core::exception; + namespace except = core::except; + namespace stroite = core::stroite; namespace naming = core::naming; namespace yaml = io::file::yaml; @@ -258,49 +309,76 @@ namespace poac::subcmd { const bool verbose = util::argparse::use(argv, "-v", "--verbose"); const auto project_name = yaml::get_with_throw(node, "name"); - build_deps(node, verbose); - stroite::builder bs; - std::cout << io::cli::to_status(project_name) << std::endl; - if (yaml::get(node, "build", "lib")) { - if (!build_link_libs(bs, verbose)) { - // compile or gen error - } - } - if (yaml::get(node, "build", "bin")) { // TODO: もし上でlibをビルドしたのなら,それを利用してバイナリをビルドする - // TODO: ディレクトリで指定できるように - if (!build_bin(bs, verbose)) { - // compile or link error + if (const auto system = stroite::utils::detect::build_system(node)) { + std::vector deps_obj_files_path; + const auto built_deps = build_deps(node, deps_obj_files_path, verbose); + const bool is_built_deps = static_cast(built_deps); + + if (*system == "poac") { + stroite::core::builder bs(verbose); + + if (is_built_deps) { + io::cli::echo(io::cli::to_status(project_name)); + } - // 一度コンパイルに成功した後にpoac runを実行し,コンパイルに失敗しても実行されるエラーの回避 - const auto binary_name = io::file::path::current_build_bin_dir / project_name; - const fs::path executable_path = fs::relative(binary_name); - boost::system::error_code error; - fs::remove(executable_path, error); +// bool built_lib = false; + if (yaml::get(node, "build", "lib")) { +// built_lib = true; + if (!build_link_libs(bs, deps_obj_files_path)) { + // compile or gen error + return EXIT_FAILURE; + } + } + if (yaml::get(node, "build", "bin")) { // TODO: もし上でlibをビルドしたのなら,それを利用してバイナリをビルドする -> まだ -> cpp_shell_cmdでテスト + // TODO: ディレクトリで指定できるように + if (!build_bin(bs, *built_deps)) { + // 一度コンパイルに成功した後にpoac runを実行し,コンパイルに失敗しても実行されるエラーの回避 + const auto binary_name = io::file::path::current_build_bin_dir / project_name; + const fs::path executable_path = fs::relative(binary_name); + boost::system::error_code error; + fs::remove(executable_path, error); + + // compile or link error + return EXIT_FAILURE; + } + } + } + else if (*system == "cmake") { + stroite::chain::cmake bs; + if (is_built_deps) { + io::cli::echo(io::cli::to_status(project_name)); + } + bs.build(); // only build + io::cli::echo(io::cli::to_green("Compiled: "), project_name); } } - + else { // error + throw except::error( + "Required key `build` does not exist in poac.yml.\n" + "Please refer to https://doc.poac.pm"); + } return EXIT_SUCCESS; } void check_arguments(const std::vector& argv) { - namespace exception = core::exception; + namespace except = core::except; if (argv.size() > 1) { - throw exception::invalid_second_arg("build"); + throw except::invalid_second_arg("build"); } } } struct build { - static const std::string summary() { + static std::string summary() { return "Compile all sources that depend on this project"; } - static const std::string options() { + static std::string options() { return "[-v | --verbose]"; } - template>> + template int operator()(VS&& argv) { _build::check_arguments(argv); - return _build::_main(std::move(argv)); + return _build::_main(std::forward(argv)); } }; } // end namespace diff --git a/include/poac/subcmd/cache.hpp b/include/poac/subcmd/cache.hpp index ea830b58c..af61ba4bf 100644 --- a/include/poac/subcmd/cache.hpp +++ b/include/poac/subcmd/cache.hpp @@ -9,7 +9,7 @@ #include #include -#include "../core/exception.hpp" +#include "../core/except.hpp" #include "../io/file.hpp" #include "../io/cli.hpp" #include "../util/argparse.hpp" @@ -64,9 +64,9 @@ namespace poac::subcmd { std::cout << io::file::path::poac_cache_dir.string() << std::endl; } - template>> + template int _main(VS&& argv) { - namespace exception = core::exception; + namespace except = core::except; if (argv[0] == "root" && argv.size() == 1) { root(); @@ -78,29 +78,29 @@ namespace poac::subcmd { clean(std::vector(argv.begin() + 1, argv.begin() + argv.size())); } else { - throw exception::invalid_second_arg("cache"); + throw except::invalid_second_arg("cache"); } return EXIT_SUCCESS; } void check_arguments(const std::vector &argv) { - namespace exception = core::exception; - if (argv.empty()) throw exception::invalid_second_arg("cache"); + namespace except = core::except; + if (argv.empty()) throw except::invalid_second_arg("cache"); } } struct cache { - static const std::string summary() { + static std::string summary() { return "Manipulate cache files"; } - static const std::string options() { + static std::string options() { return ""; } - template >> + template int operator()(VS&& argv) { _cache::check_arguments(argv); - return _cache::_main(std::move(argv)); + return _cache::_main(std::forward(argv)); } }; } // end namespace diff --git a/include/poac/subcmd/cleanup.hpp b/include/poac/subcmd/cleanup.hpp index 827566291..3883c8025 100644 --- a/include/poac/subcmd/cleanup.hpp +++ b/include/poac/subcmd/cleanup.hpp @@ -10,21 +10,21 @@ #include "./install.hpp" #include "./uninstall.hpp" -#include "../core/exception.hpp" -#include "../core/resolver.hpp" +#include "../core/except.hpp" #include "../core/naming.hpp" -#include "../core/lock.hpp" +#include "../core/deper/resolver.hpp" +#include "../core/deper/lock.hpp" #include "../io/file/yaml.hpp" #include "../io/cli.hpp" namespace poac::subcmd { namespace _cleanup { - template>> + template int _main([[maybe_unused]] VS&& argv) { namespace yaml = io::file::yaml; - namespace resolver = core::resolver; - namespace lock = core::lock; + namespace resolver = core::deper::resolver; + namespace lock = core::deper::lock; namespace naming = core::naming; namespace fs = boost::filesystem; namespace cli = io::cli; @@ -66,24 +66,24 @@ namespace poac::subcmd { } void check_arguments(const std::vector& argv) { - namespace exception = core::exception; + namespace except = core::except; if (!argv.empty()) { - throw exception::invalid_second_arg("cleanup"); + throw except::invalid_second_arg("cleanup"); } } } struct cleanup { - static const std::string summary() { + static std::string summary() { return "Delete unnecessary things"; } - static const std::string options() { + static std::string options() { return ""; } - template>> + template int operator()(VS&& argv) { _cleanup::check_arguments(argv); - return _cleanup::_main(std::move(argv)); + return _cleanup::_main(std::forward(argv)); } }; } // end namespace diff --git a/include/poac/subcmd/graph.hpp b/include/poac/subcmd/graph.hpp index f04b59d5d..db8b72b80 100644 --- a/include/poac/subcmd/graph.hpp +++ b/include/poac/subcmd/graph.hpp @@ -17,9 +17,9 @@ #include #include -#include "../core/exception.hpp" -#include "../core/lock.hpp" -#include "../core/resolver.hpp" +#include "../core/except.hpp" +#include "../core/deper/lock.hpp" +#include "../core/deper/resolver.hpp" #include "../io/file/yaml.hpp" #include "../io/cli.hpp" #include "../util/argparse.hpp" @@ -42,10 +42,10 @@ namespace poac::subcmd { using Graph = boost::adjacency_list; - core::resolver::Resolved create_resolved_deps() { - namespace lock = core::lock; - namespace resolver = core::resolver; - namespace exception = core::exception; + core::deper::resolver::Resolved create_resolved_deps() { + namespace lock = core::deper::lock; + namespace resolver = core::deper::resolver; + namespace except = core::except; namespace yaml = io::file::yaml; // FIXME: uninstall.hppに同じのがある @@ -55,7 +55,7 @@ namespace poac::subcmd { deps_node = *deps_map; } else { - throw exception::error("Could not read deps in poac.yml"); + throw except::error(except::msg::could_not_read("deps in poac.yml")); } // create resolved deps @@ -103,10 +103,10 @@ namespace poac::subcmd { return { g, names }; } - template>> + template int _main(VS&& argv) { namespace fs = boost::filesystem; - namespace exception = core::exception; + namespace except = core::except; if (const auto output_op = util::argparse::use_get(argv, "-o", "--output")) { fs::path output = *output_op; @@ -124,9 +124,8 @@ namespace poac::subcmd { io::cli::echo(io::cli::status_done()); } else { - throw exception::error( - "To output with .png you need graphviz.\n" - "You need to install the graphviz.\n" + throw except::error( + "To output with .png you need to install the graphviz.\n" "Or please consider outputting in .dot format."); } } @@ -137,7 +136,7 @@ namespace poac::subcmd { io::cli::echo(io::cli::status_done()); } else { - throw exception::error( + throw except::error( "The extension of the output file must be .dot or .png."); } } @@ -155,11 +154,11 @@ namespace poac::subcmd { } struct graph { - static const std::string summary() { return "Create a dependency graph"; } - static const std::string options() { return "[-o | --output]"; } - template >> + static std::string summary() { return "Create a dependency graph"; } + static std::string options() { return "[-o | --output]"; } + template int operator()(VS&& argv) { - return _graph::_main(std::move(argv)); + return _graph::_main(std::forward(argv)); } }; } // end namespace diff --git a/include/poac/subcmd/init.hpp b/include/poac/subcmd/init.hpp index 48d8d38c3..88318d26c 100644 --- a/include/poac/subcmd/init.hpp +++ b/include/poac/subcmd/init.hpp @@ -9,29 +9,24 @@ #include #include +#include "./new.hpp" #include "../io/cli.hpp" #include "../io/file/yaml.hpp" -#include "../core/exception.hpp" -#include "../util/ftemplate.hpp" +#include "../core/except.hpp" +#include "../core/naming.hpp" namespace poac::subcmd { namespace _init { - // To snake_case - void conv_prohibit_char(std::string& s) { - std::transform(s.cbegin(), s.cend(), s.begin(), tolower); - std::replace(s.begin(), s.end(), '-', '_'); - } - std::string basename(boost::filesystem::path&& s) { namespace fs = boost::filesystem; std::string tmp = fs::basename(s); - conv_prohibit_char(tmp); + core::naming::validate_package_name(tmp); return tmp; } std::string check_requirements() { - namespace exception = core::exception; + namespace except = core::except; if (const auto result = io::file::yaml::exists_config()) { std::cerr << io::cli::bold << io::cli::red @@ -50,41 +45,40 @@ namespace poac::subcmd { if (ans == "y" || ans == "yes") return *result; else - throw exception::error("canceled"); + throw except::error("canceled"); } - // default setting file name return "poac.yml"; } - template>> + template int _main([[maybe_unused]] VS&& argv) { namespace fs = boost::filesystem; const std::string filename = check_requirements(); std::ofstream yml_ofs(filename); - yml_ofs << util::ftemplate::poac_yml(basename(fs::current_path())); + yml_ofs << _new::files::poac_yml(basename(fs::current_path()), "bin"); std::cout << fs::path(".") / filename << " was created." << std::endl; return EXIT_SUCCESS; } void check_arguments(const std::vector& argv) { - namespace exception = core::exception; - if (!argv.empty()) throw exception::invalid_second_arg("init"); + namespace except = core::except; + if (!argv.empty()) throw except::invalid_second_arg("init"); } } struct init { - static const std::string summary() { + static std::string summary() { return "Create the poac.yml"; } - static const std::string options() { + static std::string options() { return ""; } - template>> + template int operator()(VS&& argv) { _init::check_arguments(argv); - return _init::_main(std::move(argv)); + return _init::_main(std::forward(argv)); } }; } // end namespace diff --git a/include/poac/subcmd/install.hpp b/include/poac/subcmd/install.hpp index 7665a6240..882a02a30 100644 --- a/include/poac/subcmd/install.hpp +++ b/include/poac/subcmd/install.hpp @@ -17,16 +17,16 @@ #include #include "../io.hpp" -#include "../core/exception.hpp" -#include "../core/resolver.hpp" -#include "../core/lock.hpp" +#include "../core/except.hpp" +#include "../core/deper/resolver.hpp" +#include "../core/deper/lock.hpp" #include "../util.hpp" // TODO: --source (source file only (not pre-built)) namespace poac::subcmd { namespace _install { - void stream_deps(YAML::Emitter& out, const core::resolver::Activated& deps) { + void stream_deps(YAML::Emitter& out, const core::deper::resolver::Activated& deps) { out << YAML::Key << "dependencies"; out << YAML::Value << YAML::BeginMap; @@ -48,7 +48,7 @@ namespace poac::subcmd { out << YAML::EndMap; } - void create_lock_file(const std::string& timestamp, const core::resolver::Activated& activated_deps) { + void create_lock_file(const std::string& timestamp, const core::deper::resolver::Activated& activated_deps) { // Create a poac.lock if (std::ofstream ofs("poac.lock"); ofs) { ofs << "# Please do not edit this file.\n"; @@ -73,20 +73,21 @@ namespace poac::subcmd { } void echo_install_status(const bool res, const std::string& n, const std::string& v, const std::string& s) { + namespace cli = io::cli; const std::string status = n + " " + v + " (from: " + s + ")"; - io::cli::echo(res ? io::cli::to_fetch_failed(status) : io::cli::to_fetched(status)); + cli::echo('\r', cli::clr_line, res ? cli::to_fetch_failed(status) : cli::to_fetched(status)); } void fetch_packages( - const core::resolver::Backtracked& deps, + const core::deper::resolver::Backtracked& deps, const bool quite, const bool verbose) { - namespace exception = core::exception; + namespace except = core::except; namespace naming = core::naming; namespace path = io::file::path; namespace tb = io::file::tarball; - namespace resolver = core::resolver; + namespace resolver = core::deper::resolver; namespace fs = boost::filesystem; int exists_count = 0; @@ -115,24 +116,31 @@ namespace poac::subcmd { echo_install_status(res, name, dep.version, dep.source); } } - else if (dep.source == "poac" || dep.source == "github") { + else if (dep.source == "poac") { const auto pkg_dir = path::poac_cache_dir / cache_name; const auto tar_dir = pkg_dir.string() + ".tar.gz"; - std::string target; - std::string host; - if (dep.source == "poac") { - target = resolver::archive_url(name, dep.version); - host = POAC_STORAGE_HOST; + const std::string target = resolver::archive_url(name, dep.version); + + { // Get archive file + std::ofstream output_file(tar_dir, std::ios::out | std::ios::binary); + const io::net::requests req{}; + req.get(target, {}, std::move(output_file)); } - else { - target = resolver::github::archive_url(name, dep.version); - host = GITHUB_HOST; + // If res is true, does not execute func. (short-circuit evaluation) + bool result = tb::extract_spec_rm(tar_dir, pkg_dir); + result = !result && copy_to_current(cache_name, current_name); + + if (!quite) { + echo_install_status(result, name, dep.version, dep.source); } + } + else if (dep.source == "github") { + util::command clone_cmd = resolver::github::clone_command(name, dep.version); + clone_cmd += (path::poac_cache_dir / cache_name).string(); + clone_cmd = clone_cmd.to_dev_null().stderr_to_stdout(); - io::network::get(target, tar_dir, POAC_STORAGE_HOST); - // If res is true, does not execute func. (short-circuit evaluation) - bool res = tb::extract_spec_rm(tar_dir, pkg_dir); - res = res || copy_to_current(cache_name, current_name); + bool res = static_cast(clone_cmd.exec()); + res = !res && copy_to_current(cache_name, current_name); if (!quite) { echo_install_status(res, name, dep.version, dep.source); @@ -140,7 +148,7 @@ namespace poac::subcmd { } else { // If called this, it is a bug. - throw exception::error("Unexcepted error"); + throw except::error("Unexcepted error"); } } if (exists_count == static_cast(deps.size())) { @@ -148,13 +156,11 @@ namespace poac::subcmd { } } - // YAML::Node -> Deps - // TODO: To resolver? - core::resolver::Deps + core::deper::resolver::Deps resolve_packages(const std::map& node) { - namespace exception = core::exception; + namespace except = core::except; namespace naming = core::naming; - namespace resolver = core::resolver; + namespace resolver = core::deper::resolver; resolver::Deps deps; @@ -169,15 +175,15 @@ namespace poac::subcmd { deps.push_back({ {parsed_name}, {interval}, {source} }); } else { // unknown source - throw exception::error("Unknown source"); + throw except::error("Unknown source"); } } return deps; } - core::resolver::Package + core::deper::resolver::Package parse_arg_package(const std::string& v) { - namespace exception = core::exception; + namespace except = core::except; namespace naming = core::naming; naming::validate_package_name(v); @@ -195,12 +201,12 @@ namespace poac::subcmd { return { {parsed_name}, {interval}, {source} }; } else { - throw exception::error("Invalid arguments"); + throw except::error("Invalid arguments"); } } std::string convert_to_interval(const std::string &version) { - core::semver::Version upper(version); + core::deper::semver::Version upper(version); upper.major += 1; upper.minor = 0; upper.patch = 0; @@ -208,14 +214,14 @@ namespace poac::subcmd { } - template>> + template int _main(VS&& argv) { namespace fs = boost::filesystem; - namespace exception = core::exception; + namespace except = core::except; namespace path = io::file::path; namespace yaml = io::file::yaml; namespace cli = io::cli; - namespace resolver = core::resolver; + namespace resolver = core::deper::resolver; fs::create_directories(path::poac_cache_dir); @@ -228,16 +234,13 @@ namespace poac::subcmd { resolver::Resolved resolved_deps{}; bool load_lock = false; if (argv.empty()) { // 引数からの指定の時,lockファイルを無視する - if (const auto locked_deps = core::lock::load(timestamp)) { + if (const auto locked_deps = core::deper::lock::load(timestamp)) { resolved_deps = *locked_deps; load_lock = true; } } - // resolve package - if (!quite) { - cli::echo(cli::to_status("Resolving packages...")); - } + // YAML::Node -> resolver:Deps resolver::Deps deps; if (!argv.empty()) { for (const auto& v : argv) { @@ -250,9 +253,9 @@ namespace poac::subcmd { deps.insert(deps.end(), resolved_packages.begin(), resolved_packages.end()); } else if (argv.empty()) { // 引数から指定しておらず(poac install),poac.ymlにdeps keyが存在しない - throw exception::error( + throw except::error( "Required key `deps` does not exist in poac.yml.\n" - "Please refer to https://docs.poac.io"); + "Please refer to https://doc.poac.pm"); } } @@ -308,15 +311,15 @@ namespace poac::subcmd { } struct install { - static const std::string summary() { + static std::string summary() { return "Install packages"; } - static const std::string options() { - return "[-v | --verbose, -q | --quite, [args]]"; + static std::string options() { + return "-v | --verbose, -q | --quite, [args]"; } - template>> + template int operator()(VS&& argv) { - return _install::_main(std::move(argv)); + return _install::_main(std::forward(argv)); } }; } // end namespace diff --git a/include/poac/subcmd/login.hpp b/include/poac/subcmd/login.hpp index 3c6ec3124..2bb658d55 100644 --- a/include/poac/subcmd/login.hpp +++ b/include/poac/subcmd/login.hpp @@ -8,20 +8,20 @@ #include -#include "../core/exception.hpp" +#include "../core/except.hpp" #include "../io/cli.hpp" #include "../io/file.hpp" namespace poac::subcmd { namespace _login { - template>> + template int _main(VS&& argv) { namespace fs = boost::filesystem; - namespace exception = core::exception; + namespace except = core::except; if (fs::create_directories(io::file::path::poac_state_dir)) { - throw exception::invalid_second_arg("login"); + throw except::invalid_second_arg("login"); } const std::string token_path = io::file::path::poac_token_dir.string(); @@ -33,27 +33,27 @@ namespace poac::subcmd { << std::endl; } else { // file open error - throw exception::invalid_second_arg("login"); + throw except::invalid_second_arg("login"); } return EXIT_SUCCESS; } void check_arguments(const std::vector &argv) { - namespace exception = core::exception; + namespace except = core::except; if (argv.size() != 1) { - throw exception::invalid_second_arg("login"); + throw except::invalid_second_arg("login"); } } } struct login { - static const std::string summary() { return "Login to poac.pm"; } - static const std::string options() { return ""; } - template >> + static std::string summary() { return "Login to poac.pm"; } + static std::string options() { return ""; } + template int operator()(VS&& argv) { _login::check_arguments(argv); - return _login::_main(std::move(argv)); + return _login::_main(std::forward(argv)); } }; } // end namespace diff --git a/include/poac/subcmd/new.hpp b/include/poac/subcmd/new.hpp index 7d7cf2f73..58b6feb20 100644 --- a/include/poac/subcmd/new.hpp +++ b/include/poac/subcmd/new.hpp @@ -11,82 +11,162 @@ #include -#include "../core/exception.hpp" +#include "../core/except.hpp" #include "../core/naming.hpp" #include "../io.hpp" -#include "../util/ftemplate.hpp" +#include "../util/argparse.hpp" #include "../util/command.hpp" namespace poac::subcmd { namespace _new { - void echo_info(const std::string& str) { - std::cout << io::cli::bold - << "\n" - "Your \"" + str + "\" project was created successfully.\n" - "\n" - "\n" - "Go into your project by running:\n" - " $ cd " + str + "\n" - "\n" - "Start your project with:\n" - " $ poac run\n" - "\n" - << io::cli::reset; + namespace files { + const std::string _gitignore( + "#\n" + "# poac\n" + "#\n" + "deps\n" + "_build\n" + ); + std::string README_md(const std::string& project_name) { + return "# " + project_name + "\n" + "**TODO: Add description**\n" + "\n" + "---\n" + "This project uses [poac](https://github.com/poacpm/poac).\n" + "\n" + "For more information on poac please see below:\n" + "* https://poac.pm\n" + "* https://github.com/poacpm\n" + "* https://github.com/poacpm/poac#readme\n" + "\n" + "## Build\n" + "\n" + "```bash\n" + "$ poac build # or run\n" + "```\n" + "\n" + "## Installation\n" + "\n" + "To install `" + project_name + "`, add it to the dependency list of `poac.yml`:\n" + "\n" + "```yaml\n" + "deps:\n" + " " + project_name + ": \">=0.1.0 and <1.0.0\"\n" + "```\n" + "\n" + "Execute the following command:\n" + "`poac install`\n"; + } + std::string poac_yml(const std::string& project_name, const std::string& type) { + return "name: " + project_name + "\n" + "version: 0.1.0\n" + "cpp_version: 17\n" + "description: \"**TODO: Add description**\"\n" + "owners:\n" + " - \"Your ID\"\n" + "build:\n" + " system: poac\n" + + " " + type + ": true\n"; + } + const std::string main_cpp( + "#include \n" + "\n" + "int main(int argc, char** argv) {\n" + " std::cout << \"Hello, world!\" << std::endl;\n" + "}\n" + ); + std::string include_hpp(const std::string& project_name) { + return "#include \n" + "\n" + "namespace " + project_name + " {\n" + "\n" + "}\n"; + } } - void exec_new(const std::string& dirname) { - namespace exception = core::exception; + template + int _main(VS&& argv) { + namespace except = core::except; namespace fs = boost::filesystem; namespace path = io::file::path; - namespace ftmpl = util::ftemplate; + namespace cli = io::cli; namespace naming = core::naming; - naming::validate_package_name(dirname); - fs::create_directories(dirname); + bool lib = util::argparse::use_rm(argv, "-l", "--lib"); + // libが存在しないならどちらにせよ,binが選択される. + // libが存在し,binも存在するなら,binが優先される. + const bool bin = !lib || util::argparse::use_rm(argv, "-b", "--bin"); + if (bin) { + lib = false; + } + // libとbinを引数から抜いた時点で,1じゃなかったらエラーになる. + if (argv.size() != 1) { + throw except::invalid_second_arg("new"); + } + + const std::string project_name = argv[0]; + const fs::path project_path = fs::path(project_name); + naming::validate_package_name(project_name); + if (io::file::path::validate_dir(project_name)) { + throw except::error( + except::msg::already_exist("The `" + project_name + "` directory")); + } + + fs::create_directories(project_name); std::ofstream ofs; - std::map file{ - {".gitignore", ftmpl::_gitignore}, - {"main.cpp", ftmpl::main_cpp}, - {"poac.yml", ftmpl::poac_yml(dirname)}, - {"README.md", ftmpl::README_md(dirname)} - }; + std::map file; + if (bin) { + file = { + { ".gitignore", files::_gitignore }, + { "README.md", files::README_md(project_name) }, + { "poac.yml", files::poac_yml(project_name, "bin") }, + { "main.cpp", files::main_cpp } + }; + } + else { + fs::create_directories(project_path / "include"); + file = { + { ".gitignore", files::_gitignore }, + { "README.md", files::README_md(project_name) }, + { "poac.yml", files::poac_yml(project_name, "lib") }, + { fs::path("include") / (project_name + ".hpp"), files::include_hpp(project_name) }, + }; + } for (const auto& [name, text] : file) { - path::write_to_file(ofs, (fs::path(dirname) / name).string(), text); + path::write_to_file(ofs, (project_path / name).string(), text); + } + std::cout << io::cli::to_green("Created: "); + if (bin) { + std::cout << "application "; + } + else { + std::cout << "library "; } + std::cout << "`" << project_name << "` " + << "project" + << std::endl; + if (util::_command::has_command("git")) { - util::command("git init " + dirname).exec(); + const std::string git_init = "git init " + project_name; + util::command(git_init).exec(); + cli::echo(cli::to_green("Running: "), git_init); } - echo_info(dirname); - } - template>> - int _main(VS&& argv) { - namespace fs = boost::filesystem; - exec_new(argv[0]); return EXIT_SUCCESS; } - - void check_arguments(const std::vector& argv) { - namespace exception = core::exception; - if (argv.size() != 1) - throw exception::invalid_second_arg("new"); - else if (io::file::path::validate_dir(argv[0])) - throw exception::error("The " + argv[0] + " directory already exists."); - } } struct new_ { - static const std::string summary() { - return "Create a new poacpm project"; + static std::string summary() { + return "Create a new poac project"; } - static const std::string options() { - return ""; + static std::string options() { + return ", (-b | --bin) | (-l | --lib)"; } - template>> + template int operator()(VS&& argv) { - _new::check_arguments(argv); - return _new::_main(std::move(argv)); + return _new::_main(std::forward(argv)); } }; } // end namespace diff --git a/include/poac/subcmd/publish.hpp b/include/poac/subcmd/publish.hpp index e4737d399..a524bbf44 100644 --- a/include/poac/subcmd/publish.hpp +++ b/include/poac/subcmd/publish.hpp @@ -19,7 +19,7 @@ #include #include "../io.hpp" -#include "../core/exception.hpp" +#include "../core/except.hpp" #include "../util.hpp" #include "../config.hpp" @@ -69,32 +69,28 @@ namespace poac::subcmd { } void check_arguments(const std::vector& argv) { - namespace exception = core::exception; + namespace except = core::except; if (argv.size() > 1) { - throw exception::invalid_second_arg("publish"); + throw except::invalid_second_arg("publish"); } } void check_requirements() { namespace fs = boost::filesystem; - io::file::yaml::load_config("name", "version", "cpp_version", "description", "owners"); - - // TODO: licenseの項があるのに,LICENSEファイルが存在しない => error - // TODO: licenseの項が無いのに,LICENSEファイルが存在する => error - if (!fs::exists("LICENSE")) { - std::cerr << io::cli::to_yellow("WARN: ") << "LICENSE does not exist" << std::endl; - } if (!fs::exists("README.md")) { + // TODO: もう少しほんわかと識別したい.README.txtやreadme.md等 + // TODO: readmeが接頭辞にありつつ,最短なファイル.README.md, README-ja.mdだと,README.mdを優先 std::cerr << io::cli::to_yellow("WARN: ") << "README.md does not exist" << std::endl; } } - template >> + template int _main(VS&& argv) { namespace fs = boost::filesystem; - namespace exception = core::exception; + namespace except = core::except; namespace cli = io::cli; + using namespace std::string_literals; check_arguments(argv); check_requirements(); @@ -115,8 +111,6 @@ namespace poac::subcmd { // TODO: poac.ymlに,system: manualが含まれている場合はpublishできない // TODO: ヘッダの名前衝突が起きそうな気がしました、#include だと安心感がある - // TODO: descriptionに,TODOが含まれてたらエラーではなく,**TODO: Add description**と完全一致ならエラー - const std::string project_dir = fs::absolute(fs::current_path()).string(); cli::echo(cli::status, "Packaging ", project_dir, "..."); @@ -133,7 +127,7 @@ namespace poac::subcmd { json.put("token", token); } else { - throw exception::error("Could not read token"); + throw except::error(except::msg::could_not_read("token")); } { const auto node = io::file::yaml::load_config("owners"); @@ -157,37 +151,44 @@ namespace poac::subcmd { if (verbose) { std::cout << json_s << std::endl; } - if (io::network::post(POAC_TOKENS_VALIDATE_API, json_s) == "err") { - throw exception::error("Token verification failed.\n" - "Please check the following check lists.\n" - "1. Does token really belong to you?\n" - "2. Is the user ID described `owners` in poac.yml\n" - " the same as that of GitHub account?"); + { + const io::net::requests req{}; + const auto res = req.post(POAC_TOKENS_VALIDATE_API, json_s); + if (res.data() != "ok"s) { + throw except::error(res.data()); + } } const auto node = io::file::yaml::load_config("name", "version"); const auto node_name = node.at("name").as(); const auto node_version = node.at("version").as(); - if (io::network::get(POAC_PACKAGES_API + node_name + "/" + node_version + "/exists") == "true") { - throw exception::error(node_name + ": " + node_version + " already exists"); + { + const io::net::requests req{}; + const auto res = req.get(POAC_EXISTS_API + "/"s + node_name + "/" + node_version); + if (res.data() == "true"s) { + throw except::error( + except::msg::already_exist(node_name + ": " + node_version)); + } } // Post tarball to API. cli::echo(cli::to_status("Uploading...")); if (!fs::exists("poac.yml")) { - throw exception::error("poac.yml does not exists"); - } - if (const auto res = io::network::post_file(token, output_dir); res != "ok") { - throw exception::error(res); // TODO: Check exists packageは飛ばして,Delete fileはしてほしい + throw except::error( + except::msg::does_not_exist("poac.yml")); } - - // Check exists package - io::network::Headers headers; - headers.emplace(io::network::http::field::cache_control, "no-cache"); - const std::string target = POAC_PACKAGES_API + node_name + "/" + node_version + "/exists"; - const std::string res = io::network::get(target, POAC_API_HOST, headers); - if (res != "true") { - std::cerr << io::cli::to_red("ERROR: ") << "Could not create package." << std::endl; + { + io::net::multiPartForm mp_form; + mp_form.set("token", token); + std::map h; + h[io::net::http::field::content_type] = "application/x-gzip"; + h[io::net::http::field::content_transfer_encoding] = "binary"; + mp_form.set("file", output_dir, h); + + const io::net::requests req{}; + if (const auto res = req.post(POAC_UPLOAD_API, std::move(mp_form)); res != "ok") { + std::cerr << io::cli::to_red("ERROR: ") << res << std::endl; + } } // Delete file @@ -200,11 +201,11 @@ namespace poac::subcmd { } struct publish { - static const std::string summary() { return "Publish a package"; } - static const std::string options() { return "[-v | --verbose, -y | --yes]"; } - template>> + static std::string summary() { return "Publish a package"; } + static std::string options() { return "[-v | --verbose, -y | --yes]"; } + template int operator()(VS&& argv) { - return _publish::_main(std::move(argv)); + return _publish::_main(std::forward(argv)); } }; } // end namespace diff --git a/include/poac/subcmd/root.hpp b/include/poac/subcmd/root.hpp index 4e343b840..76b9e0a42 100644 --- a/include/poac/subcmd/root.hpp +++ b/include/poac/subcmd/root.hpp @@ -8,13 +8,13 @@ namespace poac::subcmd { struct root { - static const std::string summary() { + static std::string summary() { return "Display the root installation directory"; } - static const std::string options() { + static std::string options() { return ""; } - template>> + template int operator()([[maybe_unused]] VS&& vs) { std::cout << POAC_PROJECT_ROOT << std::endl; return EXIT_SUCCESS; diff --git a/include/poac/subcmd/run.hpp b/include/poac/subcmd/run.hpp index 92175fcde..6bf5d2306 100644 --- a/include/poac/subcmd/run.hpp +++ b/include/poac/subcmd/run.hpp @@ -8,17 +8,18 @@ #include -#include "../core/exception.hpp" +#include "./build.hpp" +#include "../core/except.hpp" +#include "../core/stroite/utils/absorb.hpp" #include "../io/file.hpp" #include "../io/cli.hpp" #include "../util/command.hpp" #include "../core/naming.hpp" -#include "./build.hpp" namespace poac::subcmd { namespace _run { - template>> + template int _main(VS&& argv) { namespace fs = boost::filesystem; @@ -26,34 +27,27 @@ namespace poac::subcmd { std::vector program_args; // poac run -v -- -h build - if (const auto result = std::find(argv.begin(), argv.end(), "--"); result != argv.end()) { + auto result = std::find(argv.begin(), argv.end(), "--"); + if (result != argv.end()) { // -h build program_args = std::vector(result + 1, argv.end()); - // -v - subcmd::build{}(std::vector(argv.begin(), result)); } - else { - subcmd::build{}(std::move(argv)); + // -v + _build::check_arguments(std::vector(argv.begin(), result)); + if (_build::_main(std::vector{}) == EXIT_FAILURE) { + return EXIT_FAILURE; } const std::string project_name = node.at("name").as(); -#ifdef _WIN32 - const std::string bin_name = project_name + ".exe"; -#else - const std::string bin_name = project_name; -#endif + const std::string bin_name = project_name + core::stroite::utils::absorb::binary_extension; const fs::path executable_path = fs::relative(io::file::path::current_build_bin_dir / bin_name); - if (!fs::exists(executable_path)) { - return EXIT_FAILURE; - } - const std::string executable = executable_path.string(); util::command cmd(executable); for (const auto &s : program_args) { cmd += s; } - std::cout << io::cli::green << "Running: " << io::cli::reset + std::cout << io::cli::to_green("Running: ") << "`" + executable + "`" << std::endl; if (const auto ret = cmd.exec()) { @@ -68,15 +62,15 @@ namespace poac::subcmd { } struct run { - static const std::string summary() { + static std::string summary() { return "Build project and exec it"; } - static const std::string options() { + static std::string options() { return "[-v | --verbose | -- [program args]]"; } - template >> + template int operator()(VS&& argv) { - return _run::_main(std::move(argv)); + return _run::_main(std::forward(argv)); } }; } // end namespace diff --git a/include/poac/subcmd/search.hpp b/include/poac/subcmd/search.hpp index 9a12d8198..8090858da 100644 --- a/include/poac/subcmd/search.hpp +++ b/include/poac/subcmd/search.hpp @@ -9,10 +9,11 @@ #include #include -#include "../core/exception.hpp" +#include "../core/except.hpp" #include "../io/cli.hpp" -#include "../io/network.hpp" +#include "../io/net.hpp" #include "../util/argparse.hpp" +#include "../util/pretty.hpp" namespace poac::subcmd { @@ -32,7 +33,7 @@ namespace poac::subcmd { } boost::property_tree::ptree get_search_api(const std::string& query) { - namespace exception = core::exception; + namespace except = core::except; std::string params; { @@ -44,34 +45,39 @@ namespace poac::subcmd { } std::stringstream ss; - io::network::Headers headers; + io::net::Headers headers; headers.emplace("X-Algolia-API-Key", ALGOLIA_SEARCH_ONLY_KEY); headers.emplace("X-Algolia-Application-Id", ALGOLIA_APPLICATION_ID); - ss << io::network::post(ALGOLIA_SEARCH_INDEX_API, params, ALGOLIA_SEARCH_INDEX_API_HOST, headers); + const io::net::requests req{ ALGOLIA_SEARCH_INDEX_API_HOST }; + const auto res = req.post(ALGOLIA_SEARCH_INDEX_API, params, headers); + ss << res.data(); boost::property_tree::ptree pt; boost::property_tree::json_parser::read_json(ss, pt); if (const auto value = pt.get_optional("nbHits")) { if (*value <= 0) { - throw exception::error(query + " not found"); + throw except::error(except::msg::not_found(query)); } } return pt; } - // If string size is over specified number of characters and it can be clipped, - // display an ellipsis (...). - std::string string_pretty(const std::string& s, const unsigned long& n) { - if (s.size() <= n) { - return s; - } - else { - return s.substr(0, n) + "..."; + unsigned int replace(std::string& s, const std::string& from, const std::string& target) { + const auto from_length = from.size(); + const auto target_length = target.size(); + std::size_t pos = 0; + unsigned int count = 0; + while ((pos = s.find(from, pos)) != std::string::npos) { + s.replace(pos, from_length, target); + pos += target_length; + ++count; } + return count; } - template>> + template int _main(VS&& argv) { + namespace cli = io::cli; using namespace boost::property_tree; const bool verbose = util::argparse::use(argv, "-v", "--verbose"); @@ -86,13 +92,19 @@ namespace poac::subcmd { echo_first_line(); for (const ptree::value_type& child : pt.get_child("hits")) { const ptree& hits = child.second; - io::cli::set_left(25); - std::cout << string_pretty(hits.get("name"), 21); - io::cli::set_left(50); - std::cout << string_pretty(hits.get("description"), 45); - io::cli::set_left(15); + + std::string name = hits.get("_highlightResult.name.value"); + auto count_s = replace(name, "", cli::red) * cli::red.size(); + auto count_l = replace(name, "", cli::reset) * cli::reset.size(); + + cli::set_left(25 + count_s + count_l); + std::cout << util::pretty::clip_string(name, 21 + count_s + count_l); + cli::set_left(50); + std::cout << util::pretty::clip_string(hits.get("description"), 45); + cli::set_left(15); + const auto cpp_version = hits.get("cpp_version"); std::cout << hits.get("version") - << " " << hits.get("cpp_version") + << " " << (cpp_version == "3" ? "03" : cpp_version) << std::endl; } @@ -100,24 +112,24 @@ namespace poac::subcmd { } void check_arguments(const std::vector& argv) { - namespace exception = core::exception; + namespace except = core::except; if (argv.size() != 1) { - throw exception::invalid_second_arg("search"); + throw except::invalid_second_arg("search"); } } } struct search { - static const std::string summary() { + static std::string summary() { return "Search for packages in poac.pm"; } - static const std::string options() { + static std::string options() { return ""; } - template>> + template int operator()(VS&& argv) { _search::check_arguments(argv); - return _search::_main(std::move(argv)); + return _search::_main(std::forward(argv)); } }; } // end namespace diff --git a/include/poac/subcmd/test.hpp b/include/poac/subcmd/test.hpp index d2368ceb4..1ca80bb28 100644 --- a/include/poac/subcmd/test.hpp +++ b/include/poac/subcmd/test.hpp @@ -8,28 +8,28 @@ #include #include -#include "../core/exception.hpp" +#include "../core/except.hpp" +#include "../core/stroite.hpp" #include "../io/file.hpp" #include "../io/cli.hpp" -#include "../util/stroite.hpp" #include "../util/argparse.hpp" -// TODO: エラーがあるならちゃんと,EXIT_FAILUREを返す namespace poac::subcmd { namespace _test { - template>> + template int _main(VS&& argv) { namespace fs = boost::filesystem; - namespace exception = core::exception; + namespace except = core::except; + namespace stroite = core::stroite; const auto node = io::file::yaml::load_config("test"); const bool verbose = util::argparse::use(argv, "-v", "--verbose"); const bool usemain = false; - stroite::builder bs; - bs.configure_compile(usemain, verbose); + stroite::core::builder bs(verbose); + bs.configure_compile(usemain); // You can use #include<> in test code. bs.compile_conf.include_search_path.push_back((fs::current_path() / "include").string()); @@ -45,7 +45,7 @@ namespace poac::subcmd { // static_link_lib = "gtest_main"; } else { - throw exception::error("Invalid test framework"); + throw except::error("Invalid test framework"); } } @@ -55,11 +55,7 @@ namespace poac::subcmd { const std::string bin_name = fs::path( boost::replace_all_copy( fs::relative(cpp_relative, "test").string(), "/", "-")).stem().string(); -#ifdef _WIN32 - const std::string extension = ".exe"; -#else - const std::string extension = ""; -#endif + const std::string extension = core::stroite::utils::absorb::binary_extension; const std::string bin_path = (io::file::path::current_build_test_bin_dir / bin_name).string() + extension; bs.compile_conf.source_files = bs.hash_source_files({cpp_relative}, usemain); @@ -71,12 +67,12 @@ namespace poac::subcmd { // continue; } else { - if (const auto obj_files_path = bs._compile()) { - bs.configure_link(*obj_files_path, verbose); + if (const auto obj_files_path = bs.compile()) { + bs.configure_link(*obj_files_path); bs.link_conf.project_name = bin_name; bs.link_conf.output_root = io::file::path::current_build_test_bin_dir; bs.link_conf.static_link_libs.push_back(static_link_lib); - if (bs._link()) { + if (bs.link()) { std::cout << io::cli::green << "Compiled: " << io::cli::reset << "Output to `" + fs::relative(bin_path).string() + @@ -139,25 +135,18 @@ namespace poac::subcmd { } return EXIT_SUCCESS; } - - void check_arguments([[maybe_unused]] const std::vector& argv) { - namespace exception = core::exception; -// if (argv.size() >= 2) -// throw except::invalid_second_arg("test"); - } } struct test { - static const std::string summary() { + static std::string summary() { return "Execute tests"; } - static const std::string options() { + static std::string options() { return "[-v | --verbose, --report, -- args]"; } - template >> + template int operator()(VS&& argv) { - _test::check_arguments(argv); - return _test::_main(std::move(argv)); + return _test::_main(std::forward(argv)); } }; } // end namespace diff --git a/include/poac/subcmd/uninstall.hpp b/include/poac/subcmd/uninstall.hpp index c83633b96..b91d31b63 100644 --- a/include/poac/subcmd/uninstall.hpp +++ b/include/poac/subcmd/uninstall.hpp @@ -12,10 +12,10 @@ #include #include "./install.hpp" -#include "../core/exception.hpp" -#include "../core/resolver.hpp" +#include "../core/except.hpp" #include "../core/naming.hpp" -#include "../core/lock.hpp" +#include "../core/deper/resolver.hpp" +#include "../core/deper/lock.hpp" #include "../io/file/path.hpp" #include "../io/file/yaml.hpp" #include "../io/cli.hpp" @@ -49,7 +49,7 @@ namespace poac::subcmd { for (const auto& v : argv) { const auto result = std::find_if(first, last, [&](auto x){ return v == x.first; }); if (result == last) { - throw core::exception::error("There is no package named " + v + " in the dependency."); + throw core::except::error("There is no package named " + v + " in the dependency."); } } } @@ -116,11 +116,11 @@ namespace poac::subcmd { void individual(VS&& argv) { namespace fs = boost::filesystem; namespace yaml = io::file::yaml; - namespace resolver = core::resolver; + namespace resolver = core::deper::resolver; namespace cli = io::cli; namespace naming = core::naming; - namespace exception = core::exception; - namespace lock = core::lock; + namespace except = core::except; + namespace lock = core::deper::lock; auto node = yaml::load_config(); std::map deps_node; @@ -129,7 +129,7 @@ namespace poac::subcmd { check_exist_name(deps_node, argv); } else { - throw exception::error("Could not read deps in poac.yml"); + throw except::error(except::msg::could_not_read("deps in poac.yml")); } // create resolved deps @@ -192,7 +192,7 @@ namespace poac::subcmd { ofs << node; } else { - throw exception::error("Could not open poac.yml"); + throw except::error(except::msg::could_not_load("poac.yml")); } fs::remove("poac.lock"); } @@ -218,7 +218,7 @@ namespace poac::subcmd { ofs << node; } else { - throw exception::error("Could not open poac.yml"); + throw except::error(except::msg::could_not_load("poac.yml")); } _install::create_lock_file(timestamp, resolved_deps.activated); } @@ -227,7 +227,7 @@ namespace poac::subcmd { cli::echo(cli::status_done()); } - template >> + template int _main(VS&& argv) { if (util::argparse::use(argv, "-a", "--all")) { all(std::move(argv)); @@ -240,20 +240,20 @@ namespace poac::subcmd { } void check_arguments(const std::vector& argv) { - namespace exception = core::exception; + namespace except = core::except; if (argv.empty()) { - throw exception::invalid_second_arg("uninstall"); + throw except::invalid_second_arg("uninstall"); } } } struct uninstall { - static const std::string summary() { return "Uninstall packages"; } - static const std::string options() { return "[, -a | --all, -y | --yes]"; } - template >> + static std::string summary() { return "Uninstall packages"; } + static std::string options() { return "[, -a | --all, -y | --yes]"; } + template int operator()(VS&& argv) { _uninstall::check_arguments(argv); - return _uninstall::_main(std::move(argv)); + return _uninstall::_main(std::forward(argv)); } }; } // end namespace diff --git a/include/poac/subcmd/update.hpp b/include/poac/subcmd/update.hpp index 63a1adc12..9db61323a 100644 --- a/include/poac/subcmd/update.hpp +++ b/include/poac/subcmd/update.hpp @@ -12,14 +12,14 @@ #include #include "./install.hpp" -#include "../core/exception.hpp" +#include "../core/except.hpp" #include "../core/naming.hpp" -#include "../core/semver.hpp" -#include "../core/resolver.hpp" +#include "../core/deper/semver.hpp" +#include "../core/deper/resolver.hpp" #include "../io/file/path.hpp" #include "../io/file/yaml.hpp" #include "../io/cli.hpp" -#include "../io/network.hpp" +#include "../io/net.hpp" #include "../util/types.hpp" @@ -27,13 +27,13 @@ // TODO: --select | --intractive とすると,インタラクティブに選択してupdateできる. namespace poac::subcmd { namespace _update { - template >> + template int _main(VS&& argv) { namespace fs = boost::filesystem; - namespace exception = core::exception; + namespace except = core::except; namespace yaml = io::file::yaml; namespace cli = io::cli; - namespace resolver = core::resolver; + namespace resolver = core::deper::resolver; namespace naming = core::naming; const bool yes = util::argparse::use_rm(argv, "-y", "--yes"); @@ -77,7 +77,7 @@ namespace poac::subcmd { current_version = "null"; } - if (core::semver::Version(dep.version) != current_version) { + if (core::deper::semver::Version(dep.version) != current_version) { update_deps[name] = { {current_version}, {dep.source} }; } } @@ -91,7 +91,7 @@ namespace poac::subcmd { for (const auto& [name, dep] : update_deps) { const auto current_version = resolved_deps.backtracked[name].version; std::cout << name << " (Current: " << current_version << " -> Update: "; - if (core::semver::Version(current_version) < dep.version) { + if (core::deper::semver::Version(current_version) < dep.version) { std::cout << cli::to_green(dep.version) << ")" << std::endl; } else { @@ -139,15 +139,15 @@ namespace poac::subcmd { } struct update { - static const std::string summary() { + static std::string summary() { return "Update package"; } - static const std::string options() { + static std::string options() { return "[ -y | --yes, -a | --all, --outside ]"; } - template >> + template int operator()(VS&& argv) { - return _update::_main(std::move(argv)); + return _update::_main(std::forward(argv)); } }; } // end namespace diff --git a/include/poac/util.hpp b/include/poac/util.hpp index 90076a834..982dd61af 100644 --- a/include/poac/util.hpp +++ b/include/poac/util.hpp @@ -3,9 +3,8 @@ #include "util/argparse.hpp" #include "util/command.hpp" -#include "util/ftemplate.hpp" -#include "util/pretty_time.hpp" -#include "util/stroite.hpp" +#include "util/misc.hpp" +#include "util/pretty.hpp" #include "util/types.hpp" #endif // !POAC_UTIL_HPP diff --git a/include/poac/util/argparse.hpp b/include/poac/util/argparse.hpp index 0e70f9674..d8c3795fc 100644 --- a/include/poac/util/argparse.hpp +++ b/include/poac/util/argparse.hpp @@ -15,20 +15,22 @@ namespace poac::util::argparse { template bool use(SinglePassRange& rng, T... args) { - const auto first = std::begin(rng); - const auto last = std::end(rng); + const auto first = std::cbegin(rng); + const auto last = std::cend(rng); return ((std::find(first, last, args) != last) || ...); } + // { arg1, arg2 }, arg2 -> { arg1 } template bool use_rm(SinglePassRange& rng, T... args) { const auto first = std::begin(rng); - const auto last = std::end(rng); + auto last = std::end(rng); bool found = false; for (const auto& a : types::tuple_to_array(std::tuple{ args... })) { if (const auto itr = std::find(first, last, a); itr != last) { rng.erase(itr); + last = std::end(rng); found = true; } } @@ -39,8 +41,8 @@ namespace poac::util::argparse { template std::optional use_get(SinglePassRange& rng, T arg) { - const auto first = std::begin(rng); - const auto last = std::end(rng); + const auto first = std::cbegin(rng); + const auto last = std::cend(rng); if (const auto result = std::find(first, last, arg); result != last) { return *(result + 1); } @@ -48,12 +50,12 @@ namespace poac::util::argparse { return std::nullopt; } } - // -o filename -> return filename + // -o filename OR --output filename -> return filename template std::optional use_get(SinglePassRange& rng, T arg1, T arg2) { - const auto first = std::begin(rng); - const auto last = std::end(rng); + const auto first = std::cbegin(rng); + const auto last = std::cend(rng); if (const auto result1 = std::find(first, last, arg1); result1 != last) { return *(result1 + 1); } diff --git a/include/poac/util/command.hpp b/include/poac/util/command.hpp index 671498f41..d84088412 100644 --- a/include/poac/util/command.hpp +++ b/include/poac/util/command.hpp @@ -6,12 +6,13 @@ #include #include #include +#include namespace poac::util { class command { public: - std::string data() const { return cmd; } + std::string string() const { return cmd; } command() { cmd = ""; } command(const std::string& c) { cmd = c; } @@ -22,7 +23,7 @@ namespace poac::util { if (count++ == 0) cmd2 = util::command(s).stderr_to_stdout(); // TODO: std_err else cmd2 &= util::command(s).stderr_to_stdout(); } - cmd = cmd2.data(); + cmd = cmd2.string(); } command env(const std::string& name, const std::string& val) { @@ -31,11 +32,14 @@ namespace poac::util { command stderr_to_stdout() { return cmd + " 2>&1"; } + command to_dev_null() { + return cmd + " >/dev/null"; + } // TODO: 全てのstderrをstdoutにパイプし,吸収した上で,resultとして返却??? // TODO: errorと,その内容を同時に捕捉できない. std::optional exec() const { - std::array buffer; + std::array buffer{}; std::string result; #ifdef _WIN32 @@ -60,6 +64,10 @@ namespace poac::util { return result; } + bool exec_incontinent() const { + return static_cast(std::system(cmd.c_str())); + } + friend std::ostream& operator<<(std::ostream& stream, const command& c) { stream << c.cmd; return stream; diff --git a/include/poac/util/ftemplate.hpp b/include/poac/util/ftemplate.hpp deleted file mode 100644 index 7120e7912..000000000 --- a/include/poac/util/ftemplate.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef POAC_UTIL_FTEMPLATE_HPP -#define POAC_UTIL_FTEMPLATE_HPP - -#include - - -namespace poac::util::ftemplate { - const std::string _gitignore( - "#\n" - "# poac\n" - "#\n" - "deps\n" - "_build\n" - ); - const std::string main_cpp( - "#include \n" - "\n" - "int main(int argc, char** argv) {\n" - " std::cout << \"Hello, world!\" << std::endl;\n" - "}\n" - ); - std::string poac_yml(const std::string& project_name) { - return "name: " + project_name + "\n" - "version: 0.1.0\n" - "cpp_version: 17\n" - "description: \"**TODO: Add description**\"\n" - "owners:\n" - " - \"Your ID\"\n" - "build:\n" - " system: poac\n" - " bin: true\n"; - } - std::string README_md(const std::string& project_name) { - return "# " + project_name + "\n" - "**TODO: Add description**\n" - "\n" - "---\n" - "This project uses [poac](https://github.com/poacpm/poac).\n" - "\n" - "For more information on poac please see below:\n" - "* https://poac.io\n" - "* https://github.com/poacpm\n" - "* https://github.com/poacpm/poac#readme\n" - "\n" - "## Build\n" - "\n" - "```bash\n" - "$ poac build # or run\n" - "```\n" - "\n" - "## Installation\n" - "\n" - "To install `" + project_name + "`, add it to the dependency list of `poac.yml`:\n" - "\n" - "```yaml\n" - "deps:\n" - " " + project_name + ": \"0.1.0\"\n" - "```\n" - "\n" - "Execute the following command:\n" - "`poac install`\n" - ; - } - // TODO: 0.6.0 >=, doc - // "\n" - // "Documentation can be generated with doc.poac.pm\n" - // "and published on [HexDocs](https://doc.poac.pm). Once published, the docs can\n" - // "be found at https://doc.poac.pm/"+ project_name + ".\n" -} // end namespace -#endif // !POAC_UTIL_FTEMPLATE_HPP diff --git a/include/poac/util/stroite/utils/misc.hpp b/include/poac/util/misc.hpp similarity index 77% rename from include/poac/util/stroite/utils/misc.hpp rename to include/poac/util/misc.hpp index 567a36dae..c7805b71f 100644 --- a/include/poac/util/stroite/utils/misc.hpp +++ b/include/poac/util/misc.hpp @@ -1,6 +1,6 @@ // Miscellaneous utility -#ifndef STROITE_UTILS_MISC_HPP -#define STROITE_UTILS_MISC_HPP +#ifndef POAC_UTIL_MISC_HPP +#define POAC_UTIL_MISC_HPP #include #include @@ -9,7 +9,7 @@ #include -namespace stroite::utils::misc { +namespace poac::util::misc { std::vector split(const std::string& raw, const std::string& delim) { using boost::algorithm::token_compress_on; @@ -20,4 +20,4 @@ namespace stroite::utils::misc { return ret; } } // end namespace -#endif // STROITE_UTILS_MISC_HPP +#endif // POAC_UTIL_MISC_HPP diff --git a/include/poac/util/pretty.hpp b/include/poac/util/pretty.hpp new file mode 100644 index 000000000..92b45de6f --- /dev/null +++ b/include/poac/util/pretty.hpp @@ -0,0 +1,63 @@ +#ifndef POAC_UTIL_PRETTY_HPP +#define POAC_UTIL_PRETTY_HPP + +#include +#include + + +namespace poac::util::pretty { + std::string to_time(const std::string& s) { + double total_seconds = std::stod(s); + if (total_seconds > 1.0) { + int days = static_cast( total_seconds / 60 / 60 / 24 ); + int hours = static_cast( total_seconds / 60 / 60 ) % 24; + int minutes = static_cast( total_seconds / 60 ) % 60; + int seconds = static_cast( total_seconds ) % 60; + + std::string res; + if (days > 0) res += std::to_string(days) + "d "; + if (hours > 0) res += std::to_string(hours) + "h "; + if (minutes > 0) res += std::to_string(minutes) + "m "; + res += std::to_string(seconds) + "s"; + + return res; + } + else { + return s + "s"; + } + } + + std::pair + to_byte(const float b) { + // 1024 + const float kb = b / 1000; + if (kb < 1) { + return { b, "B" }; + } + const float mb = kb / 1000; + if (mb < 1) { + return { kb, "KB" }; + } + const float gb = mb / 1000; + if (gb < 1) { + return { mb, "MB" }; + } + const float tb = gb / 1000; + if (tb < 1) { + return { gb, "GB" }; + } + return { tb, "TB" }; + } + + // If string size is over specified number of characters and it can be clipped, + // display an ellipsis (...). + std::string clip_string(const std::string& s, const unsigned long& n) { + if (s.size() <= n) { + return s; + } + else { + return s.substr(0, n) + "..."; + } + } +} // end namespace +#endif // !POAC_UTIL_PRETTY_HPP diff --git a/include/poac/util/pretty_time.hpp b/include/poac/util/pretty_time.hpp deleted file mode 100644 index 6867f7ec2..000000000 --- a/include/poac/util/pretty_time.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef POAC_UTIL_PRETTY_TIME_HPP -#define POAC_UTIL_PRETTY_TIME_HPP - -#include - - -namespace poac::util::pretty_time { - std::string to(const std::string& s) { - double total_seconds = std::stod(s); - if (total_seconds > 1.0) { - int days = static_cast( total_seconds / 60 / 60 / 24 ); - int hours = static_cast( total_seconds / 60 / 60 ) % 24; - int minutes = static_cast( total_seconds / 60 ) % 60; - int seconds = static_cast( total_seconds ) % 60; - - std::string res; - if (days > 0) res += std::to_string(days) + "d "; - if (hours > 0) res += std::to_string(hours) + "h "; - if (minutes > 0) res += std::to_string(minutes) + "m "; - res += std::to_string(seconds) + "s"; - - return res; - } - else { - return s + "s"; - } - } -} // end namespace -#endif // !POAC_UTIL_PRETTY_TIME_HPP diff --git a/include/poac/util/stroite.hpp b/include/poac/util/stroite.hpp deleted file mode 100644 index 978e6451d..000000000 --- a/include/poac/util/stroite.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef STROITE_HPP -#define STROITE_HPP - -#include "stroite/core.hpp" -#include "stroite/utils.hpp" - -#endif // STROITE_HPP \ No newline at end of file diff --git a/include/poac/util/stroite/core/builder.hpp b/include/poac/util/stroite/core/builder.hpp deleted file mode 100644 index ca9575e0b..000000000 --- a/include/poac/util/stroite/core/builder.hpp +++ /dev/null @@ -1,409 +0,0 @@ -#ifndef STROITE_CORE_BUILDER_HPP -#define STROITE_CORE_BUILDER_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "./compiler.hpp" -#include "./depends.hpp" -#include "../utils.hpp" - -#include "../../../core/exception.hpp" -#include "../../../core/lock.hpp" -#include "../../../io/file/path.hpp" -#include "../../../core/naming.hpp" -#include "../../../io/cli.hpp" -#include "../../../io/file/yaml.hpp" - - -namespace stroite { - struct builder { - utils::options::compile compile_conf; - utils::options::link link_conf; - utils::options::static_lib static_lib_conf; - utils::options::dynamic_lib dynamic_lib_conf; - - std::string system; - std::string project_name; - boost::filesystem::path base_dir; - - std::map node; - std::map> depends_ts; - std::optional> deps_node; - - - bool is_cpp_file(const boost::filesystem::path& p) { - namespace fs = boost::filesystem; - return !fs::is_directory(p) - && (p.extension().string() == ".cpp" - || p.extension().string() == ".cxx" - || p.extension().string() == ".cc" - || p.extension().string() == ".cp"); - } - - auto make_source_files() { - namespace fs = boost::filesystem; - namespace io = poac::io::file; - - std::vector source_files; - if (io::path::validate_dir(base_dir / "src")) { - for (const fs::path& p : fs::recursive_directory_iterator(base_dir / "src")) { - if (is_cpp_file(p)) { - source_files.push_back(p.string()); - } - } - } - return source_files; - } - - auto make_include_search_path() { - namespace fs = boost::filesystem; - namespace naming = poac::core::naming; - namespace exception = poac::core::exception; - namespace lock = poac::core::lock; - namespace yaml = poac::io::file::yaml; - namespace io = poac::io::file; - - std::vector include_search_path; - if (deps_node) { // subcmd/build.hppで,存在確認が取れている - if (const auto locked_deps = lock::load_ignore_timestamp()) { - for (const auto& [name, dep] : (*locked_deps).backtracked) { - const std::string current_package_name = naming::to_current(dep.source, name, dep.version); - const fs::path package_path = io::path::current_deps_dir / current_package_name; - - if (const fs::path include_dir = package_path / "include"; fs::exists(include_dir)) {// io::file::path::validate_dir?? - include_search_path.push_back(include_dir.string()); - } - else { - throw exception::error( - name + " is not installed.\n" - "Please build after running `poac install`"); - } - } - } - else { - throw exception::error( - "Could not load poac.lock.\n" - "Please build after running `poac install`"); - } - } - return include_search_path; - } - - auto make_macro_defns() { - namespace fs = boost::filesystem; - namespace configure = utils::configure; - - std::vector macro_defns; - // poac automatically define the absolute path of the project's root directory. - macro_defns.push_back(configure::make_macro_defn("POAC_PROJECT_ROOT", fs::current_path().string())); - macro_defns.push_back(configure::make_macro_defn("POAC_VERSION", node.at("version").as())); - return macro_defns; - } - - auto make_compile_other_args() { - namespace yaml = poac::io::file::yaml; - if (const auto compile_args = yaml::get>(node.at("build"), "compile_args")) { - return *compile_args; - } - else { - return std::vector{}; - } - } - - - std::string to_cache_hash_path(const std::string& s) { - namespace fs = boost::filesystem; - namespace io = poac::io::file; - - const auto hash_path = io::path::current_build_cache_hash_dir / fs::relative(s); - return hash_path.string() + ".hash"; - } - - std::optional> - load_timestamps(const std::string& src_cpp_hash) { - namespace io = poac::io::file; - - std::ifstream ifs(src_cpp_hash); - if(!ifs.is_open()){ - return std::nullopt; - } - - std::string buff; - std::map hash; - while (std::getline(ifs, buff)) { - const auto list_string = io::path::split(buff, ": \n"); - hash[list_string[0]] = list_string[1]; - } - return hash; - } - - void generate_timestamp( - const std::string& filename, - std::map& timestamp) - { - namespace fs = boost::filesystem; - namespace io = poac::io::file; - - boost::system::error_code error; - const std::time_t last_time = fs::last_write_time(filename, error); - timestamp.emplace(filename, std::to_string(last_time)); - } - - // *.cpp -> hash - std::optional> - generate_timestamps(const std::string& source_file) - { - if (const auto deps_headers = core::depends::gen(compile_conf, source_file)) - { - std::map hash; - for (const auto& name : *deps_headers) { - // Calculate the hash of the source dependent files. - generate_timestamp(name, hash); - } - // Calculate the hash of the source file itself. - generate_timestamp(source_file, hash); - return hash; - } - return std::nullopt; - } - - auto check_src_cpp(const std::vector& source_files) - { - namespace fs = boost::filesystem; - - std::vector new_source_files; - for (const auto& sf : source_files) { - if (const auto previous_ts = load_timestamps(to_cache_hash_path(sf))) { - if (const auto current_ts = generate_timestamps(sf)) - { - // Since hash of already existing hash file - // does not match hash of current cpp file, - // it does not exclude it from compilation, - // and generates hash for overwriting. - if (*previous_ts != *current_ts) { - depends_ts[to_cache_hash_path(sf)] = *current_ts; - new_source_files.push_back(sf); - } - } - } - else { - // Since hash file does not exist, generates hash and compiles source file. - if (const auto cur_hash = generate_timestamps(sf)) - { - depends_ts[to_cache_hash_path(sf)] = *cur_hash; - new_source_files.push_back(sf); - } - } - } - return new_source_files; - } - - auto hash_source_files( - std::vector&& source_files, - const bool usemain ) - { - namespace fs = boost::filesystem; - namespace exception = poac::core::exception; - - if (usemain) { - if (!fs::exists("main.cpp")) { - throw exception::error("main.cpp does not exists"); - } - else { - source_files.push_back("main.cpp"); - } - } - return check_src_cpp(source_files); - } - - void configure_compile(const bool usemain, const bool verbose) - { - compile_conf.system = system; - compile_conf.version_prefix = utils::configure::default_version_prefix(); - // TODO: 存在することが確約されているときのyaml::get - compile_conf.cpp_version = node.at("cpp_version").as(); - compile_conf.include_search_path = make_include_search_path(); - compile_conf.other_args = make_compile_other_args(); - compile_conf.verbose = verbose; - compile_conf.source_files = hash_source_files(make_source_files(), usemain); - compile_conf.macro_defns = make_macro_defns(); - compile_conf.base_dir = base_dir; - compile_conf.output_root = poac::io::file::path::current_build_cache_obj_dir; - } - std::optional> - _compile() { - namespace io = poac::io::file; - - if (const auto ret = core::compiler::compile(compile_conf)) { - namespace fs = boost::filesystem; - // Since compile succeeded, save hash - std::ofstream ofs; - for (const auto& [hash_name, data] : depends_ts) { - std::string output_string; - for (const auto& [fname, hash] : data) { - output_string += fname + ": " + hash + "\n"; - } - fs::create_directories(fs::path(hash_name).parent_path()); - io::path::write_to_file(ofs, hash_name, output_string); - } - // Because it is excluded for the convenience of cache, - // ignore the return value of compiler.compile. - std::vector obj_files; - for (const auto& s : compile_conf.source_files) { - obj_files.push_back( - (compile_conf.output_root / fs::relative(s)) - .replace_extension("o") - .string() - ); - } - return obj_files; - } - else { - return std::nullopt; - } - } - - auto make_link_other_args() { - namespace yaml = poac::io::file::yaml; - if (const auto link_args = yaml::get>(node.at("build"), "link_args")) { - return *link_args; - } - else { - return std::vector{}; - } - } - // TODO: Divide it finer... - auto make_link() { - namespace fs = boost::filesystem; - namespace yaml = poac::io::file::yaml; - namespace naming = poac::core::naming; - - std::vector library_search_path; - std::vector static_link_libs; - std::vector library_path; - - if (deps_node) { - for (const auto& [name, next_node] : *deps_node) { - const auto[src, name2] = naming::get_source(name); - const std::string version = naming::get_version(next_node, src); - - if (src != "poac") { - const std::string pkgname = naming::to_cache(src, name2, version); - const fs::path pkgpath = poac::io::file::path::current_deps_dir / pkgname; - - // TODO: できればlockファイルに書かれたパッケージの./depsディレクトリのpoac.ymlを読むのが好ましい - if (const fs::path lib_dir = pkgpath / "lib"; fs::exists(lib_dir)) { - library_search_path.push_back(lib_dir.string()); - - if (const auto link = yaml::get>(next_node, "link", "include")) { - for (const auto &l : *link) { - static_link_libs.push_back(l); - } - } - else { - static_link_libs.push_back(pkgname); - } - } - } - - // TODO: 上がpoacがソースでないために,./deps/pkg/lib にlibが存在する - // TODO: 下がpoacがソースであるために,./deps/pkg/_build/lib に存在する - // TODO: しかし,library_search_path.push_back(lib_dir.string()); 以降の文では, - // TODO: poacがソースの場合,ユーザーが選択する必要は無いと判断する.(あとで直す?) - - else { - const std::string pkgname = name2; - const fs::path pkgpath = poac::io::file::path::current_build_lib_dir / pkgname; - - // TODO: dynamic libを指定できるように - if (const auto lib_dir = pkgpath.string() + ".a"; fs::exists(lib_dir)) { - library_path.push_back(lib_dir); - } - } - } - } - return std::make_tuple(library_search_path, static_link_libs, library_path); - } - void configure_link( - const std::vector& obj_files_path, - const bool verbose ) - { - link_conf.system = system; - link_conf.project_name = project_name; - link_conf.output_root = poac::io::file::path::current_build_bin_dir; - link_conf.obj_files_path = obj_files_path; - const auto links = make_link(); - link_conf.library_search_path = std::get<0>(links); - link_conf.static_link_libs = std::get<1>(links); - link_conf.library_path = std::get<2>(links); - link_conf.other_args = make_link_other_args(); - link_conf.verbose = verbose; - } - auto _link() - { - return core::compiler::link(link_conf); - } - - void configure_static_lib( - const std::vector& obj_files_path, - const bool verbose ) - { - namespace io = poac::io::file; - static_lib_conf.project_name = project_name; - static_lib_conf.output_root = io::path::current_build_lib_dir; - static_lib_conf.obj_files_path = obj_files_path; - static_lib_conf.verbose = verbose; - } - auto _gen_static_lib() - { - return core::compiler::gen_static_lib(static_lib_conf); - } - - void configure_dynamic_lib( - const std::vector& obj_files_path, - const bool verbose ) - { - namespace io = poac::io::file; - dynamic_lib_conf.system = system; - dynamic_lib_conf.project_name = project_name; - // outputを一箇所か分散か選べるように.boost::hoghoeみたいに,enumのオプションを渡すとOK - // 一箇所ってのは,./ poac build -> ./_buildだけど,depsも./_buildに配置されるやつ - dynamic_lib_conf.output_root = io::path::current_build_lib_dir; - dynamic_lib_conf.obj_files_path = obj_files_path; - dynamic_lib_conf.verbose = verbose; - } - auto _gen_dynamic_lib() - { - return core::compiler::gen_dynamic_lib(dynamic_lib_conf); - } - - // TODO: poac.ymlのhashもcheckしてほしい - // TODO: 自らのinclude,dirも,(存在するなら!) includeパスに渡してほしい.そうすると,poacでincludeできる - explicit builder(const boost::filesystem::path& base_path = boost::filesystem::current_path()) - { - namespace naming = poac::core::naming; - namespace yaml = poac::io::file::yaml; - - const auto config_file = yaml::load_config_by_dir(base_path); - node = yaml::get_by_width(config_file, "name", "version", "cpp_version", "build"); - deps_node = yaml::get>(config_file, "deps"); - project_name = naming::slash_to_hyphen(node.at("name").as()); - system = utils::configure::auto_select_compiler(); - base_dir = base_path; - } - }; -} // end namespace -#endif // STROITE_CORE_BUILDER_HPP diff --git a/include/poac/util/stroite/utils.hpp b/include/poac/util/stroite/utils.hpp deleted file mode 100644 index 9c9d133c6..000000000 --- a/include/poac/util/stroite/utils.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef STROITE_UTILS_HPP -#define STROITE_UTILS_HPP - -#include "utils/configure.hpp" -#include "utils/misc.hpp" -#include "utils/options.hpp" - -#endif // STROITE_UTILS_HPP \ No newline at end of file diff --git a/include/poac/util/stroite/utils/configure.hpp b/include/poac/util/stroite/utils/configure.hpp deleted file mode 100644 index fd786bc58..000000000 --- a/include/poac/util/stroite/utils/configure.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef STROITE_UTILS_CONFIGURE_HPP -#define STROITE_UTILS_CONFIGURE_HPP - -#include -#include -#include - -#include - -#include "../../../core/exception.hpp" -#include "../../command.hpp" - - -namespace stroite::utils::configure { - template - void enable_gnu(Opts& opts) { - opts.version_prefix = "-std=gnu++"; - } - std::string default_version_prefix() { - return "-std=c++"; - } - std::string make_macro_defn(const std::string& first, const std::string& second) { - return "-D" + first + "=" + R"(\")" + second + R"(\")"; - } - - // Automatic selection of compiler - auto auto_select_compiler() { - using poac::core::exception::error; - namespace command = poac::util::_command; - - if (const char* cxx = std::getenv("CXX")) { - return cxx; - } - else if (command::has_command("g++")) { - return "g++"; - } - else if (command::has_command("clang++")) { - return "clang++"; - } - else { - throw error( - "Environment variable \"CXX\" was not found.\n" - "Select the compiler and export it."); - } - } -} // end namespace -#endif // STROITE_UTILS_CONFIGURE_HPP diff --git a/include/poac/util/types.hpp b/include/poac/util/types.hpp index 9afc644f5..4ee799512 100644 --- a/include/poac/util/types.hpp +++ b/include/poac/util/types.hpp @@ -28,9 +28,9 @@ namespace poac::util::types { template std::optional - indexof(const SinglePassRange& rng, const T& t) { - const auto first = std::begin(rng); - const auto last = std::end(rng); + index_of(const SinglePassRange& rng, const T& t) { + auto first = std::cbegin(rng); + auto last = std::cend(rng); const auto result = std::find(first, last, t); if (result == last) { return std::nullopt; @@ -39,12 +39,16 @@ namespace poac::util::types { return std::distance(first, result); } } + template + inline auto index_of(InputIterator first, InputIterator last, const T& value) { + return std::distance(first, std::find(first, last, value)); + } // Check if it has duplicate elements. template bool duplicate(const SinglePassRange& rng) { - const auto first = std::begin(rng); - const auto last = std::end(rng); + auto first = std::cbegin(rng); + auto last = std::cend(rng); for (const auto& r : rng) { int c = std::count(first, last, r); if (c > 1) { diff --git a/main.cpp b/main.cpp index 41896f877..2b01859be 100644 --- a/main.cpp +++ b/main.cpp @@ -7,34 +7,33 @@ #include "./include/poac/poac.hpp" -using VS = std::vector; - // TODO: このあたりの処理をmain.cppがするべきではない.もう一段階抽象化すべき +template int exec(std::string&& str, VS&& vs) { namespace inference = poac::core::infer; - namespace exception = poac::core::exception; + namespace except = poac::core::except; namespace cli = poac::io::cli; using namespace std::string_literals; // TODO: 広い空間でcatchするのは危険.Result typeを使用したい try { - return std::stoi(inference::apply("exec"s, str, std::move(vs))); + return std::stoi(inference::apply("exec"s, std::forward(str), std::forward(vs))); } - catch (const exception::invalid_first_arg& e) { + catch (const except::invalid_first_arg& e) { std::cerr << cli::to_red("ERROR: ") << e.what() << std::endl << std::endl; inference::apply("exec"s, "--help"s, VS()); return EXIT_FAILURE; } - catch (const exception::invalid_second_arg& e) { + catch (const except::invalid_second_arg& e) { inference::apply("exec"s, "--help"s, VS({e.what()})); return EXIT_FAILURE; } - catch (const exception::error& e) { + catch (const except::error& e) { std::cerr << cli::to_red("ERROR: ") << e.what() << std::endl; return EXIT_FAILURE; } - catch (const exception::warn& e) { + catch (const except::warn& e) { std::cout << cli::to_yellow("WARN: ") << e.what() << std::endl; return EXIT_SUCCESS; } @@ -54,6 +53,7 @@ int exec(std::string&& str, VS&& vs) int main(int argc, const char** argv) { + using VS = std::vector; using namespace std::string_literals; // argv[0]: poac, argv[1]: install, argv[2]: 1, ... diff --git a/poac.lock b/poac.lock new file mode 100644 index 000000000..5ab7f6faa --- /dev/null +++ b/poac.lock @@ -0,0 +1,6 @@ +# Please do not edit this file. +timestamp: 1550874492 +dependencies: + jbeder/yaml-cpp: + version: yaml-cpp-0.6.2 + source: github diff --git a/poac.yml b/poac.yml index 7dd00db99..2d3eab9a0 100644 --- a/poac.yml +++ b/poac.yml @@ -1,7 +1,7 @@ # Package name name: poac # Package version -version: 0.1.2 +version: 0.2.0 # 98, 03, 11(Include TR1), 14, 17, 20 cpp_version: 17 description: "poac is a package manager for C++" @@ -9,35 +9,36 @@ description: "poac is a package manager for C++" # of the poac.pm account your created owners: - matken11235 -license: GPL-3.0 links: - homepage: "https://poac.io" + homepage: "https://poac.pm" github: "https://github.com/poacpm/poac" # Describe deps as dependencies # Writing latest will automatically # fetch the latest package deps: - boost/predef: ">=1.64.0 and <1.70.0" - boost/property_tree: ">=1.64.0 and <1.70.0" - boost/filesystem: ">=1.64.0 and <1.70.0" - boost/range: ">=1.64.0 and <1.70.0" - boost/algorithm: ">=1.64.0 and <1.70.0" - boost/foreach: ">=1.64.0 and <1.70.0" - boost/dynamic_bitset: ">=1.64.0 and <1.70.0" - boost/beast: ">=1.64.0 and <1.70.0" +# boost/predef: ">=1.64.0 and <1.70.0" +# boost/property_tree: ">=1.64.0 and <1.70.0" +# boost/filesystem: ">=1.64.0 and <1.70.0" +# boost/range: ">=1.64.0 and <1.70.0" +# boost/algorithm: ">=1.64.0 and <1.70.0" +# boost/foreach: ">=1.64.0 and <1.70.0" +# boost/dynamic_bitset: ">=1.64.0 and <1.70.0" +# boost/beast: ">=1.64.0 and <1.70.0" github/jbeder/yaml-cpp: tag: yaml-cpp-0.6.2 build: cmake link: static # If nothing is specified, it is regarded as header only library +# build: poac = build: system: poac build: - system: poac + system: cmake # Enable binary install (for CLI application) # when you use poac as system. bin: true # lib: true # Generate library from src/* . +# link: static # このライブラリに依存した時,使用者側から指定が無ければこれが使用される compile_args: - "-pthread" link_args: diff --git a/test/poac/io/file/yaml.cpp b/test/poac/io/file/yaml.cpp index bd612875d..7c94a3bc5 100644 --- a/test/poac/io/file/yaml.cpp +++ b/test/poac/io/file/yaml.cpp @@ -17,8 +17,8 @@ BOOST_AUTO_TEST_CASE( poac_io_file_yaml_gets ) "fuga: boo"); if (const auto res = yaml::get_by_width(node, "hoge", "fuga")) { - BOOST_TEST( (*res).at("hoge").as() == "foo" ); - BOOST_TEST( (*res).at("fuga").as() == "boo" ); + BOOST_TEST( res->at("hoge").as() == "foo" ); + BOOST_TEST( res->at("fuga").as() == "boo" ); } else { @@ -50,7 +50,7 @@ BOOST_AUTO_TEST_CASE( poac_io_file_yaml_gets3 ) " tag: yaml-cpp-0.6.2\n"); if (const auto res = yaml::get_by_width(node, "jbeder/yaml-cpp")) { - const auto mp = (*res).at("jbeder/yaml-cpp").as>(); + const auto mp = res->at("jbeder/yaml-cpp").as>(); BOOST_TEST( mp.at("src") == "github" ); BOOST_TEST( mp.at("tag") == "yaml-cpp-0.6.2" ); } @@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE( poac_io_file_yaml_gets4 ) " - boost_filesystem\n"); if (const auto res = yaml::get_by_width(node, "include")) { - const auto mp = (*res).at("include").as>(); + const auto mp = res->at("include").as>(); BOOST_TEST( mp[0] == "boost_system" ); BOOST_TEST( mp[1] == "boost_filesystem" ); }