mirror of
https://github.com/TheLartians/ModernCppStarter.git
synced 2025-08-30 21:51:12 +02:00
Merge d36cb2e388
into 12cf5de1a8
This commit is contained in:
commit
e4d34b3edc
8 changed files with 256 additions and 49 deletions
6
.dockerignore
Normal file
6
.dockerignore
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
/build*
|
||||||
|
/.vscode
|
||||||
|
/cpm_modules
|
||||||
|
.DS_Store
|
||||||
|
/.github
|
||||||
|
/standalone/Dockerfile
|
94
.github/workflows/docker-cd.yml
vendored
Normal file
94
.github/workflows/docker-cd.yml
vendored
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
name: run Docker CD
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "v*.*.*"
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
tag:
|
||||||
|
description: "Test scenario tag"
|
||||||
|
required: true
|
||||||
|
default: "test"
|
||||||
|
set-latest-tag:
|
||||||
|
description: "Also set the 'latest' tag with this run? (y/n)"
|
||||||
|
required: true
|
||||||
|
default: "n"
|
||||||
|
|
||||||
|
env:
|
||||||
|
CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm_modules
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: CD build docker and push to DockerHub
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: handle manual workflow start and prepare docker image tag(s)
|
||||||
|
id: docker-tags
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
if [[ "x${{ github.event.inputs.tag }}" != "x" ]]; then
|
||||||
|
echo "Workflow started via workflow_dispatch! Parameters: tag=${{ github.event.inputs.tag }}, set-latest-tag=${{ github.event.inputs.set-latest-tag }}"
|
||||||
|
tag="${{ github.event.inputs.tag }}"
|
||||||
|
else
|
||||||
|
echo "Workflow started via push with tag! Complete tag: ${GITHUB_REF:10}"
|
||||||
|
tag="${GITHUB_REF:11}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "x${{ github.event.inputs.set-latest-tag }}" == "xy" || "x${{ github.event.inputs.tag }}" == "x" ]]; then
|
||||||
|
tags="${{ secrets.DOCKERHUB_USERNAME }}/greeter-webapi:$tag, ${{ secrets.DOCKERHUB_USERNAME }}/greeter-webapi:latest"
|
||||||
|
echo "Docker image release tags: $tags"
|
||||||
|
else
|
||||||
|
tags="${{ secrets.DOCKERHUB_USERNAME }}/greeter-webapi:$tag"
|
||||||
|
echo "Docker image release tag: $tags"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ::set-output name=tags::$tags
|
||||||
|
|
||||||
|
#
|
||||||
|
# configure and build in GitHub CI as smoke test
|
||||||
|
|
||||||
|
# speed up configure step by installing boost as system lib, also use Ninja for faster builds
|
||||||
|
- name: speed up configure and build
|
||||||
|
shell: bash
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y libboost-all-dev ninja-build
|
||||||
|
|
||||||
|
# use GitHub cache to cache dependencies
|
||||||
|
- uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: "**/cpm_modules"
|
||||||
|
key: ${{ github.workflow }}-cpm-modules-${{ hashFiles('**/CMakeLists.txt', '**/*.cmake') }}
|
||||||
|
|
||||||
|
- name: configure
|
||||||
|
run: cmake -S standalone -B build -G Ninja -D CMAKE_BUILD_TYPE=Release
|
||||||
|
|
||||||
|
- name: build
|
||||||
|
run: cmake --build build
|
||||||
|
|
||||||
|
#
|
||||||
|
# end GitHub CI local build
|
||||||
|
|
||||||
|
- name: set up Docker Buildx for multi-platform support
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
|
||||||
|
- name: set up QEMU for multi-platform support
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
|
||||||
|
- name: login to DockerHub
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: build Docker image and push to DockerHub
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
file: ./standalone/Dockerfile
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.docker-tags.outputs.tags }}
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
63
.github/workflows/docker-ci.yml
vendored
Normal file
63
.github/workflows/docker-ci.yml
vendored
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
name: run Docker CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
- add-docker-build
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
|
||||||
|
env:
|
||||||
|
CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm_modules
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: CI build docker
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
#
|
||||||
|
# configure and build in GitHub CI as smoke test
|
||||||
|
|
||||||
|
# speed up configure step by installing boost as system lib, also use Ninja for faster builds
|
||||||
|
- name: speed up configure and build
|
||||||
|
shell: bash
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y libboost-all-dev ninja-build
|
||||||
|
|
||||||
|
# use GitHub cache to cache dependencies
|
||||||
|
- uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: "**/cpm_modules"
|
||||||
|
key: ${{ github.workflow }}-cpm-modules-${{ hashFiles('**/CMakeLists.txt', '**/*.cmake') }}
|
||||||
|
|
||||||
|
- name: configure
|
||||||
|
run: cmake -S standalone -B build -G Ninja -D CMAKE_BUILD_TYPE=Release
|
||||||
|
|
||||||
|
- name: build
|
||||||
|
run: cmake --build build
|
||||||
|
|
||||||
|
#
|
||||||
|
# end GitHub CI local build
|
||||||
|
|
||||||
|
- name: set up Docker Buildx for multi-platform support
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
|
||||||
|
- name: set up QEMU for multi-platform support
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
|
||||||
|
# build image but do NOT push to DockerHub
|
||||||
|
- name: build Docker image
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
file: ./standalone/Dockerfile
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: false
|
||||||
|
tags: ${{ secrets.DOCKERHUB_USERNAME }}/greeter-webapi:ci
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
2
.github/workflows/standalone.yml
vendored
2
.github/workflows/standalone.yml
vendored
|
@ -32,4 +32,4 @@ jobs:
|
||||||
run: cmake --build build -j4
|
run: cmake --build build -j4
|
||||||
|
|
||||||
- name: run
|
- name: run
|
||||||
run: ./build/Greeter
|
run: ./build/GreeterStandalone
|
||||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,4 +1,4 @@
|
||||||
/build*
|
/build*
|
||||||
/.vscode
|
/.vscode
|
||||||
/cpm_modules
|
/cpm_modules
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
cmake_minimum_required(VERSION 3.14...3.22)
|
cmake_minimum_required(VERSION 3.14...3.22)
|
||||||
|
|
||||||
project(GreeterStandalone LANGUAGES CXX)
|
project(
|
||||||
|
GreeterStandalone
|
||||||
|
DESCRIPTION "A standalone minimal webapi application using the Crow framework"
|
||||||
|
LANGUAGES CXX
|
||||||
|
)
|
||||||
|
|
||||||
# --- Import tools ----
|
# --- Import tools ----
|
||||||
|
|
||||||
|
@ -10,12 +14,38 @@ include(../cmake/tools.cmake)
|
||||||
|
|
||||||
include(../cmake/CPM.cmake)
|
include(../cmake/CPM.cmake)
|
||||||
|
|
||||||
|
# Crow needs Boost 1.64 and does not provide CPM.cmake integration itself, so we have to get Boost
|
||||||
|
# first
|
||||||
|
find_package(Boost 1.64 QUIET)
|
||||||
|
if(NOT Boost_FOUND)
|
||||||
|
# Use CPM.cmake to get Boost from the official repo if not provided as system lib
|
||||||
|
message(STATUS "GreeterStandalone: Boost system lib NOT found")
|
||||||
|
CPMAddPackage(
|
||||||
|
NAME Boost
|
||||||
|
GITHUB_REPOSITORY boostorg/boost
|
||||||
|
GIT_TAG boost-1.78.0
|
||||||
|
VERSION 1.78.0
|
||||||
|
)
|
||||||
|
# Ugly workaround: Boost cmake support is still experimental, the Boost::boost target is not
|
||||||
|
# provided if downloaded via FetchContent_declare / CPM.cmake. Crow uses it for asio, so we fake
|
||||||
|
# the Boost:boost target as asio
|
||||||
|
if(NOT TARGET Boost::boost)
|
||||||
|
add_library(Boost::boost INTERFACE IMPORTED)
|
||||||
|
target_link_libraries(Boost::boost INTERFACE Boost::asio)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message(STATUS "GreeterStandalone: Boost system lib found")
|
||||||
|
endif()
|
||||||
|
# add Crow
|
||||||
CPMAddPackage(
|
CPMAddPackage(
|
||||||
GITHUB_REPOSITORY jarro2783/cxxopts
|
NAME Crow
|
||||||
VERSION 3.0.0
|
GITHUB_REPOSITORY CrowCpp/Crow
|
||||||
OPTIONS "CXXOPTS_BUILD_EXAMPLES NO" "CXXOPTS_BUILD_TESTS NO" "CXXOPTS_ENABLE_INSTALL YES"
|
GIT_TAG v1.0+1
|
||||||
|
VERSION 1.0.1
|
||||||
|
OPTIONS "CROW_INSTALL OFF"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# get the Greeter lib
|
||||||
CPMAddPackage(NAME Greeter SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
|
CPMAddPackage(NAME Greeter SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
|
||||||
|
|
||||||
# ---- Create standalone executable ----
|
# ---- Create standalone executable ----
|
||||||
|
@ -23,7 +53,5 @@ CPMAddPackage(NAME Greeter SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
|
||||||
file(GLOB sources CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp)
|
file(GLOB sources CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} ${sources})
|
add_executable(${PROJECT_NAME} ${sources})
|
||||||
|
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_11)
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 17 OUTPUT_NAME "Greeter")
|
target_link_libraries(${PROJECT_NAME} PRIVATE Greeter::Greeter Crow::Crow)
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME} Greeter::Greeter cxxopts)
|
|
||||||
|
|
21
standalone/Dockerfile
Normal file
21
standalone/Dockerfile
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# build
|
||||||
|
FROM buildpack-deps:bullseye as webapp-build
|
||||||
|
RUN set -eux; \
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
cmake \
|
||||||
|
ninja-build \
|
||||||
|
# configure/build with Boost as system lib - this should be orders of magnitude faster to configure than
|
||||||
|
# downloading via CPM.cmake while Boost's CMake support is still experimental
|
||||||
|
libboost-all-dev \
|
||||||
|
;
|
||||||
|
COPY . .
|
||||||
|
RUN cmake -S standalone -B build -G Ninja -D CMAKE_BUILD_TYPE=Release
|
||||||
|
RUN cmake --build build
|
||||||
|
|
||||||
|
|
||||||
|
# deploy
|
||||||
|
FROM debian:bullseye-slim as webapp-run
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=webapp-build /build/GreeterStandalone .
|
||||||
|
CMD ["./GreeterStandalone"]
|
|
@ -1,53 +1,48 @@
|
||||||
|
#include <crow.h>
|
||||||
#include <greeter/greeter.h>
|
#include <greeter/greeter.h>
|
||||||
#include <greeter/version.h>
|
#include <greeter/version.h>
|
||||||
|
|
||||||
#include <cxxopts.hpp>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
auto main(int argc, char** argv) -> int {
|
int main() {
|
||||||
const std::unordered_map<std::string, greeter::LanguageCode> languages{
|
crow::SimpleApp app;
|
||||||
{"en", greeter::LanguageCode::EN},
|
|
||||||
{"de", greeter::LanguageCode::DE},
|
|
||||||
{"es", greeter::LanguageCode::ES},
|
|
||||||
{"fr", greeter::LanguageCode::FR},
|
|
||||||
};
|
|
||||||
|
|
||||||
cxxopts::Options options(*argv, "A program to welcome the world!");
|
CROW_ROUTE(app, "/hello")
|
||||||
|
([](const crow::request& req) {
|
||||||
|
// check params
|
||||||
|
std::cout << "Params: " << req.url_params << "\n";
|
||||||
|
std::cout << "The key 'language' was "
|
||||||
|
<< (req.url_params.get("language") == nullptr ? "not " : "") << "found.\n";
|
||||||
|
|
||||||
std::string language;
|
if (req.url_params.get("language") == nullptr) {
|
||||||
std::string name;
|
// return bad request
|
||||||
|
return crow::response(400, "please provide a 'language' argument");
|
||||||
|
}
|
||||||
|
const auto language = req.url_params.get("language");
|
||||||
|
|
||||||
// clang-format off
|
// see if langauge was found
|
||||||
options.add_options()
|
const std::unordered_map<std::string, greeter::LanguageCode> languages{
|
||||||
("h,help", "Show help")
|
{"en", greeter::LanguageCode::EN},
|
||||||
("v,version", "Print the current version number")
|
{"de", greeter::LanguageCode::DE},
|
||||||
("n,name", "Name to greet", cxxopts::value(name)->default_value("World"))
|
{"es", greeter::LanguageCode::ES},
|
||||||
("l,lang", "Language code to use", cxxopts::value(language)->default_value("en"))
|
{"fr", greeter::LanguageCode::FR},
|
||||||
;
|
};
|
||||||
// clang-format on
|
const auto langIt = languages.find(language);
|
||||||
|
if (langIt == languages.end()) {
|
||||||
|
// return bad request
|
||||||
|
std::cout << "Greeting for language '" << language << "' is not available\n";
|
||||||
|
return crow::response(400, "language not recognized");
|
||||||
|
}
|
||||||
|
|
||||||
auto result = options.parse(argc, argv);
|
const greeter::Greeter greeter("Crow & Greeter");
|
||||||
|
std::cout << "Greeting for language '" << language << "' is available, returning message\n";
|
||||||
|
const auto message = greeter.greet(langIt->second);
|
||||||
|
|
||||||
if (result["help"].as<bool>()) {
|
crow::json::wvalue ret({{"answer", message}});
|
||||||
std::cout << options.help() << std::endl;
|
return crow::response(200, ret);
|
||||||
return 0;
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if (result["version"].as<bool>()) {
|
app.port(3080).multithreaded().run();
|
||||||
std::cout << "Greeter, version " << GREETER_VERSION << std::endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto langIt = languages.find(language);
|
|
||||||
if (langIt == languages.end()) {
|
|
||||||
std::cerr << "unknown language code: " << language << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
greeter::Greeter greeter(name);
|
|
||||||
std::cout << greeter.greet(langIt->second) << std::endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue