Skip to content

Commit 4afe1e3

Browse files
authored
Merge pull request #38 from yabjames/37-feature-add-reproducibility-with-docker-and-nix
[FEATURE] Add reproducibility with docker and nix
2 parents 397ae9e + 5150716 commit 4afe1e3

6 files changed

Lines changed: 152 additions & 18 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ set(TEST_TARGET "server_tests_bin")
66
set(TARGET "server_impl_bin")
77
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
88

9-
find_package(GTest REQUIRED)
9+
find_package(GTest CONFIG REQUIRED)
1010
find_package(Threads REQUIRED)
1111

1212

Dockerfile

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
FROM ubuntu:24.04
2+
LABEL authors="james"
3+
4+
5+
RUN apt-get update && apt-get install -y \
6+
build-essential \
7+
gcc \
8+
g++ \
9+
cmake \
10+
git \
11+
python3 \
12+
python3-pip \
13+
python3-venv \
14+
lcov \
15+
pkg-config \
16+
&& rm -rf /var/lib/apt/lists/*
17+
18+
# Create a venv for Conan
19+
RUN python3 -m venv /opt/venv
20+
# Activate venv
21+
ENV PATH="/opt/venv/bin:$PATH"
22+
23+
# Install Conan inside the venv
24+
RUN pip install --upgrade pip \
25+
&& pip install conan
26+
27+
# Configure Conan default profile
28+
RUN conan profile detect --force
29+
30+
# Set working dir and copy project files
31+
WORKDIR /app
32+
COPY --exclude=build/ . .
33+
34+
# Build with Conan
35+
RUN conan build . --build=missing
36+
37+
38+
CMD ["/bin/bash"]

README.md

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ A modern C++ HTTP server implementation with routing, testing, and CI-driven qua
99
* [Features](#features)
1010
* [Usage](#usage)
1111
* [Project Structure](#project-structure)
12+
* [Using Docker](#using-docker)
13+
* [Using Nix](#using-nix)
1214
* [Building the Source Code](#building-the-source-code)
13-
1415
* [Building for Release Mode](#building-for-release-mode)
1516
* [Running the Server](#running-the-server)
1617
* [Running the Tests](#running-the-tests)
@@ -33,6 +34,8 @@ A modern C++ HTTP server implementation with routing, testing, and CI-driven qua
3334
* Build verification
3435
* Automated test execution
3536
* Coverage report generation
37+
* **Docker** for reproducible builds and containerization
38+
* **Nix flake** for reproducible development environments
3639
* **Project tracking** using GitHub Projects (Kanban board)
3740

3841
---
@@ -45,20 +48,24 @@ A modern C++ HTTP server implementation with routing, testing, and CI-driven qua
4548
HttpServer server{};
4649

4750
server.get_mapping(
48-
"/test", [](const HttpServer::Request &, HttpServer::Response &res) {
51+
"/test", [](HttpServer::Request &req, HttpServer::Response &res) {
4952
res.body = "testing new api route";
5053
});
5154

52-
server.post_mapping(
53-
"/test2/{id}", [](const HttpServer::Request &, HttpServer::Response &res) {
54-
std::stringstream ss;
55-
try {
56-
ss << req.path_params.get_path_param("id").value() << "\n";
57-
res.body = ss.str();
58-
} catch (const std::bad_optional_access &e) {
59-
res.body = "could not get path parameter foo";
60-
}
61-
});
55+
server.post_mapping(
56+
"/test2/{id}/foo/{user}",
57+
[](HttpServer::Request &req, HttpServer::Response &res) {
58+
std::stringstream ss;
59+
try {
60+
ss << "{\"id\":" << "\"" << req.path_params.get_path_param("id").value() << "\","
61+
<< "\"user\":" << "\"" << req.path_params.get_path_param("user").value() << "\""
62+
<< "}";
63+
res.body = ss.str();
64+
} catch (const std::bad_optional_access &e) {
65+
res.body = "could not get path parameter";
66+
}
67+
});
68+
6269

6370
try {
6471
server.listen(3490); // use any port you like
@@ -82,6 +89,27 @@ try {
8289

8390
---
8491

92+
## Using Docker
93+
94+
```bash
95+
# build the docker image
96+
docker build -t cpp_http_server .
97+
98+
# run a container in interactive mode
99+
# discards after use
100+
docker run --rm -it cpp_http_server
101+
```
102+
103+
---
104+
105+
## Using Nix
106+
107+
The `flake.nix` can only be used if your system has the Nix package manager with flakes enabled.
108+
109+
```bash
110+
nix develop
111+
```
112+
85113
## Building the Source Code
86114

87115
This project uses **Conan** for dependency management and **CMake** for builds.

flake.lock

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
description = "A C/C++ development environment";
3+
4+
inputs = {
5+
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
6+
};
7+
8+
outputs = {nixpkgs, ...}: let
9+
system = "x86_64-linux";
10+
pkgs = import nixpkgs { inherit system; };
11+
in {
12+
devShells.${system}.default = pkgs.mkShell {
13+
packages = with pkgs; [
14+
git
15+
16+
gcc
17+
lcov
18+
gdb
19+
20+
# If you want to use clang and llvm-cov instead of gcc, uncomment
21+
# clang
22+
# llvmPackages.llvm
23+
24+
gnumake
25+
cmake
26+
conan
27+
28+
python312
29+
];
30+
};
31+
};
32+
}

src/main.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,22 @@ int main() {
66
HttpServer server{};
77

88
server.get_mapping(
9-
"/test", [](const HttpServer::Request &, HttpServer::Response &res) {
9+
"/test", [](HttpServer::Request &req, HttpServer::Response &res) {
1010
res.body = "testing new api route";
1111
});
1212

13-
server.get_mapping(
14-
"/test2", [](const HttpServer::Request &, HttpServer::Response &res) {
15-
res.body = "this is the other route";
13+
server.post_mapping(
14+
"/test2/{id}/foo/{user}",
15+
[](HttpServer::Request &req, HttpServer::Response &res) {
16+
std::stringstream ss;
17+
try {
18+
ss << "{\"id\":" << "\"" << req.path_params.get_path_param("id").value() << "\","
19+
<< "\"user\":" << "\"" << req.path_params.get_path_param("user").value() << "\""
20+
<< "}";
21+
res.body = ss.str();
22+
} catch (const std::bad_optional_access &e) {
23+
res.body = "could not get path parameter";
24+
}
1625
});
1726

1827
try {
@@ -21,4 +30,4 @@ int main() {
2130
std::cerr << err.what() << '\n';
2231
return EXIT_FAILURE;
2332
}
24-
}
33+
}

0 commit comments

Comments
 (0)