Commit 505403d0 authored by Valentin Volkl's avatar Valentin Volkl Committed by Marco Clemencic
Browse files

Doc: Add Sphinx-based Documentation

parent 1ca2e11c
......@@ -14,6 +14,7 @@ stages:
- pre-build-checks
- build
- test
- deploy
variables:
LCG_VERSION: "100"
......@@ -253,3 +254,68 @@ check-copyright:
- curl -o lb-check-copyright "https://gitlab.cern.ch/lhcb-core/LbDevTools/-/raw/master/LbDevTools/SourceTools.py?inline=false"
- python lb-check-copyright --exclude lhcbproject.yml origin/${TARGET_BRANCH}
allow_failure: true
website:
stage: build
image: python
script:
- rm -rf public
- mkdir -p public
- cd docs
- pip install -r source/requirements.txt
- make html
- cp -a build/html/. ../public/.
allow_failure: true
artifacts:
paths:
- public
expire_in: 1 day
doxygen:
stage: test
tags:
- cvmfs
needs:
- job: "view-gcc8"
artifacts: true
script:
- . /cvmfs/sft.cern.ch/lcg/views/LCG_${LCG_VERSION}/x86_64-centos7-gcc8-opt/setup.sh
# Override CMake from the view (too old in LCG 97a)
- export PATH="/cvmfs/sft.cern.ch/lcg/contrib/CMake/3.18.3/Linux-x86_64/bin:$PATH"
- find build -type f -exec touch -d $(date +@%s) \{} \; # not to re-run cmake
- cmake --build build --target doc
- rm -rf public
- mkdir -p public/doxygen
- cp -r GaudiRelease/web_helpers/. public/doxygen/.
- mv build/doxygen/html ${CI_COMMIT_REF_SLUG}
- zip -r -q public/doxygen/${CI_COMMIT_REF_SLUG}.zip ${CI_COMMIT_REF_SLUG}
artifacts:
paths:
- public
expire_in: 1 day
# see https://gitlab.cern.ch/gitlabci-examples/deploy_eos for the details
# of the configuration
deploy-website:
stage: deploy
needs:
- job: "website"
artifacts: true
- job: "doxygen"
artifacts: true
rules:
- if: $CI_COMMIT_BRANCH == "master"
- if: $CI_COMMIT_TAG
image: gitlab-registry.cern.ch/ci-tools/ci-web-deployer:latest
script:
- test -z "$EOS_ACCOUNT_USERNAME" -o -z "$EOS_ACCOUNT_PASSWORD" -o -z "$EOS_PATH" && exit 0 || true
# Script that performs the deploy to EOS. Makes use of the variables defined in the project
# It will copy the generated content to the folder in EOS
- export CI_OUTPUT_DIR=public/
- deploy-eos
# do not run any globally defined before_script or after_script for this step
before_script: []
after_script: []
Gaudi Contribution Guide
========================
The Gaudi project is open source (see the LICENSE) and welcomes
contributions from experiments and users.
To contribute to Gaudi development you can *fork* the project from
CERN GitLab, where the Gaudi source is held.
Bug fixes and features should be developed in your own branch, then
a *merge request* made back to the upstream Gaudi repository.
By submitting a merge request to the Gaudi repository you agree that
your contribution will be copyrighted to CERN and covered by the Apache 2
licence, as per the LICENSE.
Coding Style Guidelines
-----------------------
Code contributions to Gaudi should adhere to the ``clang-format`` rules
(an automatic check is part of the Continuous Integration system).
......@@ -40,14 +40,15 @@ file(GLOB project_rel_notes ${CMAKE_CURRENT_SOURCE_DIR}/doc/release.notes*.html)
set(DOXYGEN_HTML_EXTRA_FILES "${CMAKE_CURRENT_SOURCE_DIR}/doc/doxygen/issue_tracker_links.js;${project_rel_notes}")
string(REPLACE ";" " " DOXYGEN_HTML_EXTRA_FILES "${DOXYGEN_HTML_EXTRA_FILES}")
# run Doxygen to generate the documentation
add_custom_target(run-doxygen
COMMAND run
Doxygen::doxygen ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
COMMENT "Running Doxygen...")
if(TARGET Doxygen::doxygen)
# run Doxygen to generate the documentation
add_custom_target(run-doxygen
COMMAND run $<TARGET_FILE:Doxygen::doxygen> ${CMAKE_CURRENT_BINARY_DIR}/doc/doxygen/Doxyfile
COMMENT "Running Doxygen...")
# 'doc' target
add_custom_target(doc DEPENDS run-doxygen)
# 'doc' target
add_custom_target(doc DEPENDS run-doxygen)
endif()
option(DOXYGEN_WITH_LOCAL_MATHJAX
"Use a local copy of MathJax instead of taking it from cdn.mathjax.org"
......
......@@ -51,7 +51,7 @@ PROJECT_BRIEF =
# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
# to the output directory.
PROJECT_LOGO = @CMAKE_CURRENT_SOURCE_DIR@/logo.png
PROJECT_LOGO = @CMAKE_CURRENT_SOURCE_DIR@/doc/doxygen/logo.png
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is
......@@ -1045,7 +1045,7 @@ HTML_FILE_EXTENSION = .html
# of the possible markers and block names see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_HEADER = @CMAKE_CURRENT_SOURCE_DIR@/header.html
HTML_HEADER = @CMAKE_CURRENT_SOURCE_DIR@/doc/doxygen/header.html
# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
# generated HTML page. If the tag is left blank doxygen will generate a standard
......
Related external libraries {#externaldocs}
==========================
From [LCG version @heptools_version@][lcg-details]:
From [LCG version @LCG_VERSION@][lcg-details]:
- LCG Application Area:
- [CORAL @CORAL_config_version@][coral] (relational access)
- [COOL @COOL_config_version@][cool] (conditions database)
- [ROOT @ROOT_config_version@][root] (persistency)
- [@RELAX_config_version@][relax] (common dictionaries for I/O and interactivity)
......@@ -13,20 +11,19 @@ From [LCG version @heptools_version@][lcg-details]:
- [Boost @Boost_version@](http://www.boost.org/doc/libs/@Boost_url_version@/)
- [AIDA @AIDA_config_version@](http://aida.freehep.org/doc/v@AIDA_config_version@/api/) (histogramming)
- [Xerces-C @XercesC_config_version@](http://xml.apache.org/xerces-c/api-@XercesC_major_version@)
- [GNU Scientific Library (GSL) @GSL_config_version@](http://www.gnu.org/software/gsl/manual/html_node/index.html)
- [Python @Python_config_version@](http://www.python.org/doc/@Python_config_version@/) (scripting and interactivity)
- [HepMC @HepMC_config_version@](http://lcgapp.cern.ch/project/simu/HepMC/)
See also:
- GNU Standard Template Library
- [gcc 4.8.1](http://gcc.gnu.org/onlinedocs/gcc-4.8.1/libstdc++/api/)
- [gcc 10.3.0](https://gcc.gnu.org/onlinedocs/gcc-10.3.0/libstdc++/api/)
- C++ Reference
- <http://en.cppreference.com/w/cpp>
- <http://www.cplusplus.com/reference/>
[lcg-details]: http://lcginfo.cern.ch/release/@heptools_version@/
[lcg-details]: http://lcginfo.cern.ch/release/@LCG_VERSION@/
[coral]: https://twiki.cern.ch/twiki/bin/view/Persistency/Coral
[cool]: https://twiki.cern.ch/twiki/bin/view/Persistency/Cool
[root]: http://root.cern.ch/
......
......@@ -25,7 +25,7 @@ the [list of classes](annotated.html) or via the [class hierarchy](hierarchy.htm
</table>
See also: \ref externaldocs (from [LCG version @heptools_version@][lcg-details])
See also: \ref externaldocs (from [LCG version @LCG_VERSION@][lcg-details])
[sources]: https://gitlab.cern.ch/gaudi/Gaudi/tags
......@@ -33,4 +33,4 @@ See also: \ref externaldocs (from [LCG version @heptools_version@][lcg-details])
[gug-pdf]: http://cern.ch/lhcb-comp/Frameworks/Gaudi/Gaudi_v9/GUG/GUG.pdf
[gug-2up-pdf]: http://cern.ch/lhcb-comp/Frameworks/Gaudi/Gaudi_v9/GUG/GUG-2up.pdf
[lcg-details]: http://lcginfo.cern.ch/release/@heptools_version@/
[lcg-details]: http://lcginfo.cern.ch/release/@LCG_VERSION@/
#!/usr/bin/env python
#####################################################################################
# (c) Copyright 1998-2019 CERN for the benefit of the LHCb and ATLAS collaborations #
# #
# This software is distributed under the terms of the Apache version 2 licence, #
# copied verbatim in the file "LICENSE". #
# #
# In applying this licence, CERN does not waive the privileges and immunities #
# granted to it by virtue of its status as an Intergovernmental Organization #
# or submit itself to any jurisdiction. #
#####################################################################################
'''
Script to prepare the release of Gaudi.
@author Marco Clemencic
'''
from __future__ import print_function
import os
import sys
import logging
import re
from subprocess import check_output, CalledProcessError
def checkGitVersion():
'''
Ensure we have a usable version of Git (>= 1.7.9.1).
See:
* https://raw.githubusercontent.com/git/git/master/Documentation/RelNotes/1.7.9.1.txt
* https://github.com/git/git/commit/36ed1913e1d5de0930e59db6eeec3ccb2bd58bd9
'''
version = check_output(['git', '--version']).split()[-1]
if versionKey(version) < versionKey('1.7.9.1'):
raise RuntimeError(
'bad version of git found: %s (1.7.9.1 required)' % version)
_VK_RE = re.compile(r'(\d+|\D+)')
def versionKey(x):
'''
Key function to be passes to list.sort() to sort strings
as version numbers.
'''
return [
int(i) if i[0] in '0123456789' else i for i in _VK_RE.split(x) if i
]
def findLatestTag():
'''
Return the latest Gaudi tag (of the format "v*r*...").
'''
logging.info('looking for latest tag')
cmd = ['git', 'tag']
logging.debug('using command %r', cmd)
output = check_output(cmd)
vers_exp = re.compile(r'^v\d+r\d+(p\d+)?$')
tags = [tag for tag in output.splitlines() if vers_exp.match(tag)]
if tags:
tags.sort(key=versionKey)
logging.info('found %s', tags[-1])
return tags[-1]
logging.info('no valid tag found')
def releaseNotes(path=os.curdir, from_tag=None, branch=None):
'''
Return the release notes (in the old LHCb format) extracted from git
commits for a given path.
'''
cmd = [
'git', 'log', '--first-parent', '--date=short',
'--pretty=format:! %ad - commit %h%n%n%w(80,1,3)- %s%n%n%b%n'
]
if from_tag:
cmd.append('{0}..{1}'.format(from_tag, branch or ''))
elif branch:
cmd.append(branch)
cmd.append('--')
cmd.append(path)
logging.info('preparing release notes for %s%s', path,
' since ' + from_tag if from_tag else '')
logging.debug('using command %r', cmd)
# remove '\r' characters from commit messages
out = check_output(cmd).replace('\r', '')
# replace ' - commit 123abc' with ' - Contributor Name (commit 123abc)'
def add_contributors(match):
try:
authors = set(
check_output([
'git',
'log',
'--pretty=format:%aN',
'{0}^1..{0}^2'.format(match.group(1)),
]).splitlines())
return ' - {0} (commit {1})'.format(', '.join(sorted(authors)),
match.group(1))
except CalledProcessError:
return match.group(0)
out = re.sub(r' - commit ([0-9a-f]+)', add_contributors, out)
return out
def updateReleaseNotes(path, notes):
'''
Smartly prepend the content of notes to the release.notes file in path.
'''
notes_filename = os.path.join(path, 'doc', 'release.notes')
logging.info('updating %s', notes_filename)
from itertools import takewhile, dropwhile
def dropuntil(predicate, iterable):
return dropwhile(lambda x: not predicate(x), iterable)
with open(notes_filename) as notes_file:
orig_data = iter(list(notes_file))
header = takewhile(str.strip, orig_data)
with open(notes_filename, 'w') as notes_file:
notes_file.writelines(header)
notes_file.write('\n')
notes_file.writelines(l.rstrip() + '\n' for l in notes.splitlines())
notes_file.write('\n')
notes_file.writelines(
dropuntil(re.compile(r'^!?============').match, orig_data))
def tag_bar(pkg, version=None):
title = ' %s %s ' % (pkg, version)
letf_chars = (78 - len(title)) / 2
right_chars = 78 - letf_chars - len(title)
separator = ('=' * letf_chars) + title + ('=' * right_chars)
return separator
def main():
logging.basicConfig(level=logging.DEBUG)
os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# Find the version of HEPTools (LCG)
for l in open('toolchain.cmake'):
m = re.match(r'^\s*set\(\s*heptools_version\s+(\S*)\s*\)', l)
if m:
HEPToolsVers = m.group(1)
print("Using HEPTools", HEPToolsVers)
break
else:
logging.error('Cannot find HEPTools version')
sys.exit(1)
# Collect all the packages in the project with their directory
def all_subdirs():
for dirpath, dirnames, filenames in os.walk(os.curdir):
if 'CMakeLists.txt' in filenames and dirpath != os.curdir:
dirnames[:] = []
yield dirpath
else:
dirnames[:] = [
dirname for dirname in dirnames
if (not dirname.startswith('build.') and dirname != 'cmake'
)
]
# Ask for the version of the project
latest_tag = findLatestTag()
old_version = latest_tag.split('_')[-1]
new_version = raw_input(("The old version of the project is %s, "
"which is the new one? ") % old_version)
release_notes = {}
# for each package in the project update the release.notes
for pkgdir in all_subdirs():
updateReleaseNotes(
pkgdir,
tag_bar('Gaudi', new_version) + '\n\n' + releaseNotes(
pkgdir, latest_tag, 'master'))
# update the global CMakeLists.txt
out = []
for l in open('CMakeLists.txt'):
if l.strip().startswith('gaudi_project'):
l = 'gaudi_project(Gaudi %s)\n' % new_version
out.append(l)
open('CMakeLists.txt', "w").writelines(out)
if __name__ == '__main__':
checkGitVersion()
main()
#!/usr/bin/env python
#####################################################################################
# (c) Copyright 1998-2019 CERN for the benefit of the LHCb and ATLAS collaborations #
# #
# This software is distributed under the terms of the Apache version 2 licence, #
# copied verbatim in the file "LICENSE". #
# #
# In applying this licence, CERN does not waive the privileges and immunities #
# granted to it by virtue of its status as an Intergovernmental Organization #
# or submit itself to any jurisdiction. #
#####################################################################################
"""
Small script to prepare the tags and the distribution special directory for a
release of Gaudi.
See https://twiki.cern.ch/twiki/bin/view/Gaudi/GaudiSVNRepository for a
description of the repository structure.
"""
from __future__ import print_function
__author__ = "Marco Clemencic <Marco.Clemencic@cern.ch>"
import os
import re
import sys
import tempfile
import shutil
from subprocess import Popen, PIPE
from ConfigParser import ConfigParser
def svn(*args, **kwargs):
print("> svn", " ".join(args))
return Popen(["svn"] + list(args), **kwargs)
def svn_ls(url):
return svn("ls", url, stdout=PIPE).communicate()[0].splitlines()
def basename(url):
return url.rsplit("/", 1)[-1]
def dirname(url):
return url.rsplit("/", 1)[1]
def svn_exists(url):
d, b = url.rsplit("/", 1)
l = [x.rstrip("/") for x in svn_ls(d)]
return b in l
def checkout_structure(url, proj, branch):
def checkout_level(base):
dirs = ["%s/%s" % (base, d) for d in svn_ls(base) if d.endswith("/")]
svn("up", "-N", *args).wait()
return dirs
root = basename(url)
svn("co", "-N", url, root).wait()
old_dir = os.getcwd()
os.chdir(root)
svn("up", "-N", proj).wait()
br = [proj] + branch.split("/")
for base in ["/".join(br[:n + 1]) for n in range(len(br))]:
checkout_level(base)
checkout_level(proj + "/tags")
os.chdir(old_dir)
return root
def main():
from optparse import OptionParser
parser = OptionParser()
parser.add_option(
"--pre",
action="store_true",
help="Create -pre tags instead of final tags.")
parser.add_option(
"-b",
"--branch",
help=
"Use the given (global) branch as source for the tags instead of the trunk"
)
opts, args = parser.parse_args()
if opts.branch:
opts.branch = "/".join(["branches", "GAUDI", opts.branch])
else:
opts.branch = "trunk"
url = "svn+ssh://svn.cern.ch/reps/gaudi"
proj = "Gaudi"
container = "GaudiRelease"
project_info = ConfigParser()
project_info.optionxform = str # make options case sensitive
project_info.read('project.info')
packages = dict(project_info.items('Packages'))
tempdir = tempfile.mkdtemp()
try:
os.chdir(tempdir)
# prepare repository structure (and move to its top level)
os.chdir(checkout_structure(url, proj, opts.branch))
# note that the project does not have "-pre"
pvers = "%s_%s" % (proj.upper(), packages[container])
# prepare project tag
ptagdir = "%s/tags/%s/%s" % (proj, proj.upper(), pvers)
if not svn_exists(ptagdir):
svn('cp', '/'.join([proj, opts.branch]), ptagdir).wait()
# prepare package tags
tag_re = re.compile(r"^v(\d+)r(\d+)(?:p(\d+))?$")
for p in packages:
tag = packages[p]
pktagdir = "%s/tags/%s/%s" % (proj, p, tag)
# I have to make the tag if it doesn't exist and (if we use -pre tags)
# neither the -pre tag exists.
no_tag = not svn_exists(pktagdir)
make_tag = no_tag or (opts.pre and no_tag
and not svn_exists(pktagdir + "-pre"))
if make_tag:
if opts.pre:
pktagdir += "-pre"
svn("cp", "/".join([proj, opts.branch, p]), pktagdir).wait()
# Atlas type of tag
tagElements = tag_re.match(tag)
if tagElements:
tagElements = "-".join([
"%02d" % int(el or "0") for el in tagElements.groups()
])
pktagdir = "%s/tags/%s/%s-%s" % (proj, p, p, tagElements)
svn("cp", "/".join([proj, opts.branch, p]),
pktagdir).wait()
else:
if not no_tag:
# needed for the copy in the global tag
svn("up", "--depth=empty", pktagdir).wait()
svn("ci").wait()
finally:
shutil.rmtree(tempdir, ignore_errors=True)
return 0
if __name__ == '__main__':
sys.exit(main())
Options +Indexes
DirectoryIndex index.php index.html index.htm index.php
RewriteEngine On
# this is a clever trick for avoiding RewriteBase
# see http://stackoverflow.com/a/21063276
RewriteCond %{REQUEST_URI}::$1 ^(.*?/)(.*)::\2$
RewriteRule ^(.*)$ - [E=BASE:%1]
# add /index.html to the top entry
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} !-f
RewriteRule ^([^/]+)/?$ %{ENV:BASE}$1/index.html [L,R]
# extract the requested file from zip, unless it exists
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} !-f
RewriteRule ^([^/]+)/(.+) %{ENV:BASE}/extract.php?zip=%{DOCUMENT_ROOT}%{ENV:BASE}$1.zip&path=$1/$2 [L]
<?php
$zip_name = $_GET['zip'];
$path = $_GET['path'];
if ( ! $zip_name || ! file_exists($zip_name) ) {
header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found', true, 404);
echo "404 - Not Found";
return;
}
switch(pathinfo($path, PATHINFO_EXTENSION)) {
case 'css': $ct = 'text/css'; break;
case 'png': $ct = 'image/png'; break;
case 'gif': $ct = 'image/gif'; break;
case 'jpg': $ct = 'image/jpeg'; break;
case 'js': $ct = 'text/javascript'; break;
case 'svg': $ct = 'image/svg+xml'; break;
case 'json': $ct = 'application/json'; break;
default: $ct = 'text/html';
}
# PHP < 5.4.5 (or < 5.3.15) has problems with zip files with more than 65535
# entries (issue in the version of libzip used, see
# https://libzip.org/news/release-0.10.html)
if (PHP_VERSION_ID >= 50405) {
$zip = new ZipArchive();
if ($zip->open($zip_name)) {
$index = $zip->locateName($path);
if ( $index === FALSE ) {
header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found', true, 404);
echo "404 - Not Found";
} else {
header('Content-Type: ' . $ct);
echo $zip->getFromIndex($index);
}
$zip->close();
}
} else {
exec('/usr/bin/unzip -qq -l "' . $zip_name . '" "' . $path. '"',
$output, $return_var);
if ( $return_var != 0 ) {
header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found', true, 404);
echo "404 - Not Found";
} else {
header('Content-Type: ' . $ct);
passthru('/usr/bin/unzip -p "' . $zip_name . '" "' . $path. '"');
}
}
?>
<!DOCTYPE html>
<html>
<head><title>Available Gaudi Doxygen documentations</title></head>
<body>
<h1>Gaudi Doxygen documentation available for the following versions:</h1>
<ul>
<?php