Changed documentation. a lot.

Added mkdocs documentation.
Altered doxygen generation (doxyfile and shell script) to work with mkdocs.
Removed the whole html folder thing for docs, now the files reside in the root gh-pages branch.
New readme.
This commit is contained in:
The-EDev 2020-11-28 17:28:47 +03:00
parent 896ec0621b
commit 23648445f3
27 changed files with 794 additions and 87 deletions

0
.gitmodules vendored
View File

View File

@ -30,14 +30,12 @@ addons:
packages: packages:
- libboost-all-dev - libboost-all-dev
- doxygen - doxygen
- doxygen-doc - mkdocs
- doxygen-latex
- doxygen-gui
- graphviz - graphviz
before_install: before_install:
- if [ "$TRAVIS_COMPILER" == "gcc" -a "$TRAVIS_CPU_ARCH" == "amd64" ]; then export PUSH_COVERAGE=ON; fi - if [ "$TRAVIS_COMPILER" == "gcc" -a "$TRAVIS_CPU_ARCH" == "amd64" ]; then export PUSH_COVERAGE=ON; fi
- if [ "$TRAVIS_BRANCH" == "master" -a "$TRAVIS_PULL_REQUEST" == "false" -a "$PUSH_COVERAGE" == "ON" ]; then export TRAVIS_BUILD_DOCS=ON; fi - if [ "$TRAVIS_BRANCH" == "master" -a "$TRAVIS_PULL_REQUEST" == "false" -a "$PUSH_COVERAGE" == "ON" ]; then export TRAVIS_BUILD_DOCS=ON; pip install mkdocs-material; fi
install: install:
- if [ "$PUSH_COVERAGE" == "ON" ]; then pip install --user cpp-coveralls; fi - if [ "$PUSH_COVERAGE" == "ON" ]; then pip install --user cpp-coveralls; fi

View File

@ -263,12 +263,6 @@ TAB_SIZE = 2
ALIASES = ALIASES =
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding "class=itcl::class"
# will allow you to use the command class in the itcl::class meaning.
TCL_SUBST =
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C. For # only. Doxygen will then generate output that is more tailored for C. For
# instance, some of the names that are used will be different. The list of all # instance, some of the names that are used will be different. The list of all
@ -990,7 +984,7 @@ FILTER_SOURCE_PATTERNS =
# (index.html). This can be useful if you have a project on for instance GitHub # (index.html). This can be useful if you have a project on for instance GitHub
# and want to reuse the introduction page also for the doxygen output. # and want to reuse the introduction page also for the doxygen output.
USE_MDFILE_AS_MAINPAGE = readme.md USE_MDFILE_AS_MAINPAGE = README.md
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to source browsing # Configuration options related to source browsing
@ -1119,7 +1113,7 @@ GENERATE_HTML = YES
# The default directory is: html. # The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = html HTML_OUTPUT = site/reference
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp). # generated HTML page (for example: .htm, .php, .asp).

113
README.md
View File

