diff --git a/CMakeLists.txt b/CMakeLists.txt index f29193b4..5681d717 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,7 @@ else(BUILD_DROGON_SHARED) add_library(${PROJECT_NAME} STATIC) endif(BUILD_DROGON_SHARED) +include(cmake/DrogonUtilities.cmake) include(CheckIncludeFileCXX) check_include_file_cxx(any HAS_ANY) @@ -456,6 +457,7 @@ install( "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/Findpg.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/FindBrotli.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/Findcoz-profiler.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/DrogonUtilities.cmake" DESTINATION "${INSTALL_DROGON_CMAKE_DIR}" COMPONENT dev) diff --git a/cmake/DrogonUtilities.cmake b/cmake/DrogonUtilities.cmake new file mode 100644 index 00000000..11ac95a7 --- /dev/null +++ b/cmake/DrogonUtilities.cmake @@ -0,0 +1,60 @@ +# ############################################################################## +# function drogon_create_views(target source_path output_path +# [use_path_as_namespace]) +# ############################################################################## +function(drogon_create_views arg) + if(ARGC LESS 3) + message(STATUS "arguments error when calling drogon_create_views") + return() + endif() + file(MAKE_DIRECTORY ${ARGV2}) + file(GLOB_RECURSE SCP_LIST ${ARGV1}/*.csp) + foreach(cspFile ${SCP_LIST}) + file(RELATIVE_PATH + inFile + ${CMAKE_CURRENT_SOURCE_DIR} + ${cspFile}) + if(ARGC GREATER 3 AND ARGV3) + string(REPLACE "/" + "_" + f1 + ${inFile}) + string(REPLACE "\\" + "_" + f2 + ${f1}) + string(REPLACE ".csp" + "" + outputFile + ${f2}) + add_custom_command(OUTPUT ${ARGV2}/${outputFile}.h ${ARGV2}/${outputFile}.cc + COMMAND drogon_ctl + ARGS + create + view + ${inFile} + --path-to-namespace + -o + ${ARGV2} + DEPENDS ${cspFile} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + VERBATIM) + set(VIEWSRC ${VIEWSRC} ${ARGV2}/${outputFile}.cc) + else() + get_filename_component(classname ${cspFile} NAME_WE) + add_custom_command(OUTPUT ${ARGV2}/${classname}.h ${ARGV2}/${classname}.cc + COMMAND drogon_ctl + ARGS + create + view + ${inFile} + -o + ${ARGV2} + DEPENDS ${cspFile} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + VERBATIM) + set(VIEWSRC ${VIEWSRC} ${ARGV2}/${classname}.cc) + endif() + endforeach() + target_sources(${ARGV0} PRIVATE ${VIEWSRC}) +endfunction(drogon_create_views) diff --git a/cmake/templates/DrogonConfig.cmake.in b/cmake/templates/DrogonConfig.cmake.in index eb6ddf82..21365e5b 100644 --- a/cmake/templates/DrogonConfig.cmake.in +++ b/cmake/templates/DrogonConfig.cmake.in @@ -42,6 +42,7 @@ endif() get_filename_component(DROGON_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) if(NOT TARGET Drogon::Drogon) include("${DROGON_CMAKE_DIR}/DrogonTargets.cmake") + include("${DROGON_CMAKE_DIR}/DrogonUtilities.cmake") endif() get_target_property(DROGON_INCLUDE_DIRS Drogon::Drogon INTERFACE_INCLUDE_DIRECTORIES) diff --git a/drogon_ctl/create.cc b/drogon_ctl/create.cc index b41ff013..574ce34b 100644 --- a/drogon_ctl/create.cc +++ b/drogon_ctl/create.cc @@ -1,7 +1,7 @@ /** * - * create.cc - * An Tao + * @file create.cc + * @author An Tao * * Copyright 2018, An Tao. All rights reserved. * https://github.com/an-tao/drogon @@ -24,7 +24,8 @@ std::string create::detail() "Usage:drogon_ctl create " "[-options] \n\n" "drogon_ctl create view [-o ] [-n " - "]//create HttpView source files from csp files\n\n" + "]|[--path-to-namespace]//create HttpView source files " + "from csp files\n\n" "drogon_ctl create controller [-s] <[namespace::]class_name> //" "create HttpSimpleController source files\n\n" "drogon_ctl create controller -h <[namespace::]class_name> //" diff --git a/drogon_ctl/create_view.cc b/drogon_ctl/create_view.cc index 7a0e755b..9ef82e9c 100644 --- a/drogon_ctl/create_view.cc +++ b/drogon_ctl/create_view.cc @@ -1,7 +1,7 @@ /** * - * create_view.cc - * An Tao + * @file create_view.cc + * @author An Tao * * Copyright 2018, An Tao. All rights reserved. * https://github.com/an-tao/drogon @@ -271,6 +271,12 @@ void create_view::handleCommand(std::vector ¶meters) } continue; } + else if (file == "--path-to-namespace") + { + iter = parameters.erase(iter); + pathToNamespaceFlag_ = true; + continue; + } else if (file[0] == '-') { std::cout << ARGS_ERROR_STR << std::endl; @@ -292,6 +298,42 @@ int create_view::createViewFile(const std::string &script_filename) { std::cout << "create HttpView Class file by " << script_filename << std::endl; + if (pathToNamespaceFlag_) + { + std::string::size_type pos1 = 0, pos2 = 0; + if (script_filename.length() >= 2 && script_filename[0] == '.' && + (script_filename[1] == '/' || script_filename[1] == '\\')) + { + pos1 = pos2 = 2; + } + else if (script_filename.length() >= 1 && + (script_filename[0] == '/' || script_filename[0] == '\\')) + { + pos1 = pos2 = 1; + } + while (pos2 < script_filename.length() - 1) + { + if (script_filename[pos2] == '/' || script_filename[pos2] == '\\') + { + if (pos2 > pos1) + { + namespaces_.push_back( + script_filename.substr(pos1, pos2 - pos1)); + } + pos1 = ++pos2; + } + else + { + ++pos2; + } + } + } + std::string npPrefix; + for (auto &np : namespaces_) + { + npPrefix += np; + npPrefix += "_"; + } std::ifstream infile(script_filename.c_str(), std::ifstream::in); if (infile) { @@ -304,8 +346,10 @@ int create_view::createViewFile(const std::string &script_filename) className = className.substr(pos + 1); } std::cout << "className=" << className << std::endl; - std::string headFileName = outputPath_ + "/" + className + ".h"; - std::string sourceFilename = outputPath_ + "/" + className + ".cc"; + std::string headFileName = + outputPath_ + "/" + npPrefix + className + ".h"; + std::string sourceFilename = + outputPath_ + "/" + npPrefix + className + ".cc"; std::ofstream oHeadFile(headFileName.c_str(), std::ofstream::out); std::ofstream oSourceFile(sourceFilename.c_str(), std::ofstream::out); @@ -317,7 +361,7 @@ int create_view::createViewFile(const std::string &script_filename) } newViewHeaderFile(oHeadFile, className); - newViewSourceFile(oSourceFile, className, infile); + newViewSourceFile(oSourceFile, className, npPrefix, infile); } else return -1; @@ -335,17 +379,16 @@ void create_view::newViewHeaderFile(std::ofstream &file, file << "//this file is generated by program automatically,don't modify " "it!\n"; file << "#include \n"; - file << "using namespace drogon;\n"; for (auto &np : namespaces_) { file << "namespace " << np << "\n"; file << "{\n"; } - file << "class " << className << ":public DrTemplate<" << className + file << "class " << className << ":public drogon::DrTemplate<" << className << ">\n"; file << "{\npublic:\n\t" << className << "(){};\n\tvirtual ~" << className << "(){};\n\t" - "virtual std::string genText(const DrTemplateData &) " + "virtual std::string genText(const drogon::DrTemplateData &) " "override;\n};\n"; for (auto i = 0; i < namespaces_.size(); ++i) { @@ -355,11 +398,12 @@ void create_view::newViewHeaderFile(std::ofstream &file, void create_view::newViewSourceFile(std::ofstream &file, const std::string &className, + const std::string &namespacePrefix, std::ifstream &infile) { file << "//this file is generated by program(drogon_ctl) " "automatically,don't modify it!\n"; - file << "#include \"" << className << ".h\"\n"; + file << "#include \"" << namespacePrefix << className << ".h\"\n"; file << "#include \n"; file << "#include \n"; file << "#include \n"; @@ -372,22 +416,7 @@ void create_view::newViewSourceFile(std::ofstream &file, file << "#include \n"; file << "#include \n"; file << "#include \n"; - if (!namespaces_.empty()) - { - file << "using namespace "; - for (int i = 0; i < namespaces_.size(); ++i) - { - if (i != namespaces_.size() - 1) - { - file << namespaces_[i] << "::"; - } - else - { - file << namespaces_[i] << ";"; - } - } - file << "\n"; - } + // Find layout tag std::string layoutName; std::regex layoutReg("<%layout[ \\t]+(((?!%\\}).)*[^ \\t])[ \\t]*%>"); @@ -457,8 +486,23 @@ void create_view::newViewSourceFile(std::ofstream &file, infile.seekg(0, std::ifstream::beg); } - // std::cout<<"file pos:"<, public CommandHandler protected: std::string outputPath_{"."}; std::vector namespaces_; + bool pathToNamespaceFlag_{false}; void createViewFiles(std::vector &cspFileNames); int createViewFile(const std::string &script_filename); void newViewHeaderFile(std::ofstream &file, const std::string &className); void newViewSourceFile(std::ofstream &file, const std::string &className, + const std::string &namespacePrefix, std::ifstream &infile); }; } // namespace drogon_ctl diff --git a/drogon_ctl/templates/cmake.csp b/drogon_ctl/templates/cmake.csp index 7c06b709..ce9ef84d 100644 --- a/drogon_ctl/templates/cmake.csp +++ b/drogon_ctl/templates/cmake.csp @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.5) +cmake_minimum_required(VERSION 3.5) project([[ProjectName]] CXX) include(CheckIncludeFileCXX) @@ -6,9 +6,9 @@ include(CheckIncludeFileCXX) check_include_file_cxx(any HAS_ANY) check_include_file_cxx(string_view HAS_STRING_VIEW) if(HAS_ANY AND HAS_STRING_VIEW) - set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_STANDARD 17) else() - set(CMAKE_CXX_STANDARD 14) + set(CMAKE_CXX_STANDARD 14) endif() set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -16,22 +16,23 @@ set(CMAKE_CXX_EXTENSIONS OFF) add_executable(${PROJECT_NAME} main.cc) -########## -# If you include the drogon source code locally in your project, use this method to add drogon -# add_subdirectory(drogon) +# ############################################################################## +# If you include the drogon source code locally in your project, use this method +# to add drogon +# add_subdirectory(drogon) # target_link_libraries(${PROJECT_NAME} PRIVATE drogon) -########## +# ############################################################################## find_package(Drogon CONFIG REQUIRED) target_link_libraries(${PROJECT_NAME} PRIVATE Drogon::Drogon) if(CMAKE_CXX_STANDARD LESS 17) -#With C++14, use boost to support any and string_view - message(STATUS "use c++14") - find_package(Boost 1.61.0 REQUIRED) - target_include_directories(${PROJECT_NAME} PRIVATE ${Boost_INCLUDE_DIRS}) + # With C++14, use boost to support any and string_view + message(STATUS "use c++14") + find_package(Boost 1.61.0 REQUIRED) + target_include_directories(${PROJECT_NAME} PRIVATE ${Boost_INCLUDE_DIRS}) else() - message(STATUS "use c++17") + message(STATUS "use c++17") endif() aux_source_directory(controllers CTL_SRC) @@ -39,21 +40,22 @@ aux_source_directory(filters FILTER_SRC) aux_source_directory(plugins PLUGIN_SRC) aux_source_directory(models MODEL_SRC) -file(GLOB_RECURSE SCP_LIST ${CMAKE_CURRENT_SOURCE_DIR}/views/*.csp) -foreach(cspFile ${SCP_LIST}) - message(STATUS "cspFile:" ${cspFile}) - get_filename_component(classname ${cspFile} NAME_WE) - message(STATUS "view classname:" ${classname}) - ADD_CUSTOM_COMMAND(OUTPUT ${classname}.h ${classname}.cc - COMMAND drogon_ctl - ARGS create view ${cspFile} - DEPENDS ${cspFile} - VERBATIM ) - set(VIEWSRC ${VIEWSRC} ${classname}.cc) -endforeach() +drogon_create_views(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/views + ${CMAKE_CURRENT_BINARY_DIR}) +# use the following line to create views with namespaces. +# drogon_create_views(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/views +# ${CMAKE_CURRENT_BINARY_DIR} TRUE) -target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models) -target_sources(${PROJECT_NAME} PRIVATE ${SRC_DIR} ${CTL_SRC} ${FILTER_SRC} ${VIEWSRC} ${PLUGIN_SRC} ${MODEL_SRC}) -################################ +target_include_directories(${PROJECT_NAME} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/models) +target_sources(${PROJECT_NAME} + PRIVATE + ${SRC_DIR} + ${CTL_SRC} + ${FILTER_SRC} + ${PLUGIN_SRC} + ${MODEL_SRC}) +# ############################################################################## # uncomment the following line for dynamically loading views -#set_property(TARGET ${PROJECT_NAME} PROPERTY ENABLE_EXPORTS ON) \ No newline at end of file +# set_property(TARGET ${PROJECT_NAME} PROPERTY ENABLE_EXPORTS ON) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 17554c4c..3095724d 100755 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,21 +1,5 @@ link_libraries(${PROJECT_NAME}) -file(GLOB SCP_LIST ${CMAKE_CURRENT_SOURCE_DIR}/simple_example/*.csp) -foreach(cspFile ${SCP_LIST}) - message(STATUS "cspFile:" ${cspFile}) - get_filename_component(classname ${cspFile} NAME_WE) - message(STATUS "view classname:" ${classname}) - add_custom_command(OUTPUT ${classname}.h ${classname}.cc - COMMAND drogon_ctl - ARGS - create - view - ${cspFile} - DEPENDS ${cspFile} - VERBATIM) - set(VIEWSRC ${VIEWSRC} ${classname}.cc) -endforeach() - set(simple_example_sources simple_example/CustomCtrl.cc simple_example/CustomHeaderFilter.cc @@ -34,7 +18,8 @@ set(simple_example_sources simple_example/DigestAuthFilter.cc simple_example/main.cc) -add_executable(webapp ${simple_example_sources} ${VIEWSRC}) +add_executable(webapp ${simple_example_sources}) +drogon_create_views(webapp ${CMAKE_CURRENT_SOURCE_DIR}/simple_example ${CMAKE_CURRENT_BINARY_DIR}) add_dependencies(webapp drogon_ctl) set(client_example_sources client_example/main.cc) diff --git a/lib/inc/drogon/DrTemplateBase.h b/lib/inc/drogon/DrTemplateBase.h index 7b4ffedc..380fcf7e 100644 --- a/lib/inc/drogon/DrTemplateBase.h +++ b/lib/inc/drogon/DrTemplateBase.h @@ -1,7 +1,7 @@ /** * - * DrTemplateBase.h - * An Tao + * @file DrTemplateBase.h + * @author An Tao * * Copyright 2018, An Tao. All rights reserved. * https://github.com/an-tao/drogon @@ -40,7 +40,7 @@ class DrTemplateBase : public virtual DrObjectBase * drogon_ctl tool to create c++ source files. */ static std::shared_ptr newTemplate( - std::string templateName); + const std::string &templateName); /// Generate the text string /** diff --git a/lib/src/DrTemplateBase.cc b/lib/src/DrTemplateBase.cc index 6e79e8e2..cd14d923 100644 --- a/lib/src/DrTemplateBase.cc +++ b/lib/src/DrTemplateBase.cc @@ -1,7 +1,7 @@ /** * - * DrTemplateBase.cc - * An Tao + * @file DrTemplateBase.cc + * @author An Tao * * Copyright 2018, An Tao. All rights reserved. * https://github.com/an-tao/drogon @@ -14,23 +14,50 @@ #include #include -#include #include +#include +#include using namespace drogon; std::shared_ptr DrTemplateBase::newTemplate( - std::string templateName) + const std::string &templateName) { LOG_TRACE << "http view name=" << templateName; - auto pos = templateName.find(".csp"); - if (pos != std::string::npos) + auto l = templateName.length(); + if (l >= 4 && templateName[l - 4] == '.' && templateName[l - 3] == 'c' && + templateName[l - 2] == 's' && templateName[l - 1] == 'p') { - if (pos == templateName.length() - 4) + std::string::size_type pos = 0; + std::string newName; + newName.reserve(templateName.size()); + if (templateName[0] == '/' || templateName[0] == '\\') { - templateName = templateName.substr(0, pos); + pos = 1; } + else if (templateName[0] == '.' && + (templateName[1] == '/' || templateName[1] == '\\')) + { + pos = 2; + } + while (pos < l - 4) + { + if (templateName[pos] == '/' || templateName[pos] == '\\') + { + newName.append("::"); + } + else + { + newName.append(1, templateName[pos]); + } + ++pos; + } + return std::shared_ptr(dynamic_cast( + drogon::DrClassMap::newObject(newName))); + } + else + { + return std::shared_ptr(dynamic_cast( + drogon::DrClassMap::newObject(templateName))); } - return std::shared_ptr(dynamic_cast( - drogon::DrClassMap::newObject(templateName))); } diff --git a/lib/src/HttpResponseImpl.cc b/lib/src/HttpResponseImpl.cc index 09bb49b6..5f71254c 100644 --- a/lib/src/HttpResponseImpl.cc +++ b/lib/src/HttpResponseImpl.cc @@ -1,7 +1,7 @@ /** * * @file HttpResponseImpl.cc - * An Tao + * @author An Tao * * Copyright 2018, An Tao. All rights reserved. * https://github.com/an-tao/drogon @@ -45,7 +45,7 @@ static inline void doResponseCreateAdvices( } } } -static inline HttpResponsePtr genHttpResponse(std::string viewName, +static inline HttpResponsePtr genHttpResponse(const std::string &viewName, const HttpViewData &data) { auto templ = DrTemplateBase::newTemplate(viewName); diff --git a/test.sh b/test.sh index 812950da..3d8e8b4e 100755 --- a/test.sh +++ b/test.sh @@ -118,6 +118,10 @@ if [ ! -f "Test_TestPlugin.h" -o ! -f "Test_TestPlugin.cc" ]; then exit -1 fi +cd ../views + +echo "Hello, world!" >> hello.csp + cd ../build cmake .. $cmake_gen