Auto-generate supported board list from BSP metadata

This updates the build system, to read BSP metadata including "name",
"url", "maker" and "arch", and auto-generate the list of supported
boards in the landing page.

It requires that each BSP is updated with this metadata, and each new
BSP has this metadata added to its "bsp.yml" file.
diff --git a/.gitignore b/.gitignore
index afb1568..e0d0a16 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@
 .*
 venv/
 site_dir
+custom-theme/supported-boards.html
diff --git a/build.py b/build.py
index 402e688..bb20c44 100755
--- a/build.py
+++ b/build.py
@@ -1,9 +1,10 @@
 #!/usr/bin/env python
 
 from __future__ import print_function
-import os
+from os import path, listdir
 import sh
 from mkdocs import config
+import yaml
 
 dependent_repos = [
     'mynewt-documentation',
@@ -13,6 +14,71 @@
     'mynewt-nimble'
 ]
 
+BSP_DIR = "hw/bsp"
+BSP_ARCH_NAMES = {
+    'arc': 'ARC',
+    'cortex_m0': 'Cortex-M0',
+    'cortex_m3': 'Cortex-M3',
+    'cortex_m33': 'Cortex-M33',
+    'cortex_m4': 'Cortex-M4',
+    'cortex_m7': 'Cortex-M7',
+    'mips': 'MIPS',
+    'pic32': 'PIC32',
+    'rv32imac': 'RISC-V',
+}
+
+
+class BSP:
+    '''
+    Stores data for Mynewt BSPs
+    '''
+
+    def __init__(self, name, url, maker, arch):
+        self.name = name
+        self.url = url
+        self.maker = maker
+        self._arch = arch
+
+    def arch(self):
+        return BSP_ARCH_NAMES[self._arch]
+
+    def repr(self):
+        return "{}(name={}, url={}, maker={})".format(
+            self.__class__.__name__, self.name, self.url, self.maker)
+
+
+def generate_supported_boards(filename, bsps):
+    with open(filename, 'w') as f:
+        f.write("<ul>\n")
+        for bsp in bsps:
+            f.write("<li>\n")
+            f.write("<a href=\"{}\"> {} </a> from {} ({})\n".format(bsp.url,
+                                                                    bsp.name,
+                                                                    bsp.maker,
+                                                                    bsp.arch()))
+            f.write("</li>\n")
+        f.write("</ul>\n")
+
+
+def find_BSPs():
+    bsp_dir = path.join(cwd, '../mynewt-core', BSP_DIR)
+    if not path.isdir(bsp_dir):
+        raise Exception("The directory %s does not exist".format(bsp_dir))
+    bsps = []
+    for bsp in listdir(bsp_dir):
+        with open(path.join(bsp_dir, bsp, "bsp.yml"), 'r') as f:
+            data = yaml.load(f)
+            for k in ['bsp.name', 'bsp.url', 'bsp.maker', 'bsp.arch']:
+                # XXX might also skip bsp.arch that starts with 'sim'?
+                if k not in data:
+                    print("{} is missing metadata".format(bsp))
+                    break
+            else:
+                bsp = BSP(name=data['bsp.name'], url=data['bsp.url'],
+                          maker=data['bsp.maker'], arch=data['bsp.arch'])
+                bsps.append(bsp)
+    return bsps
+
 
 def build(cwd, site_dir):
 
@@ -21,17 +87,17 @@
     # sanity check - the version dirs exist as named
     for version in cfg['extra']['versions']:
         if 'separate' not in version or not version['separate']:
-            d = os.path.join('versions', version['dir'])
+            d = path.join('versions', version['dir'])
             print('Verifying dir {}'.format(d))
-            if not os.path.isdir(d):
+            if not path.isdir(d):
                 print("The directory {} does not exist".format(d))
                 return
 
     # sanity check - dependent_repos exist in '..'
     for repo in dependent_repos:
-        d = os.path.join(cwd, '..', repo)
+        d = path.join(cwd, '..', repo)
         print('Verifying repo dependency in {}'.format(d))
-        if not os.path.isdir(d):
+        if not path.isdir(d):
             print("The directory %s does not exist".format(d))
             return
 
@@ -49,29 +115,33 @@
 
     print("Building site pages")
     sh.rm('-rf', site_dir)
