mirror of
https://github.com/eclipse/upm.git
synced 2025-06-07 22:00:24 +03:00
Travis CI and Documentation Generation Improvements
* Use docker images from docker hub instead of building them on Travis * Fix doxygen warnings for Markdown Files * Modify Travis build matrix to include stages and additional jobs * Add doxygen2jsdoc submodule * Add doxyport submodule * Remove duplicated code in doxy/node directory * Generate documentation for each language in Travis Signed-off-by: Nicolas Oliver <dario.n.oliver@intel.com>
This commit is contained in:
parent
ae77966204
commit
9e09f899cf
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
[submodule "doxy/doxygen2jsdoc"]
|
||||
path = doxy/doxygen2jsdoc
|
||||
url = https://github.com/intel-iot-devkit/doxygen2jsdoc
|
||||
[submodule "doxy/doxyport"]
|
||||
path = doxy/doxyport
|
||||
url = https://github.com/intel-iot-devkit/doxyport
|
116
.travis.yml
116
.travis.yml
@ -3,45 +3,6 @@ sudo: required
|
||||
|
||||
language: cpp
|
||||
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
|
||||
env:
|
||||
- TARGET=doc
|
||||
- TARGET=python
|
||||
- TARGET=java
|
||||
- TARGET=node4
|
||||
- TARGET=node5
|
||||
- TARGET=node6
|
||||
- TARGET=android
|
||||
- TARGET=sonar-scan
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- compiler: clang
|
||||
env: TARGET=java
|
||||
- compiler: gcc
|
||||
env: TARGET=android
|
||||
- compiler: clang
|
||||
env: TARGET=sonar-scan
|
||||
include:
|
||||
- compiler: gcc
|
||||
env: GCC_VERSION=6 TARGET=doc
|
||||
- compiler: gcc
|
||||
env: GCC_VERSION=6 TARGET=python
|
||||
- compiler: gcc
|
||||
env: GCC_VERSION=6 TARGET=java
|
||||
- compiler: gcc
|
||||
env: GCC_VERSION=6 TARGET=node4
|
||||
- compiler: gcc
|
||||
env: GCC_VERSION=6 TARGET=node5
|
||||
- compiler: gcc
|
||||
env: GCC_VERSION=6 TARGET=node6
|
||||
allow_failures:
|
||||
- compiler: gcc
|
||||
env: TARGET=sonar-scan
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
@ -51,14 +12,71 @@ before_install:
|
||||
- chmod +x docker-compose
|
||||
- sudo mv docker-compose /usr/local/bin
|
||||
|
||||
before_script:
|
||||
- if [ "$CC" == "gcc" ]; then export CC=gcc-${GCC_VERSION:-5}; fi
|
||||
- if [ "$CXX" == "g++" ]; then export CXX=g++-${GCC_VERSION:-5}; fi
|
||||
- if [ "$CC" == "clang" ]; then export CC=clang-3.8; fi
|
||||
- if [ "$CXX" == "clang++" ]; then export CXX=clang++-3.8; fi
|
||||
- docker-compose build base
|
||||
- if [ "$TARGET" == "android" ]; then docker-compose build java; fi
|
||||
- docker-compose build ${TARGET}
|
||||
|
||||
script:
|
||||
jobs:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- env: TARGET=sonar-scan
|
||||
- env: TARGET=ipk
|
||||
include:
|
||||
- &run-with-clang
|
||||
stage: Clang 3.8
|
||||
env: TARGET=python
|
||||
before_script: docker-compose pull ${TARGET}
|
||||
script:
|
||||
- export CC=clang-3.8 CXX=clang++-3.8
|
||||
- docker-compose run ${TARGET}
|
||||
- <<: *run-with-clang
|
||||
env: TARGET=node4
|
||||
- <<: *run-with-clang
|
||||
env: TARGET=node5
|
||||
- <<: *run-with-clang
|
||||
env: TARGET=node6
|
||||
- <<: *run-with-clang
|
||||
env: TARGET=java
|
||||
- &run-with-gcc-5
|
||||
stage: Gcc 5
|
||||
env: TARGET=python
|
||||
before_script: docker-compose pull ${TARGET}
|
||||
script:
|
||||
- export CC=gcc-5 CXX=g++-5
|
||||
- docker-compose run ${TARGET}
|
||||
- <<: *run-with-gcc-5
|
||||
env: TARGET=node4
|
||||
- <<: *run-with-gcc-5
|
||||
env: TARGET=node5
|
||||
- <<: *run-with-gcc-5
|
||||
env: TARGET=node6
|
||||
- <<: *run-with-gcc-5
|
||||
env: TARGET=java
|
||||
- &run-with-gcc-6
|
||||
stage: Gcc 6
|
||||
env: TARGET=python
|
||||
before_script: docker-compose pull ${TARGET}
|
||||
script:
|
||||
- export CC=gcc-6 CXX=g++-6
|
||||
- docker-compose run ${TARGET}
|
||||
- <<: *run-with-gcc-6
|
||||
env: TARGET=node4
|
||||
- <<: *run-with-gcc-6
|
||||
env: TARGET=node5
|
||||
- <<: *run-with-gcc-6
|
||||
env: TARGET=node6
|
||||
- <<: *run-with-gcc-6
|
||||
env: TARGET=java
|
||||
- &run-additional-jobs
|
||||
stage: Additional Jobs
|
||||
env: TARGET=doc
|
||||
before_script: docker-compose pull ${TARGET}
|
||||
script:
|
||||
- export CC=clang-3.8 CXX=clang++-3.8
|
||||
- docker-compose run ${TARGET}
|
||||
- <<: *run-additional-jobs
|
||||
env: TARGET=android
|
||||
- <<: *run-additional-jobs
|
||||
env: TARGET=sonar-scan
|
||||
- <<: *run-additional-jobs
|
||||
env: TARGET=ipk
|
||||
- <<: *run-additional-jobs
|
||||
env: TARGET=rpm
|
||||
- <<: *run-additional-jobs
|
||||
env: TARGET=npm
|
||||
|
@ -318,7 +318,7 @@ if (BUILDDOC)
|
||||
COMMENT "Generating API documentation with Doxygen" VERBATIM
|
||||
)
|
||||
|
||||
# Check if Sphinx is installed and add target to generate API documentationa
|
||||
# Check if Sphinx is installed and add target to generate API documentation
|
||||
# Currently, the per-module documentation for python is generated from the
|
||||
# python2 modules.
|
||||
if(BUILDSWIGPYTHON)
|
||||
@ -343,14 +343,10 @@ if (BUILDDOC)
|
||||
# Check if Yuidoc is installed and add target for API documentation
|
||||
if(BUILDSWIGNODE)
|
||||
find_package(Yuidoc REQUIRED)
|
||||
file(GLOB_RECURSE JSDOC_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/doxy/node doxy/node/*)
|
||||
foreach(JSDOC_FILE ${JSDOC_FILES})
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doxy/node/${JSDOC_FILE} ${CMAKE_CURRENT_BINARY_DIR}/${JSDOC_FILE} COPYONLY)
|
||||
endforeach()
|
||||
add_custom_target(jsdoc ALL
|
||||
COMMAND ${NODEJS_EXECUTABLE} docgen -m upm -i xml -t ${CMAKE_CURRENT_SOURCE_DIR}/src -g ../../
|
||||
COMMAND ${YUIDOC_EXECUTABLE} -C --no-sort --helpers generators/yuidoc/helper.js --themedir generators/yuidoc/tmpl -o html/node jsdoc/yuidoc/upm
|
||||
COMMAND ${NODEJS_EXECUTABLE} tolower -i html/node
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/doxy/doxygen2jsdoc/docgen.js -m upm -i xml -o jsdoc -t ${CMAKE_CURRENT_SOURCE_DIR}/src -g ../../
|
||||
COMMAND ${YUIDOC_EXECUTABLE} -C --no-sort --helpers ${CMAKE_SOURCE_DIR}/doxy/node/generators/yuidoc/helper.js --themedir ${CMAKE_SOURCE_DIR}/doxy/node/generators/yuidoc/tmpl -o html/node jsdoc/yuidoc/upm
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/doxy/doxygen2jsdoc/tolower.js -i html/node
|
||||
DEPENDS doc
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Generating API documentation with Yuidoc" VERBATIM
|
||||
|
@ -3,14 +3,7 @@ version: '2.1'
|
||||
services:
|
||||
|
||||
base:
|
||||
image: upm-base
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/Dockerfile.base
|
||||
args:
|
||||
- http_proxy
|
||||
- https_proxy
|
||||
- no_proxy
|
||||
image: dnoliver/upm-base
|
||||
environment:
|
||||
- http_proxy
|
||||
- https_proxy
|
||||
@ -35,17 +28,38 @@ services:
|
||||
|
||||
doc:
|
||||
extends: base
|
||||
image: dnoliver/upm-all
|
||||
environment:
|
||||
- BUILDSWIGPYTHON=ON
|
||||
- BUILDSWIGJAVA=ON
|
||||
- BUILDSWIGNODE=ON
|
||||
- BUILDDOC=ON
|
||||
command: bash -c "./scripts/run-cmake.sh && make -j8 -Cbuild doc"
|
||||
command: bash -c "./scripts/run-cmake.sh && ./scripts/build-doc.sh"
|
||||
|
||||
ipk:
|
||||
extends: base
|
||||
environment:
|
||||
- IPK=ON
|
||||
- BUILDDOC=OFF
|
||||
command: bash -c "./scripts/run-cmake.sh && make -Cbuild -j8 package"
|
||||
|
||||
rpm:
|
||||
extends: doc
|
||||
environment:
|
||||
- RPM=ON
|
||||
- BUILDDOC=OFF
|
||||
command: bash -c "./scripts/run-cmake.sh && make -Cbuild -j8 package"
|
||||
|
||||
npm:
|
||||
extends: doc
|
||||
environment:
|
||||
- NPM=ON
|
||||
- BUILDDOC=OFF
|
||||
command: bash -c "./scripts/run-cmake.sh && make -Cbuild -j8 npmpkg"
|
||||
|
||||
sonar-scan:
|
||||
extends: base
|
||||
image: upm-sonar
|
||||
build:
|
||||
dockerfile: docker/Dockerfile.sonar
|
||||
args:
|
||||
- NODE_VERSION=v5.12.0
|
||||
image: dnoliver/upm-all
|
||||
environment:
|
||||
- BUILDSWIGPYTHON=ON
|
||||
- BUILDSWIGNODE=ON
|
||||
@ -63,52 +77,36 @@ services:
|
||||
|
||||
python:
|
||||
extends: base
|
||||
image: upm-python
|
||||
build:
|
||||
dockerfile: docker/Dockerfile.python
|
||||
image: dnoliver/upm-python
|
||||
environment:
|
||||
- BUILDSWIGPYTHON=ON
|
||||
command: bash -c "./scripts/run-cmake.sh && cd build && make -j8 && make -j8 install && ldconfig && ctest --output-on-failure"
|
||||
|
||||
java:
|
||||
extends: base
|
||||
image: upm-java
|
||||
build:
|
||||
dockerfile: docker/Dockerfile.java
|
||||
image: dnoliver/upm-java
|
||||
environment:
|
||||
- BUILDSWIGJAVA=ON
|
||||
command: bash -c "./scripts/run-cmake.sh && cd build && make -j8 && make -j8 install && ldconfig && ctest --output-on-failure"
|
||||
|
||||
android:
|
||||
extends: java
|
||||
image: upm-android
|
||||
build:
|
||||
dockerfile: docker/Dockerfile.android
|
||||
image: dnoliver/upm-android
|
||||
environment:
|
||||
- BUILDTESTS=OFF
|
||||
command: bash -c "./scripts/build-android.sh"
|
||||
|
||||
node4:
|
||||
extends: base
|
||||
image: upm-node4
|
||||
build:
|
||||
dockerfile: docker/Dockerfile.node
|
||||
args:
|
||||
- NODE_VERSION=v4.4.7
|
||||
image: dnoliver/upm-node4
|
||||
environment:
|
||||
- BUILDSWIGNODE=ON
|
||||
command: bash -c "./scripts/run-cmake.sh && cd build && make -j8 && make -j8 install && ldconfig && ctest --output-on-failure -E examplenames_js"
|
||||
|
||||
node5:
|
||||
extends: node4
|
||||
image: upm-node5
|
||||
build:
|
||||
args:
|
||||
- NODE_VERSION=v5.12.0
|
||||
image: dnoliver/upm-node5
|
||||
|
||||
node6:
|
||||
extends: node4
|
||||
image: upm-node6
|
||||
build:
|
||||
args:
|
||||
- NODE_VERSION=v6.11.0
|
||||
image: dnoliver/upm-node6
|
||||
|
@ -1,67 +0,0 @@
|
||||
FROM upm-java
|
||||
|
||||
WORKDIR /opt
|
||||
|
||||
# Install CMake 3.6.2
|
||||
RUN wget -q https://cmake.org/files/v3.6/cmake-3.6.2-Linux-x86_64.sh && \
|
||||
mkdir /opt/cmake && \
|
||||
sh /opt/cmake-3.6.2-Linux-x86_64.sh --prefix=/opt/cmake --skip-license && \
|
||||
ln -s /opt/cmake/bin/cmake /usr/local/bin/cmake && \
|
||||
cmake --version && \
|
||||
rm -fr /opt/cmake-3.6.2-Linux-x86_64.sh
|
||||
|
||||
# Android NDK build Dependencies
|
||||
RUN wget -q https://dl.google.com/android/repository/android-ndk-r14b-linux-x86_64.zip && \
|
||||
unzip -qq android-ndk-r14b-linux-x86_64.zip && \
|
||||
rm -fr android-ndk-r14b-linux-x86_64.zip
|
||||
ENV NDK_HOME /opt/android-ndk-r14b
|
||||
ENV NDK_MODULE_PATH /opt/android-ndk-r14b
|
||||
|
||||
# Android Things library
|
||||
RUN wget -q https://github.com/androidthings/native-libandroidthings/archive/0.4.1-devpreview.tar.gz && \
|
||||
tar xf 0.4.1-devpreview.tar.gz && \
|
||||
rm -fr /opt/0.4.1-devpreview.tar.gz
|
||||
ENV ANDROIDTHINGS_NATIVE_LIB /opt/native-libandroidthings-0.4.1-devpreview
|
||||
|
||||
# Build Mraa For Android Things
|
||||
RUN git clone --depth 1 https://github.com/intel-iot-devkit/mraa.git && \
|
||||
cd mraa && \
|
||||
cmake \
|
||||
-DANDROID_COMPILER_FLAGS_CXX='-std=c++11' \
|
||||
-DANDROID_PIE=1 \
|
||||
-DANDROID_PLATFORM=android-24 \
|
||||
-DANDROID_STL_FORCE_FEATURES=on \
|
||||
-DANDROID_STL=c++_shared \
|
||||
-DANDROID_TOOLCHAIN_NAME=x86-i686 \
|
||||
-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \
|
||||
-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY \
|
||||
-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=BOTH \
|
||||
-DCMAKE_FIND_ROOT_PATH=$NDK_HOME/platforms/android-24/arch-x86/ \
|
||||
-DCMAKE_MODULE_PATH=$ANDROIDTHINGS_NATIVE_LIB \
|
||||
-DCMAKE_TOOLCHAIN_FILE=$NDK_HOME/build/cmake/android.toolchain.cmake \
|
||||
-DCMAKE_INSTALL_PREFIX=/opt/mraa/install \
|
||||
-DJAVA_AWT_INCLUDE_PATH=$JAVA_HOME/include \
|
||||
-DJAVA_AWT_LIBRARY=$JAVA_HOME/jre/lib/amd64/libjawt.so \
|
||||
-DJAVA_INCLUDE_PATH=$JAVA_HOME/include \
|
||||
-DJAVA_INCLUDE_PATH2=$JAVA_HOME/include/linux \
|
||||
-DJAVA_JVM_LIBRARY=$JAVA_HOME/jre/lib/amd64/server/libjvm.so \
|
||||
-DBUILDARCH=PERIPHERALMAN \
|
||||
-DJSONPLAT=OFF \
|
||||
-DBUILDDOC=OFF \
|
||||
-DBUILDSWIG=ON \
|
||||
-DBUILDSWIGPYTHON=OFF \
|
||||
-DBUILDSWIGNODE=OFF \
|
||||
-DBUILDSWIGJAVA=ON \
|
||||
-DENABLEEXAMPLES=OFF \
|
||||
-DINSTALLGPIOTOOL=OFF \
|
||||
-DINSTALLTOOLS=OFF \
|
||||
-DBUILDTESTS=OFF \
|
||||
-H. \
|
||||
-Bbuild && \
|
||||
make -j8 -Cbuild install
|
||||
ENV MRAA_INSTALL_DIR /opt/mraa/install
|
||||
|
||||
# Set Workdir
|
||||
WORKDIR $UPM_SRC_DIR
|
||||
|
||||
CMD bash
|
@ -1,68 +0,0 @@
|
||||
FROM ubuntu:16.04
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
|
||||
# Prepare apt-get
|
||||
RUN apt-get update && apt-get -y --no-install-recommends install software-properties-common
|
||||
|
||||
# Add Mraa Repository
|
||||
RUN add-apt-repository ppa:mraa/mraa && \
|
||||
# Update apt-get
|
||||
apt-get -y update && \
|
||||
# Install apt-utils
|
||||
apt-get -y --no-install-recommends install apt-utils && \
|
||||
# Main Build Dependencies
|
||||
apt-get -y --no-install-recommends install git build-essential cmake swig clang-3.8 gcc-5 g++-5 libpthread-stubs0-dev pkg-config wget unzip \
|
||||
# Mraa Build Dependencies
|
||||
libmraa1 libmraa-dev mraa-tools \
|
||||
# Docs Build Dependencies
|
||||
python-sphinx doxygen graphviz \
|
||||
# Sensor Specific Build Dependencies
|
||||
libjpeg-dev
|
||||
|
||||
# Test Build Dependencies
|
||||
RUN apt-get -y --no-install-recommends install python python-dev python-pip && \
|
||||
pip install chardet
|
||||
|
||||
# Install gcc-6 g++-6
|
||||
RUN add-apt-repository ppa:ubuntu-toolchain-r/test && \
|
||||
apt-get update && \
|
||||
apt-get -y --no-install-recommends install gcc-6 g++-6
|
||||
|
||||
WORKDIR /opt
|
||||
|
||||
# Install libbacnet 0.3.12
|
||||
RUN wget https://downloads.sourceforge.net/project/bacnet/bacnet-stack/bacnet-stack-0.8.3/bacnet-stack-0.8.3.zip && \
|
||||
unzip -qq bacnet-stack-0.8.3.zip && cd bacnet-stack-0.8.3 && \
|
||||
BACDL_DEFINE=-DBACDL_MSTP=1 MAKE_DEFINE=-fPIC make clean all && \
|
||||
cp /opt/bacnet-stack-0.8.3/lib/libbacnet.a /usr/lib/libbacnet.a && \
|
||||
echo "prefix=/usr" >> /usr/lib/pkgconfig/libbacnet.pc && \
|
||||
echo "exec_prefix=\${prefix}" >> /usr/lib/pkgconfig/libbacnet.pc && \
|
||||
echo "libdir=\${exec_prefix}/lib" >> /usr/lib/pkgconfig/libbacnet.pc && \
|
||||
echo "includedir=\${exec_prefix}/include" >> /usr/lib/pkgconfig/libbacnet.pc && \
|
||||
echo "Name: bacnet" >> /usr/lib/pkgconfig/libbacnet.pc && \
|
||||
echo "Description: BACnet library" >> /usr/lib/pkgconfig/libbacnet.pc && \
|
||||
echo "Version: 0.8.3" >> /usr/lib/pkgconfig/libbacnet.pc && \
|
||||
echo "Libs: -L\${libdir} -lbacnet" >> /usr/lib/pkgconfig/libbacnet.pc && \
|
||||
echo "Cflags: -I\${includedir}/bacnet" >> /usr/lib/pkgconfig/libbacnet.pc && \
|
||||
mkdir /usr/include/bacnet && \
|
||||
cp /opt/bacnet-stack-0.8.3/include/* /usr/include/bacnet/ && \
|
||||
rm -fr /opt/bacnet-stack-0.8.3.zip
|
||||
|
||||
# Install libmodbus 3.1.4
|
||||
RUN wget http://libmodbus.org/releases/libmodbus-3.1.4.tar.gz && \
|
||||
tar xf libmodbus-3.1.4.tar.gz && cd libmodbus-3.1.4 && \
|
||||
./configure && make -j8 && make install && \
|
||||
rm -fr /opt/libmodbus-3.1.4.tar.gz
|
||||
|
||||
# Install openzwave
|
||||
RUN apt-get update && apt-get -y --no-install-recommends install libudev-dev && \
|
||||
git clone --depth 1 https://github.com/OpenZWave/open-zwave.git && cd open-zwave && make -j8 install && \
|
||||
echo "/usr/local/lib64" >> /etc/ld.so.conf.d/openzwave.conf
|
||||
|
||||
# Set Workdir
|
||||
ARG UPM_SRC_DIR=/usr/src/app
|
||||
ENV UPM_SRC_DIR $UPM_SRC_DIR
|
||||
WORKDIR $UPM_SRC_DIR
|
||||
|
||||
CMD bash
|
@ -1,15 +0,0 @@
|
||||
FROM upm-base
|
||||
|
||||
# Update apt-get
|
||||
RUN apt-get -y update && \
|
||||
# Java Build Dependencies
|
||||
apt-get -y --no-install-recommends install libmraa-java \
|
||||
default-jre default-jdk
|
||||
|
||||
# Configure Java Home
|
||||
ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64/
|
||||
|
||||
# Set Workdir
|
||||
WORKDIR $UPM_SRC_DIR
|
||||
|
||||
CMD bash
|
@ -1,17 +0,0 @@
|
||||
FROM upm-base
|
||||
|
||||
WORKDIR /opt
|
||||
|
||||
# Node.js Build Dependencies
|
||||
RUN wget -q -O - https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | bash
|
||||
ENV NVM_DIR /root/.nvm
|
||||
ARG NODE_VERSION
|
||||
RUN . $NVM_DIR/nvm.sh && nvm install $NODE_VERSION && nvm use $NODE_VERSION && \
|
||||
npm install -g node-gyp && node-gyp install
|
||||
ENV PATH $NVM_DIR/versions/node/$NODE_VERSION/bin:$PATH
|
||||
|
||||
# Set Workdir
|
||||
WORKDIR $UPM_SRC_DIR
|
||||
|
||||
CMD bash
|
||||
|
@ -1,16 +0,0 @@
|
||||
FROM upm-base
|
||||
|
||||
# Update apt-get
|
||||
RUN apt-get -y update && \
|
||||
# Python Build Dependencies
|
||||
apt-get -y --no-install-recommends install python-mraa python3-mraa \
|
||||
python python-dev python3 python3-dev python-pip python3-pip
|
||||
|
||||
# Install Python Test Dependencies
|
||||
RUN pip install chardet && pip3 install chardet
|
||||
|
||||
# Set Workdir
|
||||
WORKDIR $UPM_SRC_DIR
|
||||
|
||||
CMD bash
|
||||
|
@ -1,41 +0,0 @@
|
||||
FROM upm-base
|
||||
|
||||
# Update apt-get
|
||||
RUN apt-get -y update && \
|
||||
# Python Build Dependencies
|
||||
apt-get -y --no-install-recommends install python-mraa python3-mraa \
|
||||
python python-dev python3 python3-dev python-pip python3-pip \
|
||||
# Java Build Dependencies
|
||||
libmraa-java default-jre default-jdk
|
||||
|
||||
# Set JAVA_HOME
|
||||
ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64/
|
||||
|
||||
WORKDIR /opt
|
||||
|
||||
# Install Python Test Dependencies
|
||||
RUN pip install chardet && pip3 install chardet
|
||||
|
||||
# Node.js Build Dependencies
|
||||
RUN wget -q -O - https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | bash
|
||||
ENV NVM_DIR /root/.nvm
|
||||
ARG NODE_VERSION
|
||||
RUN . $NVM_DIR/nvm.sh && nvm install $NODE_VERSION && nvm use $NODE_VERSION && \
|
||||
npm install -g node-gyp && node-gyp install
|
||||
ENV PATH $NVM_DIR/versions/node/$NODE_VERSION/bin:$PATH
|
||||
|
||||
# Static Code Analysis Scanner
|
||||
ENV SONAR_DIR /opt/sonar
|
||||
ENV SONAR_VER "3.0.3.778"
|
||||
WORKDIR $SONAR_DIR
|
||||
RUN wget https://sonarsource.bintray.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SONAR_VER}-linux.zip && \
|
||||
wget https://sonarqube.com/static/cpp/build-wrapper-linux-x86.zip && \
|
||||
unzip sonar-scanner-cli-${SONAR_VER}-linux.zip && \
|
||||
unzip build-wrapper-linux-x86.zip && \
|
||||
rm sonar-scanner-cli-${SONAR_VER}-linux.zip build-wrapper-linux-x86.zip
|
||||
ENV PATH $SONAR_DIR/sonar-scanner-${SONAR_VER}-linux/bin:$SONAR_DIR/build-wrapper-linux-x86:$PATH
|
||||
|
||||
# Set Workdir
|
||||
WORKDIR $UPM_SRC_DIR
|
||||
|
||||
CMD bash
|
@ -139,61 +139,6 @@ Requirements:
|
||||
**NOTE:** docker-compose is an optional requirement. It actually make running complex
|
||||
docker build and run command easier. But you can just use docker to build and run.
|
||||
|
||||
### Docker Images Hierarchy
|
||||
|
||||
To improve build times and images sizes, upm use a build hierarchy to incrementally
|
||||
create a build environment. Find below a brief description of them:
|
||||
|
||||
1. **upm-base:** Provides the basic infrastructure and tools to compile C/C++ code and documentation.
|
||||
2. **upm-python:** Provides the python2/python3 build tools. Depends on `upm-base`.
|
||||
3. **upm-java:** Provides the Java build tools. Depends on `upm-base`.
|
||||
4. **upm-android:** Provides the Android Things build tools. Depends on `upm-java`.
|
||||
5. **upm-node4:** Provides the Node.js v4.4.7 build tools. Depends on `upm-base`.
|
||||
6. **upm-node5:** Same as `upm-node4`, but using Node.js v5.12.0.
|
||||
7. **upm-node6:** Same as `upm-node4`, but using Node.js v6.11.0.
|
||||
|
||||
**NOTE:** If you want to know which tools are installed for each of the upm targets,
|
||||
just take a look at the `docker/` folder. All the related Dockerfiles are stored there!
|
||||
|
||||
### Building Docker Images
|
||||
|
||||
**tl;dr:** Just use this commands to build the hierarchy:
|
||||
|
||||
```sh
|
||||
# Build the base image
|
||||
$ docker-compose build base
|
||||
# Build python image
|
||||
$ docker-compose build python
|
||||
# Build java image
|
||||
$ docker-compose build java
|
||||
# Build node4 image
|
||||
$ docker-compose build node4
|
||||
# Build node5 image
|
||||
$ docker-compose build node5
|
||||
# Build node6 image
|
||||
$ docker-compose build node6
|
||||
# Build android things image
|
||||
$ docker-compose build android
|
||||
```
|
||||
|
||||
**docker-compose** will take a look at the `docker-compose.yaml` file in the repository
|
||||
root directory, and build the requested target for you. At the end, docker-compose will
|
||||
tag the image built with an `upm-` prefix. You can check them by running `docker images`.
|
||||
|
||||
If you don't want to use docker-compose, you can also use `docker build` to generate every image.
|
||||
For example, to create the base image, you can do:
|
||||
|
||||
```sh
|
||||
# From the repository root folder
|
||||
$ docker build -d docker/Dockerfile.base -t upm-base .
|
||||
```
|
||||
|
||||
Now, you don't actually need to build every image to start working. Let's say you
|
||||
are a Python developer, and has no idea what Node.js is, just build the base and
|
||||
python image!
|
||||
|
||||
**NOTE:** If you work on Android Things, you will need the base, java, and android image.
|
||||
|
||||
### Using Docker Images to build Upm
|
||||
|
||||
**tl;dr:** Just use this commands to build upm:
|
||||
@ -242,7 +187,7 @@ $ docker run \
|
||||
--env BUILDSWIGPYTHON=ON \
|
||||
--env BUILDSWIGJAVA=OFF \
|
||||
--env BUILDSWIGNODE=OFF \
|
||||
upm-python \
|
||||
dnoliver/upm-python \
|
||||
bash -c "./scripts/run-cmake.sh && make -Cbuild"
|
||||
```
|
||||
|
||||
@ -256,25 +201,6 @@ to proxy settings:
|
||||
Visit [this link](https://docs.docker.com/engine/admin/systemd/#httphttps-proxy)
|
||||
to configure docker daemon behind a proxy.
|
||||
|
||||
**docker build fails to fetch packages from internet**
|
||||
|
||||
docker-compose will automatically take `http_proxy`, `https_proxy`, and `no_proxy`
|
||||
environment variables and use it as build arguments. Be sure to properly configure
|
||||
this variables before building.
|
||||
|
||||
docker, unlinke docker-compose, do not take the proxy settings from the environment
|
||||
automatically. You need to send them as build arguments:
|
||||
|
||||
```sh
|
||||
# From the repository root folder
|
||||
$ docker build \
|
||||
-d docker/Dockerfile.base \
|
||||
--build-arg http_proxy=$http_proxy \
|
||||
--build-arg https_proxy=$https_proxy \
|
||||
--build-arg no_proxy=$no_proxy \
|
||||
-t upm-base .
|
||||
```
|
||||
|
||||
**docker run fails to access the internet**
|
||||
|
||||
docker-compose will automatically take `http_proxy`, `https_proxy`, and `no_proxy`
|
||||
@ -295,6 +221,6 @@ $ docker run \
|
||||
--env http_proxy=$http_proxy \
|
||||
--env https_proxy=$https_proxy \
|
||||
--env no_proxy=$no_proxy \
|
||||
upm-python \
|
||||
dnoliver/upm-python \
|
||||
bash -c "./scripts/run-cmake.sh && make -Cbuild"
|
||||
```
|
||||
|
@ -129,8 +129,6 @@ ABBREVIATE_BRIEF = "The $name class" \
|
||||
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
|
||||
DETAILS_AT_TOP = YES
|
||||
|
||||
# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
|
||||
# inherited members of a class in the documentation of that class as if those
|
||||
# members were ordinary class members. Constructors, destructors and assignment
|
||||
@ -1861,18 +1859,6 @@ GENERATE_XML = YES
|
||||
|
||||
XML_OUTPUT = xml
|
||||
|
||||
# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a
|
||||
# validating XML parser to check the syntax of the XML files.
|
||||
# This tag requires that the tag GENERATE_XML is set to YES.
|
||||
|
||||
XML_SCHEMA =
|
||||
|
||||
# The XML_DTD tag can be used to specify a XML DTD, which can be used by a
|
||||
# validating XML parser to check the syntax of the XML files.
|
||||
# This tag requires that the tag GENERATE_XML is set to YES.
|
||||
|
||||
XML_DTD =
|
||||
|
||||
# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
|
||||
# listings (including syntax highlighting and cross-referencing information) to
|
||||
# the XML output. Note that enabling this will significantly increase the size
|
||||
|
@ -129,8 +129,6 @@ ABBREVIATE_BRIEF = "The $name class" \
|
||||
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
|
||||
DETAILS_AT_TOP = YES
|
||||
|
||||
# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
|
||||
# inherited members of a class in the documentation of that class as if those
|
||||
# members were ordinary class members. Constructors, destructors and assignment
|
||||
@ -1818,18 +1816,6 @@ GENERATE_XML = YES
|
||||
|
||||
XML_OUTPUT = xml
|
||||
|
||||
# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a
|
||||
# validating XML parser to check the syntax of the XML files.
|
||||
# This tag requires that the tag GENERATE_XML is set to YES.
|
||||
|
||||
XML_SCHEMA =
|
||||
|
||||
# The XML_DTD tag can be used to specify a XML DTD, which can be used by a
|
||||
# validating XML parser to check the syntax of the XML files.
|
||||
# This tag requires that the tag GENERATE_XML is set to YES.
|
||||
|
||||
XML_DTD =
|
||||
|
||||
# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
|
||||
# listings (including syntax highlighting and cross-referencing information) to
|
||||
# the XML output. Note that enabling this will significantly increase the size
|
||||
|
1
doxy/doxygen2jsdoc
Submodule
1
doxy/doxygen2jsdoc
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 67cad692720982ac3cbd99bf1c3421edc69b08f9
|
1
doxy/doxyport
Submodule
1
doxy/doxyport
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit db3e1a6eb8677d3166d90d82c3068689803ce547
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Author: Heidi Pan <heidi.pan@intel.com>
|
||||
* Copyright (c) 2015 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// dependencies
|
||||
var xml2js = require('./xml2js')
|
||||
, fs = require('fs')
|
||||
, Promise = require('bluebird')
|
||||
, opts = require('commander')
|
||||
, _ = require('lodash')
|
||||
, mkdirp = require('mkdirp');
|
||||
|
||||
|
||||
// parse command line arguments
|
||||
_.extend(opts, { addOptions: function(module) { return module.addOptions(opts); } });
|
||||
opts
|
||||
.option('-m, --module [module]', 'module name for which to build documentation', 'mraa')
|
||||
.option('-f, --formats [formats]', 'format for js comments', 'yuidoc,ternjs')
|
||||
.option('-o, --outdir [directory]', 'top directory to build documentation', __dirname + '/jsdoc')
|
||||
.addOptions(xml2js)
|
||||
.parse(process.argv);
|
||||
|
||||
|
||||
// use promise-style programming rather than spaghetti callbacks
|
||||
Promise.promisifyAll(fs);
|
||||
Promise.promisifyAll(mkdirp);
|
||||
|
||||
|
||||
// main
|
||||
xml2js.parse().then(function(specjs) {
|
||||
var formats = opts.formats.split(',');
|
||||
Promise.all(_.map(formats, function(format) {
|
||||
var generateDocs = require(__dirname + '/generators/' + format + '/generator');
|
||||
var dir = opts.outdir + '/' + format + '/' + specjs.MODULE;
|
||||
return mkdirp.mkdirpAsync(dir).then(function() {
|
||||
return fs.writeFileAsync(dir + '/doc.js', generateDocs(specjs));
|
||||
});
|
||||
}));
|
||||
});
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"templates": {
|
||||
"default": {
|
||||
"outputSourceFiles": false
|
||||
}
|
||||
}
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Author: Heidi Pan <heidi.pan@intel.com>
|
||||
* Copyright (c) 2015 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// dependencies
|
||||
var _ = require('lodash');
|
||||
|
||||
|
||||
// generate JSDoc-style documentation
|
||||
function generateDocs(specjs) {
|
||||
var docs = GENERATE_MODULE(specjs.MODULE);
|
||||
docs = _.reduce(specjs.METHODS, function(memo, methodSpec, methodName) {
|
||||
return memo += GENERATE_METHOD(methodName, methodSpec);
|
||||
}, docs);
|
||||
docs = _.reduce(specjs.ENUMS, function(memo, enumSpec, enumName) {
|
||||
return memo += GENERATE_ENUM(enumName, enumSpec);
|
||||
}, docs);
|
||||
docs = _.reduce(specjs.CLASSES, function(memo, classSpec, parentClass) {
|
||||
return _.reduce(classSpec.methods, function(memo, methodSpec, methodName) {
|
||||
return memo += GENERATE_METHOD(methodName, methodSpec, parentClass);
|
||||
}, memo);
|
||||
}, docs);
|
||||
return docs;
|
||||
}
|
||||
|
||||
|
||||
// comment wrapper around entire spec
|
||||
function GENERATE_DOC(text) {
|
||||
return '/**\n' + text + ' */\n';
|
||||
}
|
||||
|
||||
|
||||
// generate module spec
|
||||
function GENERATE_MODULE(module) {
|
||||
return GENERATE_DOC('@module ' + module + '\n');
|
||||
}
|
||||
|
||||
|
||||
// generate method spec with parent module/class
|
||||
function GENERATE_METHOD(name, spec, parent) {
|
||||
name = name.replace(/!+$/, '');
|
||||
return GENERATE_DOC(spec.description + '\n'
|
||||
+ '@method ' + name + '\n'
|
||||
+ '@instance\n'
|
||||
+ (parent ? ('@memberof ' + parent + '\n') : '')
|
||||
+ _.reduce(spec.params, function(memo, paramSpec, paramName) {
|
||||
return '@param {' + paramSpec.type + '} ' + paramName + ' ' + paramSpec.description + '\n';
|
||||
}, '')
|
||||
+ ( !_.isEmpty(spec.return) ? ('@return {' + spec.return.type + '} ' + spec.return.description + '\n') : ''));
|
||||
}
|
||||
|
||||
|
||||
// generate enum spec
|
||||
function GENERATE_ENUM(name, spec) {
|
||||
return GENERATE_DOC(spec.description + '\n\n'
|
||||
+ '@var ' + name + '\n'
|
||||
+ '@type Enum(' + spec.type + ')\n'
|
||||
+ '@instance\n');
|
||||
}
|
||||
|
||||
|
||||
// TODO
|
||||
// generate link spec
|
||||
function GENERATE_LINK(text) {
|
||||
return '{@link ' + text + '}';
|
||||
}
|
||||
|
||||
|
||||
module.exports = generateDocs;
|
@ -1,132 +0,0 @@
|
||||
/*
|
||||
* Author: Heidi Pan <heidi.pan@intel.com>
|
||||
* Copyright (c) 2015 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// dependencies
|
||||
var _ = require('lodash');
|
||||
|
||||
|
||||
// generate json for ternjs input
|
||||
function generateDocs(specjs) {
|
||||
GENERATE_TYPE = (function(enums) {
|
||||
return function(type) {
|
||||
return (_.contains(enums, type) ? ('Enum ' + type) : type);
|
||||
}
|
||||
})(_.keys(specjs.ENUMS_BY_GROUP));
|
||||
var docs = { '!name': specjs.MODULE + 'library' };
|
||||
_.extend(docs, GENERATE_MODULE(specjs.MODULE));
|
||||
_.each(specjs.ENUMS, function(enumSpec, enumName) {
|
||||
_.extend(docs[specjs.MODULE], GENERATE_ENUM(enumName, enumSpec));
|
||||
});
|
||||
_.each(specjs.METHODS, function(methodSpec, methodName) {
|
||||
_.extend(docs[specjs.MODULE], GENERATE_METHOD(methodName, methodSpec));
|
||||
});
|
||||
|
||||
if (_.isEmpty(specjs.CLASSGROUPS)) {
|
||||
_.extend(docs[specjs.MODULE], GENERATE_CLASSES(specjs.CLASSES));
|
||||
} else {
|
||||
var grouped = _.flatten(_.pluck(_.values(specjs.CLASSGROUPS), 'classes'));
|
||||
var ungrouped = _.difference(_.keys(specjs.CLASSES), grouped);
|
||||
_.extend(docs[specjs.MODULE], GENERATE_CLASSES(_.pick(specjs.CLASSES, ungrouped)));
|
||||
_.each(specjs.CLASSGROUPS, function(groupSpec, groupName) {
|
||||
_.extend(docs, GENERATE_MODULE(groupName));
|
||||
_.extend(docs[groupName], GENERATE_CLASSES(_.pick(specjs.CLASSES, groupSpec.classes), groupName));
|
||||
});
|
||||
}
|
||||
return JSON.stringify(docs, null, 2);
|
||||
}
|
||||
|
||||
|
||||
// generate module spec
|
||||
function GENERATE_MODULE(module) {
|
||||
var docs = {};
|
||||
docs[module] = {};
|
||||
return docs;
|
||||
}
|
||||
|
||||
|
||||
// generate the spec for the given list of classes
|
||||
function GENERATE_CLASSES(classes) {
|
||||
var docs = {};
|
||||
_.each(classes, function(classSpec, parentClass) {
|
||||
var constructor = classSpec.methods[parentClass];
|
||||
_.extend(docs, GENERATE_METHOD(parentClass, constructor ? constructor : { params: {}, return: {}, description: '' } ));
|
||||
if (_.has(docs, parentClass)) {
|
||||
_.each(classSpec.enums, function(enumSpec, enumName) {
|
||||
_.extend(docs[parentClass], GENERATE_ENUM(enumName, enumSpec));
|
||||
});
|
||||
docs[parentClass].prototype = {};
|
||||
_.each(_.omit(classSpec.methods, parentClass), function(methodSpec, methodName) {
|
||||
_.extend(docs[parentClass].prototype, GENERATE_METHOD(methodName, methodSpec));
|
||||
});
|
||||
_.each(classSpec.variables, function(variableSpec, variableName) {
|
||||
_.extend(docs[parentClass].prototype, GENERATE_VARIABLE(variableName, variableSpec));
|
||||
});
|
||||
}
|
||||
});
|
||||
return docs;
|
||||
}
|
||||
|
||||
|
||||
// generate method spec
|
||||
function GENERATE_METHOD(name, spec) {
|
||||
var doc = {};
|
||||
doc[name] = {
|
||||
'!type': 'fn(' + GENERATE_PARAMS(spec.params) + ')' + GENERATE_RETURN(spec.return),
|
||||
'!doc': spec.description
|
||||
}
|
||||
return doc;
|
||||
}
|
||||
|
||||
|
||||
// generate parameter signatures for method
|
||||
function GENERATE_PARAMS(spec) {
|
||||
return _.map(spec, function(paramSpec, paramName) {
|
||||
return paramName + ': ' + paramSpec.type;
|
||||
}).join(', ');
|
||||
}
|
||||
|
||||
|
||||
// generate return signature for method
|
||||
function GENERATE_RETURN(spec) {
|
||||
return (_.isEmpty(spec) ? '' : (' -> ' + spec.type));
|
||||
}
|
||||
|
||||
|
||||
// generate enum spec
|
||||
function GENERATE_ENUM(name, spec) {
|
||||
var doc = {};
|
||||
doc[name] = 'Enum ' + spec.type ;
|
||||
return doc;
|
||||
}
|
||||
|
||||
|
||||
// generate variable spec
|
||||
function GENERATE_VARIABLE(name, spec) {
|
||||
var doc = {};
|
||||
doc[name]= spec.type ;
|
||||
return doc;
|
||||
}
|
||||
|
||||
|
||||
module.exports = generateDocs;
|
144
doxy/node/generators/yuidoc/generator.js
vendored
144
doxy/node/generators/yuidoc/generator.js
vendored
@ -1,144 +0,0 @@
|
||||
/*
|
||||
* Author: Heidi Pan <heidi.pan@intel.com>
|
||||
* Copyright (c) 2015 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// dependencies
|
||||
var _ = require('lodash');
|
||||
|
||||
|
||||
// generate YuiDocs-style documentation
|
||||
function generateDocs(specjs) {
|
||||
var docs = GENERATE_MODULE(specjs.MODULE, '');
|
||||
GENERATE_TYPE = (function(enums) {
|
||||
return function(type) {
|
||||
return (_.contains(enums, type) ? ('Enum ' + type) : type);
|
||||
}
|
||||
})(_.keys(specjs.ENUMS_BY_GROUP));
|
||||
docs = _.reduce(specjs.METHODS, function(memo, methodSpec, methodName) {
|
||||
return memo += GENERATE_METHOD(methodName, methodSpec);
|
||||
}, docs);
|
||||
docs = _.reduce(specjs.ENUMS, function(memo, enumSpec, enumName) {
|
||||
return memo += GENERATE_ENUM(enumName, enumSpec);
|
||||
}, docs);
|
||||
if (_.isEmpty(specjs.CLASSGROUPS)) {
|
||||
docs += GENERATE_CLASSES(specjs.CLASSES);
|
||||
} else {
|
||||
docs += GENERATE_MODULE('common', '');
|
||||
var grouped = _.flatten(_.pluck(_.values(specjs.CLASSGROUPS), 'classes'));
|
||||
var ungrouped = _.difference(_.keys(specjs.CLASSES), grouped);
|
||||
docs += GENERATE_CLASSES(_.pick(specjs.CLASSES, ungrouped), 'common');
|
||||
_.each(specjs.CLASSGROUPS, function(groupSpec, groupName) {
|
||||
docs += GENERATE_CLASSES(_.pick(specjs.CLASSES, groupSpec.classes), groupName);
|
||||
});
|
||||
// TODO: figure out why yuidoc won't associate the class with the right module if module definitions are interspersed
|
||||
_.each(specjs.CLASSGROUPS, function(groupSpec, groupName) {
|
||||
docs += GENERATE_MODULE(groupName, groupSpec.description);
|
||||
});
|
||||
}
|
||||
return docs;
|
||||
}
|
||||
|
||||
|
||||
// comment wrapper around entire spec
|
||||
function GENERATE_DOC(text) {
|
||||
return '/**\n' + text + ' */\n';
|
||||
}
|
||||
|
||||
|
||||
// generate module spec
|
||||
function GENERATE_MODULE(name, description) {
|
||||
return GENERATE_DOC(description + '\n'
|
||||
+ '@module ' + name + '\n');
|
||||
}
|
||||
|
||||
|
||||
// generate spec for the given list of classes
|
||||
function GENERATE_CLASSES(classes, parent) {
|
||||
return _.reduce(classes, function(memo, classSpec, className) {
|
||||
return memo
|
||||
+ GENERATE_CLASS(className, classSpec.description, parent, classSpec.parent)
|
||||
+ _.reduce(classSpec.methods, function(memo, methodSpec, methodName) {
|
||||
return memo += GENERATE_METHOD(methodName, methodSpec, className);
|
||||
}, '')
|
||||
+ _.reduce(classSpec.variables, function(memo, variableSpec, variableName) {
|
||||
return memo += GENERATE_VAR(variableName, variableSpec, className);
|
||||
}, '')
|
||||
+ _.reduce(classSpec.enums, function(memo, enumSpec, enumName) {
|
||||
return memo += GENERATE_ENUM(enumName, enumSpec, className);
|
||||
}, '');
|
||||
}, '');
|
||||
}
|
||||
|
||||
|
||||
// generate class spec
|
||||
function GENERATE_CLASS(name, description, namespace, parent) {
|
||||
return GENERATE_DOC(description + '\n'
|
||||
+ '@class ' + name + '\n'
|
||||
+ (namespace ? ('@module ' + namespace + '\n') : '')
|
||||
/*
|
||||
TODO: leave out until figure out what swig does with inheritance
|
||||
+ (parent ? ('@extends ' + parent + '\n') : '')
|
||||
*/
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// generate method spec with parent module/class
|
||||
function GENERATE_METHOD(name, spec, parent) {
|
||||
name = name.replace(/!+$/, '');
|
||||
return GENERATE_DOC(spec.description + '\n'
|
||||
+ '@method ' + name + '\n'
|
||||
+ (parent ? ('@for ' + parent + '\n') : '@for common\n')
|
||||
+ _.reduce(spec.params, function(memo, paramSpec, paramName) {
|
||||
return memo + '@param {' + GENERATE_TYPE(paramSpec.type) + '} ' + paramName + ' ' + paramSpec.description + '\n';
|
||||
}, '')
|
||||
+ ( !_.isEmpty(spec.return) ? ('@return {' + GENERATE_TYPE(spec.return.type) + '} ' + spec.return.description + '\n') : ''));
|
||||
}
|
||||
|
||||
|
||||
// generate enum spec
|
||||
function GENERATE_ENUM(name, spec, parent) {
|
||||
return GENERATE_DOC(spec.description + '\n'
|
||||
+ '@property ' + name + '\n'
|
||||
+ '@type Enum ' + spec.type + '\n'
|
||||
+ '@for ' + (parent ? parent : 'common') + '\n');
|
||||
}
|
||||
|
||||
|
||||
// generate variable specs
|
||||
function GENERATE_VAR(name, spec, parent) {
|
||||
return GENERATE_DOC(spec.description + '\n'
|
||||
+ '@property ' + name + '\n'
|
||||
+ '@type ' + spec.type + '\n'
|
||||
+ '@for ' + parent + '\n');
|
||||
}
|
||||
|
||||
|
||||
// TODO
|
||||
// generate link spec
|
||||
function GENERATE_LINK(text) {
|
||||
return '{{#crossLink "' + text + '"}}{{/crossLink}}';
|
||||
}
|
||||
|
||||
|
||||
module.exports = generateDocs;
|
@ -1,45 +0,0 @@
|
||||
document
|
||||
= _ ignore* _ "<doxygen " _ attr:attr* _ ">" body:elements _ "</doxygen>" _ { return body; }
|
||||
|
||||
|
||||
elements
|
||||
= element*
|
||||
|
||||
element
|
||||
= _ "<" startTag:id _ attr:attr* _ ">" _ children:elements _ "</" endTag:id ">" _ {
|
||||
if (startTag != endTag) {
|
||||
throw new Error("Expected </" + startTag + "> but </" + endTag + "> found.");
|
||||
}
|
||||
return {name: startTag, attr: attr, children: children }
|
||||
}
|
||||
/ "<" tag:id _ attr:attr* _ "/>" _ {
|
||||
return {name: tag, attr: attr }
|
||||
}
|
||||
/ _ text:text _ { return text }
|
||||
|
||||
ignore
|
||||
= "<?xml" _ attr* _ "?>" { return }
|
||||
|
||||
attr
|
||||
= name:id _ "=" _ value:string { return { name:name, value:value } }
|
||||
|
||||
string
|
||||
= '"' '"' _ { return ""; }
|
||||
/ "'" "'" _ { return ""; }
|
||||
/ '"' text:quoted '"' _ { return text; }
|
||||
/ "'" text:quoted "'" _ { return text; }
|
||||
|
||||
quoted
|
||||
= chars:[^<>'" \t\n\r]+ { return chars.join(""); }
|
||||
|
||||
text
|
||||
= chars:[^<> \t\n\r]+ { return chars.join(""); }
|
||||
|
||||
id
|
||||
= chars:[^<>/'"=? \t\n\r]+ { return chars.join(""); }
|
||||
|
||||
_ "whitespace"
|
||||
= whitespace*
|
||||
|
||||
whitespace
|
||||
= [ \t\n\r]
|
@ -1,125 +0,0 @@
|
||||
/*
|
||||
* Author: Dina M Suehiro <dina.m.suehiro@intel.com>
|
||||
* Copyright (c) 2015 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// dependencies
|
||||
var opts = require('commander'), // for command line args
|
||||
fs = require('fs'), // for file system access
|
||||
path = require('path'); // for file path parsing
|
||||
|
||||
// parse command line arguments
|
||||
opts
|
||||
.option('-i, --inputdir [directory]', 'product documents directory', __dirname + '/docs/yuidoc/upm')
|
||||
.parse(process.argv);
|
||||
|
||||
// Set to true for console output
|
||||
var debug = true;
|
||||
|
||||
// Global arrays tracking the files that have been renamed
|
||||
var originalFiles = [];
|
||||
var renamedFiles = [];
|
||||
|
||||
// Filter to get html files from different directories
|
||||
var rootFiles = getHtmlFilenames(opts.inputdir);
|
||||
var classesFiles = getHtmlFilenames(opts.inputdir + "/classes");
|
||||
var modulesFiles = getHtmlFilenames(opts.inputdir + "/modules");
|
||||
|
||||
// Rename files in the classes directory to have lower-cased file names.
|
||||
renameFiles(classesFiles);
|
||||
|
||||
classesFiles = getHtmlFilenames(opts.inputdir + "/classes");
|
||||
|
||||
// Go through the html files and update links to reflect the file names that we changed.
|
||||
renameLinks(rootFiles);
|
||||
renameLinks(classesFiles);
|
||||
renameLinks(modulesFiles);
|
||||
|
||||
// Helper function that returns paths to the html files in the specified directory
|
||||
function getHtmlFilenames (directory)
|
||||
{
|
||||
return fs.readdirSync(directory).map(function (file) {
|
||||
return path.join(directory, file);
|
||||
}).filter(function (file) {
|
||||
return fs.statSync(file).isFile();
|
||||
}).filter(function (file) {
|
||||
return path.extname(file).toLowerCase() == ".html";
|
||||
});
|
||||
}
|
||||
|
||||
// Goes through the files and renames them to be lower-cased and tracks them the
|
||||
// renamed files in the originalFiles[] and renamedFiles[] arrays.
|
||||
function renameFiles(files)
|
||||
{
|
||||
files.forEach(function (file)
|
||||
{
|
||||
var originalName = path.basename(file);
|
||||
var newFileName = originalName.toLowerCase();
|
||||
var directory = path.dirname(file);
|
||||
if (originalName != newFileName)
|
||||
{
|
||||
fs.renameSync(file, directory + "/" + newFileName); //, function(err)
|
||||
|
||||
if (debug)
|
||||
console.log('Renamed: %s --> %s', originalName, newFileName);
|
||||
|
||||
originalFiles.push(originalName);
|
||||
renamedFiles.push(newFileName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Helper function goes through the specified files and does a file/replace of the
|
||||
// originalFiles to the renamedFiles so that the .html links match what has been renamed.
|
||||
function renameLinks (files)
|
||||
{
|
||||
if (originalFiles.length <= 0)
|
||||
{
|
||||
if (debug)
|
||||
console.log("No links to rename.");
|
||||
return;
|
||||
}
|
||||
|
||||
files.forEach(function (file)
|
||||
{
|
||||
// Read the file
|
||||
data = fs.readFileSync(file, 'ascii');
|
||||
|
||||
// Find/replace the file names that were renamed
|
||||
for (var i = 0; i < originalFiles.length; i++)
|
||||
{
|
||||
var findString = '/' + originalFiles[i] + '\"';
|
||||
var replaceString = '/' + renamedFiles[i] + '\"';
|
||||
|
||||
data = data.replace(findString, replaceString);
|
||||
}
|
||||
|
||||
// Write back
|
||||
fs.writeFile(file, data, 'ascii', function (err) {
|
||||
if (err)
|
||||
throw err;
|
||||
});
|
||||
|
||||
if (debug)
|
||||
console.log('Renamed links in: %s', file);
|
||||
});
|
||||
}
|
@ -1,935 +0,0 @@
|
||||
/*
|
||||
* Author: Heidi Pan <heidi.pan@intel.com>
|
||||
* Copyright (c) 2015 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// dependencies
|
||||
var peg = require('pegjs')
|
||||
, fs = require('fs')
|
||||
, path = require('path')
|
||||
, Promise = require('bluebird')
|
||||
, _ = require('lodash')
|
||||
, util = require('util');
|
||||
|
||||
|
||||
// use promise-style programming rather than spaghetti callbacks
|
||||
Promise.promisifyAll(fs);
|
||||
|
||||
|
||||
var xml2js = {
|
||||
|
||||
// js-format specs
|
||||
// MODULE: <module name>
|
||||
// ENUMS: {
|
||||
// <enum name>: {
|
||||
// type: <enum type>,
|
||||
// description: <enum description>
|
||||
// }, ...
|
||||
// }
|
||||
// ENUMS_BY_GROUP: {
|
||||
// <enum type>: {
|
||||
// description: <enum group description>
|
||||
// members: [ <enum name>, ... ]
|
||||
// }, ...
|
||||
// }
|
||||
// METHODS: {
|
||||
// <method name>: {
|
||||
// description: <method description>,
|
||||
// params: {
|
||||
// <param name>: {
|
||||
// type: <param type>,
|
||||
// description: <param description >
|
||||
// }, ...
|
||||
// },
|
||||
// return: {
|
||||
// type: <return type>,
|
||||
// description: <return description>
|
||||
// }
|
||||
// }, ...
|
||||
// }
|
||||
// CLASSES: {
|
||||
// <class name>: {
|
||||
// description: <class description>,
|
||||
// parent: <parent class name>,
|
||||
// group: <group name>,
|
||||
// methods: { ... },
|
||||
// variables: {
|
||||
// <variable name>: {
|
||||
// type: <variable type>,
|
||||
// description: <variable description>
|
||||
// }
|
||||
// },
|
||||
// enums: { ... },
|
||||
// enums_by_group: { ... }
|
||||
// }, ...
|
||||
// }
|
||||
// CLASSGROUPS: {
|
||||
// <group name>: {
|
||||
// description: <group description>,
|
||||
// classes: [ <class name>, ... ],
|
||||
// enums: { ... },
|
||||
// enums_by_group: { ... }
|
||||
// }, ...
|
||||
// }
|
||||
MODULE: '',
|
||||
ENUMS: {},
|
||||
ENUMS_BY_GROUP: {},
|
||||
METHODS: {},
|
||||
CLASSES: {},
|
||||
CLASSGROUPS: {},
|
||||
|
||||
|
||||
// baseline c -> js type mapping
|
||||
TYPEMAPS: {
|
||||
'^(const)?\\s*(unsigned|signed)?\\s*(int|short|long|float|double|size_t|u?int\\d{1,2}_t)?$': 'Number',
|
||||
'^bool$': 'Boolean',
|
||||
'^(const)?\\s*(unsigned|signed)?\\s*(char|char\\s*\\*|std::string)$': 'String', // TODO: verify that swig does this mapping
|
||||
'^void\\s*\\(\\s*\\*\\s*\\)\\s*\\(\\s*void\\s*\\*\\)\\s*$': 'Function'
|
||||
},
|
||||
|
||||
|
||||
// custom c -> js type mapping for pointers
|
||||
// ARRAY_TYPEMAPS: {
|
||||
// <pointer data type>: {
|
||||
// arrayType: <swig generated array type that will replace pointers of data type>,
|
||||
// classes: [ <class that contains arrayType>, ... ]
|
||||
// }, ...
|
||||
// }
|
||||
// POINTER_TYPEMAPS: {
|
||||
// <class that contains pointerType>: {
|
||||
// <c pointer data type>: <js swig generated pointer type that will replace pointers of data type>, ...
|
||||
// }, ...
|
||||
// }
|
||||
ARRAY_TYPEMAPS: {},
|
||||
POINTER_TYPEMAPS: {},
|
||||
|
||||
|
||||
// add command line options for this module
|
||||
addOptions: function(opts) {
|
||||
xml2js.opts = opts;
|
||||
return opts
|
||||
.option('-i, --inputdir [directory]', 'directory for xml files', __dirname + '/xml/mraa')
|
||||
.option('-c, --custom [file]', 'json for customizations')
|
||||
.option('-t, --typemaps [directory]', 'directory for custom pointer type maps')
|
||||
.option('-g, --imagedir [directory]', 'directory to link to where the images will be kept', '')
|
||||
.option('-s, --strict', 'leave out methods/variables if unknown type')
|
||||
},
|
||||
|
||||
|
||||
// parse doxygen xml -> js-format specs
|
||||
// TODO: figure out whether we need to document any protected methods/variables
|
||||
parse: function() {
|
||||
var XML_GRAMMAR_SPEC = 'grammars/xml.peg';
|
||||
var NAMESPACE_SPEC = xml2js.opts.inputdir + '/namespace' + xml2js.opts.module + '.xml';
|
||||
var CLASS_SPEC = function(c) { return xml2js.opts.inputdir + '/' + c + '.xml'; }
|
||||
var TYPES_SPEC = xml2js.opts.inputdir + '/types_8h.xml';
|
||||
xml2js.MODULE = xml2js.opts.module;
|
||||
return Promise.join(createXmlParser(XML_GRAMMAR_SPEC),
|
||||
xml2js.opts.typemaps ? initCustomPointerTypemaps(xml2js.opts.typemaps) : Promise.resolve(),
|
||||
fs.readFileAsync(NAMESPACE_SPEC, 'utf8'),
|
||||
fs.existsSync(TYPES_SPEC) ? fs.readFileAsync(TYPES_SPEC, 'utf8') : Promise.resolve(null),
|
||||
function(xmlparser, ignore, xml, xml_types) {
|
||||
if (xml_types != null) {
|
||||
_.extend(xml2js.ENUMS, getEnums(xmlparser.parse(xml_types)[0], false));
|
||||
_.extend(xml2js.ENUMS_BY_GROUP, getEnums(xmlparser.parse(xml_types)[0], true));
|
||||
}
|
||||
var spec_c = xmlparser.parse(xml)[0];
|
||||
_.extend(xml2js.ENUMS, getEnums(spec_c, false));
|
||||
_.extend(xml2js.ENUMS_BY_GROUP, getEnums(spec_c, true));
|
||||
_.extend(xml2js.METHODS, getMethods(spec_c));
|
||||
_.each(getSubclassNames(spec_c), function(className) { xml2js.CLASSES[className] = {} });
|
||||
var parseClasses = _.map(getSubclasses(spec_c), function(c) {
|
||||
return fs.readFileAsync(CLASS_SPEC(c), 'utf8').then(function(xml) {
|
||||
try {
|
||||
var spec_c = xmlparser.parse(xml)[0];
|
||||
var className = getName(spec_c);
|
||||
_.extend(xml2js.CLASSES[className], {
|
||||
description: getDescription(spec_c),
|
||||
parent: getParent(spec_c, className),
|
||||
enums: getEnums(spec_c, false, className),
|
||||
enums_by_group: getEnums(spec_c, true, className),
|
||||
variables: getVariables(spec_c, className),
|
||||
methods: getMethods(spec_c, className)
|
||||
});
|
||||
} catch(e) {
|
||||
console.log(e.toString() + ': class ' + className + ' was not parsed correctly.');
|
||||
}
|
||||
});
|
||||
});
|
||||
var parseGroups = fs.readdirAsync(xml2js.opts.inputdir).then(function(files) {
|
||||
var groupxmlfiles = _.filter(files, function(fn) {
|
||||
return ((path.extname(fn) == '.xml') && (path.basename(fn).search(/^group/) != -1));
|
||||
});
|
||||
return Promise.all(_.map(groupxmlfiles, function(fn) {
|
||||
return fs.readFileAsync(xml2js.opts.inputdir + '/' + fn, 'utf8').then(function(xml) {
|
||||
var spec_c = xmlparser.parse(xml)[0];
|
||||
if (_.isEmpty(getSubmodules(spec_c))) {
|
||||
var group = getName(spec_c);
|
||||
var classes = getSubclassNames(spec_c);
|
||||
xml2js.CLASSGROUPS[group] = {
|
||||
description: getDescription(spec_c),
|
||||
classes: classes
|
||||
};
|
||||
_.each(classes, function(c) {
|
||||
if (_.has(xml2js.CLASSES, c)) {
|
||||
xml2js.CLASSES[c].group = group;
|
||||
} else {
|
||||
console.log('Warning: Group ' + group + ' has unknown class ' + c);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
});
|
||||
return Promise.all(parseClasses.concat(parseGroups));
|
||||
}).then(function() {
|
||||
if (!_.isEmpty(xml2js.CLASSGROUPS)) {
|
||||
// try to categorize ungrouped classes, if any
|
||||
var grouped = _.flatten(_.pluck(_.values(xml2js.CLASSGROUPS), 'classes'));
|
||||
var ungrouped = _.difference(_.keys(xml2js.CLASSES), grouped);
|
||||
_.each(ungrouped, function(c) {
|
||||
_.each(findUsage(c), function(group) {
|
||||
xml2js.CLASSGROUPS[group].classes.push(c);
|
||||
});
|
||||
});
|
||||
grouped = _.flatten(_.pluck(_.values(xml2js.CLASSGROUPS), 'classes'));
|
||||
ungrouped = _.difference(_.keys(xml2js.CLASSES), grouped);
|
||||
// try to categorize ungrouped enums, if any
|
||||
_.each(xml2js.ENUMS_BY_GROUP, function(enumGroupSpec, enumGroupName) {
|
||||
_.each(findUsage(enumGroupName, true), function(c) {
|
||||
xml2js.CLASSES[c].enums_by_group[enumGroupName] = enumGroupSpec;
|
||||
_.each(enumGroupSpec.members, function(enumName) {
|
||||
xml2js.CLASSES[c].enums[enumName] = xml2js.ENUMS[enumName];
|
||||
delete xml2js.ENUMS[enumName];
|
||||
});
|
||||
delete xml2js.ENUMS_BY_GROUP[enumGroupName];
|
||||
});
|
||||
});
|
||||
}
|
||||
}).then(function() {
|
||||
if (xml2js.opts.custom && fs.existsSync(xml2js.opts.custom)) {
|
||||
return fs.readFileAsync(xml2js.opts.custom, 'utf8').then(function(custom) {
|
||||
try {
|
||||
customizeMethods(JSON.parse(custom));
|
||||
} catch(e) {
|
||||
console.log('invalid custom.json, ignored. ' + e.toString());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log(xml2js.opts.custom ? ('Error: No such customization file exists: ' + xml2js.opts.custom) : 'No customizations given.');
|
||||
}
|
||||
}).then(function() {
|
||||
generateCustomPointerClasses();
|
||||
validateMethods();
|
||||
validateVars();
|
||||
return _.pick(xml2js, 'MODULE', 'ENUMS', 'ENUMS_BY_GROUP', 'METHODS', 'CLASSES', 'CLASSGROUPS');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// create an xml parser
|
||||
function createXmlParser(XML_GRAMMAR_SPEC) {
|
||||
return fs.readFileAsync(XML_GRAMMAR_SPEC, 'utf8').then(function(xmlgrammar) {
|
||||
return peg.buildParser(xmlgrammar);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// configure c->js typemaps from custom swig directives
|
||||
// TODO: many built in assumptions based on current upm file structures & .i customizations
|
||||
function initCustomPointerTypemaps(typemapsdir) {
|
||||
return fs.readdirAsync(typemapsdir).then(function(dirs) {
|
||||
return Promise.all(_.map(dirs, function(dir) {
|
||||
// get all js*.i directives from class-specific subdirectories, to be parsed below for %typemaps directives
|
||||
return fs.readdirAsync(typemapsdir + '/' + dir).then(function(files) {
|
||||
var directive = _.find(files, function(fn) {
|
||||
return ((path.extname(fn) == '.i') && (path.basename(fn).search(/^js/) != -1));
|
||||
});
|
||||
var data = {};
|
||||
if (directive) {
|
||||
data[dir] = typemapsdir + '/' + dir + '/' + directive;
|
||||
}
|
||||
return data;
|
||||
}).catch(function(e) {
|
||||
// get all .i directives from top level directory, and parse for %array_class directives
|
||||
if (e.code == 'ENOTDIR') {
|
||||
var fn = dir;
|
||||
if (path.extname(fn) == '.i') {
|
||||
return fs.readFileAsync(typemapsdir + '/' + fn, 'utf8').then(function(directives) {
|
||||
var arraytypes = _.filter(directives.split(/\n/), function(line) {
|
||||
return (line.search(/^%array_class/) != -1);
|
||||
});
|
||||
_.each(arraytypes, function(arraytype) {
|
||||
var parsed = arraytype.match(/%array_class\(([A-Za-z0-9_]+)[\s]*,[\s]*([A-Za-z0-9_]+)\)/);
|
||||
if (parsed) {
|
||||
var from = parsed[1];
|
||||
var to = parsed[2];
|
||||
xml2js.ARRAY_TYPEMAPS[from] = { arrayType: to, classes: [] };
|
||||
} else {
|
||||
console.log('Incorrectly parsed array_class from ' + fn + ': ' + arraytype);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
}));
|
||||
}).then(function(__directivesFiles) {
|
||||
// parse for %typemaps & %pointer_functions directives
|
||||
var _directivesFiles = _.filter(__directivesFiles, function(data) { return !_.isEmpty(data); });
|
||||
var directivesFiles = _.object(_.map(_directivesFiles, _.keys), _.flatten(_.map(_directivesFiles, _.values)));
|
||||
return Promise.all(_.map(directivesFiles, function(directivesFn, className) {
|
||||
return fs.readFileAsync(directivesFn, 'utf8').then(function(directives) {
|
||||
var typemaps = _.filter(directives.split(/\n/), function(line) {
|
||||
return (line.search(/^%typemap/) != -1);
|
||||
});
|
||||
_.each(typemaps, function(typemap) {
|
||||
var parsed = typemap.match(/%typemap\((in|out)\)[\s]+([A-Za-z0-9_]+[\s]*[\*])/);
|
||||
if (parsed) {
|
||||
var dir = parsed[1]; // TODO: ignored for now
|
||||
var type = normalizePointer(parsed[2]);
|
||||
var datatype = getPointerDataType(type);
|
||||
if (_.has(xml2js.ARRAY_TYPEMAPS, datatype)) {
|
||||
xml2js.ARRAY_TYPEMAPS[datatype].classes.push(className);
|
||||
} else {
|
||||
console.log('Ignored typemap from ' + directivesFn + ': ' + typemap.replace('{', '') + ' (no %array_class directive found for ' + datatype + ')');
|
||||
}
|
||||
} else {
|
||||
console.log('Ignored typemap from ' + directivesFn + ': ' + typemap.replace('{', '') + ' (only considering in/out typemaps of pointer types)');
|
||||
}
|
||||
});
|
||||
var ptrfns = _.filter(directives.split(/\n/), function(line) {
|
||||
return (line.search(/^%pointer_functions/) != -1);
|
||||
});
|
||||
_.each(ptrfns, function(ptrfn) {
|
||||
var parsed = ptrfn.match(/%pointer_functions\(([A-Za-z0-9_]+)[\s]*,[\s]*([A-Za-z0-9_]+)\)/);
|
||||
if (parsed) {
|
||||
var from = parsed[1];
|
||||
var to = parsed[2];
|
||||
if (!_.has(xml2js.POINTER_TYPEMAPS, className)) {
|
||||
xml2js.POINTER_TYPEMAPS[className] = {};
|
||||
}
|
||||
xml2js.POINTER_TYPEMAPS[className][from] = to;
|
||||
}
|
||||
});
|
||||
});
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// generate class specs for custom pointer types
|
||||
function generateCustomPointerClasses() {
|
||||
var arrayTypes = _.pluck(_.values(xml2js.ARRAY_TYPEMAPS), 'arrayType');
|
||||
var pointerTypes = _.uniq(_.flatten(_.map(_.values(xml2js.POINTER_TYPEMAPS), _.values)));
|
||||
_.each(arrayTypes, function(arrayType) {
|
||||
var dataType = _.findKey(xml2js.ARRAY_TYPEMAPS, function(to) { return to.arrayType == arrayType; });
|
||||
xml2js.CLASSES[arrayType] = {
|
||||
description: 'Array of type ' + dataType + '.',
|
||||
enums: {},
|
||||
enums_by_group: {},
|
||||
variables: {},
|
||||
methods: {}
|
||||
};
|
||||
xml2js.CLASSES[arrayType].methods[arrayType] = {
|
||||
description: 'Instantiates the array.',
|
||||
params: {
|
||||
nelements: {
|
||||
type: 'Number',
|
||||
description: 'number of elements in the array'
|
||||
}
|
||||
},
|
||||
return: {}
|
||||
};
|
||||
xml2js.CLASSES[arrayType].methods.getitem = {
|
||||
description: 'Access a particular element in the array.',
|
||||
params: {
|
||||
index: {
|
||||
type: 'Number',
|
||||
description: 'index of array to read from'
|
||||
},
|
||||
},
|
||||
return: {
|
||||
type: getType(dataType),
|
||||
description: 'the value of the element found at the given index of the array'
|
||||
}
|
||||
};
|
||||
xml2js.CLASSES[arrayType].methods.setitem = {
|
||||
description: 'Modify a particular element in the array.',
|
||||
params: {
|
||||
index: {
|
||||
type: 'Number',
|
||||
description: 'index of array to write to'
|
||||
},
|
||||
value: {
|
||||
type: getType(dataType),
|
||||
description: 'the value to set the element found at the given index of the array'
|
||||
}
|
||||
},
|
||||
return: {}
|
||||
};
|
||||
});
|
||||
var pointerDataTypeMap = _.reduce(_.map(_.values(xml2js.POINTER_TYPEMAPS), _.invert), function(memo, typemap) {
|
||||
return _.extend(memo, typemap);
|
||||
}, {});
|
||||
_.each(pointerTypes, function(pointerType) {
|
||||
var dataType = pointerDataTypeMap[pointerType];
|
||||
xml2js.CLASSES[pointerType] = {
|
||||
description: 'Proxy object to data of type ' + dataType + '.',
|
||||
enums: {},
|
||||
enums_by_group: {},
|
||||
variables: {},
|
||||
methods: {}
|
||||
};
|
||||
xml2js.CLASSES[pointerType].methods[pointerType] = {
|
||||
description: 'Instantiates the proxy object.',
|
||||
params: {},
|
||||
return: {}
|
||||
};
|
||||
xml2js.CLASSES[pointerType].methods.value = {
|
||||
description: 'Get the value of the object.',
|
||||
params: {},
|
||||
return: {
|
||||
type: getType(dataType),
|
||||
description: 'the value of the object'
|
||||
}
|
||||
};
|
||||
xml2js.CLASSES[pointerType].methods.assign = {
|
||||
description: 'Set the value of the object.',
|
||||
params: {
|
||||
value: {
|
||||
type: getType(dataType),
|
||||
description: 'the value to set the object to'
|
||||
}
|
||||
},
|
||||
return: {}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// search for usage of a type
|
||||
function findUsage(type, classOnly) {
|
||||
var filterClasses = function(fn) { return _.without(_.map(xml2js.CLASSES, fn), undefined); };
|
||||
var usesType = function(classSpec, className) {
|
||||
var methodsOfType = (_.find(classSpec.methods, function(methodSpec, methodName) {
|
||||
return ((!_.isEmpty(methodSpec.return) && methodSpec.return.type == type) ||
|
||||
(_.contains(_.pluck(methodSpec.params, 'type'), type)));
|
||||
}) != undefined);
|
||||
var variablesOfType = _.contains(_.pluck(classSpec.variable, 'type'), type);
|
||||
return ((methodsOfType || variablesOfType) ? className : undefined);
|
||||
};
|
||||
var extendsType = function(classSpec, className) {
|
||||
return ((classSpec.parent == type) ? className : undefined);
|
||||
};
|
||||
var classes = _.union(filterClasses(usesType), filterClasses(extendsType));
|
||||
if (classOnly) {
|
||||
return classes;
|
||||
} else {
|
||||
return _.without(_.uniq(_.pluck(_.pick(xml2js.CLASSES, classes), 'group')), undefined);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// override autogenerated methods with custom configuration
|
||||
function customizeMethods(custom) {
|
||||
_.each(custom, function(classMethods, className) {
|
||||
_.extend(xml2js.CLASSES[className].methods, _.pick(classMethods, function(methodSpec, methodName) {
|
||||
return isValidMethodSpec(methodSpec, className + '.' + methodName);
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// make sure methods have valid types, otherwise warn (& don't include if strict)
|
||||
function validateMethods() {
|
||||
xml2js.METHODS = _.pick(xml2js.METHODS, function(methodSpec, methodName) {
|
||||
return hasValidTypes(methodSpec, methodName);
|
||||
});
|
||||
_.each(xml2js.CLASSES, function(classSpec, className) {
|
||||
var valid = _.pick(classSpec.methods, function(methodSpec, methodName) {
|
||||
return hasValidTypes(methodSpec, className + '.' + methodName, className);
|
||||
});
|
||||
if (xml2js.opts.strict) {
|
||||
xml2js.CLASSES[className].methods = valid;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// make sure variables have valid types, otherwise warn (& don't include if strict)
|
||||
function validateVars() {
|
||||
_.each(xml2js.CLASSES, function(classSpec, className) {
|
||||
var valid = _.pick(classSpec.variables, function(varSpec, varName) {
|
||||
return ofValidType(varSpec, className + '.' + varName, className);
|
||||
});
|
||||
if (xml2js.opts.strict) {
|
||||
xml2js.CLASSES[className].variables = valid;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// verify that the json spec is well formatted
|
||||
function isValidMethodSpec(methodSpec, methodName) {
|
||||
var valid = true;
|
||||
var printIgnoredMethodOnce = _.once(function() { console.log(methodName + ' from ' + path.basename(xml2js.opts.custom) + ' is omitted from JS documentation.'); });
|
||||
function checkRule(rule, errMsg) {
|
||||
if (!rule) {
|
||||
printIgnoredMethodOnce();
|
||||
console.log(' ' + errMsg);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
checkRule(_.has(methodSpec, 'description'), 'no description given');
|
||||
checkRule(_.has(methodSpec, 'params'), 'no params given (specify "params": {} for no params)');
|
||||
_.each(methodSpec.params, function(paramSpec, paramName) {
|
||||
checkRule(_.has(paramSpec, 'type'), 'no type given for param ' + paramName);
|
||||
checkRule(_.has(paramSpec, 'description'), 'no description given for param ' + paramName);
|
||||
});
|
||||
checkRule(_.has(methodSpec, 'return'), 'no return given (specify "return": {} for no return value)');
|
||||
checkRule(_.has(methodSpec.return, 'type'), 'no type given for return value');
|
||||
checkRule(_.has(methodSpec.return, 'description'), 'no description given for return value');
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
||||
// get enum specifications
|
||||
function getEnums(spec_c, bygroup, parent) {
|
||||
var spec_js = {};
|
||||
var enumGroups = _.find(getChildren(spec_c, 'sectiondef'), function(section) {
|
||||
var kind = getAttr(section, 'kind');
|
||||
return ((kind == 'enum') || (kind == 'public-type'));
|
||||
});
|
||||
if (enumGroups) {
|
||||
_.each(enumGroups.children, function(enumGroup) {
|
||||
var enumGroupName = getText(getChild(enumGroup, 'name'), 'name');
|
||||
var enumGroupDescription = getText(getChild(enumGroup, 'detaileddescription'), 'description');
|
||||
var enumGroupVals = getChildren(enumGroup, 'enumvalue');
|
||||
if (bygroup) {
|
||||
spec_js[enumGroupName] = {
|
||||
description: enumGroupDescription,
|
||||
members: []
|
||||
};
|
||||
}
|
||||
_.each(enumGroupVals, function(e) {
|
||||
// TODO: get prefix as option
|
||||
var enumName = getText(getChild(e, 'name'), 'name').replace(/^MRAA_/, '');
|
||||
var enumDescription = getText(getChild(e, 'detaileddescription'), 'description');
|
||||
if (!bygroup) {
|
||||
spec_js[enumName] = {
|
||||
type: enumGroupName,
|
||||
description: enumDescription
|
||||
};
|
||||
} else {
|
||||
spec_js[enumGroupName].members.push(enumName);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
return spec_js;
|
||||
}
|
||||
|
||||
|
||||
// get the name for the module/group/class
|
||||
function getName(spec_c) {
|
||||
return getText(getChild(spec_c, 'compoundname'), 'name').replace(xml2js.opts.module + '::', '');
|
||||
}
|
||||
|
||||
|
||||
// get the description for the module/group/class
|
||||
function getDescription(spec_c) {
|
||||
return getText(getChild(spec_c, 'detaileddescription'), 'description');
|
||||
}
|
||||
|
||||
|
||||
// get the classes (xml file names) for the given module
|
||||
function getSubclasses(spec_c) {
|
||||
return _.map(getChildren(spec_c, 'innerclass'), function(innerclass) {
|
||||
return getAttr(innerclass, 'refid');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// get the classes (class names) for the given module
|
||||
function getSubclassNames(spec_c) {
|
||||
return _.map(getChildren(spec_c, 'innerclass'), function(innerclass) {
|
||||
return getText(innerclass).replace(xml2js.opts.module + '::', '');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// get the submodules (xml file names) for the given module
|
||||
function getSubmodules(spec_c) {
|
||||
return _.map(getChildren(spec_c, 'innergroup'), function(innergroup) {
|
||||
return getAttr(innergroup, 'refid');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// get parent class, if any
|
||||
function getParent(spec_c, className) {
|
||||
var parent = getChild(spec_c, 'basecompoundref');
|
||||
if (parent) {
|
||||
parent = getText(parent);
|
||||
if (!_.has(xml2js.CLASSES, parent)) {
|
||||
console.log('WARNING: Class ' + className + ' has unknown parent class ' + parent);
|
||||
}
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
|
||||
function hasParams(paramsSpec) {
|
||||
return !(_.isEmpty(paramsSpec) ||
|
||||
((_.size(paramsSpec) == 1) && getText(getChild(paramsSpec[0], 'type')) == 'void'));
|
||||
}
|
||||
|
||||
|
||||
// get method specifications for top-level module or a given class
|
||||
// TODO: overloaded functions
|
||||
// TODO: functions w/ invalid parameter(s)/return
|
||||
function getMethods(spec_c, parent) {
|
||||
var spec_js = {};
|
||||
var methods = _.find(getChildren(spec_c, 'sectiondef'), function(section) {
|
||||
var kind = getAttr(section, 'kind');
|
||||
return ((kind == 'public-func') || (kind == 'func'));
|
||||
});
|
||||
if (methods) {
|
||||
_.each(methods.children, function(method) {
|
||||
var methodName = getText(getChild(method, 'name'), 'name');
|
||||
if (methodName[0] != '~') { // filter out destructors
|
||||
try {
|
||||
var description = getChild(method, 'detaileddescription');
|
||||
var methodDescription = getText(description, 'description');
|
||||
var paramsSpec = getChildren(method, 'param');
|
||||
var params = {};
|
||||
if (hasParams(paramsSpec)) {
|
||||
params = getParams(paramsSpec, getParamsDetails(description), methodName, parent);
|
||||
}
|
||||
var returnSpec = getChild(method, 'type');
|
||||
var retval = {};
|
||||
if (!_.isEmpty(returnSpec)) {
|
||||
retval = getReturn(returnSpec, getReturnDetails(description), methodName, parent);
|
||||
}
|
||||
methodName = getUniqueMethodName(methodName, spec_js, parent);
|
||||
spec_js[methodName] = {
|
||||
description: methodDescription,
|
||||
params: params,
|
||||
return: retval
|
||||
};
|
||||
} catch(e) {
|
||||
console.log((parent ? (parent + '.') : '') + methodName + ' is omitted from JS documentation.');
|
||||
console.log(' ' + e.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return spec_js;
|
||||
}
|
||||
|
||||
|
||||
// get a unique string to represent the name of an overloaded method
|
||||
function getUniqueMethodName(methodName, module, parent) {
|
||||
if (methodName in module) {
|
||||
do {
|
||||
methodName += '!';
|
||||
} while (methodName in module);
|
||||
}
|
||||
return methodName;
|
||||
}
|
||||
|
||||
|
||||
// get variable specifications for a class
|
||||
function getVariables(spec_c, parent) {
|
||||
var spec_js = {};
|
||||
var vars = _.find(getChildren(spec_c, 'sectiondef'), function(section) {
|
||||
var kind = getAttr(section, 'kind');
|
||||
return (kind == 'public-attrib');
|
||||
});
|
||||
if (vars) {
|
||||
_.each(_.filter(vars.children, function(variable) {
|
||||
return (getAttr(variable, 'kind') == 'variable');
|
||||
}), function(variable) {
|
||||
var varName = getText(getChild(variable, 'name'), 'name');
|
||||
var varType = getType(getText(getChild(variable, 'type')), parent);
|
||||
var varDescription = getText(getChild(variable, 'detaileddescription'));
|
||||
spec_js[varName] = {
|
||||
type: varType,
|
||||
description: varDescription
|
||||
}
|
||||
});
|
||||
}
|
||||
return spec_js;
|
||||
}
|
||||
|
||||
|
||||
// get return value specs of a method
|
||||
function getReturn(spec_c, details, method, parent) {
|
||||
var retType = getType(getText(spec_c, 'type'), parent);
|
||||
var retDescription = (details ? getText(details, 'description') : '');
|
||||
return ((retType == 'void') ? {} : {
|
||||
type: retType,
|
||||
description: retDescription
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// get paramater specs of a method
|
||||
function getParams(spec_c, details, method, parent) {
|
||||
var spec_js = {};
|
||||
_.each(spec_c, function(param) {
|
||||
try {
|
||||
var paramType = getType(getText(getChild(param, 'type'), 'type'), parent);
|
||||
var paramName = getText(getChild(param, 'declname'), 'name');
|
||||
spec_js[paramName] = { type: paramType };
|
||||
} catch(e) {
|
||||
if (paramType == '...') {
|
||||
spec_js['arguments'] = { type: paramType };
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
});
|
||||
_.each(details, function(param) {
|
||||
var getParamName = function(p) { return getText(getChild(getChild(p, 'parameternamelist'), 'parametername'), 'name'); }
|
||||
var paramName = getParamName(param);
|
||||
var paramDescription = getText(getChild(param, 'parameterdescription'), 'description');
|
||||
if (_.has(spec_js, paramName)) {
|
||||
spec_js[paramName].description = paramDescription;
|
||||
} else {
|
||||
var msg = ' has documentation for an unknown parameter: ' + paramName + '. ';
|
||||
var suggestions = _.difference(_.keys(spec_js), _.map(details, getParamName));
|
||||
var msgAddendum = (!_.isEmpty(suggestions) ? ('Did you mean ' + suggestions.join(', or ') + '?') : '');
|
||||
console.log('Warning: ' + (parent ? (parent + '.') : '') + method + msg + msgAddendum);
|
||||
}
|
||||
});
|
||||
return spec_js;
|
||||
}
|
||||
|
||||
|
||||
// get the equivalent javascript type from the given c type
|
||||
function getType(type_c, parent) {
|
||||
var type_js = type_c;
|
||||
_.find(xml2js.TYPEMAPS, function(to, from) {
|
||||
var pattern = new RegExp(from, 'i');
|
||||
if (type_c.search(pattern) == 0) {
|
||||
type_js = to;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (isPointer(type_js)) {
|
||||
var dataType = getPointerDataType(type_js);
|
||||
var className = parent.toLowerCase();
|
||||
if (_.has(xml2js.ARRAY_TYPEMAPS, dataType) && _.contains(xml2js.ARRAY_TYPEMAPS[dataType].classes, className)) {
|
||||
type_js = xml2js.ARRAY_TYPEMAPS[dataType].arrayType;
|
||||
} else if (_.has(xml2js.POINTER_TYPEMAPS, className) && _.has(xml2js.POINTER_TYPEMAPS[className], dataType)) {
|
||||
type_js = xml2js.POINTER_TYPEMAPS[className][dataType];
|
||||
} else if (_.has(xml2js.CLASSES, dataType)) { // TODO: verify that swig does this mapping
|
||||
type_js = dataType;
|
||||
} else {
|
||||
type_js = dataType + ' *'
|
||||
}
|
||||
}
|
||||
return type_js;
|
||||
}
|
||||
|
||||
|
||||
// verify that all types associated with the method are valid
|
||||
function hasValidTypes(methodSpec, methodName, parent) {
|
||||
var valid = true;
|
||||
var msg = (xml2js.opts.strict ? ' is omitted from JS documentation.' : ' has invalid type(s).');
|
||||
var printIgnoredMethodOnce = _.once(function() { console.log(methodName + msg); });
|
||||
_.each(methodSpec.params, function(paramSpec, paramName) {
|
||||
if (!isValidType(paramSpec.type, parent)) {
|
||||
valid = false;
|
||||
printIgnoredMethodOnce();
|
||||
console.log(' Error: parameter ' + paramName + ' has invalid type ' + typeToString(paramSpec.type));
|
||||
}
|
||||
});
|
||||
if (!_.isEmpty(methodSpec.return) && !isValidType(methodSpec.return.type, parent)) {
|
||||
valid = false;
|
||||
printIgnoredMethodOnce();
|
||||
console.log(' Error: returns invalid type ' + typeToString(methodSpec.return.type));
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
||||
// verify that type of variable is valid
|
||||
function ofValidType(varSpec, varName, parent) {
|
||||
if (isValidType(varSpec.type, parent)) {
|
||||
return true;
|
||||
} else {
|
||||
var msgAddendum = (xml2js.opts.strict ? ' Omitted from JS documentation.' : '');
|
||||
console.log('Error: ' + varName + ' is of invalid type ' + typeToString(varSpec.type) + '.' + msgAddendum);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// verify whether the given type is valid JS
|
||||
function isValidType(type, parent) {
|
||||
return (_.contains(_.values(xml2js.TYPEMAPS), type) ||
|
||||
_.has(xml2js.CLASSES, type) ||
|
||||
_.has(xml2js.ENUMS_BY_GROUP, type) ||
|
||||
_.contains(['Buffer', 'Function', 'mraa_result_t'], type) ||
|
||||
_.has((parent ? xml2js.CLASSES[parent].enums_by_group : []), type) ||
|
||||
isValidPointerType(type, parent));
|
||||
}
|
||||
|
||||
|
||||
function isValidPointerType(type, parent) {
|
||||
var className = parent.toLowerCase();
|
||||
var arrayTypemap = _.find(xml2js.ARRAY_TYPEMAPS, function(to) { return to.arrayType == type; });
|
||||
var valid = ((arrayTypemap && _.contains(arrayTypemap.classes, className)) ||
|
||||
(_.has(xml2js.POINTER_TYPEMAPS, className) && (_.contains(_.values(xml2js.POINTER_TYPEMAPS[className]), type))));
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
||||
// determines whether a type looks like a c pointer
|
||||
function isPointer(type) {
|
||||
return (type.search(/\w+\s*(\*|&)$/) != -1);
|
||||
}
|
||||
|
||||
|
||||
// remove extraneous whitespace from pointer types as canonical representation
|
||||
function normalizePointer(ptr) {
|
||||
return ptr.replace(/\s*$/, '');
|
||||
}
|
||||
|
||||
|
||||
// get the data type of a pointer (e.g. int is the data type of int*)
|
||||
function getPointerDataType(ptr) {
|
||||
return ptr.replace(/\s*(\*|&)$/, '');
|
||||
}
|
||||
|
||||
|
||||
// print more human friendly type for error messages
|
||||
function typeToString(type) {
|
||||
return type.replace('*', '*');
|
||||
}
|
||||
|
||||
|
||||
// get the detailed description of a method's parameters
|
||||
function getParamsDetails(spec_c) {
|
||||
var paras = getChildren(spec_c, 'para');
|
||||
var details = _.find(_.map(paras, function(para) {
|
||||
return getChild(para, 'parameterlist');
|
||||
}), function(obj) { return (obj != undefined); });
|
||||
return (details ? details.children : undefined);
|
||||
}
|
||||
|
||||
|
||||
// get the detailed description of a method's return value
|
||||
function getReturnDetails(spec_c) {
|
||||
var paras = getChildren(spec_c, 'para');
|
||||
return _.find(_.map(paras, function(para) {
|
||||
return getChild(para, 'simplesect');
|
||||
}), function(obj) { return ((obj != undefined) && (getAttr(obj, 'kind') == 'return')); });
|
||||
}
|
||||
|
||||
|
||||
// get (and flatten) the text of the given object
|
||||
function getText(obj, why) {
|
||||
// TODO: links ignored for now, patched for types for
|
||||
var GENERATE_LINK = function(x) { return x + ' '; }
|
||||
return _.reduce(obj.children, function(text, elem) {
|
||||
if (_.isString(elem)) {
|
||||
return text += elem.trim() + ' ';
|
||||
} else if (_.isPlainObject(elem)) {
|
||||
switch(elem.name) {
|
||||
case 'para':
|
||||
return text += getText(elem, why) + ' \n';
|
||||
case 'ref':
|
||||
return text += GENERATE_LINK(getText(elem, why));
|
||||
case 'parameterlist':
|
||||
case 'simplesect':
|
||||
return text; // to be handled elsewhere
|
||||
case 'programlisting':
|
||||
case 'htmlonly':
|
||||
return text; // ignored
|
||||
// TODO: html doesn't seem to work for yuidoc, using markdown for now
|
||||
case 'itemizedlist':
|
||||
return text += '\n' + getText(elem, why) + ' \n \n';
|
||||
case 'listitem':
|
||||
return text += '+ ' + getText(elem, why) + '\n';
|
||||
case 'bold':
|
||||
return text += '__' + getText(elem, why).trim() + '__ ';
|
||||
case 'ulink':
|
||||
return text += '[' + getText(elem, why).trim() + '](' + getAttr(elem, 'url').trim() + ') ';
|
||||
case 'image':
|
||||
// TODO: copy images over; hard coded for now
|
||||
var fn = getAttr(elem, 'name');
|
||||
return text += ' \n \n ';
|
||||
case 'linebreak':
|
||||
return text += ' \n';
|
||||
case 'ndash':
|
||||
return text += '– ';
|
||||
default:
|
||||
// TODO: incomplete list of doxygen xsd implemented
|
||||
console.warn('NYI Unknown Object Type: ' + elem.name);
|
||||
return text;
|
||||
//throw new Error('NYI Unknown Object Type: ' + elem.name);
|
||||
}
|
||||
} else {
|
||||
throw new Error('NYI Unknown Type: ' + (typeof elem));
|
||||
}
|
||||
}, '').trim();
|
||||
}
|
||||
|
||||
|
||||
// get the value of attribute with the given name of the given object
|
||||
function getAttr(obj, name) {
|
||||
return _.find(obj.attr, function(item) {
|
||||
return item.name == name;
|
||||
}).value;
|
||||
}
|
||||
|
||||
|
||||
// get the child object with the given name of the given object
|
||||
function getChild(obj, name) {
|
||||
return _.find(obj.children, function(child) {
|
||||
return child.name == name;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// get all children objects with the given name of the given object
|
||||
function getChildren(obj, name) {
|
||||
return _.filter(obj.children, function(child) {
|
||||
return child.name == name;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// debug helper: print untruncated object
|
||||
function printObj(obj) {
|
||||
console.log(util.inspect(obj, false, null));
|
||||
}
|
||||
|
||||
|
||||
module.exports = xml2js;
|
35
scripts/build-doc.sh
Executable file
35
scripts/build-doc.sh
Executable file
@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -x
|
||||
set -e
|
||||
|
||||
# Folders Location
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
ROOT_DIR="${DIR}/.."
|
||||
BUILD_DIR="${ROOT_DIR}/build"
|
||||
BUILD_LOGS_DIR="${BUILD_DIR}/logs"
|
||||
|
||||
# Install doxygen2jsdoc dependencies
|
||||
cd ${ROOT_DIR}/doxy/doxygen2jsdoc && npm install
|
||||
|
||||
# Install doxyport dependencies
|
||||
cd ${ROOT_DIR}/doxy/doxyport && make setup
|
||||
|
||||
# Create logs folder if not exists
|
||||
mkdir -p ${BUILD_LOGS_DIR}
|
||||
|
||||
# Make Documentation
|
||||
cd ${ROOT_DIR} && make -j8 -Cbuild 2> ${BUILD_LOGS_DIR}/build-doc.log
|
||||
|
||||
# Make Java Documentation
|
||||
cd ${BUILD_DIR} && find ../src/ -name "javaupm_*.i" > upm.i.list && \
|
||||
../doxy/doxyport/doxyport upm.i.list \
|
||||
--cmake ./compile_commands.json \
|
||||
--source ../src/interfaces/,../src/bacnetmstp \
|
||||
--destination src/ \
|
||||
--convert-protected-to-private \
|
||||
--output upm-java-files.txt \
|
||||
--mapping ../doxy/samples.mapping.txt 1> ${BUILD_LOGS_DIR}/doxyport.log && \
|
||||
rm -fr java && mkdir java && cd java && \
|
||||
doxygen ../Doxyfile-java 2> ${BUILD_LOGS_DIR}/doxygen-java.log
|
||||
|
@ -15,6 +15,6 @@ cmake \
|
||||
-DNPM=$NPM \
|
||||
-DBUILDTESTS=$BUILDTESTS \
|
||||
-DWERROR=$WERROR \
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||
-H. \
|
||||
-Bbuild
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user