diff --git a/Makefile b/Makefile
index c5f4bf67ce..e0c2860873 100644
--- a/Makefile
+++ b/Makefile
@@ -11,11 +11,23 @@ VERSION_FULL=$(REPO)-`cat VERSION`
VERSION_MIN=$(REPO)-`cat VERSION`-minimal
HAVE_MODULES=git submodule | grep -v cmake >/dev/null
-SUBDIRS = $(BUILD)
-$(SUBDIRS):: configured
- $(MAKE) -C $@ $(MAKECMDGOALS)
+all: configured
+ $(MAKE) -C $(BUILD) $@
-all install install-aux doc docclean clean: $(SUBDIRS)
+install: configured
+ $(MAKE) -C $(BUILD) $@
+
+install-aux: configured
+ $(MAKE) -C $(BUILD) $@
+
+clean: configured docclean
+ $(MAKE) -C $(BUILD) $@
+
+doc: configured
+ $(MAKE) -C $(BUILD) $@
+
+docclean: configured
+ $(MAKE) -C $(BUILD) $@
dist:
@rm -rf $(VERSION_FULL) $(VERSION_FULL).tgz
diff --git a/aux/binpac b/aux/binpac
index 0f99acfbf6..34d9043740 160000
--- a/aux/binpac
+++ b/aux/binpac
@@ -1 +1 @@
-Subproject commit 0f99acfbf6205830f0db699a75554262c26427f9
+Subproject commit 34d90437403e4129468f89acce0bd1a99813a2f4
diff --git a/aux/bro-aux b/aux/bro-aux
index 1a7a9357fb..7ea5837b4b 160000
--- a/aux/bro-aux
+++ b/aux/bro-aux
@@ -1 +1 @@
-Subproject commit 1a7a9357fba88a43c90a39d8d72b42fa53b89b75
+Subproject commit 7ea5837b4ba8403731ca4a9875616c0ab501342f
diff --git a/aux/broccoli b/aux/broccoli
index a1a03c6868..d281350dbc 160000
--- a/aux/broccoli
+++ b/aux/broccoli
@@ -1 +1 @@
-Subproject commit a1a03c686866bd30ee086ff933128055a20ebd56
+Subproject commit d281350dbcc19c24aa6b6d89a4edc08a5c74a790
diff --git a/aux/broctl b/aux/broctl
index 03d39aa5d4..ed4d4ce1ad 160000
--- a/aux/broctl
+++ b/aux/broctl
@@ -1 +1 @@
-Subproject commit 03d39aa5d4ab24cd9b8e404a9ceb583d5270444c
+Subproject commit ed4d4ce1add51f0e08e6e8d2f5f247c2cbb422da
diff --git a/cmake b/cmake
index 44f2985475..f0f7958639 160000
--- a/cmake
+++ b/cmake
@@ -1 +1 @@
-Subproject commit 44f2985475e5ff6cc9061683e21ef4b184bdfc7e
+Subproject commit f0f7958639bb921985c1f58f1186da4b49b5d54d
diff --git a/doc/_static/broxygen-extra.css b/doc/_static/broxygen-extra.css
new file mode 100644
index 0000000000..dd56416783
--- /dev/null
+++ b/doc/_static/broxygen-extra.css
@@ -0,0 +1,3 @@
+.highlight {
+ background-color: #ffffff;
+}
diff --git a/doc/_static/broxygen.css b/doc/_static/broxygen.css
deleted file mode 100644
index d9c39a8506..0000000000
--- a/doc/_static/broxygen.css
+++ /dev/null
@@ -1,16 +0,0 @@
-a:hover
-{
- text-decoration:none;
- color:#c24444;
-}
-
-div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6
-{
-background-color:#ffffff;
-border-bottom: 1px solid #aaa;
-}
-
-th.field-name
-{
-white-space:nowrap;
-}
diff --git a/doc/_static/default.css_t b/doc/_static/default.css_t
new file mode 100644
index 0000000000..34c2157b25
--- /dev/null
+++ b/doc/_static/default.css_t
@@ -0,0 +1,309 @@
+/*
+ * default.css_t
+ * ~~~~~~~~~~~~~
+ *
+ * Sphinx stylesheet -- default theme.
+ *
+ * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+@import url("basic.css");
+
+/* -- page layout ----------------------------------------------------------- */
+
+body {
+ font-family: {{ theme_bodyfont }};
+ font-size: 100%;
+ background-color: {{ theme_footerbgcolor }};
+ color: #000;
+ margin: 0;
+ padding: 0;
+}
+
+div.document {
+ background-color: {{ theme_sidebarbgcolor }};
+}
+
+div.documentwrapper {
+ float: left;
+ width: 100%;
+}
+
+div.bodywrapper {
+ margin: 0 0 0 {{ theme_sidebarwidth|toint }}px;
+}
+
+div.body {
+ background-color: {{ theme_bgcolor }};
+ color: {{ theme_textcolor }};
+ padding: 0 20px 30px 20px;
+}
+
+{%- if theme_rightsidebar|tobool %}
+div.bodywrapper {
+ margin: 0 {{ theme_sidebarwidth|toint }}px 0 0;
+}
+{%- endif %}
+
+div.footer {
+ color: {{ theme_footertextcolor }};
+ background-color: {{ theme_footerbgcolor }};
+ width: 100%;
+ padding: 9px 0 9px 0;
+ text-align: center;
+ font-size: 75%;
+}
+
+div.footer a {
+ color: {{ theme_footertextcolor }};
+ text-decoration: underline;
+}
+
+div.related {
+ background-color: {{ theme_relbarbgcolor }};
+ line-height: 30px;
+ color: {{ theme_relbartextcolor }};
+}
+
+div.related a {
+ color: {{ theme_relbarlinkcolor }};
+}
+
+div.sphinxsidebar {
+ {%- if theme_stickysidebar|tobool %}
+ top: 30px;
+ bottom: 0;
+ margin: 0;
+ position: fixed;
+ overflow: auto;
+ height: auto;
+ {%- endif %}
+ {%- if theme_rightsidebar|tobool %}
+ float: right;
+ {%- if theme_stickysidebar|tobool %}
+ right: 0;
+ {%- endif %}
+ {%- endif %}
+}
+
+{%- if theme_stickysidebar|tobool %}
+/* this is nice, but it it leads to hidden headings when jumping
+ to an anchor */
+/*
+div.related {
+ position: fixed;
+}
+
+div.documentwrapper {
+ margin-top: 30px;
+}
+*/
+{%- endif %}
+
+div.sphinxsidebar h3 {
+ font-family: {{ theme_bodyfont }};
+ color: {{ theme_sidebartextcolor }};
+ font-size: 1.4em;
+ font-weight: normal;
+ margin: 0;
+ padding: 0;
+}
+
+div.sphinxsidebar h3 a {
+ color: {{ theme_sidebartextcolor }};
+}
+
+div.sphinxsidebar h4 {
+ font-family: {{ theme_bodyfont }};
+ color: {{ theme_sidebartextcolor }};
+ font-size: 1.3em;
+ font-weight: normal;
+ margin: 5px 0 0 0;
+ padding: 0;
+}
+
+div.sphinxsidebar p {
+ color: {{ theme_sidebartextcolor }};
+}
+
+div.sphinxsidebar p.topless {
+ margin: 5px 10px 10px 10px;
+}
+
+div.sphinxsidebar ul {
+ margin: 10px;
+ padding: 0;
+ color: {{ theme_sidebartextcolor }};
+}
+
+div.sphinxsidebar a {
+ color: {{ theme_sidebarlinkcolor }};
+}
+
+div.sphinxsidebar input {
+ border: 1px solid {{ theme_sidebarlinkcolor }};
+ font-family: sans-serif;
+ font-size: 1em;
+}
+
+{% if theme_collapsiblesidebar|tobool %}
+/* for collapsible sidebar */
+div#sidebarbutton {
+ background-color: {{ theme_sidebarbtncolor }};
+}
+{% endif %}
+
+/* -- hyperlink styles ------------------------------------------------------ */
+
+a {
+ color: {{ theme_linkcolor }};
+ text-decoration: none;
+}
+
+a:visited {
+ color: {{ theme_visitedlinkcolor }};
+ text-decoration: none;
+}
+
+{% if theme_externalrefs|tobool %}
+a.external {
+ text-decoration: none;
+ border-bottom: 1px dashed {{ theme_linkcolor }};
+}
+
+a.external:hover {
+ text-decoration: none;
+ border-bottom: none;
+}
+
+a.external:visited {
+ text-decoration: none;
+ border-bottom: 1px dashed {{ theme_visitedlinkcolor }};
+}
+{% endif %}
+
+/* -- body styles ----------------------------------------------------------- */
+
+div.body h1,
+div.body h2,
+div.body h3,
+div.body h4,
+div.body h5,
+div.body h6 {
+ font-family: {{ theme_bodyfont }};
+ background-color: #ffffff;
+ font-weight: normal;
+ color: {{ theme_headtextcolor }};
+ border-bottom: 1px solid #aaa;
+ margin: 20px -20px 10px -20px;
+ padding: 3px 0 3px 10px;
+}
+
+div.body h1 {
+ font-family: {{ theme_headfont }};
+ text-align: center;
+ border-bottom: none;
+}
+
+div.body h1 { margin-top: 0; font-size: 200%; }
+div.body h2 { font-size: 160%; }
+div.body h3 { font-size: 140%; }
+div.body h4 { font-size: 120%; }
+div.body h5 { font-size: 110%; }
+div.body h6 { font-size: 100%; }
+
+a.headerlink {
+ color: {{ theme_headlinkcolor }};
+ font-size: 0.8em;
+ padding: 0 4px 0 4px;
+ text-decoration: none;
+}
+
+a.headerlink:hover {
+ background-color: {{ theme_headlinkcolor }};
+ color: white;
+}
+
+div.admonition p.admonition-title + p {
+ display: inline;
+}
+
+div.admonition p {
+ margin-bottom: 5px;
+}
+
+div.admonition pre {
+ margin-bottom: 5px;
+}
+
+div.admonition ul, div.admonition ol {
+ margin-bottom: 5px;
+}
+
+div.note {
+ background-color: #eee;
+ border: 1px solid #ccc;
+}
+
+div.seealso {
+ background-color: #ffc;
+ border: 1px solid #ff6;
+}
+
+div.warning {
+ background-color: #ffe4e4;
+ border: 1px solid #f66;
+}
+
+p.admonition-title {
+ display: inline;
+}
+
+p.admonition-title:after {
+ content: ":";
+}
+
+pre {
+ padding: 5px;
+ background-color: {{ theme_codebgcolor }};
+ color: {{ theme_codetextcolor }};
+ line-height: 120%;
+ border: 1px solid #ac9;
+ border-left: none;
+ border-right: none;
+}
+
+tt {
+ background-color: #ecf0f3;
+ padding: 0 1px 0 1px;
+ font-size: 0.95em;
+}
+
+th {
+ background-color: #ede;
+}
+
+.warning tt {
+ background: #efc2c2;
+}
+
+.note tt {
+ background: #d6d6d6;
+}
+
+.viewcode-back {
+ font-family: {{ theme_bodyfont }};
+}
+
+div.viewcode-block:target {
+ background-color: #f4debf;
+ border-top: 1px solid #ac9;
+ border-bottom: 1px solid #ac9;
+}
+
+th.field-name
+{
+ white-space:nowrap;
+}
diff --git a/doc/_static/download.js b/doc/_static/download.js
new file mode 100644
index 0000000000..82bfe502cb
--- /dev/null
+++ b/doc/_static/download.js
@@ -0,0 +1,3 @@
+$(document).ready(function() {
+ $('.docutils.download').removeClass('download');
+});
diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html
index 90c448037e..518718c55c 100644
--- a/doc/_templates/layout.html
+++ b/doc/_templates/layout.html
@@ -1,10 +1,10 @@
{% extends "!layout.html" %}
-{% set css_files = css_files + ["_static/broxygen.css"] %}
-
{% block extrahead %}
-
+
+
+
{% endblock %}
{% block relbar2 %}{% endblock %}
diff --git a/doc/conf.py.in b/doc/conf.py.in
index e997796eda..72337b930f 100644
--- a/doc/conf.py.in
+++ b/doc/conf.py.in
@@ -59,7 +59,7 @@ release = '@VERSION@'
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
+today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
@@ -92,13 +92,15 @@ pygments_style = 'sphinx'
# a list of builtin themes.
html_theme = 'default'
+html_last_updated_fmt = '%B %d, %Y'
+
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
html_theme_options = {
"rightsidebar": "true",
"stickysidebar": "true",
-"externalrefs": "true",
+"externalrefs": "false",
"footerbgcolor": "#333",
"footertextcolor": "#ddd",
"sidebarbgcolor": "#ffffff",
diff --git a/doc/ext/bro.py b/doc/ext/bro.py
index 7ec02f76a8..a4f0142ce3 100644
--- a/doc/ext/bro.py
+++ b/doc/ext/bro.py
@@ -4,6 +4,9 @@
def setup(Sphinx):
Sphinx.add_domain(BroDomain)
+ Sphinx.add_node(see)
+ Sphinx.add_directive_to_domain('bro', 'see', SeeDirective)
+ Sphinx.connect('doctree-resolved', process_see_nodes)
from sphinx import addnodes
from sphinx.domains import Domain, ObjType, Index
@@ -18,7 +21,57 @@ from docutils.parsers.rst import Directive
from docutils.parsers.rst import directives
from docutils.parsers.rst.roles import set_classes
+class see(nodes.General, nodes.Element):
+ refs = []
+
+class SeeDirective(Directive):
+ has_content = True
+
+ def run(self):
+ n = see('')
+ n.refs = string.split(string.join(self.content))
+ return [n]
+
+def process_see_nodes(app, doctree, fromdocname):
+ for node in doctree.traverse(see):
+ content = []
+ para = nodes.paragraph()
+ para += nodes.Text("See also:", "See also:")
+ for name in node.refs:
+ join_str = " "
+ if name != node.refs[0]:
+ join_str = ", "
+ link_txt = join_str + name;
+
+ if name not in app.env.domaindata['bro']['idtypes']:
+ # Just create the text and issue warning
+ app.env.warn(fromdocname,
+ 'unknown target for ".. bro:see:: %s"' % (name))
+ para += nodes.Text(link_txt, link_txt)
+ else:
+ # Create a reference
+ typ = app.env.domaindata['bro']['idtypes'][name]
+ todocname = app.env.domaindata['bro']['objects'][(typ, name)]
+
+ newnode = nodes.reference('', '')
+ innernode = nodes.literal(_(name), _(name))
+ newnode['refdocname'] = todocname
+ newnode['refuri'] = app.builder.get_relative_uri(
+ fromdocname, todocname)
+ newnode['refuri'] += '#' + typ + '-' + name
+ newnode.append(innernode)
+ para += nodes.Text(join_str, join_str)
+ para += newnode
+
+ content.append(para)
+ node.replace_self(content)
+
class BroGeneric(ObjectDescription):
+ def update_type_map(self, idname):
+ if 'idtypes' not in self.env.domaindata['bro']:
+ self.env.domaindata['bro']['idtypes'] = {}
+ self.env.domaindata['bro']['idtypes'][idname] = self.objtype
+
def add_target_and_index(self, name, sig, signode):
targetname = self.objtype + '-' + name
if targetname not in self.state.document.ids:
@@ -29,9 +82,6 @@ class BroGeneric(ObjectDescription):
objects = self.env.domaindata['bro']['objects']
key = (self.objtype, name)
-# this is commented out mostly just to avoid having a special directive
-# for events in order to avoid the duplicate warnings in that case
- """
if key in objects:
self.env.warn(self.env.docname,
'duplicate description of %s %s, ' %
@@ -39,8 +89,9 @@ class BroGeneric(ObjectDescription):
'other instance in ' +
self.env.doc2path(objects[key]),
self.lineno)
- """
objects[key] = self.env.docname
+ self.update_type_map(name)
+
indextext = self.get_index_text(self.objtype, name)
if indextext:
self.indexnode['entries'].append(('single', indextext,
@@ -65,6 +116,8 @@ class BroNamespace(BroGeneric):
objects = self.env.domaindata['bro']['objects']
key = (self.objtype, name)
objects[key] = self.env.docname
+ self.update_type_map(name)
+
indextext = self.get_index_text(self.objtype, name)
self.indexnode['entries'].append(('single', indextext,
targetname, targetname))
@@ -91,10 +144,17 @@ class BroEnum(BroGeneric):
objects = self.env.domaindata['bro']['objects']
key = (self.objtype, name)
objects[key] = self.env.docname
+ self.update_type_map(name)
+
indextext = self.get_index_text(self.objtype, name)
#self.indexnode['entries'].append(('single', indextext,
# targetname, targetname))
m = sig.split()
+ if m[1] == "Notice::Type":
+ if 'notices' not in self.env.domaindata['bro']:
+ self.env.domaindata['bro']['notices'] = []
+ self.env.domaindata['bro']['notices'].append(
+ (m[0], self.env.docname, targetname))
self.indexnode['entries'].append(('single',
"%s (enum values); %s" % (m[1], m[0]),
targetname, targetname))
@@ -113,6 +173,26 @@ class BroAttribute(BroGeneric):
def get_index_text(self, objectname, name):
return _('%s (attribute)') % (name)
+class BroNotices(Index):
+ """
+ Index subclass to provide the Bro notices index.
+ """
+
+ name = 'noticeindex'
+ localname = l_('Bro Notice Index')
+ shortname = l_('notices')
+
+ def generate(self, docnames=None):
+ content = {}
+ for n in self.domain.env.domaindata['bro']['notices']:
+ modname = n[0].split("::")[0]
+ entries = content.setdefault(modname, [])
+ entries.append([n[0], 0, n[1], n[2], '', '', ''])
+
+ content = sorted(content.iteritems())
+
+ return content, False
+
class BroDomain(Domain):
"""Bro domain."""
name = 'bro'
@@ -140,8 +220,13 @@ class BroDomain(Domain):
'id': XRefRole(),
'enum': XRefRole(),
'attr': XRefRole(),
+ 'see': XRefRole(),
}
+ indices = [
+ BroNotices,
+ ]
+
initial_data = {
'objects': {}, # fullname -> docname, objtype
}
@@ -154,13 +239,24 @@ class BroDomain(Domain):
def resolve_xref(self, env, fromdocname, builder, typ, target, node,
contnode):
objects = self.data['objects']
- objtypes = self.objtypes_for_role(typ)
- for objtype in objtypes:
- if (objtype, target) in objects:
- return make_refnode(builder, fromdocname,
- objects[objtype, target],
- objtype + '-' + target,
- contnode, target + ' ' + objtype)
+ if typ == "see":
+ if target not in self.data['idtypes']:
+ self.env.warn(fromdocname,
+ 'unknown target for ":bro:see:`%s`"' % (target))
+ return []
+ objtype = self.data['idtypes'][target]
+ return make_refnode(builder, fromdocname,
+ objects[objtype, target],
+ objtype + '-' + target,
+ contnode, target + ' ' + objtype)
+ else:
+ objtypes = self.objtypes_for_role(typ)
+ for objtype in objtypes:
+ if (objtype, target) in objects:
+ return make_refnode(builder, fromdocname,
+ objects[objtype, target],
+ objtype + '-' + target,
+ contnode, target + ' ' + objtype)
def get_objects(self):
for (typ, name), docname in self.data['objects'].iteritems():
diff --git a/doc/index.rst b/doc/index.rst
index 022552f3d4..ba3df81e7d 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -57,10 +57,11 @@ Other Bro Components
components/pysubnettree/README
components/trace-summary/README
-Indices and tables
-------------------
+Other Indices and References
+----------------------------
-* :ref:`genindex`
+* :ref:`General Index `
+* `Notice Index `_
* :ref:`search`
Internal References
diff --git a/doc/scripts/example.bro b/doc/scripts/example.bro
index c239f2d2a2..d2d0ec6879 100644
--- a/doc/scripts/example.bro
+++ b/doc/scripts/example.bro
@@ -5,6 +5,16 @@
##! (reST) document's summary section.
##!
##! .. tip:: You can embed directives and roles within ``##``-stylized comments.
+##!
+##! There's also a custom role to reference any identifier node in
+##! the Bro Sphinx domain that's good for "see alsos", e.g.
+##!
+##! See also: :bro:see:`Example::a_var`, :bro:see:`Example::ONE`,
+##! :bro:see:`SSH::Info`
+##!
+##! And a custom directive does the equivalent references:
+##!
+##! .. bro:see:: Example::a_var Example::ONE SSH::Info
# Comments that use a single pound sign (#) are not significant to
# a script's auto-generated documentation, but ones that use a
diff --git a/testing/btest/Baseline/doc.autogen-reST-example/example.rst b/testing/btest/Baseline/doc.autogen-reST-example/example.rst
index b76b9af59b..880fa0e171 100644
--- a/testing/btest/Baseline/doc.autogen-reST-example/example.rst
+++ b/testing/btest/Baseline/doc.autogen-reST-example/example.rst
@@ -15,6 +15,16 @@ these comments are transferred directly into the auto-generated
.. tip:: You can embed directives and roles within ``##``-stylized comments.
+There's also a custom role to reference any identifier node in
+the Bro Sphinx domain that's good for "see alsos", e.g.
+
+See also: :bro:see:`Example::a_var`, :bro:see:`Example::ONE`,
+:bro:see:`SSH::Info`
+
+And a custom directive does the equivalent references:
+
+.. bro:see:: Example::a_var Example::ONE SSH::Info
+
:Imports: :doc:`policy/frameworks/software/vulnerable `
Summary