+
+    bsps = find_BSPs()
+    generate_supported_boards("custom-theme/supported-boards.html", bsps)
+
     sh.mkdocs('build', '--clean', '--site-dir', site_dir)
 
     for version in cfg['extra']['versions']:
         print("Building doc pages for: {}".format(version['dir']))
         if 'separate' not in version or not version['separate']:
             sh.mkdocs('build', '--site-dir',
-                      os.path.join(site_dir, version['dir']),
-                      _cwd=os.path.join("versions", version['dir']))
+                      path.join(site_dir, version['dir']),
+                      _cwd=path.join("versions", version['dir']))
         else:
-            repo_dir = os.path.join(cwd, '..', 'mynewt-documentation')
+            repo_dir = path.join(cwd, '..', 'mynewt-documentation')
             if version['dir'] != 'master':
-                repo_dir = os.path.join(repo_dir,
-                                        'versions',
-                                        version['dir'],
-                                        'mynewt-documentation')
+                repo_dir = path.join(repo_dir,
+                                     'versions',
+                                     version['dir'],
+                                     'mynewt-documentation')
             sh.make('clean', _cwd=repo_dir)
             sh.make('docs', _cwd=repo_dir)
-            sh.mv(os.path.join(repo_dir, '_build', 'html'),
-                  os.path.join(site_dir, version['dir']))
+            sh.mv(path.join(repo_dir, '_build', 'html'),
+                  path.join(site_dir, version['dir']))
         if 'latest' in version and version['latest']:
             sh.ln('-s', version['dir'], 'latest', _cwd=site_dir)
 
 
 if __name__ == '__main__':
-    cwd = os.path.dirname(os.path.abspath(__file__))
-    build(cwd, os.path.join(cwd, "site"))
+    cwd = path.dirname(path.abspath(__file__))
+    build(cwd, path.join(cwd, "site"))
diff --git a/custom-theme/landing.html b/custom-theme/landing.html
index cd1e967..1ccd375 100644
--- a/custom-theme/landing.html
+++ b/custom-theme/landing.html
@@ -98,7 +98,7 @@
             <p> Compose, fine-tune, and build your image within hours or even minutes. </p>
 
             <ul>
-	      <li> Hardware initialization in single configuration file for the chosen BSP </li>
+              <li> Hardware initialization in single configuration file for the chosen BSP </li>
               <li> Initialization of service parameters in a single configuration file for the chosen module e.g. BLE controller </li>
               <li> Smart package management and build using Newt Tool </li>
               <li> Automatic configuration audits using Newt Tool </li>
@@ -115,90 +115,8 @@
             <div class="col-xs-12">
 
             <h2>Supported Boards</h2>
+            {% include "supported-boards.html" %}
 