@ -1,12 +1,39 @@
![Crow logo](https://pixeldrain.com/api/file/DMc7xYye) <p align="center"><img src="https://pixeldrain.com/api/file/DMc7xYye" width=600></p>
Crow is a C++ microframework for web. (inspired by Python Flask) <h4 align="center">A Fast and Easy to use microframework for the web.</h4>
<p align="center">
<a href="https://travis-ci.com/mrozigor/crow"><img src="https://travis-ci.com/mrozigor/crow.svg?branch=master" alt="Build Status"></a>
<a href="https://coveralls.io/github/mrozigor/crow?branch=master"><img src="https://coveralls.io/repos/github/mrozigor/crow/badge.svg?branch=master" alt="Coverage Status"></a>
<a href="https://mrozigor.github.io/crow"><img src="https://img.shields.io/badge/-Documentation-informational" alt="Documentation"></a>
<a href="https://gitter.im/crowfork/community?utm_source=badge&amp;utm_medium=badge&amp;utm_campaign=pr-badge"><img src="https://badges.gitter.im/crowfork/community.svg" alt="Gitter"></a>
</p>
[![Build Status](https://travis-ci.com/mrozigor/crow.svg?branch=master)](https://travis-ci.com/mrozigor/crow)
[![Coverage Status](https://coveralls.io/repos/github/mrozigor/crow/badge.svg?branch=master)](https://coveralls.io/github/mrozigor/crow?branch=master)
[![Documentation](https://img.shields.io/badge/-Documentation-informational)](https://mrozigor.github.io/crow)
[![Gitter](https://badges.gitter.im/crowfork/community.svg)](https://gitter.im/crowfork/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
## Description
Crow is a C++ microframework for running web services. It uses routing similar to Python's Flask which makes it easy to use. It is also extremely fast, beating multiple existing C++ frameworks as well as non C++ frameworks.
### Features
- Easy Routing (similar to flask).
- Type-safe Handlers.
- Blazingly fast (see [this benchmark](https://github.com/ipkn/crow-benchmark) and [this benchmark](https://github.com/guteksan/REST-CPP-benchmark)).
- Built in JSON support.
- [Mustache](http://mustache.github.io/) based templating library (`crow::mustache`).
- Header only library (single header file available).
- Middleware support for extensions.
- HTTP/1.1 and Websocket support.
- Multi-part request and response support.
- Uses modern C++ (11/14)
### Still in development
- [HTTP/2 support](https://github.com/mrozigor/crow/issues/8)
## Documentation
Available [here](https://mrozigor.github.io/crow).
## Examples
#### Hello World
```c++ ```c++
#include "crow.h" #include "crow.h"
@ -22,32 +49,8 @@ int main()
} }
``` ```
## Features
- Easy routing
- Similiar to Flask
- Type-safe Handlers (see Example)
- Very Fast
- ![Benchmark Result in one chart](https://docs.google.com/spreadsheets/d/1KidO9XpuwCRZ2p_JRDJj2aep61H8Sh_KDOhApizv4LE/pubchart?oid=2041467789&format=image)
- More data on [crow-benchmark](https://github.com/ipkn/crow-benchmark)
- Fast built-in JSON parser (crow::json)
- You can also use [json11](https://github.com/dropbox/json11) or [rapidjson](https://github.com/miloyip/rapidjson) for better speed or readability
- [Mustache](http://mustache.github.io/) based templating library (crow::mustache)
- Header only
- All-in-one header file available
- Middleware support
- Websocket support
## Still in development
- [Informational webpage](https://mrozigor.github.io/crow) (what is crow, guides, examples, etc..)
- [HTTP/2 support](https://github.com/mrozigor/crow/issues/8)
- ~~Built-in ORM~~
- Check [sqlpp11](https://github.com/rbock/sqlpp11) if you want one.
## Examples
#### JSON Response #### JSON Response
```c++ ```cpp
CROW_ROUTE(app, "/json") CROW_ROUTE(app, "/json")
([]{ ([]{
crow::json::wvalue x; crow::json::wvalue x;
@ -57,7 +60,7 @@ CROW_ROUTE(app, "/json")
``` ```
#### Arguments #### Arguments
```c++ ```cpp
CROW_ROUTE(app,"/hello/<int>") CROW_ROUTE(app,"/hello/<int>")
([](int count){ ([](int count){
if (count > 100) if (count > 100)
@ -68,7 +71,7 @@ CROW_ROUTE(app,"/hello/<int>")
}); });
``` ```
Handler arguments type check at compile time Handler arguments type check at compile time
```c++ ```cpp
// Compile error with message "Handler type is mismatched with URL paramters" // Compile error with message "Handler type is mismatched with URL paramters"
CROW_ROUTE(app,"/another/<int>") CROW_ROUTE(app,"/another/<int>")
([](int a, int b){ ([](int a, int b){
@ -77,7 +80,7 @@ CROW_ROUTE(app,"/another/<int>")
``` ```
#### Handling JSON Requests #### Handling JSON Requests
```c++ ```cpp
CROW_ROUTE(app, "/add_json") CROW_ROUTE(app, "/add_json")
.methods("POST"_method) .methods("POST"_method)
([](const crow::request& req){ ([](const crow::request& req){
@ -91,47 +94,17 @@ CROW_ROUTE(app, "/add_json")
}); });
``` ```
## How to Build More examples can be found [here](https://github.com/mrozigor/crow/tree/master/examples).
If you just want to use crow, generate `crow_all.h` (use script `scripts/merge_all.py`) and include it. ## Setting Up / Building
Available [here](https://mrozigor.github.io/crow/getting_started/setup).
### Requirements
- C++ compiler with good C++14 support.
- Tested on g++-9.3 and clang-7.0, AMD64 (x86_64) and Arm64 v8
- boost 1.7 library.
- (optional) CMake to build tests and/or examples.
- (optional) Linking with tcmalloc/jemalloc is recommended for speed.
### Building (Tests, Examples)
Out-of-source build with CMake is recommended.
```
mkdir build
cd build
cmake ..
make
```
You can run tests with following commands:
```
ctest
```
### Installing missing dependencies
#### Ubuntu
sudo apt-get install build-essential libtcmalloc-minimal4 && sudo ln -s /usr/lib/libtcmalloc_minimal.so.4 /usr/lib/libtcmalloc_minimal.so
#### OSX
brew install boost google-perftools
### Attributions ### Attributions
Crow uses the following libraries. Crow uses the following libraries.
http-parser http-parser (used for converting http strings to crow::request objects)
https://github.com/nodejs/http-parser https://github.com/nodejs/http-parser
@ -160,7 +133,7 @@ Crow uses the following libraries.
IN THE SOFTWARE. IN THE SOFTWARE.
qs_parse qs_parse (used for reading query string parameters)
https://github.com/bartgrantham/qs_parse https://github.com/bartgrantham/qs_parse
@ -175,7 +148,7 @@ Crow uses the following libraries.
all copies or substantial portions of the Software. all copies or substantial portions of the Software.
TinySHA1 TinySHA1 (used during the websocket handshake, not for security)
https://github.com/mohaps/TinySHA1 https://github.com/mohaps/TinySHA1

70
docs/assets/crowlogo.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/assets/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

66
docs/assets/favicon.svg Normal file
View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="95mm"
height="95mm"
viewBox="0 0 95 95"
version="1.1"
id="svg8"
sodipodi:docname="crowbirdlight.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.98994949"
inkscape:cx="148.31628"
inkscape:cy="216.73575"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1007"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-52.906909,-78.735456)">
<path
style="fill:#ffffff;stroke-width:0.0846667;fill-opacity:1"
d="m 71.571997,171.19568 c -3.572219,-2.5391 -6.958416,-4.99717 -7.297368,-5.29725 l -0.255219,-0.22595 0.463991,-1.397 c 0.255194,-0.76835 1.834897,-5.5499 3.510451,-10.62566 3.505253,-10.61849 6.335239,-19.079 8.227096,-24.59567 1.239876,-3.61549 1.312204,-3.86077 1.176445,-3.98957 -0.07956,-0.0755 -2.002027,-1.49736 -4.272152,-3.15973 -2.270126,-1.66237 -4.127501,-3.03677 -4.127501,-3.05422 0,-0.0174 0.447675,-0.17021 0.994834,-0.33945 4.886112,-1.51137 7.962219,-2.73416 9.445623,-3.75477 0.362819,-0.24963 0.387836,-0.2923 0.440626,-0.75162 0.254599,-2.21523 1.509656,-5.3475 3.28228,-8.19164 0.769332,-1.23437 1.327539,-1.89818 2.310037,-2.74704 1.807481,-1.56165 2.634149,-2.51067 2.87318,-3.298457 l 0.06174,-0.20349 -2.402627,0.0407 c -0.884406,-0.0983 -3.436624,1.252417 -4.036603,1.362387 -0.186563,0.0342 0.182778,-0.48865 0.827027,-0.8947 0.608067,-0.383237 2.967885,-1.868996 2.967885,-1.997926 0,-0.15087 -1.203166,0.2373 -2.304491,0.84657 -1.380268,0.763599 -2.708103,1.732686 -3.500379,2.442516 -0.395318,0.35418 -0.527363,0.47539 -0.576329,0.38396 -0.06369,-0.11892 1.312215,-2.814056 2.077584,-4.104836 0.984944,-1.661076 1.899268,-2.849086 2.965763,-3.853476 0.843653,-0.79454 1.169069,-1.00799 2.819519,-1.84946 0.6985,-0.35612 1.337903,-0.70012 1.420901,-0.76444 0.08299,-0.0643 0.438345,-0.85281 0.789669,-1.7522 0.762127,-1.95101 1.125034,-2.52632 2.402087,-3.80797 1.702596,-1.70871 3.541031,-2.68504 7.45234,-3.95765 2.632654,-0.85657 3.351464,-1.00385 5.868544,-1.20244 1.91219,-0.15087 2.39954,-0.16398 3.09033,-0.0831 3.13159,0.36649 5.80893,1.54633 9.04058,3.98397 0.85831,0.64742 1.46873,1.21026 2.54753,2.34895 0.78031,0.82364 1.59139,1.60837 1.80239,1.74385 0.48283,0.31002 1.36664,0.63352 2.66964,0.97715 2.19445,0.57872 3.18724,0.98741 4.488,1.84752 3.01295,1.99228 4.94472,5.175526 5.50942,9.078652 0.16952,1.17171 0.12699,3.48039 -0.0873,4.74136 -0.6988,4.11128 -2.69437,8.25567 -5.88294,12.21763 -2.65138,3.29447 -6.19099,6.58361 -9.38246,8.71852 -0.38426,0.25705 -1.69459,0.97024 -2.91184,1.58486 -2.34712,1.18513 -3.18189,1.65693 -3.57412,2.02002 -0.32252,0.29857 -4.7335,1.93493 -5.57734,3.13278 -1.4867,2.11039 -2.81695,9.84328 -3.87325,13.56096 l -0.86395,3.04071 1.60672,2.35209 c 0.88369,1.29365 3.39835,4.98099 5.58814,8.19409 5.88176,8.63041 5.30521,7.83167 5.65314,7.83167 0.16249,0 1.33262,-0.0797 2.60029,-0.17705 3.58462,-0.27535 5.36791,-0.16751 6.66165,0.4029 0.53171,0.23444 1.31143,0.79856 1.44267,1.04376 0.0828,0.15478 0.0726,0.16086 -0.13666,0.0813 -0.1244,-0.0473 -0.35049,-0.21254 -0.53149,-0.32585 -0.60447,-0.37843 -0.80593,-0.43812 -2.50665,-0.55585 -1.41918,0.003 -3.18867,0.13023 -3.62073,0.26008 -0.35615,0.10703 0.0151,0.17949 1.19163,0.23259 1.82677,0.0824 3.32001,0.3425 4.45473,0.77585 0.34294,0.13097 0.37119,0.21293 0.56494,0.52514 0.24967,0.40148 0.44912,0.77 0.6691,1.1632 0,0.0755 -0.31013,-0.0966 -0.93952,-0.52131 -0.50651,-0.34182 -0.66835,-0.3991 -1.73854,-0.61535 -4.11561,-0.83164 -9.67012,-0.84815 -12.8894,-0.0383 -0.60141,0.1513 -0.83385,0.17774 -0.96159,0.10937 -0.23979,-0.12833 -0.12667,-0.19934 0.78105,-0.49027 0.97335,-0.31197 2.06406,-0.85524 2.10087,-1.04641 0.0148,-0.0767 -0.88293,-1.46501 -1.99488,-3.08513 -1.11197,-1.62011 -2.98963,-4.35536 -4.17261,-6.07833 -1.18298,-1.72297 -3.10541,-4.52332 -4.27208,-6.223 l -2.121217,-3.09033 -0.561707,-0.0557 c -0.672863,-0.0668 -0.65693,-0.61032 -1.066759,-1.02015 -0.393624,-0.39363 -0.327565,-0.76458 -0.321727,-1.56889 0.0042,-0.58339 0.04272,-0.93417 0.237368,-2.88281 0.343284,-3.43671 0.648721,-11.14728 0.594721,-11.20128 -0.0118,-0.0119 -2.390554,0.778 -2.736553,0.88937 -4.142858,1.33368 -6.369262,1.9958 -6.719782,1.99843 -0.142629,0.001 -0.754625,0.0789 -1.359992,0.173 -0.605367,0.0941 -2.23724,0.3376 -3.626375,0.54116 -1.389143,0.20355 -2.545901,0.39029 -2.570573,0.41496 -0.02467,0.0247 -0.360833,1.771 -0.747034,3.88073 -0.386197,2.10973 -0.955554,5.16937 -1.26524,6.79921 -0.976296,5.13812 -2.064443,10.8145 -2.669894,13.92766 -0.548282,2.8192 -1.290101,6.64221 -1.872882,9.652 -0.288412,1.48953 -0.318055,1.60918 -0.398208,1.60737 -0.03179,-8.5e-4 -1.356829,-0.92465 -2.944538,-2.05317 z"
id="path26"
sodipodi:nodetypes="cscsssssscsssssccsssssssssssssscsssssscsssssscssscsssscscsccsssssssssccssscccsssssssccc" />
<path
style="fill:#ffffff;fill-opacity:1;stroke-width:0.0846667"
d="m 103.24635,166.01478 c -4.1e-4,-0.0172 0.42481,-0.16375 0.94495,-0.32557 0.52013,-0.16182 0.99458,-0.31099 1.05432,-0.33149 0.0849,-0.0292 0.0862,-0.0768 0.006,-0.21787 -0.20866,-0.36832 -10.950188,-15.72058 -11.242607,-16.06842 -0.05962,-0.0709 -0.295982,-0.2506 -0.52525,-0.39928 -0.895092,-0.58043 -0.863337,-1.85618 -0.80318,-3.21042 0.02658,-0.59894 0.771215,-5.06795 1.491861,-9.39694 l 0.297644,-1.78798 c 0,0 -0.607552,-0.94689 3.600609,-2.41413 0.343222,-0.11967 0.633892,-0.20822 0.645912,-0.19675 0.012,0.0114 0.616817,1.86077 0.21254,4.03222 l -0.706969,3.79731 c 0,0 0,0 -0.417463,1.55135 -0.663151,2.46437 -0.798564,3.08375 -1.610943,5.38562 -0.439112,1.24422 -0.6823,2.26031 -0.70158,2.3144 -0.01927,0.0541 0.198595,0.47031 0.484162,0.92491 0.285576,0.4546 2.107625,3.3418 4.049014,6.41599 4.99398,7.90797 5.77721,9.08693 5.98879,9.01462 0.0719,-0.0245 0.36278,-0.14845 0.64644,-0.27532 0.58431,-0.2613 2.24506,-0.77345 3.30998,-1.02073 l 0.71353,-0.16568 0.42505,0.25623 0.42502,0.25623 -0.77419,0.0186 c -0.86578,0.0208 -1.566,0.15966 -1.70733,0.33853 -0.0785,0.0994 0.0348,0.1144 0.69539,0.0922 0.43405,-0.0144 1.19084,-0.0306 1.68176,-0.0354 l 0.89256,-0.009 0.33,0.29661 c 0.12162,0.10931 0.19804,0.18983 0.23555,0.25196 0.0376,0.0621 0.0362,0.10584 0.002,0.14154 -0.034,0.0357 -0.0753,0.053 -0.13356,0.0519 -0.0583,-0.002 -0.13345,-0.0211 -0.23537,-0.0598 -0.91405,-0.34638 -2.21414,-0.39029 -3.79182,-0.12849 -0.90397,0.15025 -2.41249,0.49222 -2.5411,0.57605 -0.0392,0.0255 -0.66947,0.11443 -1.40058,0.19738 -1.49048,0.16924 -1.54048,0.17343 -1.54153,0.1296 z"
id="path28"
sodipodi:nodetypes="sssssssscscscsssssssscccsscccsssscsscss" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -0,0 +1,105 @@
This page explains how to set Crow up for use with your porject.
##Requirements
- C++ compiler with good C++14 support.
- Continuous Testing on g++-9.3 and clang-7.0, AMD64 (x86_64) and Arm64 v8
- C++11 should also work.
- boost library (1.70 or later).
- (optional) CMake and Python3 to build tests and/or examples.
- (optional) Linking with jemalloc/tcmalloc is recommended for speed.
<br><br>
##Installing Requirements
###Ubuntu
`sudo apt-get install libboost-all-dev`
###OSX
`brew install boost`
###Windows
Download boost from [here](https://www.boost.org/) and install it
##Downloading
Either run `git clone https://github.com/mrozigor/crow.git` or download `crow_all.h` from the releases section. You can also download a zip of the project on github.
##Includes folder
1. Copy the `/includes` folder to your project's root folder.
2. Add `#!cpp #include "path/to/includes/crow.h"` to your `.cpp` file.
3. For any middlewares, add `#!cpp #include "path/to/includes/middlewares/some_middleware.h"`.
<br><br>
##Single header file
If you've downloaded `crow_all.h`, you can skip to step 4.
1. Make sure you have python 3 installed.
2. Open a terminal (or `cmd.exe`) instance in `/path/to/crow/scripts`.
3. Run `python merge_all.py ../include crow_all.h` (replace `/` with `\` if you're on Windows).
4. Copy the `crow_all.h` file to where you put your libraries (if you don't know where this is, you can put it anywhere).
5. Add `#!cpp #include "path/to/crow_all.h"` to your `.cpp` file.
<br><br>
**Note**: All middlewares are included with the merged header file, if you would like to include or exclude middlewares use the `-e` or `-i` arguments.
<br><br>
##building via CLI
To build a crow Project, do the following:
###GCC (G++)
- Release: `g++ main.cpp -lpthread -lboost_system`.
- Debug: `g++ main.cpp -ggdb -lpthread -lboost_system -D CROW_ENABLE_DEBUG`.
- SSL: `g++ main.cpp -lssl -lpthread -lboost_system -D CROW_ENABLE_SSL`.
###Clang
- Release: `clang++ main.cpp -lpthread -lboost_system`.
- Debug: `clang++ main.cpp -g -lpthread -lboost_system -DCROW_ENABLE_DEBUG`.
- SSL: `clang++ main.cpp -lssl -lpthread -lboost_system -DCROW_ENABLE_SSL`.
###Microsoft Visual Studio
***Help needed***
##building via CMake
Add the following to your `CMakeLists.txt`:
``` cmake linenums="1"
find_package(Threads)
find_package(OpenSSL)
if(OPENSSL_FOUND)
include_directories(${OPENSSL_INCLUDE_DIR})
endif()
if (NOT CMAKE_BUILD_TYPE)
message(STATUS "No build type selected, default to Release")
set(CMAKE_BUILD_TYPE "Release")
endif()
if (MSVC)
set(Boost_USE_STATIC_LIBS "On")
find_package( Boost 1.70 COMPONENTS system thread regex REQUIRED )
else()
find_package( Boost 1.70 COMPONENTS system thread REQUIRED )
endif()
include_directories(${Boost_INCLUDE_DIR})
set(PROJECT_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include)
include_directories("${PROJECT_INCLUDE_DIR}")
```
**Note**: The last 2 lines are unnecessary if you're using `crow_all.h`.
##Building Crow tests and examples
Out-of-source build with CMake is recommended.
```
mkdir build
cd build
cmake ..
make
```
Running Cmake will create `crow_all.h` file and place it in the build directory.
You can run tests with following commands:
```
ctest -V
```

View File

@ -0,0 +1,55 @@
This page shows how you can get started with a simple hello world application.
##1. Include
Starting with an empty `main.cpp` file, add `#!cpp #include "crow.h"` or `#!cpp #include "crow_all.h"` if you're using the single header file.
##2. App declaration
Next Create a `main()` and declare a `#!cpp crow::SimpleApp` inside, your code should look like this
``` cpp
int main()
{
crow::SimpleApp app;
}
```
The App (or SimpleApp) class organizes all the different parts of Crow and provides the developer (you) a simple interface to interact with these parts.
For more information, please go [here](/guides/app).
##3. Adding routes
Once you have your app, the next step is to add routes (or endpoints). You can do so with the `CROW_ROUTE` macro.
``` cpp
CROW_ROUTE(app, "/")([](){
return "Hello world";
});
```
For more details on routes, please go [here](/guides/routes).
#4. Running the app
Once you're happy with how you defined all your routes, you're going to want to instruct Crow to run your app. This is done using the `run()` method.
``` cpp
app.port(18080).multithreaded().run();
```
Please note that the `port()` and `multithreaded()` methods aren't needed, <del>we just put them there to confuse you.</del> Though not using `port()` will cause the default port (`80`) to be used.<br>
If you are using the default port, you can use `localhost` instead of `localhost:80` in your browser or client.<br>
##Putting it all together
Once you've followed all the steps above, your code should look similar to this
``` cpp linenums="1"
#include "crow.h"
//#include "crow_all.h"
int main()
{
crow::SimpleApp app; //define your crow application
//define your endpoint at the root directory
CROW_ROUTE(app, "/")([](){
return "Hello world";
});
//set the port, set the app to run on multiple threads, and run the app
app.port(18080).multithreaded().run();
}
```
After building and running your .cpp file, you should be able to access your endpoint at [http://localhost:18080](http://localhost:18080). Opening this URL in your browser will show a white screen with "Hello world" typed on it.

29
docs/guides/app.md Normal file
View File

@ -0,0 +1,29 @@
A Crow app defines an interface to allow the developer access to all the different parts of the framework, without having to manually deal with each one.<br><br>
An app allows access to the http server (for handling connections), router (for handling URLs and requests), Middlewares (for extending Crow), amoung many others.<br><br>
Crow has 2 different app types:
##SimpleApp
Has no middlewares.
##App&lt;m1, m2, ...&gt;
Has middlewares.
##Using the app
To use a Crow app, simply define `#!cpp crow::SimpleApp` or `#!cpp crow::App<m1, m2 ...>` if you're using middlewares.<br>
The methods of an app can be chained. That means that you can configure and run your app in the same code line.
``` cpp
app.bindaddr(192.168.1.2).port(443).ssl_file("certfile.crt","keyfile.key").multithreaded().run();
```
Or if you like your code neat
``` cpp
app.bindaddr(192.168.1.2)
.port(443)
.ssl_file("certfile.crt","keyfile.key")
.multithreaded()
.run();
```
<br><br>
For more info on middlewares, check out [this page](/guides/middleware).<br><br>
For more info on what functions are available to a Crow app, go [here](/reference/classcrow_1_1_crow.html).

29
docs/guides/json.md Normal file
View File

@ -0,0 +1,29 @@
Crow has built in support for JSON data.<br><br>
##rvalue
JSON read value, used for taking a JSON string and parsing it into `crow::json`.<br><br>
You can read individual items of the rvalue, but you cannot add items to it.<br>
To do that, you need to convert it to a `wvalue`, which can be done by simply writing `#!cpp crow::json::wvalue wval (rval);` (assuming `rval` is your `rvalue`).<br><br>
For more info on read values go [here](/reference/classcrow_1_1json_1_1rvalue.html).<br><br>
#wvalue
JSON write value, used for creating, editing and converting JSON to a string.<br><br>
The types of values that `wvalue` can take are as follows:<br>
- `False`: from type `bool`.
- `True`: from type `bool`.
- `Number`
- `Floating_point`: from type `double`.
- `Signed_integer`: from type `int`.
- `Unsigned_integer`: from type `unsigned int`.
- `String`: from type `std::string`.
- `List`: from type `std::vector`.
- `Object`: from type `crow::json::wvalue`.<br>
This last type means that `wvalue` can have keys, this is done by simply assigning a value to whatever string key you like, something like `#!cpp wval["key1"] = val1;`. Keep in mind that val1 can be any of the above types.<br><br>
A JSON wvalue can be returned directly inside a route handler, this will canse the `content-type` header to automatically be set to `Application/json` and the JSON value will be converted to string and placed in the response body. For more information go to [Routes](/guides/routes).<br><br>
For more info on write values go [here](/reference/classcrow_1_1json_1_1wvalue.html).

20
docs/guides/logging.md Normal file
View File

@ -0,0 +1,20 @@
Crow comes with a simple and easy to use logging system.<br><br>
##Setting up logging level
You can set up the level at which crow displays logs by using the app's `loglevel(crow::logLevel)` method.<br><br>
The available log levels are as follows (please not that setting a level will also display all logs below this level):
- Debug
- Info
- Warning
- Error
- Critical
<br><br>
To set a logLevel, just use `#!cpp app.loglevel(crow::logLevel::Warning)`, This will not show any debug or info logs. It will however still show error and critical logs.<br><br>
Please note that setting the Macro `CROW_ENABLE_DEBUG` during compilation will also set the log level to `Debug`.
##Writing a log
Writing a log is as simple as `#!cpp CROW_LOG_<LOG LEVEL> << "Hello";` (replace&lt;LOG LEVEL&gt; with the actual level in all caps, so you have `CROW_LOG_WARNING`).

29
docs/guides/middleware.md Normal file
View File

@ -0,0 +1,29 @@
Any middleware requires following 3 members:
##struct context
Storing data for the middleware; can be read from another middleware or handlers
##before_handle
Called before handling the request.<br>
If `res.end()` is called, the operation is halted. (`after_handle` will still be called)<br>
2 signatures:<br>
`#!cpp void before_handle(request& req, response& res, context& ctx)`
if you only need to access this middleware's context.
``` cpp
template <typename AllContext>
void before_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
```
You can access other middlewares' context by calling `#!cpp all_ctx.template get<MW>()`<br>
`#!cpp ctx == all_ctx.template get<CurrentMiddleware>()`
##after_handle
Called after handling the request.<br>
`#!cpp void after_handle(request& req, response& res, context& ctx)`
``` cpp
template <typename AllContext>
void after_handle(request& req, response& res, context& ctx, AllContext& all_ctx)
```
<br><br>
This was pulled from `cookie_parser.h`. Further Editing required, possibly use parts of [@ipkn's wiki page](https://github.com/ipkn/crow/wiki/Middleware).

20
docs/guides/multipart.md Normal file
View File

@ -0,0 +1,20 @@
Multipart is a way of forming HTTP requests or responses to contain multiple distinct parts.<br>
Such an approach allows a request to contain multiple different pieces of data with potentially conflicting data types in a single response payload.<br>
It is typically used either in html forms, or when uploading multiple files.<br><br>
The structure of a multipart request is typically consistent of:<br>
- A Header: Typically `multipart/form-data;boundary=<boundary>`, This defines the HTTP message as being multipart, as well as defining the separator used to distinguish the different parts.<br>
- 1 or more parts:
- `--<boundary>`
- Part header: typically `content-disposition: mime/type; name="<fieldname>"` (`mime/type` should be replaced with the actual mime-type), can also contain a `filename` property (separated from the rest by a `;` and structured similarly to the `name` property)
- Value
- `--<boundary>--`<br><br>
Crow supports multipart requests and responses though `crow::multipart::message`.<br>
A message can be created either by defining the headers, boundary, and individual parts and using them to create the message. or simply by reading a `crow::request`.<br><br>
Once a multipart message has been made, the individual parts can be accessed throught `mpmes.parts`, `parts` is an `std::vector`, so accessing the individual parts should be straightforward.<br>
In order to access the individual part's name or filename, something like `#!cpp mpmes.parts[0].headers[0].params["name"]` sould do the trick.<br><br>
For more info on Multipart messages, go [here](/reference/namespacecrow_1_1multipart.html)

1
docs/guides/proxies.md Normal file
View File

@ -0,0 +1 @@
***HELP NEEDED***

46
docs/guides/routes.md Normal file
View File

@ -0,0 +1,46 @@
Routes define what happens when your client connects to a certain URL.<br>
##Macro
`CROW_ROUTE(app, url)`<br>
Can be replaced with `#!cpp app.route<crow::black_magick::get_parameter_tag(url)>(url)` or `#!cpp app.route_dynamic(url)` if you're using VS2013 or want runtime url evaluation. Although this usage is **NOT** recommended.
##App
Which app class to assign the route to.
##Path (URL)
Which relative path is assigned to the route.<br>
Using `/hello` means the client will need to access `http://example.com/hello` in order to access the route.<br>
A path can have parameters, for example `/hello/<int>` will allow a client to input an int into the url which will be in the handler (something like `http://example.com/hello/42`).<br>
Parameters can be `<int>`, `<uint>`, `<double>`, `<string>`, or `<path>`.<br>
It's worth nothing that the parameters also need to be defined in the handler, an example of using parameters would be to add 2 numbers based on input:
```cpp
CROW_ROUTE(app, "/add/<int>/<int>")
([](int a, int b)
{
return std::to_string(a+b);
});
```
you can see the first `<int>` is defined as `a` and the second as `b`. If you were to run this and call `http://example.com/add/1/2`, the result would be a page with `3`. Exciting!
##Handler
Basically a piece of code that gets executed whenever the client calls the associated route, usually in the form of a [lambda expression](https://en.cppreference.com/w/cpp/language/lambda). It can be as simple as `#!cpp ([](){return "Hello World"})`.<br><br>
###Request
Handlers can also use information from the request by adding it as a parameter `#!cpp ([](const crow::request& req){...})`.<br><br>
You can also access the url parameters in the handler using `#!cpp req.url_params.get("param_name");`. If the parameter doesn't exist, `nullptr` is returned.<br><br>
For more information on `crow::request` go [here](/reference/structcrow_1_1request.html).<br><br>
###Response
Crow also provides the ability to define a response in the parameters by using `#!cpp ([](const crow::request& req, crow::response& res){...})`.<br>
If you don't want to use the request you can write `#!cpp ([](const crow::request& , crow::response& res){...})`.<br>
Yes I know there's a pull request to make it as simple as `#!cpp ([](crow::response& res){...})`, but I can't test it and add it to the repository while writing this documentation.<br><br>
Please note that in order to return a response defined as a parameter you'll need to use `res.end();`.<br><br>
Alternatively, you can define the response in the body and return it (`#!cpp ([](){return crow::response()})`).<br>
For more information on `crow::response` go [here](/reference/structcrow_1_1response.html).<br><br>
###return statement
A `crow::response` is very strictly tied to a route. If you can have something in a response constructor, you can return it in a handler.<br><br>
The main return type is `std::string`. although you could also return a `crow::json::wvalue` directly. ***(Support for more data types including third party libraries is coming soon)***<br><br>
For more information on the specific constructors for a `crow::response` go [here](/reference/structcrow_1_1response.html).

10
docs/guides/ssl.md Normal file
View File

@ -0,0 +1,10 @@
Crow supports HTTPS though SSL or TLS.<br><br>
When mentioning SSL in this documentation, it is often a reference to openSSL, which includes TLS. Don't worry, we don't use obsolete security standards :)<br><br>
To enable SSL, first your application needs to define either a `.crt` and `.key` files, or a `.pem` file. Once you have your files, you can add them to your app like this:<br>
`#!cpp app.ssl_file("/path/to/cert.crt", "/path/to/keyfile.key")` or `#!cpp app.ssl_file("/path/to/pem_file.pem")`. Please note that this method can be part of the app method chain, which means it can be followed by `.run()` or any other method.<br><br>
You can also set your own SSL context (by using `boost::asio::ssl::context ctx`) and then applying it via the `#!cpp app.ssl(ctx)` method.<br><br>
**IMPORTANT NOTICE**: If you plan on using a proxy like Nginx or Apache2, **DO NOT** use SSL in crow, instead define it in your proxy instead and keep the connection between the proxy and Crow non-SSL.

14
docs/guides/static.md Normal file
View File

@ -0,0 +1,14 @@
A static file is any file that resides in the server's storage.
Crow supports returning Static files as responses in 2 ways.
##Implicit
Crow implicitly returns any static files placed in a `static` directory and any subdirectories, as long as the user calls the endpoint `/static/path/to/file`.<br><br>
The static folder or endpoint can be changed by defining the macros `CROW_STATIC_DRIECTORY "alternative_directory/"` and `CROW_STATIC_ENDPOINT "/alternative_endpoint/<path>"`.<br>
static directory changes the directory in the server's filesystem, while the endpoint changes the URL that the client needs to access.
##Explicit
You can directly return a static file by using the `crow::response` method `#!cpp response.set_static_file_info("path/to/file");`. The path is relative to the executable unless preceded by `/`, then it is an absolute path.<br>
Please keep in mind that using the `set_static_file_info` method does invalidate any data already in your response body.<br><br>
**Note**: Crow sets the `content-type` header automatically based on the file's extension, if an extension is unavailable or undefined, Crow uses `text/plain`, if you'd like to explicitly set a `content-type`, use `#!cpp response.set_header("content-type", "mime/type");` **AFTER** calling `set_static_file_info`.

1
docs/guides/syste.md Normal file
View File

@ -0,0 +1 @@
https://www.howtogeek.com/687970/how-to-run-a-linux-program-at-startup-with-systemd/

23
docs/guides/templating.md Normal file
View File

@ -0,0 +1,23 @@
Templating is when you return an html page with custom data. You can probably tell why that's useful.<br><br>
Crow supports [mustache](http://mustache.github.io) for templates through its own implementation `crow::mustache`.<br><br>
##Components of mustache
There are 2 components of a mustaceh template:
- Page
- Context
###Page
The HTML page (including the mustache tags). usually loaded into `crow::mustache::template_t` Needs to be placed in "templates" directory (relative to where the crow executable is).<br><br>
For more inforation on how to formulate a template, see [this mustache manual](http://mustache.github.io/mustache.5.html).
###Context
A JSON object containing the tags as keys and their values. `crow::mustache::context` is actually a [crow::json::wvalue](/guides/json#wvalue).
##Returning a template
To return a mustache template, you need to load a page using `#!cpp auto page = crow::mustache::load("path/to/template.html");`, keep in mind that the path is relative to the templates directory.<br>
You also need to set up the context by useing `#!cpp crow::mustache::context ctx;`. Then you need to assign the keys and values, this can be done the same way you assign values to a json write value (`ctx["key"] = value;`).<br>
With your context and page ready, just `#!cpp return page.render(ctx);`. This will use the context data to return a filled template.

31
docs/guides/websockets.md Normal file
View File

@ -0,0 +1,31 @@
Websockets are a way of connecting a client and a server without the request response nature of HTTP.<br><br>
To create a websocket in Crow, you need a websocket route.<br>
A websocket route differs from a normal route quite a bit. While it uses the same `CROW_ROUTE(app, "/url")` macro, that's about where the similarities end.<br>
A websocket route follows the macro with `.websocket()` which is then followed by a series of methods (with handlers inside) for each event. These are:
- `#!cpp onopen([&](crow::websocket::connection& conn){handler code goes here})`
- `#!cpp onaccept([&](const crow::request&){handler code goes here})` (This handler has to return bool)
- `#!cpp onmessage([&](crow::websocket::connection& conn, const std::string message, bool is_binary){handler code goes here})`
- `#!cpp onclose([&](crow::websocket::connection& conn, const std::string reason){handler code goes here})`
- `#!cpp onerror([&](crow::websocket::connection& conn){handler code goes here})`<br><br>
These event methods and their handlers can be chained. The full Route should look similar to this:
```cpp
CROW_ROUTE(app, "/ws")
.websocket()
.onopen([&](crow::websocket::connection& conn){
do_something();
})
.onclose([&](crow::websocket::connection& conn, const std::string& reason){
do_something();
})
.onmessage([&](crow::websocket::connection& /*conn*/, const std::string& data, bool is_binary){
if (is_binary)
do_something(data);
else
do_something_else(data);
});
```
<br><br>
For more info go [here](/reference/classcrow_1_1_web_socket_rule.html).

101
docs/index.md Normal file
View File

@ -0,0 +1,101 @@
#
<p align="center"><img src="assets/crowlogo.svg" width=600></p>
<h4 align="center">A Fast and Easy to use microframework for the web.</h4>
<p align="center">
<a href="https://travis-ci.com/mrozigor/crow"><img src="https://travis-ci.com/mrozigor/crow.svg?branch=master" alt="Build Status"></a>
<a href="https://coveralls.io/github/mrozigor/crow?branch=master"><img src="https://coveralls.io/repos/github/mrozigor/crow/badge.svg?branch=master" alt="Coverage Status"></a>
<a href="https://mrozigor.github.io/crow"><img src="https://img.shields.io/badge/-Documentation-informational" alt="Documentation"></a>
<a href="https://gitter.im/crowfork/community?utm_source=badge&amp;utm_medium=badge&amp;utm_campaign=pr-badge"><img src="https://badges.gitter.im/crowfork/community.svg" alt="Gitter"></a>
</p>
## Description
Crow is a C++ microframework for running web services. It uses routing similar to Python's Flask which makes it easy to use. It is also extremely fast, beating multiple existing C++ frameworks as well as non C++ frameworks.
### Features
- Easy Routing (similar to flask).
- Type-safe Handlers.
- Blazingly fast (see [this benchmark](https://github.com/ipkn/crow-benchmark) and [this benchmark](https://github.com/guteksan/REST-CPP-benchmark)).
- Built in JSON support.
- [Mustache](http://mustache.github.io/) based templating library (`crow::mustache`).
- Header only library (single header file available).
- Middleware support for extensions.
- HTTP/1.1 and Websocket support.
- Multi-part request and response support.
- Uses modern C++ (11/14)
### Still in development
- [HTTP/2 support](https://github.com/mrozigor/crow/issues/8)
## Documentation
Available [here](https://mrozigor.github.io/crow).
## Examples
#### Hello World
```c++
#include "crow.h"
int main()
{
crow::SimpleApp app;
CROW_ROUTE(app, "/")([](){
return "Hello world";
});
app.port(18080).multithreaded().run();
}
```
#### JSON Response
```cpp
CROW_ROUTE(app, "/json")
([]{
crow::json::wvalue x;
x["message"] = "Hello, World!";
return x;
});
```
#### Arguments
```cpp
CROW_ROUTE(app,"/hello/<int>")
([](int count){
if (count > 100)
return crow::response(400);
std::ostringstream os;
os << count << " bottles of beer!";
return crow::response(os.str());
});
```
Handler arguments type check at compile time
```cpp
// Compile error with message "Handler type is mismatched with URL paramters"
CROW_ROUTE(app,"/another/<int>")
([](int a, int b){
return crow::response(500);
});
```
#### Handling JSON Requests
```cpp
CROW_ROUTE(app, "/add_json")
.methods("POST"_method)
([](const crow::request& req){
auto x = crow::json::load(req.body);
if (!x)
return crow::response(400);
int sum = x["a"].i()+x["b"].i();
std::ostringstream os;
os << sum;
return crow::response{os.str()};
});
```
More examples can be found [here](https://github.com/mrozigor/crow/tree/master/examples).
## Setting Up / Building
Available [here](https://mrozigor.github.io/crow/getting_started/setup).

Binary file not shown.

View File

@ -0,0 +1,6 @@
:root {
--md-primary-fg-color: #161616;
--md-accent-fg-color: #396A97;
--md-typeset-a-color: var(--md-accent-fg-color);
}

View File

@ -0,0 +1,10 @@
/* Webfont: Lato-Medium */@font-face {
font-family: 'Lato';
src: url('Lato-Medium.ttf') format('truetype');
font-style: normal;
font-weight: normal;
text-rendering: optimizeLegibility;
}
body, input {
font-family: "Lato", -apple-system, Helvetica, Arial, sans-serif;
}

61
mkdocs.yml Normal file
View File

@ -0,0 +1,61 @@
site_name: Crow
# Repository
repo_name: mrozigor/crow
repo_url: https://github.com/mrozigor/crow
edit_uri: ""
theme:
name: material
palette:
- scheme: Crow
font: false
language: 'en'
features:
navigation.tabs
favicon: 'assets/favicon.svg'
logo: 'assets/favicon.svg'
icon:
repo: fontawesome/brands/github-square
markdown_extensions:
- pymdownx.highlight
- pymdownx.superfences
- pymdownx.inlinehilite
- pymdownx.keys
nav:
- Home: index.md
- Getting Started:
- Setup: getting_started/setup.md
- Your First Application: getting_started/your_first_application.md
- Guides:
- Different parts of Crow:
- App: guides/app.md
- Routes: guides/routes.md
- Logging: guides/logging.md
- JSON: guides/json.md
- Templating (Mustache): guides/templating.md
- Multipart: guides/multipart.md
- Middleware: guides/middleware.md
- SSL: guides/ssl.md
- Static Files: guides/static.md
- Websockets: guides/websockets.md
- Server setup:
- Proxies: guides/proxies.md
- Systemd run on startup: guides/syste.md
- API Reference:
- API Reference: '/reference/index.html'
extra:
social:
- icon: fontawesome/brands/github
link: https://github.com/mrozigor/crow
- icon: fontawesome/brands/gitter
link: https://gitter.im/crowfork/community
extra_css:
- 'stylesheets/colors.css'
- 'stylesheets/latofonts.css'
copyright: 'Copyright &copy; 2020 Farook Al-Sammarraie'

View File

@ -60,9 +60,15 @@ git config user.email "travis@travis-ci.org"
# stayed the same and will only update the changed files. So the gh-pages branch # stayed the same and will only update the changed files. So the gh-pages branch
# can be safely cleaned, and it is sure that everything pushed later is the new # can be safely cleaned, and it is sure that everything pushed later is the new
# documentation. # documentation.
cp index.html .. #cp index.html ..
rm -rf * rm -rf *
mv ../index.html . #mv ../index.html .
# Copy the mkdocs documentation to the work directory and generate the mkdocs
# 'site' directory
cp ../../mkdocs.yml .
cp -r ../../docs .
mkdocs build
# Need to create a .nojekyll file to allow filenames starting with an underscore # Need to create a .nojekyll file to allow filenames starting with an underscore
# to be seen on the gh-pages site. Therefore creating an empty .nojekyll file. # to be seen on the gh-pages site. Therefore creating an empty .nojekyll file.
@ -76,12 +82,21 @@ echo 'Generating Doxygen code documentation...'
# Redirect both stderr and stdout to the log file AND the console. # Redirect both stderr and stdout to the log file AND the console.
doxygen $DOXYFILE 2>&1 | tee doxygen.log doxygen $DOXYFILE 2>&1 | tee doxygen.log
# Rename mkdocs' output folder to 'html' to retain compatibility with the
# existing index.html and the rest of this code.
# Also remove any remaining documentation files.
mv site/* .
rm -r site
rm mkdocs.yml
rm -r docs
################################################################################ ################################################################################
##### Upload the documentation to the gh-pages branch of the repository. ##### ##### Upload the documentation to the gh-pages branch of the repository. #####
# Only upload if Doxygen successfully created the documentation. # Only upload if Doxygen successfully created the documentation.
# Check this by verifying that the html directory and the file html/index.html # Check this by verifying that the reference directory (for doxygen) and
# both exist. This is a good indication that Doxygen did it's work. # the file index.html (for mkdocs) both exist.
if [ -d "html" ] && [ -f "html/index.html" ]; then # This is a good indication that Doxygen and Mkdocs did their work.
if [ -d "reference" ] && [ -f "index.html" ]; then
echo 'Uploading documentation to the gh-pages branch...' echo 'Uploading documentation to the gh-pages branch...'
# Add everything in this directory (the Doxygen code documentation) to the # Add everything in this directory (the Doxygen code documentation) to the