diff options
-rw-r--r-- | cmake/Common/BuildSphinxDoc.cmake | 30 | ||||
-rw-r--r-- | cmake/SphinxCopyDoc.cmake | 14 | ||||
-rw-r--r-- | cmake/SphinxDesignDocStatus.cmake | 208 | ||||
-rw-r--r-- | docs/index.rst.in (renamed from docs/index.rst) | 19 | ||||
-rw-r--r-- | docs/processes/tfm_design_proposal_process.rst | 151 |
5 files changed, 409 insertions, 13 deletions
diff --git a/cmake/Common/BuildSphinxDoc.cmake b/cmake/Common/BuildSphinxDoc.cmake index 68887ff217..997de3b9c7 100644 --- a/cmake/Common/BuildSphinxDoc.cmake +++ b/cmake/Common/BuildSphinxDoc.cmake @@ -78,6 +78,9 @@ if (NOT SPHINX_NODOC) set(SPHINXCFG_TEMPLATE_FILE "${TFM_ROOT_DIR}/docs/conf.py.in") set(SPHINXCFG_CONFIGURED_FILE "${SPHINXCFG_OUTPUT_PATH}/conf.py") + set(SPHINX_TEMPLATE_INDEX_FILE "${TFM_ROOT_DIR}/docs/index.rst.in") + set(SPHINX_CONFIGURED_INDEX_FILE "${SPHINX_TMP_DOC_DIR}/index.rst") + set(SPHINX_DESIGN_DOC_ROOT "${TFM_ROOT_DIR}/docs/design_documents") #Version ID of TF-M. #TODO: this shall not be hard-coded here. We need a process to define the @@ -85,11 +88,34 @@ if (NOT SPHINX_NODOC) set(SPHINXCFG_TFM_VERSION "1.0.0-Beta") set(SPHINXCFG_TFM_VERSION_FULL "Version 1.0.0-Beta") + get_filename_component(_NDX_FILE_DIR ${SPHINX_CONFIGURED_INDEX_FILE} DIRECTORY ) + + #This command does not generates the specifyed output file and thus it will + #allways be run. Any other command or target depending on the "run-allways" + #output will be alwways executed too. + add_custom_command(OUTPUT run-allways + COMMAND "${CMAKE_COMMAND}" -E echo) + #Using add_custom_command allows CMake to generate proper clean commands #for document generation. add_custom_command(OUTPUT "${SPHINX_TMP_DOC_DIR}" - COMMAND "${CMAKE_COMMAND}" -D TFM_ROOT_DIR=${TFM_ROOT_DIR} -D DST_DIR=${SPHINX_TMP_DOC_DIR} -P "${TFM_ROOT_DIR}/cmake/SphinxCopyDoc.cmake" + "${SPHINX_CONFIGURED_INDEX_FILE}" + #Create target directory for SPHINX_CONFIGURED_INDEX_FILE. Needed + #by the next command. + COMMAND "${CMAKE_COMMAND}" -E make_directory "${_NDX_FILE_DIR}" + #Fill out index.rst template + COMMAND "${CMAKE_COMMAND}" -D TFM_ROOT_DIR=${TFM_ROOT_DIR} + -D SPHINX_TEMPLATE_INDEX_FILE=${SPHINX_TEMPLATE_INDEX_FILE} + -D SPHINX_CONFIGURED_INDEX_FILE=${SPHINX_CONFIGURED_INDEX_FILE} + -D SPHINX_DESIGN_DOC_ROOT=${SPHINX_DESIGN_DOC_ROOT} + -P "${TFM_ROOT_DIR}/cmake/SphinxDesignDocStatus.cmake" + #Copy document files to temp direcotry + COMMAND "${CMAKE_COMMAND}" -D TFM_ROOT_DIR=${TFM_ROOT_DIR} + -D DST_DIR=${SPHINX_TMP_DOC_DIR} + -D BINARY_DIR=${CMAKE_BINARY_DIR} + -P "${TFM_ROOT_DIR}/cmake/SphinxCopyDoc.cmake" WORKING_DIRECTORY "${TFM_ROOT_DIR}" + DEPENDS run-allways VERBATIM ) @@ -100,7 +126,7 @@ if (NOT SPHINX_NODOC) add_custom_command(OUTPUT "${SPHINXCFG_OUTPUT_PATH}/html" COMMAND "${SPHINX_EXECUTABLE}" -c "${SPHINXCFG_OUTPUT_PATH}" -b html "${SPHINX_TMP_DOC_DIR}" "${SPHINXCFG_OUTPUT_PATH}/html" WORKING_DIRECTORY "${TFM_ROOT_DIR}" - DEPENDS create_sphinx_input + DEPENDS create_sphinx_input run-allways COMMENT "Running Sphinx to generate user guide (HTML)." VERBATIM ) diff --git a/cmake/SphinxCopyDoc.cmake b/cmake/SphinxCopyDoc.cmake index 0dc1b71327..e95757c739 100644 --- a/cmake/SphinxCopyDoc.cmake +++ b/cmake/SphinxCopyDoc.cmake @@ -26,10 +26,10 @@ # #Usage: # cmake -DDST_DIR=<path to destination> -DTFM_ROOT_DIR=<path to tf-m root> \ -# -P SphinxCopyDoc.cmake +# -DBINARY_DIR=${CMAKE_BINARY_DIR} -P SphinxCopyDoc.cmake #Check input parameters -foreach(_PARAM IN ITEMS TFM_ROOT_DIR DST_DIR) +foreach(_PARAM IN ITEMS TFM_ROOT_DIR DST_DIR BINARY_DIR) if (NOT DEFINED ${_PARAM}) message(FATAL_ERROR "Variable ${_PARAM} is undefined. Please add -D${_PARAM}=<...> when calling this script.") endif() @@ -47,14 +47,14 @@ file(GLOB_RECURSE _COPY_FILES "${TFM_ROOT_DIR}/*.jpg" "${TFM_ROOT_DIR}/dco.txt") -#Subtract exluded files from copy files -list(REMOVE_ITEM _COPY_FILES "docs/index.rst") +#Remove intermediate and final document build outputs. +foreach(_PATH IN ITEMS BINARY_DIR DST_DIR) + file(RELATIVE_PATH _REL_DIR ${TFM_ROOT_DIR} ${${_PATH}}) + list(FILTER _COPY_FILES EXCLUDE REGEX "${_REL_DIR}/.*") +endforeach() #Copy files with directory tree. foreach(_FILE ${_COPY_FILES}) get_filename_component(_DIR ${_FILE} DIRECTORY) file(COPY ${_FILE} DESTINATION "${DST_DIR}/${_DIR}") endforeach() - -#Copy index.rst to the top level -file(COPY "${TFM_ROOT_DIR}/docs/index.rst" DESTINATION "${DST_DIR}") diff --git a/cmake/SphinxDesignDocStatus.cmake b/cmake/SphinxDesignDocStatus.cmake new file mode 100644 index 0000000000..e76c448a6c --- /dev/null +++ b/cmake/SphinxDesignDocStatus.cmake @@ -0,0 +1,208 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2019, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +#------------------------------------------------------------------------------- + +#A script to fill out the "toctree" file lists in index.rst.in to put design +#documents into the correct section based on their state. +# +#First rst files are parsed under a defined directory, to identify document +#status based on value of the ":Status:" field. Each state will have a list +#being generated to which matching documents are added. These lists are used +#then to fill template values using configure_file() +# +#Functions are used whenever possible to avoid global variable name space +#pollution. +# + +Include(CMakeParseArguments) + +#This function will search for .rst files in a given directory, read them and +#check if the “:Status:” field is defined in them. Then will add each file to a +#list with a name matching the status value. +#See the definition of _STATE_VALUES below for a list of valid state values. +#Files with missing or invalid state value will be placed on the "unknown" list. +#State value comparison is case insensitive. +# +#The output lists will have the prefix specified in the PREFIX parameter. +# +#Inputs: +# DIR Directory to scan for rst files. +# PREFIX The prefix of output list variables. +# +#Outputs: +# <prefix>_<state> - list; will hold all files with a valid state value. +# <prefix>_unknown - list; all files with missing or invalid state +# value. +#Examples +# sphinx_categorize_rst(DIR ${TFM_ROOT_DIR}/docs/design_documents +# PREFIX "DESIGN_DOCS") +# +function(sphinx_categorize_rst) + #Valid state values. "unknown" is used as a quard to detect invalid status + #values. + set(_STATE_VALUES "draft" "rejected" "accepted" "detailed" "unknown") + + #No option (on/off) arguments + set( _OPTIONS_ARGS ) + #Single option arguments (e.g. PROJ_NAME "bubu_project") + set( _ONE_VALUE_ARGS DIR PREFIX) + #List arguments (e.g. LANGUAGES C ASM CXX) + set( _MULTI_VALUE_ARGS ) + + cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" + "${_MULTI_VALUE_ARGS}" ${ARGN} ) + + #Check parameters + foreach(_PARAM IN LISTS _ONE_VALUE_ARGS) + if (NOT DEFINED _MY_PARAMS_${_PARAM}) + message(FATAL_ERROR "Parameter ${_PARAM} is missing!") + endif() + endforeach() + + #Search for .rst files + file(GLOB_RECURSE _RST_FILES + LIST_DIRECTORIES False + ${_MY_PARAMS_DIR}/**.rst) + + #Loop over .rst files + foreach(_FILE IN LISTS _RST_FILES) + #Read the file and return the first status line. + file(STRINGS ${_FILE} _CONTENT REGEX ":Status:" LIMIT_COUNT 1) + + #Nothing read -> the field is missing + if (_CONTENT STREQUAL "") + list(APPEND _STATUS_UNKNOWN ${_FILE}) + else() + #convert to upper case for case insensitive matching. + string(TOUPPER ${_CONTENT} _CONTENT) + + #loop over status values + foreach(_STATUS IN LISTS _STATE_VALUES) + #convert to upper case for case insensitive matching. + string(TOUPPER ${_STATUS} _STATUS) + #does status match the value from the file? + if (_CONTENT MATCHES ":STATUS:[ ]*${_STATUS}") + #add it to the list + list(APPEND _STATUS_${_STATUS} ${_FILE}) + #and exit the loop + break() + endif() + #"unknown" status is used as a quard and is an invalid value. + #If we reach it the file has invalid status value. + if (_STATUS STREQUAL "UNKNOWN") + #add the file to the unknown list + list(APPEND _STATUS_${_STATUS} ${_FILE}) + endif() + endforeach() + endif() + endforeach() + + #return the lists to the caller + foreach(_STATUS IN LISTS _STATE_VALUES) + string(TOUPPER ${_STATUS} _STATUS) + + if (DEFINED _STATUS_${_STATUS}) + set(${_MY_PARAMS_PREFIX}_${_STATUS} ${_STATUS_${_STATUS}} + PARENT_SCOPE) + endif() + endforeach() +endfunction() + +#Configure (fill in) the Sphinx index.rst.in template file. +#Call sphinx_categorize_rst() to get the .rst files sorted to lists, and then +#create the list of files for each design document section (convert the CMake +#lists to properly formatted text). +#Finally call configure_file() to fill in the values. +# +#Inputs: +# SRC Full path to template index file +# DST Full patch to configured output file. +#....DOC_DIR Path to design documents directory. +# DOC_ROOT Path to root directory of documentation +# +#Outputs: +# Configured <DST> file. +# +#Examples +# sphinx_categorize_rst(DIR ${TFM_ROOT_DIR}/docs/design_documents +# PREFIX "DESIGN_DOCS") +# +function(sphinx_configure_index) + set(_STATE_VALUES "draft" "rejected" "accepted" "detailed" "unknown") + + #No option (on/off) arguments + set( _OPTIONS_ARGS ) + #Single option arguments (e.g. PROJ_NAME "bubu_project") + set( _ONE_VALUE_ARGS SRC DST DOC_ROOT DOC_DIR) + #List arguments (e.g. LANGUAGES C ASM CXX) + set( _MULTI_VALUE_ARGS ) + + cmake_parse_arguments(_MY_PARAMS "${_OPTIONS_ARGS}" "${_ONE_VALUE_ARGS}" + "${_MULTI_VALUE_ARGS}" ${ARGN} ) + + #Check parameters + foreach(_PARAM IN LISTS _ONE_VALUE_ARGS) + if (NOT DEFINED _MY_PARAMS_${_PARAM}) + message(FATAL_ERROR "Parameter ${_PARAM} is missing!") + endif() + endforeach() + + #Assign design documents to lists based on their status + sphinx_categorize_rst(DIR ${_MY_PARAMS_DOC_DIR} PREFIX "_DD") + + #Look for invalid documents + if (DEFINED _DD_UNKNOWN) + string(REPLACE ";" "\n \t" _DD_UNKNOWN "${_DD_UNKNOWN}") + message(FATAL_ERROR " The following documents have no or invalid status:\n \t${_DD_UNKNOWN}") + endif() + + #The document root must be an absolute path + get_filename_component(_MY_PARAMS_DOC_ROOT "${_MY_PARAMS_DOC_ROOT}" + ABSOLUTE) + + #Loop over status lists + foreach(_STATUS IN ITEMS "DRAFT" "DETAILED" "ACCEPTED" "REJECTED") + #Create an empty file list for this status + set(${_STATUS}_DD_LIST "") + #If the source list is empty go to next iteration + if (NOT DEFINED _DD_${_STATUS}) + continue() + endif() + + #Loop over files on the list of this status + foreach(_FILE IN LISTS _DD_${_STATUS}) + #Get the path of the file relative to the document root + file(RELATIVE_PATH _REL_FILE ${_MY_PARAMS_DOC_ROOT} ${_FILE}) + #Detailed and Draft files go to the same section + if (_STATUS STREQUAL "DETAILED") + set(_STATUS "DRAFT") + endif() + + #Append the file to the output string + string(APPEND ${_STATUS}_DD_LIST "\n ${_REL_FILE}") + endforeach() + endforeach() + + #Call configure file to fill out the template. + configure_file(${_MY_PARAMS_SRC} ${_MY_PARAMS_DST} @ONLY) +endfunction() + +#If being run in script mode (cmake -P) and not included. +if (DEFINED CMAKE_SCRIPT_MODE_FILE + AND (CMAKE_CURRENT_LIST_FILE STREQUAL CMAKE_SCRIPT_MODE_FILE)) + #Check input variables. + foreach(_PARAM IN ITEMS SPHINX_TEMPLATE_INDEX_FILE SPHINX_CONFIGURED_INDEX_FILE + SPHINX_DESIGN_DOC_ROOT TFM_ROOT_DIR) + if (NOT DEFINED ${_PARAM}) + message(FATAL_ERROR "Parameter ${_PARAM} is not set!") + endif() + endforeach() + + sphinx_configure_index(SRC ${SPHINX_TEMPLATE_INDEX_FILE} + DST ${SPHINX_CONFIGURED_INDEX_FILE} + DOC_DIR ${SPHINX_DESIGN_DOC_ROOT} + DOC_ROOT ${TFM_ROOT_DIR}) +endif() diff --git a/docs/index.rst b/docs/index.rst.in index f9c1282979..e2151a468a 100644 --- a/docs/index.rst +++ b/docs/index.rst.in @@ -3,8 +3,11 @@ .. The build-system will copy all documents into a temporary directory tree before the documentation is built. - This fill will be copied to the top level and thus please use relative paths + This file will be copied to the top level and thus please use relative paths as if this file would be in <TFM_ROOT_DIR>. + + The values between @ characters will be filled in by CMake. + Welcome to TF-M's documentation! ================================ @@ -29,6 +32,14 @@ Welcome to TF-M's documentation! .. toctree:: :maxdepth: 2 + :caption: Processes + :glob: + :hidden: + + docs/processes/** + +.. toctree:: + :maxdepth: 2 :caption: Secure services :glob: :hidden: @@ -57,7 +68,7 @@ Welcome to TF-M's documentation! :glob: :hidden: - docs/design_documents/* + @ACCEPTED_DD_LIST@ .. toctree:: :caption: Draft design documents @@ -65,7 +76,7 @@ Welcome to TF-M's documentation! :glob: :hidden: - docs/design_documents/drafts/* + @DRAFT_DD_LIST@ .. toctree:: :caption: Rejected design documents @@ -73,7 +84,7 @@ Welcome to TF-M's documentation! :glob: :hidden: - docs/design_documents/rejected/* + @REJECTED_DD_LIST@ .. include:: readme.rst diff --git a/docs/processes/tfm_design_proposal_process.rst b/docs/processes/tfm_design_proposal_process.rst new file mode 100644 index 0000000000..478220e0b4 --- /dev/null +++ b/docs/processes/tfm_design_proposal_process.rst @@ -0,0 +1,151 @@ +Design proposal process +======================= + +:Author: Gyorgy Szing +:Organisation: Arm Limited +:Contact: Gyorgy Szing <gyorgy.szing@arm.com> + +Purpose and Content +------------------- +This document describes the steps of changing Trusted Firmware design. It +specifies: + + - the documentation format to be used + - the information which shall be captured + - the steps of the process + - and the location where the information shall be captured during the process. + +General +------- +The Trusted Firmware project uses the +`reStructuredText <http://docutils.sourceforge.net/rst.html>`_ format with +`Sphinx <http://www.sphinx-doc.org/en/master/usage/restructuredtext/index.html>`_ +extensions for documentation. Design documents shall be captured in this format. + +Design documents are kept under version control at the project's +`Gerrit server <https://review.trustedfirmware.org>`_. All decisions made and +important information gathered during the design discussion, which is not part +of the design document shall be captured as Gerrit comments or notes for +archiving purposes. To meet this requirement this process encourages the use of +the Gerrit web UI for communication. + + +Status of a document +--------------------- +The status of the document is captured in a *reST filed* called *Status*. +Bibliographic fields like the *Status* shall be kept near to the top of the +document after the document title. + +Example document fragment:: + + TF-M Crypto Service design + -------------------------- + + :Author: Antonio de Angelis + :Organization: Arm Limited + :Contact: Antonio de Angelis <antonio.deangelis@arm.com> + :Status: Draft + +Design documents are kept in three different sections of the documentation +reflecting the status of the document. The status of the document determines +the section it is in. Open (*Draft* and *Detailed* status) and accepted design +documents shall be put to the ``docs/design_documents`` +directory and rejected documents to the ``docs/design_documents/rejected`` +directory. + +Preparation +------------- +In order to work on TF-M documentation the TF-M git repository has to be +available locally. Setting up the documentation tools will allow pre-viewing the +documentation file in preparation. +For information on what tools are needed please refer to +:doc:`sw requirements </docs/user_guides/tfm_sw_requirement>`. To see how to get +a local copy of the TF-M repository please see +:doc:`build instructions </docs/user_guides/tfm_build_instruction>` + +Process steps +------------- + +- Write the design proposal in the format that is described in this document + with the status set to *Draft*. Put it to the ``docs/design_documents`` + directory and create a pull request. +- Start an e-mail thread on the + `TF-M mailing list <mailto:tf-m@lists.trustedfirmware.org>`_ for discussing + the proposal. +- Build initial consensus within the community about the proposed design + change, rework it according to the feedbacks and identify members who would + like to participate in the detailed review. +- When the "short list" of members who are willing to participate in the + detailed review is established, set the *Status* field to *Detailed* and + push the change to Gerrit. +- Add the members of the "short list" to the Gerrit review as reviewers. +- The detailed discussion then takes place in the Gerrit review and gets + recorded there. + Additional changes are submitted as new commits to the review. +- When the proposal is accepted, the status field is set to *Accepted*, the + change updated and merged. +- If at any point the proposal is rejected its status field is set to + *Rejected*, and the document is moved to the *rejected design documents* + section. + +.. uml:: + + @startuml + !define DRAFT_DIR **docs/design_documents/** + !define REJECTED_DIR **docs/design_documents/rejected/** + !define GERRIT_URL https://review.trustedfirmware.org + !define GERRIT_LINK [[GERRIT_URL trustedfirmware.org]] + !define MAINTAINER_RST_URL https://git.trustedfirmware.org/trusted-firmware-m.git/tree/maintainers.rst + !define TFM_MAILING_LIST mailto:tf-m@lists.trustedfirmware.org + !define NO_DECISION **no** + !define YES_DECISION **yes** + !define STATUS_DRAFT **Draft** + !define STATUS_DETAILED **Detailed** + !define STATUS_REJECTED **Rejected** + !define STATUS_ACCEPTED **Accepted** + + title Design Proposal Process + + start + :Create first draft.in [[http://docutils.sourceforge.net/rst.html ReST format]]; + :Set it's status to STATUS_DRAFT.; + + :Add your document under DRAFT_DIR.; + :Create pull-request at GERRIT_LINK.; + partition "Initial review." { + :Start an e-mail thread at [[TFM_MAILING_LIST tf-m mailing list]].; + repeat + :Build initial consensus within the + community about the proposed design change.; + :Gather developers interested in detailed review.; + repeat while (Ready for detailed review?) + } + + partition "Detailed review." { + :Set document status to STATUS_DETAILED.; + :Add reviewers to pull request.; + + repeat + :Discuss design in Gerrit comments/notes.; + :Log the result of discussions over + other communication channels + as Gerrit comments/notes.; + :Push new document version if needed.; + repeat while (Consensus reached?) + } + + if (Design is rejected?) then (YES_DECISION) + :Set document status to STATUS_REJECTED.; + :Move the document to REJECTED_DIR.; + else (NO_DECISION) + :Sets the document status to STATUS_ACCEPTED.; + endif + + ://Submit// the pull-request.; + stop + + @enduml + +-------------- + +*Copyright (c) 2019, Arm Limited. All rights reserved.* |