-              <ul>
-                  <li>
-                      <a href="https://www.nordicsemi.com/eng/Products/Bluetooth-Smart-Bluetooth-low-energy/nRF52832/"> nRF52 DK </a> from Nordic Semiconductor (Cortex-M4)
-                  </li>
-                   <li>
-                      <a href="https://www.nordicsemi.com/eng/Products/nRF52840-Preview-DK"> nRF52840 Preview DK </a> from Nordic Semiconductor (Cortex-M4)
-                  </li>
-                  <li>
-                      <a href="https://www.nordicsemi.com/eng/Products/Bluetooth-Smart-Bluetooth-low-energy/nRF51822"> nRF51 DK </a> from Nordic Semiconductor (Cortex-M0)
-                  </li>
-                  <li>
-                      <a href="https://vngiotlab.github.io/vbluno/"> VBLUno51 and VBLUno52 boards </a> from VNG IoT Lab (Cortex-M0)
-                  </li>
-                  <li>
-                      <a href="http://ruuvitag.com"> RuuviTag </a> Sensor beacon platform (Nordic nRF52832 based)
-                  </li>
-                  <li>
-                      <a href="http://redbearlab.com/blenano/"> BLE Nano </a> from RedBear (Nordic nRF51822 SoC based)
-                  </li>
-                  <li>
-                      <a href="https://www.kickstarter.com/projects/1991736672/bluetooth-5-ready-ble-module-nano-2-and-blend-2"> BLE Nano2 and Blend2 </a> from RedBear (Nordic nRF52832 SoC based)
-                  </li>
-                  <li>
-                      <a href="https://www.rigado.com/products/bmd-300-eval-kit/"> BMD-300-EVAL-ES </a> from Rigado (Cortex-M4)
-                  </li>
-                  <li>
-                      <a href="http://www.st.com/en/evaluation-tools/stm32f4discovery.html"> STM32F4DISCOVERY </a> from ST Micro (Cortex-M4)
-                  </li>
-                  <li>
-                      <a href=" https://www.olimex.com/Products/ARM/ST/STM32-E407/open-source-hardware"> STM32-E407 </a> from Olimex (Cortex-M4)
-                  </li>
-                  <li>
-                      <a href="https://www.arduino.cc/en/Main/ArduinoBoardZero"> Arduino Zero </a> (Cortex-M0)
-                  </li>
-                  <li>
-                      <a href="http://www.arduino.org/products/previous-version-boards/11-previous-version-boards/arduino-zero-pro"> Arduino Zero Pro </a> (Cortex-M0)
-                  </li>
-                  <li>
-                      <a href="http://www.arduino.org/products/boards/4-arduino-boards/arduino-m0-pro"> Arduino M0 Pro </a> (Cortex-M0)
-                  </li>
-                  <li>
-                      <a href="http://www.st.com/en/evaluation-tools/nucleo-f401re.html"> NUCLEO-F401RE </a> (Cortex-M4)
-                  </li>
-                  <li>
-                      <a href="http://www.st.com/en/evaluation-tools/nucleo-f767zi.html"> NUCLEO-F767ZI </a> (Cortex-M7)
-                  </li>
-                  <li>
-                      <a href="http://www.st.com/en/evaluation-tools/stm32-mcu-discovery-kits.html?querycriteria=productId=LN1848"> Discovery kit for STM32F7 Series  </a> (Cortex-M7)
-                  </li>
-                  <li>
-                      <a href="http://www.nxp.com/products/software-and-tools/hardware-development-tools/freedom-development-boards/freedom-development-platform-for-kinetis-k64-k63-and-k24-mcus:FRDM-K64F"> FRDM-K64F </a> from NXP (Cortex-M4)
-                  </li>
-                  <li>
-                      <a href="https://creatordev.io/ci40-iot-dev-kit.html"> Creator Ci40 IoT Kit </a> from Imagination Technologies (MIPS CPU)
-                  </li>
-                  <li>
-                      <a href="http://microbit.org/hardware"> BBC micro:bit </a> with Nordic nRF51822 (Cortex-M0)
-                  </li>
-                  <li>
-                      <a href="https://www.adafruit.com/feather"> Adafruit Feather </a> with Nordic nRF52 (Cortex-M4)
-                  </li>
-                  <li>
-                      <a href="https://www.sifive.com/products/hifive1/"> HiFive1 Dev Kit </a> featuring the Freedom E310 from SiFive from (RISC-V)
-                  </li>
-                  <li>
-                      <a href="https://shop.mikroe.com/clicker-6lowpan"> 6LoWPAN Clicker </a> from MikroElektronika (PIC32MX)
-                  </li>
-                  <li>
-                      <a href="https://store.digilentinc.com/wi-fire-wifi-enabled-pic32mz-microcontroller-board/"> chipKIT Wi-FIRE </a> from Digilent (PIC32MZ)
-                  </li>
-                  <li>
-                      <a href="https://www.u-blox.com/en/product/nina-b1-series"> NINA-B1 BLE module </a> from u-blox (Cortex-M4)
-                  </li>
-                  <li>
-                      <a href="https://www.calliope.cc/en/ueber-mini"> Calliope Mini </a> from Calliope gGmbH
-                  </li>
-                  <li>
-                      <a href="https://www.telenor.com/"> EE-02 and EE-04 boards with Semtech Sx1276 LoRa chip  </a> from Telenor Digital (Cortex-M4)
-                  </li>
-                  <li>
-                      <a href="http://ambiqmicro.com/apollo-ultra-low-power-mcus/apollo2-mcu/"> Apollo2 Ultra-Low Power Microcontroller </a> from Ambiq Micro (Cortex-M4)
-                  </li>
-              </ul>
             </div>
           </div>
         </div>