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
|
||||
|
||||
- name: run
|
||||
run: ./build/Greeter
|
||||
run: ./build/GreeterStandalone
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
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 ----
|
||||
|
||||
|
@ -10,12 +14,38 @@ include(../cmake/tools.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(
|
||||
GITHUB_REPOSITORY jarro2783/cxxopts
|
||||
VERSION 3.0.0
|
||||
OPTIONS "CXXOPTS_BUILD_EXAMPLES NO" "CXXOPTS_BUILD_TESTS NO" "CXXOPTS_ENABLE_INSTALL YES"
|
||||
NAME Crow
|
||||
GITHUB_REPOSITORY CrowCpp/Crow
|
||||
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}/..)
|
||||
|
||||
# ---- 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)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${sources})
|
||||
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 17 OUTPUT_NAME "Greeter")
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} Greeter::Greeter cxxopts)
|
||||
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_11)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE Greeter::Greeter Crow::Crow)
|
||||
|
|
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/version.h>
|
||||
|
||||
#include <cxxopts.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
auto main(int argc, char** argv) -> int {
|
||||
const std::unordered_map<std::string, greeter::LanguageCode> languages{
|
||||
{"en", greeter::LanguageCode::EN},
|
||||
{"de", greeter::LanguageCode::DE},
|
||||
{"es", greeter::LanguageCode::ES},
|
||||
{"fr", greeter::LanguageCode::FR},
|
||||
};
|
||||
int main() {
|
||||
crow::SimpleApp app;
|
||||
|
||||
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;
|
||||
std::string name;
|
||||
if (req.url_params.get("language") == nullptr) {
|
||||
// return bad request
|
||||
return crow::response(400, "please provide a 'language' argument");
|
||||
}
|
||||
const auto language = req.url_params.get("language");
|
||||
|
||||
// clang-format off
|
||||
options.add_options()
|
||||
("h,help", "Show help")
|
||||
("v,version", "Print the current version number")
|
||||
("n,name", "Name to greet", cxxopts::value(name)->default_value("World"))
|
||||
("l,lang", "Language code to use", cxxopts::value(language)->default_value("en"))
|
||||
;
|
||||
// clang-format on
|
||||
// see if langauge was found
|
||||
const std::unordered_map<std::string, greeter::LanguageCode> languages{
|
||||
{"en", greeter::LanguageCode::EN},
|
||||
{"de", greeter::LanguageCode::DE},
|
||||
{"es", greeter::LanguageCode::ES},
|
||||
{"fr", greeter::LanguageCode::FR},
|
||||
};
|
||||
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>()) {
|
||||
std::cout << options.help() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
crow::json::wvalue ret({{"answer", message}});
|
||||
return crow::response(200, ret);
|
||||
});
|
||||
|
||||
if (result["version"].as<bool>()) {
|
||||
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;
|
||||
app.port(3080).multithreaded().run();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue