diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index dafa309..23e8e85 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -29,7 +29,7 @@ jobs: uses: py-actions/py-dependency-install@v4 - name: Install C++ dependencies - run: sudo apt-get install -y libboost-program-options-dev libmicrohttpd-dev libfmt-dev pybind11-dev + run: sudo apt-get install -y libmicrohttpd-dev libfmt-dev pybind11-dev - name: Build and install libhttpserver run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index b510d98..d560a54 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,6 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20") list(APPEND CMAKE_MODULE_PATH "/usr/local/share/cmake/Modules") find_package(Python COMPONENTS Interpreter Development) -find_package(Boost REQUIRED program_options) find_package(fmt REQUIRED) find_package(LibHttpServer MODULE REQUIRED) find_package(pybind11 REQUIRED) @@ -20,7 +19,7 @@ find_package(pybind11 REQUIRED) include(CTest) add_executable(tuberd src/server.cpp) -target_link_libraries(tuberd PRIVATE Boost::program_options fmt::fmt ${LIBHTTPSERVER_LIBRARIES} pybind11::embed) +target_link_libraries(tuberd PRIVATE fmt::fmt ${LIBHTTPSERVER_LIBRARIES} pybind11::embed) pybind11_add_module(test_module MODULE tests/test_module.cpp) target_include_directories(test_module PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) diff --git a/src/server.cpp b/src/server.cpp index 63e5d17..83e2c03 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include @@ -19,7 +19,6 @@ using namespace pybind11::literals; using namespace httpserver; -namespace po = boost::program_options; namespace fs = std::filesystem; /* Formatter for Python objects */ @@ -365,62 +364,89 @@ static void sigint(int signo) { ws->stop(); } +/* pretty print CLI options */ +#define PRINTOPT(o, h) \ + fmt::print(" {}\n {}\n", o, h) +#define PRINTOPT2(o, h, d) \ + fmt::print(" {}\n {} (default: {})\n", o, h, d) + int main(int argc, char **argv) { /* * Parse command-line arguments */ - int port; - int max_age; - bool orjson_with_numpy=false; - std::string preamble, registry, webroot; - std::string json_module; - - po::options_description desc("tuberd"); - desc.add_options() - ("help,h", "produce help message") - - ("max-age", - po::value(&max_age)->default_value(3600), - "maximum cache residency for static (file) assets") - - ("json,j", - po::value(&json_module)->default_value("json"), - "Python JSON module to use for serialization/deserialization") - - ("orjson-with-numpy", - po::bool_switch(&orjson_with_numpy)->default_value(false), - "Use ORJSON module with fast NumPy serialization support") - - ("port,p", - po::value(&port)->default_value(80), - "port") - - ("preamble", - po::value(&preamble)->default_value("/usr/share/tuberd/preamble.py"), - "location of slow-path Python code") - - ("registry", - po::value(®istry)->default_value("/usr/share/tuberd/registry.py"), - "location of registry Python code") - - ("webroot,w", - po::value(&webroot)->default_value("/var/www/"), - "location to serve static content") - - ("verbose,v", - po::value(&verbose), - "verbosity (default: 0)") - - ; - - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, desc), vm); - po::notify(vm); - - if(vm.count("help")) { - std::cout << desc << std::endl; - return 1; + int port = 80; + int max_age = 3600; + int orjson_with_numpy = 0; + std::string preamble = "/usr/share/tuberd/preamble.py"; + std::string registry = "/usr/share/tuberd/registry.py"; + std::string webroot = "/var/www/"; + std::string json_module = "json"; + + const option long_opts[] = { + {"orjson-with-numpy", no_argument, &orjson_with_numpy, 1}, + {"max-age", required_argument, nullptr, 'a'}, + {"json", required_argument, nullptr, 'j'}, + {"port", required_argument, nullptr, 'p'}, + {"preamble", required_argument, nullptr, 'm'}, + {"registry", required_argument, nullptr, 'r'}, + {"webroot", required_argument, nullptr, 'w'}, + {"verbose", required_argument, nullptr, 'v'}, + {"help", no_argument, nullptr, 'h'}, + {nullptr, no_argument, nullptr, 0} + }; + + while (true) { + const auto c = getopt_long(argc, argv, "j:p:w:v:h", long_opts, nullptr); + if (c == -1) + break; + + switch (c) { + case 0: + break; + case 'a': + max_age = std::stoi(optarg); + break; + case 'j': + json_module = std::string(optarg); + break; + case 'p': + port = std::stoi(optarg); + break; + case 'm': + preamble = std::string(optarg); + break; + case 'r': + registry = std::string(optarg); + break; + case 'w': + webroot = std::string(optarg); + break; + case 'v': + verbose = static_cast(std::stoi(optarg)); + break; + case 'h': + case '?': + default: + fmt::print("Usage: {} [options]\n\nOptions:\n", argv[0]); + PRINTOPT("-h [ --help ]", "produce help message"); + PRINTOPT2("--max-age N", + "maximum cache residency for static (file) assets", max_age); + PRINTOPT2("-j [ --json ] NAME", + "Python JSON module to use for serialization/deserialization", + json_module); + PRINTOPT("--orjson-with-numpy", + "use ORJSON module with fast NumPy serialization support"); + PRINTOPT2("-p [ --port ] PORT", "port", port); + PRINTOPT2("--preamble PATH", "location of slow-path Python code", + preamble); + PRINTOPT2("--registry PATH", "location of registry Python code", + registry); + PRINTOPT2("-w [ --webroot ] PATH", + "location to serve static content", webroot); + PRINTOPT2("-v [ --verbose ] N", "verbosity", (int)verbose); + return 1; + } } /*