Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • experimental
  • v2023.2.5-ffs
  • nrb/ex400-remove-wps
  • nrb/airmax-test
  • v2023.2.4-ffs
  • nrb/ar9344-reset-sequence
  • autinerd/experimental-openwrt-24.10
  • v2023.2.3-ffs
  • v2023.2.2-ffs
  • v2023.2-ffs
  • v2023.1-ffs
  • v2022.1.4-ffs
  • feature/addMikrotikwAP
  • v2022.1.3-ffs
  • v2021.1.2-ffs
  • v2022.1.1-ffs
  • master
  • v2021.1.1-ffs
  • nrb/gluon-master-cpe510
  • v2021.1-ffs
  • v2020.2.3-ffs
  • nrbffs/fastd-remove-delay
  • v2020.2.2-ffs
  • v2020.2.1-ffs
  • v2020.2-ffs
  • v2020.1.3-ffs
  • v2020.1.1-ffs
  • v2020.1-ffs
  • v2019.1.2-ffs
  • v2019.1.1-ffs
  • nrb/test-radv-filter
  • v2019.1-ffs
  • nrbffs/netgear-ex6120
  • v2018.2.3-ffs
  • 0x4A6F-rpi4
  • 0x4A6F-master
  • v2018.2.2-ffs
  • experimental-2022-09-24
  • experimental-2022-09-24-base
  • experimental-2023-03-11
  • experimental-2023-03-11-base
  • experimental-2023-03-12
  • experimental-2023-03-12-base
  • experimental-2023-03-16
  • experimental-2023-03-16-base
  • experimental-2023-03-20
  • experimental-2023-03-20-base
  • experimental-2023-03-23
  • experimental-2023-03-23-base
  • experimental-2023-03-25
  • experimental-2023-03-25-base
  • experimental-2023-03-26
  • experimental-2023-03-26-base
  • experimental-2023-03-30
  • experimental-2023-03-30-base
  • experimental-2023-03-31
  • experimental-2023-03-31-base
  • experimental-2023-04-01
  • experimental-2023-04-01-base
  • experimental-2023-04-08
  • experimental-2023-04-08-base
  • experimental-2023-04-10
  • experimental-2023-04-10-base
  • experimental-2023-04-13
  • experimental-2023-04-13-base
  • experimental-2023-04-15
  • experimental-2023-04-15-base
  • experimental-2023-04-16
  • experimental-2023-04-16-base
  • experimental-2023-04-18
  • experimental-2023-04-18-base
  • experimental-2023-04-20
  • experimental-2023-04-20-base
  • experimental-2023-04-26
  • experimental-2023-04-26-base
  • experimental-2023-04-28
  • experimental-2023-04-28-base
  • experimental-2023-04-30
  • experimental-2023-04-30-base
  • experimental-2023-05-02
  • experimental-2023-05-02-base
  • experimental-2023-05-03
  • experimental-2023-05-03-base
  • experimental-2023-05-12
  • experimental-2023-05-12-base
  • experimental-2023-05-21
  • experimental-2023-05-21-base
  • experimental-2023-05-25
  • experimental-2023-05-25-base
  • experimental-2023-07-02
  • experimental-2023-07-02-base
  • experimental-2023-07-04
  • experimental-2023-07-04-base
  • experimental-2023-07-12
  • experimental-2023-07-12-base
  • experimental-2023-07-16
  • experimental-2023-07-16-base
  • experimental-2023-08-04
  • experimental-2023-08-04-base
  • experimental-2023-08-10
  • experimental-2023-08-10-base
  • experimental-2023-09-08
  • experimental-2023-09-08-base
  • experimental-2023-09-09
  • experimental-2023-09-09-base
  • experimental-2023-09-10
  • experimental-2023-09-10-base
  • experimental-2023-09-11
  • experimental-2023-09-11-base
  • experimental-2023-09-12
  • experimental-2023-09-12-base
  • experimental-2023-09-13
  • experimental-2023-09-13-base
  • experimental-2023-09-15
  • experimental-2023-09-15-base
  • experimental-2023-09-16
  • experimental-2023-09-16-base
  • experimental-2023-09-18
  • experimental-2023-09-18-base
  • experimental-2023-09-20
  • experimental-2023-09-20-base
  • experimental-2023-09-27
  • experimental-2023-09-27-base
  • experimental-2023-09-28
  • experimental-2023-09-28-base
  • experimental-2023-09-29
  • experimental-2023-09-29-base
  • experimental-2023-10-02
  • experimental-2023-10-02-base
  • experimental-2023-10-13
  • experimental-2023-10-13-base
  • experimental-2023-10-14
  • experimental-2023-10-14-base
  • experimental-2023-10-16
  • experimental-2023-10-16-base
  • experimental-2023-10-23
  • experimental-2023-10-23-base
137 results

Target

Select target project
No results found
Select Git revision
  • experimental
  • master
  • v2021.1.2-ffs
  • v2021.1.1-ffs
  • nrb/gluon-master-cpe510
  • v2021.1-ffs
  • v2020.2.3-ffs
  • nrbffs/fastd-remove-delay
  • v2020.2.2-ffs
  • v2020.2.1-ffs
  • v2020.2-ffs
  • v2020.2.x
  • v2020.1.3-ffs
  • v2020.1.1-ffs
  • v2020.1-ffs
  • v2019.1.2-ffs
  • v2019.1.1-ffs
  • nrb/test-radv-filter
  • v2019.1-ffs
  • nrbffs/netgear-ex6120
  • v2018.2.3-ffs
  • 0x4A6F-rpi4
  • 0x4A6F-master
  • v2018.2.2-ffs
  • v2018.2.x
  • v2016.2.4-batmanbug
  • radv-filterd
  • v2016.2.x
  • hoodselector
  • v2016.1.x
  • babel
  • v2015.1.x
  • 2014.4.x
  • 2014.3.x
  • v2014.1
  • v2014.2
  • v2014.3
  • v2014.3.1
  • v2014.4
  • v2015.1
  • v2015.1.1
  • v2015.1.2
  • v2016.1
  • v2016.1.1
  • v2016.1.2
  • v2016.1.3
  • v2016.1.4
  • v2016.1.5
  • v2016.1.6
  • v2016.2
  • v2016.2.1
  • v2016.2.2
  • v2016.2.3
  • v2016.2.4
  • v2016.2.5
  • v2016.2.6
  • v2016.2.7
  • v2017.1
  • v2017.1.1
  • v2017.1.2
  • v2017.1.3
  • v2017.1.4
  • v2017.1.5
  • v2017.1.6
  • v2017.1.7
  • v2017.1.8
  • v2018.1
  • v2018.1.1
  • v2018.1.2
  • v2018.1.3
  • v2018.1.4
  • v2018.2
  • v2018.2-ffs0.1
  • v2018.2.1
  • v2018.2.1-ffs0.1
  • v2018.2.2-ffs0.1
  • v2018.2.3-ffs0.1
  • v2019.1-ffs0.1
  • v2019.1.1-ffs0.1
  • v2019.1.2-ffs0.1
  • v2020.1-ffs0.1
  • v2020.1.1-ffs0.1
  • v2020.1.3-ffs0.1
  • v2020.2
  • v2020.2-ffs0.1
  • v2020.2.1-ffs0.1
  • v2020.2.2-ffs0.1
  • v2020.2.3-ffs0.1
  • v2020.2.3-ffs0.2
  • v2020.2.3-ffs0.3
  • v2020.2.x-ffs0.1
  • v2021.1-ffs0.1
  • v2021.1.1-ffs0.1
  • v2021.1.1-ffs0.2
  • v2021.1.1-ffs0.3
  • v2021.1.1-ffs0.4
  • v2021.1.2-ffs0.1
  • v2021.1.2-ffs0.2
98 results
Show changes
868 files
+ 49242
16382
Compare changes
  • Side-by-side
  • Inline

Files

.ecrc

0 → 100644
+3 −0
Original line number Diff line number Diff line
{
  "Exclude": ["docs/_build"]
}

.editorconfig

0 → 100644
+67 −0
Original line number Diff line number Diff line
# Top-most EditorConfig file
root = true

[*]
end_of_line = lf
insert_final_newline = true
indent_style = tab
charset = utf-8

[Dockerfile]
indent_style = space
indent_size = 4

[/patches/**]
indent_style = unset
indent_size = unset

[*.c]

[*.css]

[*.dia]
indent_style = space
indent_size = 2

[*.h]

[*.html]

[*.js]

[*{.json,.ecrc}]
indent_style = space
indent_size = 2

[*.lua]

[{Makefile,*.mk}]
indent_style = unset

[*.md]
indent_style = space
indent_size = 4

[*.pl]

[*.py]
indent_style = space
indent_size = 4

[*.rst]
indent_style = space
indent_size = 2

[*.sh]

[*.yml]
indent_style = space
indent_size = 2

[CMakeLists.txt]
indent_style = space
indent_size = 2

[{docs,contrib/ci}/*site*/**/*.conf]
indent_style = space
indent_size = 2
+71 −0
Original line number Diff line number Diff line
---
name: Bug report
about: Report a bug in a recent version of Gluon
label: bug
---

<!--

Please carefully fill out the questionnaire below to help improve the
timely triaging of issues. Walk through the questions below and use
them as an inspiration for what information you can provide.

Make use of codeblocks (three backticks before and after) where
appropriate (configuration excerpts, log output, etc.). Example:

```
your code goes here
```

You can use the "Preview" tab to check how your issue is going to look
before you actually send it in.

Thank you for taking the time to report a bug with the Gluon project.

-->

### Bug report

**What is the problem?**
<!--
- What is not working as expected?
- How is it misbehaving?
- When did the problem first start showing up?
- What were you doing when you first noticed the problem?
- On which devices (vendor, model and revision) is it misbehaving?
- Does the issue appear on multiple devices or targets?
-->

**What is the expected behaviour?**
<!--
- How do you think it should work instead?
- Did it work like that before?
-->

**Gluon Version:**
<!--
Please provide a usable Git reference before applying custom patches:

By using a Git reference:
    $ git describe --always
    v2018.2-17-g3abadc28

Or the URL to the relevant Gluon commit
    https://github.com/freifunk-gluon/gluon/commit/<commit hash here>
-->

**Site Configuration:**
<!--
Please provide the URL to your site configuration repository and the
explicit commit used to build the firmware experiencing the problem.

Additionally excerpts of problem-related configuration parts are 
often helpful.
-->

**Custom patches:**
<!--
Be upfront about any custom patches you have applied to your Gluon build, as they might
be part of your problem.
-->

.github/dependabot.yml

0 → 100644
+12 −0
Original line number Diff line number Diff line
# Docs: <https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/customizing-dependency-updates>

version: 2

updates:
  - package-ecosystem: github-actions
    directory: /
    schedule: {interval: monthly}

  - package-ecosystem: pip
    directory: /docs/
    schedule: {interval: monthly}

.github/filters.yml

0 → 100644
+345 −0
Original line number Diff line number Diff line
{
  "armsr-armv7": [
    "targets/armsr-armv7",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/armsr.inc"
  ],
  "armsr-armv8": [
    "targets/armsr-armv8",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/armsr.inc"
  ],
  "ath79-generic": [
    "targets/ath79-generic",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "ath79-nand": [
    "targets/ath79-nand",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "ath79-mikrotik": [
    "targets/ath79-mikrotik",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/mikrotik.inc"
  ],
  "bcm27xx-bcm2708": [
    "targets/bcm27xx-bcm2708",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/bcm27xx.inc"
  ],
  "bcm27xx-bcm2709": [
    "targets/bcm27xx-bcm2709",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/bcm27xx.inc"
  ],
  "ipq40xx-generic": [
    "targets/ipq40xx-generic",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "ipq40xx-mikrotik": [
    "targets/ipq40xx-mikrotik",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/mikrotik.inc"
  ],
  "ipq806x-generic": [
    "targets/ipq806x-generic",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "lantiq-xrx200": [
    "targets/lantiq-xrx200",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "lantiq-xrx200_legacy": [
    "targets/lantiq-xrx200_legacy",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "lantiq-xway": [
    "targets/lantiq-xway",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "mediatek-filogic": [
    "targets/mediatek-filogic",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "mediatek-mt7622": [
    "targets/mediatek-mt7622",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "mvebu-cortexa53": [
    "targets/mvebu-cortexa53",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "mpc85xx-p1010": [
    "targets/mpc85xx-p1010",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "mpc85xx-p1020": [
    "targets/mpc85xx-p1020",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "qualcommax-ipq807x": [
    "targets/qualcommax-ipq807x",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "ramips-mt7620": [
    "targets/ramips-mt7620",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "ramips-mt7621": [
    "targets/ramips-mt7621",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "ramips-mt76x8": [
    "targets/ramips-mt76x8",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "rockchip-armv8": [
    "targets/rockchip-armv8",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "sunxi-cortexa7": [
    "targets/sunxi-cortexa7",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "x86-generic": [
    "targets/x86-generic",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/x86.inc"
  ],
  "x86-geode": [
    "targets/x86-geode",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "x86-legacy": [
    "targets/x86-legacy",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/x86.inc"
  ],
  "x86-64": [
    "targets/x86-64",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/x86.inc",
    "contrib/ci/minimal-site/**",
    "package/**"
  ],
  "bcm27xx-bcm2710": [
    "targets/bcm27xx-bcm2710",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/bcm27xx.inc"
  ],
  "bcm27xx-bcm2711": [
    "targets/bcm27xx-bcm2711",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
    "targets/bcm27xx.inc"
  ],
  "ipq40xx-chromium": [
    "targets/ipq40xx-chromium",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "kirkwood-generic": [
    "targets/kirkwood-generic",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ],
  "mvebu-cortexa9": [
    "targets/mvebu-cortexa9",
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk"
  ]
}

.github/labeler.yml

0 → 100644
+89 −0
Original line number Diff line number Diff line
---
"3. topic: batman-adv":
  - changed-files:
    - any-glob-to-any-file:
      - docs/package/gluon-mesh-batman-adv*
      - package/gluon-alfred/**
      - package/gluon-client-bridge/**
      - package/gluon-mesh-batman-adv/**
      - package/libbatadv/**
"3. topic: build":
  - changed-files:
    - any-glob-to-any-file:
      - Makefile
      - scripts/**
"3. topic: config-mode":
  - changed-files:
    - any-glob-to-any-file:
      - docs/dev/web/config-mode.rst
      - docs/package/gluon-config-mode-*
      - package/gluon-config-mode-*/**
      - package/gluon-web*/**
"3. topic: continuous integration":
  - changed-files:
    - any-glob-to-any-file:
      - .github/workflows/*
      - contrib/actions/**
      - contrib/ci/**
"3. topic: docs":
  - changed-files:
    - any-glob-to-any-file:
      - docs/**
"3. topic: fastd":
  - changed-files:
    - any-glob-to-any-file:
      - docs/features/fastd*
      - package/gluon-mesh-vpn-fastd/**
"3. topic: firewall":
  - changed-files:
    - any-glob-to-any-file:
      - package/**/*-firewall
      - package/gluon-ebtables-*/**
"3. topic: hardware":
  - changed-files:
    - any-glob-to-any-file:
      - package/gluon-core/luasrc/lib/gluon/upgrade/010-primary-mac
      - package/gluon-core/luasrc/usr/lib/lua/gluon/platform.lua
      - targets/*
"3. topic: multidomain":
  - changed-files:
    - any-glob-to-any-file:
      - docs/features/multidomain*
      - docs/multidomain-site-example/**
      - package/gluon-config-mode-domain-select/**
      - package/gluon-scheduled-domain-switch/**
"3. topic: olsr":
  - changed-files:
    - any-glob-to-any-file:
      - package/gluon-l3roamd/**
      - package/gluon-mesh-olsrd/**
      - package/gluon-mmfd/**
"3. topic: package":
  - changed-files:
    - any-glob-to-any-file:
      - package/**
"3. topic: respondd":
  - changed-files:
    - any-glob-to-any-file:
      - package/**/*respondd*
      - package/gluon-respondd/**
"3. topic: status-page":
  - changed-files:
    - any-glob-to-any-file:
      - package/gluon-status-page/**
"3. topic: tests":
  - changed-files:
    - any-glob-to-any-file:
      - tests/**
"3. topic: wireguard":
  - changed-files:
    - any-glob-to-any-file:
      - package/gluon-mesh-vpn-wireguard/**
"3. topic: wireless":
  - changed-files:
    - any-glob-to-any-file:
      - package/gluon-mesh-wireless-sae/**
      - package/gluon-private-wifi/**
      - package/gluon-web-private-wifi/**
      - package/gluon-web-wifi-config/**
      - package/gluon-wireless-encryption-wpa3/**
+20 −0
Original line number Diff line number Diff line
name: Backport
on:
  pull_request_target:
    types: [closed, labeled]
permissions:
  contents: write # so it can comment
  pull-requests: write # so it can create pull requests
jobs:
  backport:
    name: Backport Pull Request
    if: github.repository_owner == 'freifunk-gluon' && github.event.pull_request.merged == true && (github.event_name != 'labeled' || startsWith('backport', github.event.label.name))
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v5
      - name: Create backport PRs
        uses: korthout/backport-action@v3.3.0
        with:
          # Config README: https://github.com/korthout/backport-action#backport-action
          pull_description: |-
            Automatic backport to `${target_branch}`, triggered by a label in #${pull_number}.
+48 −0
Original line number Diff line number Diff line
# Based on the example from https://docs.github.com/en/actions/publishing-packages/publishing-docker-images
name: Create and publish a Docker image

on:
  push:
    branches:
      - 'main'
      - 'next'
      - 'v202[0-9].[0-9].x'
    tags:
      - 'v*'
  pull_request:

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}-build

jobs:
  build-and-push-image:
    runs-on: ubuntu-22.04
    permissions: write-all
    steps:
      - name: Checkout repository
        uses: actions/checkout@v5
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      - name: Log in to the Container registry
        uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1
        if: ${{ github.repository_owner == 'freifunk-gluon' && github.event_name == 'push' }}
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
      - name: Build and push Docker image
        uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
        with:
          context: ./contrib/docker
          push: ${{ github.repository_owner == 'freifunk-gluon' && github.event_name == 'push' }}
          platforms: linux/amd64,linux/arm64
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
+29 −0
Original line number Diff line number Diff line
name: Build Documentation
on:
  push:
    paths:
      - 'docs/**'
      - '.github/workflows/build-docs.yml'
  pull_request:
    types: [opened, synchronize, reopened]
    paths:
      - 'docs**/'
      - '.github/workflows/build-docs.yml'
permissions:
  contents: read

jobs:
  build-documentation:
    name: docs
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v5
      - name: Install Dependencies
        run: sudo pip3 install -r docs/requirements.txt
      - name: Build documentation
        run: make -C docs html
      - name: Archive build output
        uses: actions/upload-artifact@v4
        with:
          name: docs_output
          path: docs/_build/html
+80 −0
Original line number Diff line number Diff line
name: Build Gluon
on:
  push:
    branches:
      - main
      - next
      - 'v20[2-9][0-9].[0-9].x'
  pull_request:
    types: [opened, synchronize, reopened]
  workflow_dispatch:

permissions:
  contents: read

concurrency:
  group: ${{ github.workflow }}-${{ github.ref || github.run_id }}-${{ github.event.pull_request.number || github.run_id }}
  cancel-in-progress: true

jobs:
  changed:
    permissions:
      contents: read  # for dorny/paths-filter to fetch a list of changed files
      pull-requests: read  # for dorny/paths-filter to read pull requests
    runs-on: ubuntu-22.04
    outputs:
      targets: ${{ steps.filter.outputs.changes }}
    steps:
      - uses: actions/checkout@v5

      # Filter targets based on changed files
      - uses: dorny/paths-filter@v3
        id: filter
        with:
          filters: .github/filters.yml

  build_firmware:
    needs: changed
    if: ${{ needs.changed.outputs.targets != '[]' && needs.changed.outputs.targets != '' }}
    strategy:
      fail-fast: false
      matrix:
        # Read back changed targets to create build matrix
        target: ${{ fromJSON(needs.changed.outputs.targets) }}
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v5

      - name: Show system information
        run: contrib/actions/show-system-info.sh

      - name: Remove non-required software
        run: contrib/actions/free-runner-space.sh

      - name: Build Docker container
        run: docker build -t gluon-ci-container contrib/docker

      - name: Build Gluon
        run: docker run --rm -v $PWD:/gluon-ci -w /gluon-ci --user "$(id -u):$(id -g)" gluon-ci-container contrib/actions/run-build.sh ${{ matrix.target }}

      - name: Check Image size
        run: contrib/check-image-size.py --github-actions --overhead 256 output/meta/openwrt-profiles/${{ matrix.target }}.json

      - name: Archive build logs
        if: ${{ !cancelled() }}
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.target }}_logs
          path: openwrt/logs

      - name: Archive build output
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.target }}_output
          path: output

      - name: Archive metadata
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.target }}_metadata
          path: output/meta
+51 −0
Original line number Diff line number Diff line
---
name: "Update OpenWrt base"

on:
  workflow_dispatch:
    inputs:
      branch:
        description: "Branch to create update for"
        required: true
        default: "main"

jobs:
  update-openwrt:
    runs-on: ubuntu-22.04
    env:
      COMMIT_NAME: Gluon CI Bot
      COMMIT_EMAIL: bot@freifunk-gluon.github.io
    steps:
      - name: Clone Gluon
        uses: actions/checkout@v5
        with:
          ref: ${{ github.event.inputs.branch }}
      
      - name: Configure Git User and E-Mail
        run: git config --global user.name "${{ env.COMMIT_NAME }}" && git config --global user.email "${{ env.COMMIT_EMAIL }}"
      
      - name: Get update branch name
        id: branch-name
        run: echo "branch-name=update-openwrt-${{ github.event.inputs.branch }}-$(date +%s)" >> $GITHUB_OUTPUT

      - name: Link example Site
        run: ln -s docs/site-example site
      
      - name: Invoke update-modules
        run: make update-modules
      
      - name: Refresh patches
        run: make refresh-patches
      
      - name: Check if unstaged commits exist
        run: git diff --exit-code || echo "::warning::Patches need a manual refresh"
      
      - name: Checkout individual branch name
        run: git checkout -b ${{ steps.branch-name.outputs.branch-name }}
      
      - name: Push branch
        run: git push origin HEAD

      - name: Emit PR creation message
        run:
          echo "::notice::Create pull-request at https://github.com/${{ github.repository }}/compare/${{ github.event.inputs.branch }}...${{ steps.branch-name.outputs.branch-name }}?quick_pull=1"
+22 −0
Original line number Diff line number Diff line
name: Check generated CI
on:
  push:
  pull_request:
    types: [opened, synchronize, reopened]
permissions:
  contents: read

jobs:
  check-ci:
    name: Check generated CI
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v5
      - name: Install example site
        run: ln -s ./docs/site-example ./site
      - name: Update CI
        run: make update-ci
      - name: Show diff
        run: git status; git diff
      - name: Patch status
        run: git diff-files --quiet
+30 −0
Original line number Diff line number Diff line
---
name: Check patches
on:
  push:
    paths:
      - 'modules'
      - 'patches/**'
      - '.github/workflows/check-patches.yml'
  pull_request:
    types: [opened, synchronize, reopened]
    paths:
      - 'modules'
      - 'patches/**'
      - '.github/workflows/check-patches.yml'
permissions:
  contents: read

jobs:
  check-patches:
    name: Check patches
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v5
      - name: Refresh patches
        run: make refresh-patches GLUON_SITEDIR="contrib/ci/minimal-site"
      - name: Show diff
        run: git status; git diff
      - name: Patch status
        run: git diff-files --quiet
+21 −0
Original line number Diff line number Diff line
name: "Label PRs"

on:
  # only execute base branch actions
  pull_request_target:

permissions:
  contents: read

jobs:
  labels:
    permissions:
      contents: read  # for actions/labeler to determine modified files
      pull-requests: write  # for actions/labeler to add labels to PRs
    runs-on: ubuntu-22.04
    if: github.repository_owner == 'freifunk-gluon'
    steps:
    - uses: actions/labeler@v5
      with:
        repo-token: ${{ secrets.GITHUB_TOKEN }}
        sync-labels: true
+54 −0
Original line number Diff line number Diff line
name: Lint
on:
  push:
  pull_request:
    types: [opened, synchronize, reopened]
permissions:
  contents: read

jobs:
  lua:
    name: Lua
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v5
      - name: Install Dependencies
        run: sudo apt-get -y update && sudo apt-get -y install lua-check
      - name: Install example site
        run: ln -s ./docs/site-example ./site
      - name: Lint Lua code
        run: make lint-lua

  sh:
    name: Shell
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v5
      - name: Install Dependencies
        run: sudo apt-get -y update && sudo apt-get -y install shellcheck
      - name: Install example site
        run: ln -s ./docs/site-example ./site
      - name: Lint shell code
        run: make lint-sh

  editorconfig:
    name: Editorconfig
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v5
      - name: Install Dependencies
        run: sudo apt install curl tar
      - name: Install editorconfig-checker
        env:
          VERSION: 2.7.0
          OS: linux
          ARCH: amd64
        run: |
          curl -O -L -C - https://github.com/editorconfig-checker/editorconfig-checker/releases/download/$VERSION/ec-$OS-$ARCH.tar.gz
          tar xzf ec-$OS-$ARCH.tar.gz
          sudo mv ./bin/ec-$OS-$ARCH /usr/bin/editorconfig-checker
          sudo chmod +x /usr/bin/editorconfig-checker
      - name: Install example site
        run: ln -s ./docs/site-example ./site
      - name: Lint editorconfig
        run: make lint-editorconfig
+7 −4
Original line number Diff line number Diff line
*~
/build
/images
/site
/openwrt
/output
/site
/tmp
/packages
/modules.local
.bash_history
.subversion
.wget-hsts
/.scmversion

.luacheckrc

0 → 100644
+119 −0
Original line number Diff line number Diff line
codes = true
std = "min"
self = false

read_globals = {
	"getfenv",
	"setfenv",
	"unpack",
}

include_files = {
	"**/*.lua",
	"package/**/luasrc/**/*",
	"targets/*",
	"package/features",
}

exclude_files = {
	"**/*.mk",
}

files["package/**/check_site.lua"] = {
	read_globals = {
		"alternatives",
		"extend",
		"in_domain",
		"in_site",
		"value",
		"need",
		"need_alphanumeric_key",
		"need_array",
		"need_array_elements_exclusive",
		"need_array_of",
		"need_boolean",
		"need_chanlist",
		"need_domain_name",
		"need_number",
		"need_number_range",
		"need_one_of",
		"need_string",
		"need_string_array",
		"need_string_array_match",
		"need_string_match",
		"need_table",
		"need_value",
		"obsolete",
		"table_keys",
		"this_domain",
	},
}

files["package/**/luasrc/lib/gluon/config-mode/*"] = {
	globals = {
		"MultiListValue",
		"DynamicList",
		"Flag",
		"Form",
		"i18n",
		"ListValue",
		"renderer.render",
		"renderer.render_string",
		"Section",
		"TextValue",
		"_translate",
		"translate",
		"translatef",
		"Value",
		"Element",
	},
}

files["package/**/luasrc/lib/gluon/**/controller/*"] = {
	read_globals = {
		"_",
		"alias",
		"call",
		"entry",
		"model",
		"node",
		"template",
	},
}

files["package/**/luasrc/lib/gluon/ebtables/*"] = {
	read_globals = {
		"chain",
		"rule",
	},
	max_line_length = false,
}

files["targets/*"] = {
	read_globals = {
		"class",
		"config",
		"defaults",
		"device",
		"env",
		"exec",
		"exec_capture",
		"exec_capture_raw",
		"exec_raw",
		"factory_image",
		"include",
		"istrue",
		"no_opkg",
		"packages",
		"sysupgrade_image",
		"try_config",
	},
}

files["package/features"] = {
	read_globals = {
		"_",
		"feature",
		"when",
	},
}

.readthedocs.yaml

0 → 100644
+20 −0
Original line number Diff line number Diff line
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

# Build documentation in the docs/ directory with Sphinx
sphinx:
  configuration: docs/conf.py

# Optionally set the version of Python and requirements required to build your docs
python:
   install:
   - requirements: docs/requirements.txt

build:
    os: ubuntu-22.04
    tools:
        python: "3.11"

CONTRIBUTING.md

0 → 100644
+53 −0
Original line number Diff line number Diff line
Contribution Guidelines
=======================

Because Gluon is such a universal software package that is used by several
different communities with different expectations and requirements, it is both
essential and difficult to have contributions from the communities. While they
are sometimes necessary to adapt Gluon to the needs of the communities, they
also have to be adaptable enough to fit as many needs as possible. On the other
hands, very special needs are better addressed in [packages] in community
repositories, because the Gluon maintainers would not use or test them and
thus couldn't do their "job" of maintaining them.

To ease the work for the maintainers and to reduce the frustration of
contributors, please adhere to the following guidelines:

Discuss first, build later
--------------------------
If you have some non-trivial enhancement like a new package, some modification
of what is announced by a node, it is often best to first discuss the precise
solution first. The maintainers might have hints as to how a solution could be
implemented easiest, point out solutions how the same thing can already be done
using other parts or why the proposed change breaks other parts of the system.
They might even refuse the idea altogether - after all, they have to sleep well
after merging the changes, too.

The preferred way to discuss is in the IRC channel ([#gluon] on irc.hackint.org)
or on the [mailing list], however, you can also open a new issue on GitHub to
discuss there. We maintain a [list of rejected features] and we'd like to
kindly ask you to review it first. In general, looking for duplicates may save
you some time.

Develop on top of main
----------------------
If you are not developing something specific to a release (like for example a
security fix to a feature that got completely rewritten since the release),
develop it on top of the main branch. New features and even feature changes
aren't usually backported to old releases, but will be included in the upcoming
release, which will be built from main.

Use descriptive commit messages
-------------------------------
If you modify a single package, start the first line of your commit message
with the package name followed by a colon. The first line should be enough to
identify the commit a week later and still know roughly what it did. If you
fix some bug, detail in the remaining commit message exactly how it could be
triggered and what you did to fix it. If in question, have a glance at the
existing commit messages to get the idea.


[packages]: https://gluon.readthedocs.io/en/latest/user/site.html#packages
[#gluon]: https://chat.hackint.org/?join=gluon
[mailing list]: mailto:gluon@luebeck.freifunk.net
[list of rejected features]: https://github.com/freifunk-gluon/gluon/issues?q=label%3A%222.+status%3A+rejected%22
+8 −5
Original line number Diff line number Diff line
BSD 2-Clause License

The code of Project Gluon may be distributed under the following terms, unless
noted otherwise in indiviual files or subtrees.
noted otherwise in individual files or subtrees.

Copyright (c) 2013, Project Gluon
Copyright (c) Project Gluon
All rights reserved.

Redistribution and use in source and binary forms, with or without
@@ -25,9 +27,10 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


OpenWRT is licensed under the terms of the GNU General Public License Version 2,
which can be found under openwrt/LICENSE after the openwrt submodule has been
obtained. This applies to the following submodules:
OpenWrt is licensed under the terms of the GNU General Public License Version 2,
which can be found at openwrt/LICENSE after the OpenWrt repository has been
obtained. This applies to the following repositories:

 * openwrt
 * packages/openwrt
 * packages/routing
+194 −326
Original line number Diff line number Diff line
@@ -4,377 +4,245 @@ LC_ALL:=C
LANG:=C
export LC_ALL LANG

empty:=
space:= $(empty) $(empty)
.SHELLFLAGS = -ec

GLUONMAKE_EARLY = $(SUBMAKE) -C $(GLUON_ORIGOPENWRTDIR) -f $(GLUONDIR)/Makefile GLUON_TOOLS=0
GLUONMAKE = $(SUBMAKE) -C $(GLUON_OPENWRTDIR) -f $(GLUONDIR)/Makefile

ifneq ($(OPENWRT_BUILD),1)

GLUONDIR:=${CURDIR}

include $(GLUONDIR)/include/gluon.mk

TOPDIR:=$(GLUON_ORIGOPENWRTDIR)
export TOPDIR


GLUON_TARGET ?= ar71xx-generic
export GLUON_TARGET


update: FORCE
	$(GLUONDIR)/scripts/update.sh $(GLUONDIR)
	$(GLUONDIR)/scripts/patch.sh $(GLUONDIR)

patch: FORCE
	$(GLUONDIR)/scripts/patch.sh $(GLUONDIR)

unpatch: FORCE
	$(GLUONDIR)/scripts/unpatch.sh $(GLUONDIR)

update-patches: FORCE
	$(GLUONDIR)/scripts/update.sh $(GLUONDIR)
	$(GLUONDIR)/scripts/update-patches.sh $(GLUONDIR)
	$(GLUONDIR)/scripts/patch.sh $(GLUONDIR)

-include $(TOPDIR)/include/host.mk

_SINGLE=export MAKEFLAGS=$(space);

override OPENWRT_BUILD=1
override GLUON_TOOLS=1
GREP_OPTIONS=
export OPENWRT_BUILD GLUON_TOOLS GREP_OPTIONS

-include $(TOPDIR)/include/debug.mk
-include $(TOPDIR)/include/depends.mk
include $(GLUONDIR)/include/toplevel.mk

define GluonProfile
image/$(1): FORCE
	+@$$(GLUONMAKE) $$@
endef

define GluonModel
# check for spaces & resolve possibly relative paths
define mkabspath
   ifneq (1,$(words [$($(1))]))
     $$(error $(1) must not contain spaces)
   endif
   override $(1) := $(abspath $($(1)))
endef

include $(GLUONDIR)/targets/targets.mk
include $(GLUONDIR)/targets/$(GLUON_TARGET)/profiles.mk


CheckExternal := test -d $(GLUON_ORIGOPENWRTDIR) || (echo 'You don'"'"'t seem to have obtained the external repositories needed by Gluon; please call `make update` first!'; false)
escape = '$(subst ','\'',$(1))'

GLUON_SITEDIR ?= site
$(eval $(call mkabspath,GLUON_SITEDIR))

prepare-target: FORCE
	@$(CheckExternal)
	+@$(GLUONMAKE_EARLY) prepare-target


all: prepare-target
	+@$(GLUONMAKE) prepare
	+@$(GLUONMAKE) images
ifeq ($(realpath $(GLUON_SITEDIR)/site.mk),)
$(error No site configuration was found. Please check out a site configuration to $(GLUON_SITEDIR))
endif

prepare: prepare-target
	+@$(GLUONMAKE) $@
include $(GLUON_SITEDIR)/site.mk

clean dirclean download images: FORCE
	@$(CheckExternal)
	+@$(GLUONMAKE_EARLY) maybe-prepare-target
	+@$(GLUONMAKE) $@
GLUON_RELEASE ?= $(error GLUON_RELEASE not set. GLUON_RELEASE can be set in site.mk or on the command line)

toolchain/% package/% target/%: FORCE
	@$(CheckExternal)
	+@$(GLUONMAKE_EARLY) maybe-prepare-target
	+@$(GLUONMAKE) $@
GLUON_DEPRECATED ?= 0

manifest: FORCE
	[ -n '$(GLUON_BRANCH)' ] || (echo 'Please set GLUON_BRANCH to create a manifest.'; false)
	echo '$(GLUON_PRIORITY)' | grep -qE '^([0-9]*\.)?[0-9]+$$' || (echo 'Please specify a numeric value for GLUON_PRIORITY to create a manifest.'; false)
	@$(CheckExternal)
	+@$(GLUONMAKE_EARLY) maybe-prepare-target
	+@$(GLUONMAKE) $@

else
ifneq ($(GLUON_BRANCH),)
  $(warning *** Warning: GLUON_BRANCH has been deprecated, please set GLUON_AUTOUPDATER_BRANCH and GLUON_AUTOUPDATER_ENABLED instead.)
  GLUON_AUTOUPDATER_BRANCH ?= $(GLUON_BRANCH)
  GLUON_AUTOUPDATER_ENABLED ?= 1
endif

TOPDIR=${CURDIR}
export TOPDIR
ifneq ($(GLUON_FEATURES)$(GLUON_FEATURES_standard)$(GLUON_FEATURES_tiny),)
  $(error GLUON_FEATURES is obsolete, please use the image-customization.lua file instead)
endif

include rules.mk
ifneq ($(GLUON_SITE_PACKAGES)$(GLUON_SITE_PACKAGES_standard)$(GLUON_SITE_PACKAGES_tiny),)
  $(error GLUON_SITE_PACKAGES is obsolete, please use the image-customization.lua file instead)
endif

include $(GLUONDIR)/include/gluon.mk
GLUON_AUTOUPDATER_ENABLED ?= 0

# initialize (possibly already user set) directory variables
GLUON_TMPDIR ?= tmp
GLUON_OUTPUTDIR ?= output
GLUON_IMAGEDIR ?= $(GLUON_OUTPUTDIR)/images
GLUON_PACKAGEDIR ?= $(GLUON_OUTPUTDIR)/packages
GLUON_DEBUGDIR ?= $(GLUON_OUTPUTDIR)/debug
GLUON_METADIR ?= $(GLUON_OUTPUTDIR)/meta
GLUON_TARGETSDIR ?= targets
GLUON_PATCHESDIR ?= patches

$(eval $(call mkabspath,GLUON_TMPDIR))
$(eval $(call mkabspath,GLUON_OUTPUTDIR))
$(eval $(call mkabspath,GLUON_IMAGEDIR))
$(eval $(call mkabspath,GLUON_PACKAGEDIR))
$(eval $(call mkabspath,GLUON_TARGETSDIR))
$(eval $(call mkabspath,GLUON_PATCHESDIR))

GLUON_VERSION := $(shell scripts/getversion.sh '.')

# Set default SITE_VERSION if not set by user
GLUON_SITE_VERSION ?= $(shell scripts/getversion.sh '$(GLUON_SITEDIR)')

GLUON_MULTIDOMAIN ?= 0
GLUON_AUTOREMOVE ?= 0
GLUON_DEBUG ?= 1
GLUON_MINIFY ?= 1

# Can be overridden via environment/command line/... to use the Gluon
# build system for non-Gluon builds
define GLUON_BASE_FEEDS ?=
src-link gluon_base ../../package
endef

include $(INCLUDE_DIR)/host.mk
include $(INCLUDE_DIR)/depends.mk
include $(INCLUDE_DIR)/subdir.mk
GLUON_VARS = \
	GLUON_VERSION GLUON_SITE_VERSION \
	GLUON_RELEASE GLUON_REGION GLUON_MULTIDOMAIN GLUON_AUTOREMOVE GLUON_DEBUG GLUON_MINIFY GLUON_DEPRECATED \
	GLUON_DEVICES GLUON_TARGETSDIR GLUON_PATCHESDIR GLUON_TMPDIR GLUON_IMAGEDIR GLUON_PACKAGEDIR GLUON_DEBUGDIR \
	GLUON_METADIR GLUON_SITEDIR GLUON_AUTOUPDATER_BRANCH GLUON_AUTOUPDATER_ENABLED GLUON_LANGS GLUON_BASE_FEEDS \
	GLUON_TARGET BOARD SUBTARGET

include package/Makefile
include tools/Makefile
include toolchain/Makefile
include target/Makefile
unexport $(GLUON_VARS)
GLUON_ENV = $(foreach var,$(GLUON_VARS),$(var)=$(call escape,$($(var))))

show-release:
	@echo '$(GLUON_RELEASE)'

PROFILES :=
PROFILE_PACKAGES :=

define Profile
  $(eval $(call Profile/Default))
  $(eval $(call Profile/$(1)))
endef
update: FORCE
	@
	export $(GLUON_ENV)
	scripts/update.sh
	scripts/patch.sh
	scripts/feeds.sh

define GluonProfile
PROFILES += $(1)
PROFILE_PACKAGES += $(filter-out -%,$(2) $(GLUON_$(1)_SITE_PACKAGES))
GLUON_$(1)_DEFAULT_PACKAGES := $(2)
GLUON_$(1)_MODELS :=
update-patches: FORCE
	@
	export $(GLUON_ENV)
	scripts/update.sh
	scripts/update-patches.sh
	scripts/patch.sh

refresh-patches: FORCE
	@
	export $(GLUON_ENV)
	scripts/update.sh
	scripts/patch.sh
	scripts/update-patches.sh

update-feeds: FORCE
	@$(GLUON_ENV) scripts/feeds.sh

update-modules: FORCE
	@scripts/update-modules.sh

update-ci: FORCE
	@$(GLUON_ENV) scripts/update-ci.sh

GLUON_TARGETS :=

define GluonTarget
gluon_target := $(1)$$(if $(2),-$(2))
GLUON_TARGETS += $$(gluon_target)
GLUON_TARGET_$$(gluon_target)_BOARD := $(1)
GLUON_TARGET_$$(gluon_target)_SUBTARGET := $(2)
endef

define GluonModel
GLUON_$(1)_MODELS += $(3)
GLUON_$(1)_MODEL_$(3) := $(2)
endef
include $(GLUON_TARGETSDIR)/targets.mk


include $(GLUONDIR)/targets/targets.mk
include $(GLUONDIR)/targets/$(GLUON_TARGET)/profiles.mk
OPENWRTMAKE = $(MAKE) -C openwrt

BOARD := $(GLUON_TARGET_$(GLUON_TARGET)_BOARD)
override SUBTARGET := $(GLUON_TARGET_$(GLUON_TARGET)_SUBTARGET)

target_prepared_stamp := $(BOARD_BUILDDIR)/target-prepared
gluon_prepared_stamp := $(BOARD_BUILDDIR)/prepared


include $(INCLUDE_DIR)/target.mk

SUBTARGET := $(GLUON_TARGET_$(GLUON_TARGET)_SUBTARGET)

prereq: FORCE
	+$(NO_TRACE_MAKE) prereq

gluon-tools: FORCE
	+$(GLUONMAKE_EARLY) tools/sed/install
	+$(GLUONMAKE_EARLY) package/lua/host/install

prepare-tmpinfo: FORCE
	mkdir -p tmp/info
	$(_SINGLE)$(NO_TRACE_MAKE) -j1 -r -s -f include/scan.mk SCAN_TARGET="packageinfo" SCAN_DIR="package" SCAN_NAME="package" SCAN_DEPS="$(TOPDIR)/include/package*.mk $(TOPDIR)/overlay/*/*.mk" SCAN_EXTRA=""
	$(_SINGLE)$(NO_TRACE_MAKE) -j1 -r -s -f include/scan.mk SCAN_TARGET="targetinfo" SCAN_DIR="target/linux" SCAN_NAME="target" SCAN_DEPS="profiles/*.mk $(TOPDIR)/include/kernel*.mk $(TOPDIR)/include/target.mk" SCAN_DEPTH=2 SCAN_EXTRA="" SCAN_MAKEOPTS="TARGET_BUILD=1"
	for type in package target; do \
		f=tmp/.$${type}info; t=tmp/.config-$${type}.in; \
		[ "$$t" -nt "$$f" ] || ./scripts/metadata.pl $${type}_config "$$f" > "$$t" || { rm -f "$$t"; echo "Failed to build $$t"; false; break; }; \
	done
	./scripts/metadata.pl package_mk tmp/.packageinfo > tmp/.packagedeps || { rm -f tmp/.packagedeps; false; }
	touch $(TOPDIR)/tmp/.build

feeds: FORCE
	rm -rf $(TOPDIR)/package/feeds
	mkdir $(TOPDIR)/package/feeds
	[ ! -f $(GLUON_SITEDIR)/modules ] || . $(GLUON_SITEDIR)/modules && for feed in $$GLUON_SITE_FEEDS; do ln -s ../../../packages/$$feed $(TOPDIR)/package/feeds/$$feed; done
	. $(GLUONDIR)/modules && for feed in $$GLUON_FEEDS; do ln -s ../../../packages/$$feed $(TOPDIR)/package/feeds/$$feed; done
	+$(GLUONMAKE_EARLY) prepare-tmpinfo

config: FORCE
	( \
		cat $(GLUONDIR)/include/config $(GLUONDIR)/targets/$(GLUON_TARGET)/config; \
		echo '$(patsubst %,CONFIG_PACKAGE_%=m,$(sort $(filter-out -%,$(GLUON_DEFAULT_PACKAGES) $(GLUON_SITE_PACKAGES) $(PROFILE_PACKAGES))))' \
			| sed -e 's/ /\n/g'; \
	) > .config
	+$(NO_TRACE_MAKE) defconfig OPENWRT_BUILD=0

prepare-target: FORCE
	mkdir -p $(GLUON_OPENWRTDIR)
	for dir in build_dir dl staging_dir tmp; do \
		mkdir -p $(GLUON_ORIGOPENWRTDIR)/$$dir; \
define CheckTarget
	if [ -z '$(BOARD)' ]; then
		echo 'Please set GLUON_TARGET to a valid target. Gluon supports the following targets:'
		for target in $(GLUON_TARGETS); do
			echo " * $$target"
		done
	for link in build_dir config Config.in dl include Makefile package rules.mk scripts staging_dir target tmp toolchain tools; do \
		ln -sf $(GLUON_ORIGOPENWRTDIR)/$$link $(GLUON_OPENWRTDIR); \
	done
	+$(GLUONMAKE_EARLY) feeds
	+$(GLUONMAKE_EARLY) gluon-tools
	+$(GLUONMAKE) config
	touch $(target_prepared_stamp)

$(target_prepared_stamp):
	+$(GLUONMAKE_EARLY) prepare-target

maybe-prepare-target: $(target_prepared_stamp)

$(BUILD_DIR)/.prepared: Makefile
	@mkdir -p $$(dirname $@)
	@touch $@

$(toolchain/stamp-install): $(tools/stamp-install)
$(package/stamp-compile): $(package/stamp-cleanup)


clean: FORCE
	+$(SUBMAKE) clean
	rm -f $(gluon_prepared_stamp)

dirclean: FORCE
	+$(SUBMAKE) dirclean
	rm -rf $(GLUON_BUILDDIR)


export MD5SUM := $(GLUONDIR)/scripts/md5sum.sh
export SHA512SUM := $(GLUONDIR)/scripts/sha512sum.sh


download: FORCE
	+$(SUBMAKE) tools/download
	+$(SUBMAKE) toolchain/download
	+$(SUBMAKE) package/download
	+$(SUBMAKE) target/download

toolchain: $(toolchain/stamp-install) $(tools/stamp-install)

include $(INCLUDE_DIR)/kernel.mk

kernel: FORCE
	+$(NO_TRACE_MAKE) -C $(TOPDIR)/target/linux/$(BOARD) -f $(GLUONDIR)/include/Makefile.target $(LINUX_DIR)/.image TARGET_BUILD=1
	+$(NO_TRACE_MAKE) -C $(TOPDIR)/target/linux/$(BOARD) -f $(GLUONDIR)/include/Makefile.target $(LINUX_DIR)/.modules TARGET_BUILD=1

packages: $(package/stamp-compile)
	$(_SINGLE)$(SUBMAKE) -r package/index

prepare-image: FORCE
	rm -rf $(BOARD_KDIR)
	mkdir -p $(BOARD_KDIR)
	cp $(KERNEL_BUILD_DIR)/vmlinux $(KERNEL_BUILD_DIR)/vmlinux.elf $(BOARD_KDIR)/
	+$(SUBMAKE) -C $(TOPDIR)/target/linux/$(BOARD)/image -f $(GLUONDIR)/include/Makefile.image prepare KDIR="$(BOARD_KDIR)"

prepare: FORCE
	@$(STAGING_DIR_HOST)/bin/lua $(GLUONDIR)/packages/gluon/gluon/gluon-core/files/usr/lib/lua/gluon/site_config.lua \
		|| (echo 'Your site configuration did not pass validation.'; false)
		exit 1
	fi
endef

	mkdir -p $(GLUON_IMAGEDIR) $(BOARD_BUILDDIR)
	echo 'src packages file:../openwrt/bin/$(BOARD)/packages' > $(BOARD_BUILDDIR)/opkg.conf
define CheckSite
	if ! GLUON_SITEDIR='$(GLUON_SITEDIR)' GLUON_SITE_CONFIG='$(1).conf' $(LUA) -e 'assert(dofile("scripts/site_config.lua")(os.getenv("GLUON_SITE_CONFIG")))'; then
		echo 'Your site configuration ($(1).conf) did not pass validation'
		exit 1
	fi
endef

	+$(GLUONMAKE) toolchain
	+$(GLUONMAKE) kernel
	+$(GLUONMAKE) packages
	+$(GLUONMAKE) prepare-image
list-targets: FORCE
	@for target in $(GLUON_TARGETS); do
		echo "$$target"
	done

	echo "$(GLUON_RELEASE)" > $(gluon_prepared_stamp)
lint: lint-editorconfig lint-lua lint-sh

$(gluon_prepared_stamp):
	+$(GLUONMAKE) prepare
lint-editorconfig: FORCE
	@scripts/lint-editorconfig.sh

lint-lua: FORCE
	@scripts/lint-lua.sh

include $(INCLUDE_DIR)/package-ipkg.mk
lint-sh: FORCE
	@scripts/lint-sh.sh

# override variables from rules.mk
PACKAGE_DIR = $(GLUON_OPENWRTDIR)/bin/$(BOARD)/packages

PROFILE_BUILDDIR = $(BOARD_BUILDDIR)/$(PROFILE)
PROFILE_KDIR = $(PROFILE_BUILDDIR)/kernel
BIN_DIR = $(PROFILE_BUILDDIR)/images
LUA := openwrt/staging_dir/hostpkg/bin/lua

TMP_DIR = $(PROFILE_BUILDDIR)/tmp
TARGET_DIR = $(PROFILE_BUILDDIR)/root
$(LUA):
	+@

IMAGE_PREFIX = gluon-$(GLUON_SITE_CODE)-$$(cat $(gluon_prepared_stamp))
	scripts/module_check.sh

OPKG:= \
  IPKG_TMP="$(TMP_DIR)/ipkgtmp" \
  IPKG_INSTROOT="$(TARGET_DIR)" \
  IPKG_CONF_DIR="$(TMP_DIR)" \
  IPKG_OFFLINE_ROOT="$(TARGET_DIR)" \
  $(STAGING_DIR_HOST)/bin/opkg \
	-f $(BOARD_BUILDDIR)/opkg.conf \
	--cache $(TMP_DIR)/dl \
	--offline-root $(TARGET_DIR) \
	--force-postinstall \
	--add-dest root:/ \
	--add-arch all:100 \
	--add-arch $(ARCH_PACKAGES):200
	$(GLUON_ENV) scripts/basic_openwrt_config.sh > openwrt/.config
	$(OPENWRTMAKE) defconfig
	$(OPENWRTMAKE) tools/install
	$(OPENWRTMAKE) package/lua/host/compile

EnableInitscript = ! grep -q '\#!/bin/sh /etc/rc.common' $(1) || bash ./etc/rc.common $(1) enable

config: $(LUA) FORCE
	+@

enable_initscripts: FORCE
	cd $(TARGET_DIR) && ( export IPKG_INSTROOT=$(TARGET_DIR); \
		$(foreach script,$(wildcard $(TARGET_DIR)/etc/init.d/*), \
			$(call EnableInitscript,$(script)); \
		) : \
	scripts/module_check.sh
	$(CheckTarget)
	$(foreach conf,site $(patsubst $(GLUON_SITEDIR)/%.conf,%,$(wildcard $(GLUON_SITEDIR)/domains/*.conf)),\
		$(call CheckSite,$(conf)); \
	)

	$(OPENWRTMAKE) prepare-tmpinfo
	$(GLUON_ENV) $(LUA) scripts/target_config.lua > openwrt/.config
	$(OPENWRTMAKE) defconfig
	$(GLUON_ENV) $(LUA) scripts/target_config_check.lua

# Generate package list
$(eval $(call merge-lists,INSTALL_PACKAGES,DEFAULT_PACKAGES GLUON_DEFAULT_PACKAGES GLUON_SITE_PACKAGES GLUON_$(PROFILE)_DEFAULT_PACKAGES GLUON_$(PROFILE)_SITE_PACKAGES))

package_install: FORCE
	$(OPKG) update
	$(OPKG) install $(PACKAGE_DIR)/libc_*.ipk
	$(OPKG) install $(PACKAGE_DIR)/kernel_*.ipk
container: FORCE
	@scripts/container.sh

	$(OPKG) install $(INSTALL_PACKAGES)
	+$(GLUONMAKE) enable_initscripts

	rm -f $(TARGET_DIR)/usr/lib/opkg/lists/* $(TARGET_DIR)/tmp/opkg.lock
all: config
	+@
	$(GLUON_ENV) $(LUA) scripts/clean_output.lua
	$(OPENWRTMAKE)
	$(GLUON_ENV) $(LUA) scripts/copy_output.lua

ifeq ($(GLUON_OPKG_CONFIG),1)
include $(INCLUDE_DIR)/version.mk
endif
clean download: config
	+@$(OPENWRTMAKE) $@

opkg_config: FORCE
	cp $(GLUON_OPENWRTDIR)/package/system/opkg/files/opkg.conf $(TARGET_DIR)/etc/opkg.conf
	for d in base luci packages routing telephony management oldpackages; do \
		echo "src/gz %n_$$d %U/$$d" >> $(TARGET_DIR)/etc/opkg.conf; \
dirclean: FORCE
	+@
	[ -e openwrt/.config ] || $(OPENWRTMAKE) defconfig
	$(OPENWRTMAKE) dirclean
	rm -rf $(GLUON_TMPDIR) $(GLUON_OUTPUTDIR)

manifest: $(LUA) FORCE
	@
	[ '$(GLUON_AUTOUPDATER_BRANCH)' ] || (echo 'Please set GLUON_AUTOUPDATER_BRANCH to create a manifest.'; false)
	echo '$(GLUON_PRIORITY)' | grep -qE '^([0-9]*\.)?[0-9]+$$' || (echo 'Please specify a numeric value for GLUON_PRIORITY to create a manifest.'; false)
	scripts/module_check.sh

	(
		export $(GLUON_ENV)
		echo 'BRANCH=$(GLUON_AUTOUPDATER_BRANCH)'
		echo "DATE=$$($(LUA) scripts/rfc3339date.lua)"
		echo 'PRIORITY=$(GLUON_PRIORITY)'
		echo
		for target in $(GLUON_TARGETS); do
			$(LUA) scripts/generate_manifest.lua "$$target"
		done
	$(VERSION_SED) $(TARGET_DIR)/etc/opkg.conf


image: FORCE
	rm -rf $(TARGET_DIR) $(BIN_DIR) $(TMP_DIR) $(PROFILE_KDIR)
	mkdir -p $(TARGET_DIR) $(BIN_DIR) $(TMP_DIR) $(TARGET_DIR)/tmp $(GLUON_IMAGEDIR)/factory $(GLUON_IMAGEDIR)/sysupgrade
	cp -r $(BOARD_KDIR) $(PROFILE_KDIR)

	+$(GLUONMAKE) package_install
	+$(GLUONMAKE) opkg_config GLUON_OPKG_CONFIG=1

	$(call Image/mkfs/prepare)
	$(_SINGLE)$(NO_TRACE_MAKE) -C $(TOPDIR)/target/linux/$(BOARD)/image install TARGET_BUILD=1 IB=1 IMG_PREFIX=gluon \
		PROFILE="$(PROFILE)" KDIR="$(PROFILE_KDIR)" TARGET_DIR="$(TARGET_DIR)" BIN_DIR="$(BIN_DIR)" TMP_DIR="$(TMP_DIR)"

	$(foreach model,$(GLUON_$(PROFILE)_MODELS), \
		rm -f $(GLUON_IMAGEDIR)/factory/gluon-*-$(model).bin && \
		rm -f $(GLUON_IMAGEDIR)/sysupgrade/gluon-*-$(model)-sysupgrade.bin && \
		\
		cp $(BIN_DIR)/gluon-$(GLUON_$(PROFILE)_MODEL_$(model))-factory.bin $(GLUON_IMAGEDIR)/factory/$(IMAGE_PREFIX)-$(model).bin && \
		cp $(BIN_DIR)/gluon-$(GLUON_$(PROFILE)_MODEL_$(model))-sysupgrade.bin $(GLUON_IMAGEDIR)/sysupgrade/$(IMAGE_PREFIX)-$(model)-sysupgrade.bin && \
	) :

image/%: $(gluon_prepared_stamp)
	+$(GLUONMAKE) image PROFILE="$(patsubst image/%,%,$@)" V=s$(OPENWRT_VERBOSE)

call_image/%: FORCE
	+$(GLUONMAKE) $(patsubst call_image/%,image/%,$@)

images: $(patsubst %,call_image/%,$(PROFILES)) ;

manifest: FORCE
	mkdir -p $(GLUON_IMAGEDIR)/sysupgrade
	(cd $(GLUON_IMAGEDIR)/sysupgrade && \
		echo 'BRANCH=$(GLUON_BRANCH)' && \
		echo 'DATE=$(shell $(STAGING_DIR_HOST)/bin/lua $(GLUONDIR)/scripts/rfc3339date.lua)' && \
		echo 'PRIORITY=$(GLUON_PRIORITY)' && \
		echo && \
		($(foreach profile,$(PROFILES), \
			$(foreach model,$(GLUON_$(profile)_MODELS), \
				for file in gluon-*-'$(model)-sysupgrade.bin'; do \
					[ -e "$$file" ] && echo \
						'$(model)' \
						"$$(echo "$$file" | sed -n -r -e 's/^gluon-$(call regex-escape,$(GLUON_SITE_CODE))-(.*)-$(call regex-escape,$(model))-sysupgrade\.bin$$/\1/p')" \
						"$$($(SHA512SUM) "$$file")" \
						"$$file" && break; \
				done; \
			) \
		) :) \
	) > $(GLUON_IMAGEDIR)/sysupgrade/$(GLUON_BRANCH).manifest


.PHONY: all images prepare clean gluon-tools
	) > 'tmp/$(GLUON_AUTOUPDATER_BRANCH).manifest.tmp'

endif
	mkdir -p '$(GLUON_IMAGEDIR)/sysupgrade'
	mv 'tmp/$(GLUON_AUTOUPDATER_BRANCH).manifest.tmp' '$(GLUON_IMAGEDIR)/sysupgrade/$(GLUON_AUTOUPDATER_BRANCH).manifest'

FORCE: ;

.PHONY: FORCE
.NOTPARALLEL:
.ONESHELL:
+59 −30
Original line number Diff line number Diff line
Documentation (incomplete at this time, contribute if you can!) may be found at
http://gluon.readthedocs.org/
[![Build Gluon](https://github.com/freifunk-gluon/gluon/actions/workflows/build-gluon.yml/badge.svg?branch=main)](https://github.com/freifunk-gluon/gluon/actions/workflows/build-gluon.yml)
[![License](https://img.shields.io/badge/License-BSD%202--Clause-orange.svg)](https://opensource.org/license/bsd-2-clause/)
[![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/freifunk-gluon/gluon?sort=semver)](https://github.com/freifunk-gluon/gluon/releases/latest)

# Gluon

Gluon is a firmware framework to build preconfigured OpenWrt images for public mesh networks.

## Overview

Gluon provides an easy-to-use firmware for a public, decentral WLAN and/or wire based mesh network.
Common network capable devices, like smartphones, laptops or desktop PCs can connect to the mesh network and communicate over it, without the need of passwords for access and without the need of installing special software.
Additionally, internet access and merging mesh clouds can be accomplished over a WAN through VPN connected gateways.

Gluon's features include:

* a decentral mesh network
* easy configuration mode for less techy users
* community-specific technical settings and customizations through a common site.conf and site.mk
* ecdsa signature-based autoupdater
* node status web page
* publication of node information + statistics through respondd
* a variety of preconfigured mesh and VPN protocols:


Supported mesh protocols:

* batman-adv (BATMAN IV fully, BATMAN V partially)
* OLSRv2 (partially)


Supported protocols for node-to-node connections:

* WLAN: 802.11s (with forwarding disabled)
* WAN: VPNs via fastd and Wireguard
* LAN: via VXLAN

## Getting started

We have a huge amount of documentation over at https://gluon.readthedocs.io/.

If you're new to Gluon and ready to get your feet wet, have a look at the
[Getting Started Guide](http://gluon.readthedocs.org/en/latest/user/getting_started.html).
[Getting Started Guide](https://gluon.readthedocs.io/en/latest/user/getting_started.html).

**Gluon IRC channel: `#gluon` in [hackint](http://hackint.org/)**
Gluon's developers frequent an IRC chatroom at [#gluon](ircs://irc.hackint.org/#gluon)
on [hackint](https://hackint.org/). There is also a [webchat](https://chat.hackint.org/?join=gluon)
that allows for uncomplicated access from within your browser. This channel is also available as a bridged Matrix Room at [#gluon:hackint.org](https://matrix.to/#/#gluon:hackint.org).

## Use a release!
## Issues & Feature requests

Please refrain from using the master branch for anything else but development purposes!
Use the most recent release instead. You can list all relaseses by running `git branch -a`
and switch to one by running `git checkout v2014.3;make update`.
Before opening an issue, make sure to check whether any existing issues
(open or closed) match. If you're suggesting a new feature, drop by on IRC or
our mailinglist to discuss it first.

If you're using the autoupdater, do not autoupdate nodes with anything but releases.
If you upgrade using random master commits the nodes *will break* eventually.
We maintain a [Roadmap](https://github.com/freifunk-gluon/gluon/wiki/Roadmap) for
the future development of Gluon.

## Mailinglist (mostly for announcements)
## Use a release!

I can handle administrative requests automatically. Please
do not send them to the list address! Instead, send
your message to the correct command address:
Please refrain from using the `main` branch for anything else but development purposes!
Use the most recent release instead. You can list all releases by running `git tag`
and switch to one by running `git checkout v2023.2.5 && make update`.

For help and a description of available commands, send a message to:
If you're using the autoupdater, do not autoupdate nodes with anything but releases.
If you upgrade using random main commits the nodes *might break* eventually.

    gluon-help@luebeck.freifunk.net
## Mailinglist

To subscribe to the list, send a message to:

    gluon-subscribe@luebeck.freifunk.net
    gluon+subscribe@luebeck.freifunk.net

To remove your address from the list, just send a message to
the address in the `List-Unsubscribe` header of any list
message. If you haven't changed addresses since subscribing,
you can also send a message to:

    gluon-unsubscribe@luebeck.freifunk.net

or for the digest to:

    gluon-digest-unsubscribe@luebeck.freifunk.net

If you need to get in touch with the human owner of this list,
please send a message to:

     gluon-owner@luebeck.freifunk.net

Please include a FORWARDED list message with ALL HEADERS intact
to make it easier to help you.
    gluon+unsubscribe@luebeck.freifunk.net
+23 −0
Original line number Diff line number Diff line
#!/usr/bin/env bash

# For a List of pre-installed packages on the runner image see
# https://github.com/actions/runner-images/tree/main?tab=readme-ov-file#available-images

echo "Disk space before cleanup"
df -h

# Remove packages not required to run the Gluon build CI
sudo apt-get -y remove \
	dotnet-* \
	firefox \
	google-chrome-stable \
	kubectl \
	microsoft-edge-stable \
	temurin-*-jdk

# Remove Android SDK tools
sudo rm -rf /usr/local/lib/android

echo "Disk space after cleanup"
df -h
Original line number Diff line number Diff line
#!/usr/bin/env python3

# Update target filters using
#   make update-ci

import re
import os
import sys
import json

# these changes trigger rebuilds on all targets
common = [
    ".github/workflows/build-gluon.yml",
    "modules",
    "Makefile",
    "patches/**",
    "scripts/**",
    "targets/generic",
    "targets/targets.mk",
]

# these changes are only built on x86-64
extra = [
    "contrib/ci/minimal-site/**",
    "package/**"
]

_filter = dict()

# INCLUDE_PATTERN matches:
# include '...'
# include "..."
# include("...")
# include('...')
INCLUDE_PATTERN = "^\\s*include *\\(? *[\"']([^\"']+)[\"']"

# construct filters map from stdin
for target in sys.stdin:
    target = target.strip()

    _filter[target] = [
        f"targets/{target}"
    ] + common

    target_file = os.path.join(os.environ['GLUON_TARGETSDIR'], target)
    with open(target_file) as f:
        includes = re.findall(INCLUDE_PATTERN, f.read(), re.MULTILINE)
        _filter[target].extend([f"targets/{i}" for i in includes])

    if target == "x86-64":
        _filter[target].extend(extra)

# print filters to stdout in json format, because json is stdlib and yaml compatible.
print(json.dumps(_filter, indent=2))
+17 −0
Original line number Diff line number Diff line
#!/bin/sh

set -e

export BROKEN=1
export GLUON_AUTOREMOVE=1
export GLUON_DEPRECATED=1
export GLUON_SITEDIR="contrib/ci/minimal-site"
export GLUON_TARGET="$1"
export BUILD_LOG=1

BUILD_THREADS="$(($(nproc) + 1))"

echo "Building Gluon with $BUILD_THREADS threads"

make update
make -j$BUILD_THREADS V=s
+16 −0
Original line number Diff line number Diff line
#!/usr/bin/env bash

echo "-- CPU --"
cat /proc/cpuinfo

echo "-- Memory --"
cat /proc/meminfo

echo "-- Disk --"
df -h

echo "-- Kernel --"
uname -a

echo "-- Network --"
ip addr
+146 −0
Original line number Diff line number Diff line
#!/usr/bin/env python3

import argparse
import json
import sys
from enum import Enum

# Enum Class for checking image size
class ImageSizeCheck(Enum):
    OK = "OK"
    TOO_BIG = "TOO_BIG"
    IGNORED = "IGNORED"
    UNKNOWN = "UNKNOWN"


# Some devices pad their images to IMAGE_SIZE and apply a firmware header.
# Exclude this from the image size check.
excluded_devices = [
    "tplink_cpe210-v1",
    "tplink_cpe210-v2",
    "tplink_cpe210-v3",
    "tplink_cpe220-v3",
    "tplink_cpe510-v1",
    "tplink_cpe510-v2",
    "tplink_cpe510-v3",
    "tplink_cpe710-v1",
    "tplink_wbs210-v1",
    "tplink_wbs210-v2",
    "tplink_wbs510-v1"
]


def open_json(file_path):
    with open(file_path, 'r') as f:
        return json.load(f)


def load_openwrt_profile_json(json_path):
    profiles = []
    profile_json = open_json(json_path)
    for profile_name, profile_data in profile_json["profiles"].items():
        device_profile = {
            "name": profile_name,
        }
        if "image" in profile_data.get("file_size_limits", {}):
            device_profile["max_image_size"] = profile_data["file_size_limits"]["image"]

        for image in profile_data["images"]:
            if image["type"] != "sysupgrade":
                continue
            if "size" in image:
                device_profile["image_size"] = image["size"]
        
        profiles.append(device_profile)
    
    return profiles


def check_image_size_below_limit(profile, overhead=0):
    # Skip devices that pad their images
    if profile["name"] in excluded_devices:
        return ImageSizeCheck.IGNORED

    if "max_image_size" in profile and "image_size" in profile:
        if profile["image_size"] + (overhead * 1024) > profile["max_image_size"]:
            return ImageSizeCheck.TOO_BIG
        else:	
            return ImageSizeCheck.OK
    
    return ImageSizeCheck.UNKNOWN


def print_github_actions_warning(message):
    print('::warning::{}'.format(message))


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Check image size of OpenWrt profiles')
    parser.add_argument(
        'profile_json',
        help='Path to profile.json',
        nargs='+'
    )
    parser.add_argument(
        '--github-actions',
        help='Generate warnings for use with GitHub Actions',
        action='store_true'
    )
    parser.add_argument(
        '--overhead',
        type=int,
        help='Additional size to add to the image size in kilobyte',
        default=0
    )
    args = parser.parse_args()

    if args.profile_json is None:
        print('Error: profile.json not specified')
        sys.exit(1)
    
    # Load all profile.json files
    profiles = []
    for profile_file in args.profile_json:
        profiles.extend(load_openwrt_profile_json(profile_file))

    # Initialize results with all available ImageSizeCheck values
    results = {}
    for check_result in ImageSizeCheck:
        results[check_result] = []

    for profile in profiles:
        check_result = check_image_size_below_limit(profile, args.overhead)
        results[check_result].append(profile)
    
    for check_result, profiles in results.items():
        if len(profiles) == 0:
            continue

        # Group by result type for GitHub Actions
        if args.github_actions:
            print('::group::{}'.format(check_result.value))

        for profile in profiles:
            if check_result == ImageSizeCheck.TOO_BIG:
                msg = 'Image size of profile {} is too big ({} > {})'.format(
                    profile["name"],
                    profile["image_size"] + (args.overhead * 1024),
                    profile["max_image_size"])
                if args.github_actions:
                    print_github_actions_warning(msg)
                else:
                    print("Warning: {}".format(msg))
            elif check_result == ImageSizeCheck.UNKNOWN:
                msg = 'Image size of profile {} is unknown'.format(
                    profile["name"])
                print(msg)
            elif check_result == ImageSizeCheck.IGNORED:
                msg = 'Image size of profile {} is ignored (Image size {})'.format(
                    profile["name"], profile.get("image_size", "unknown"))
                print(msg)
            else:
                msg = 'Image size of profile {} is OK ({} < {})'.format(
                    profile["name"], 
                    profile["image_size"] + (args.overhead * 1024),
                    profile["max_image_size"])
                print(msg)
+1 −0
Original line number Diff line number Diff line
../../../docs/site-example/i18n/
 No newline at end of file
Original line number Diff line number Diff line
features {
	'autoupdater',
	'ebtables-filter-multicast',
	'ebtables-filter-ra-dhcp',
	'ebtables-limit-arp',
	'mesh-batman-adv-15',
	'mesh-vpn-fastd',
	'respondd',
	'status-page',
	'web-advanced',
	'web-wizard',
}

if not device_class('tiny') then
	features {'wireless-encryption-wpa3'}
end
+1 −0
Original line number Diff line number Diff line
../../../docs/site-example/modules
 No newline at end of file
+180 −0
Original line number Diff line number Diff line
-- This is an example site configuration
--
-- Take a look at the documentation located at
-- https://gluon.readthedocs.io/ for details.
--
-- This configuration will not work as is. You're required to make
-- community specific changes to it!
{
  -- Used for generated hostnames, e.g. freifunk-abcdef123456. (optional)
  -- hostname_prefix = 'freifunk-',

  -- Name of the community.
  site_name = 'Continuous Integration',

  -- Shorthand of the community.
  site_code = 'ci',

  -- 32 bytes of random data, encoded in hexadecimal
  -- This data must be unique among all sites and domains!
  -- Can be generated using: echo $(hexdump -v -n 32 -e '1/1 "%02x"' </dev/urandom)
  domain_seed = 'e9608c4ff338b920992d629190e9ff11049de1dfc3f299eac07792dfbcda341c',

  -- Prefixes used within the mesh.
  -- prefix6 is required, prefix4 can be omitted if next_node.ip4
  -- is not set.
  prefix4 = '10.0.0.0/20',
  prefix6 = 'fd::/64',

  -- Timezone of your community.
  -- See https://openwrt.org/docs/guide-user/base-system/system_configuration#time_zones
  timezone = 'CET-1CEST,M3.5.0,M10.5.0/3',

  -- List of NTP servers in your community.
  -- Must be reachable using IPv6!
  --  ntp_servers = {'1.ntp.services.ffxx'},

  -- Wireless regulatory domain of your community.
  regdom = 'DE',

  -- Wireless configuration for 2.4 GHz interfaces.
  wifi24 = {
    -- Wireless channel.
    channel = 1,

    -- ESSIDs used for client network.
    ap = {
      ssid = 'gluon-ci-ssid',
      -- disabled = true, -- (optional)

      -- Configuration for a backward compatible OWE network below.
      owe_ssid = 'owe.gluon-ci-ssid', -- (optional - SSID for OWE client network)
      owe_transition_mode = true, -- (optional - enables transition-mode - requires ssid as well as owe_ssid)
    },

    mesh = {
      -- Adjust these values!
      id = 'ueH3uXjdp', -- usually you don't want users to connect to this mesh-SSID, so use a cryptic id that no one will accidentally mistake for the client WiFi
      mcast_rate = 12000,
      -- disabled = true, -- (optional)
    },
  },

  -- Wireless configuration for 5 GHz interfaces.
  -- This should be equal to the 2.4 GHz variant, except
  -- for channel.
  wifi5 = {
    channel = 44,
    outdoor_chanlist = '100-140',
    ap = {
      ssid = 'gluon-ci-ssid',
    },
    mesh = {
      -- Adjust these values!
      id = 'ueH3uXjdp',
      mcast_rate = 12000,
    },
  },

  mesh = {
    vxlan = true,
    batman_adv = {
      routing_algo = 'BATMAN_IV',
    },
  },

  -- The next node feature allows clients to always reach the node it is
  -- connected to using a known IP address.
  next_node = {
    -- anycast IPs of all nodes
    -- name = { 'nextnode.location.community.example.org', 'nextnode', 'nn' },
    ip4 = '10.0.0.1',
    ip6 = 'fd::1',
  },

  -- Options specific to routing protocols (optional)
  -- mesh = {
    -- Options specific to the batman-adv routing protocol (optional)
    -- batman_adv = {
      -- Gateway selection class (optional)
      -- The default class 20 is based on the link quality (TQ) only,
      -- class 1 is calculated from both the TQ and the announced bandwidth
      -- gw_sel_class = 1,
    -- },
  -- },

  mesh_vpn = {
    -- enabled = true,

    fastd = {
      -- Refer to https://fastd.readthedocs.io/en/latest/ to better understand
      -- what these options do.

      -- List of crypto-methods to use.
      methods = {'salsa2012+umac'},
      mtu = 1312,
      -- configurable = true,
      -- syslog_level = 'warn',

      groups = {
        backbone = {
          -- Limit number of connected peers to reduce bandwidth.
          limit = 1,

          -- List of peers.
          peers = {
          },

          -- Optional: nested peer groups
          -- groups = {
            -- backbone_sub = {
              -- ...
            -- },
          -- ...
          -- },
        },
        -- Optional: additional peer groups, possibly with other limits
        -- backbone2 = {
          -- ...
        -- },
      },
    },

    bandwidth_limit = {
      -- The bandwidth limit can be enabled by default here.
      enabled = false,

      -- Default upload limit (kbit/s).
      egress = 200,

      -- Default download limit (kbit/s).
      ingress = 3000,
    },
  },

  autoupdater = {
    -- Default branch (optional), can be overridden by setting GLUON_AUTOUPDATER_BRANCH when building.
    -- Set GLUON_AUTOUPDATER_ENABLED to enable the autoupdater by default for newly installed nodes.
    branch = 'stable',

    -- List of branches. You may define multiple branches.
    branches = {
      stable = {
        name = 'stable',

        -- List of mirrors to fetch images from. IPv6 required!
        mirrors = {'http://1.updates.services.ffhl/stable/sysupgrade'},

        -- Number of good signatures required.
        -- Have multiple maintainers sign your build and only
        -- accept it when a sufficient number of them have
        -- signed it.
        good_signatures = 0,

        -- List of public keys of maintainers.
        pubkeys = {
        },
      },
    },
  },
}
+1 −0
Original line number Diff line number Diff line
../../../docs/site-example/site.mk
 No newline at end of file
+1 −0
Original line number Diff line number Diff line
../minimal-site/i18n
 No newline at end of file
Original line number Diff line number Diff line
features {
	'autoupdater',
	'ebtables-filter-multicast',
	'ebtables-filter-ra-dhcp',
	'ebtables-limit-arp',
	'mesh-olsrd',
	'mesh-vpn-fastd',
	'respondd',
	'status-page',
	'web-advanced',
	'web-wizard',
}

packages {
	'iwinfo',
}

if not device_class('tiny') then
	features {'wireless-encryption-wpa3'}
end
+1 −0
Original line number Diff line number Diff line
../minimal-site/modules
 No newline at end of file
+176 −0
Original line number Diff line number Diff line
-- This is an example site configuration
--
-- Take a look at the documentation located at
-- https://gluon.readthedocs.io/ for details.
--
-- This configuration will not work as is. You're required to make
-- community specific changes to it!
{
  -- Used for generated hostnames, e.g. freifunk-abcdef123456. (optional)
  -- hostname_prefix = 'freifunk-',

  -- Name of the community.
  site_name = 'Continuous Integration',

  -- Shorthand of the community.
  site_code = 'ci',

  -- 32 bytes of random data, encoded in hexadecimal
  -- This data must be unique among all sites and domains!
  -- Can be generated using: echo $(hexdump -v -n 32 -e '1/1 "%02x"' </dev/urandom)
  domain_seed = 'e9608c4ff338b920992d629190e9ff11049de1dfc3f299eac07792dfbcda341c',

  -- Prefixes used by clients within the mesh.
  -- prefix6 is required, prefix4 can be omitted if next_node.ip4
  -- is not set.
  prefix6 = 'fdff:cafe:cafe:cafe::/64',

  -- Prefixes used by nodes within the mesh
  node_prefix6 = 'fdff:cafe:cafe:cafe::/64',

  -- Timezone of your community.
  -- See https://openwrt.org/docs/guide-user/base-system/system_configuration#time_zones
  timezone = 'CET-1CEST,M3.5.0,M10.5.0/3',

  -- List of NTP servers in your community.
  -- Must be reachable using IPv6!
  --  ntp_servers = {'1.ntp.services.ffxx'},

  -- Wireless regulatory domain of your community.
  regdom = 'DE',

  -- Wireless configuration for 2.4 GHz interfaces.
  wifi24 = {
    -- Wireless channel.
    channel = 1,

    -- ESSIDs used for client network.
    ap = {
      ssid = 'gluon-ci-ssid',
      -- disabled = true, -- (optional)

      -- Configuration for a backward compatible OWE network below.
      owe_ssid = 'owe.gluon-ci-ssid', -- (optional - SSID for OWE client network)
      owe_transition_mode = true, -- (optional - enables transition-mode - requires ssid as well as owe_ssid)
    },

    mesh = {
      -- Adjust these values!
      id = 'ueH3uXjdp', -- usually you don't want users to connect to this mesh-SSID, so use a cryptic id that no one will accidentally mistake for the client WiFi
      mcast_rate = 12000,
      -- disabled = true, -- (optional)
    },
  },

  -- Wireless configuration for 5 GHz interfaces.
  -- This should be equal to the 2.4 GHz variant, except
  -- for channel.
  wifi5 = {
    channel = 44,
    outdoor_chanlist = '100-140',
    ap = {
      ssid = 'gluon-ci-ssid',
      -- disabled = true, -- (optional)

      -- Configuration for a backward compatible OWE network below.
      owe_ssid = 'owe.gluon-ci-ssid', -- (optional - SSID for OWE client network)
      owe_transition_mode = true, -- (optional - enables transition-mode - requires ssid as well as owe_ssid)
    },
    mesh = {
      -- Adjust these values!
      id = 'ueH3uXjdp',
      mcast_rate = 12000,
    },
  },


  -- The next node feature allows clients to always reach the node it is
  -- connected to using a known IP address.
  next_node = {
    -- anycast IPs of all nodes
    name = { 'nextnode.location.community.example.org', 'nextnode', 'nn' },
    ip4 = '10.0.0.1',
    ip6 = 'fd::1',
  },

  -- Options specific to routing protocols (optional)
  mesh = {
    vxlan = true,
    olsrd = {},
  },

  mesh_vpn = {
    -- enabled = true,

    fastd = {
      -- Refer to https://fastd.readthedocs.io/en/latest/ to better understand
      -- what these options do.

      -- List of crypto-methods to use.
      methods = {'salsa2012+umac'},
      mtu = 1312,
      -- configurable = true,
      -- syslog_level = 'warn',

      groups = {
        backbone = {
          -- Limit number of connected peers to reduce bandwidth.
          limit = 1,

          -- List of peers.
          peers = {
          },

          -- Optional: nested peer groups
          -- groups = {
            -- backbone_sub = {
              -- ...
            -- },
          -- ...
          -- },
        },
        -- Optional: additional peer groups, possibly with other limits
        -- backbone2 = {
          -- ...
        -- },
      },
    },

    bandwidth_limit = {
      -- The bandwidth limit can be enabled by default here.
      enabled = false,

      -- Default upload limit (kbit/s).
      egress = 200,

      -- Default download limit (kbit/s).
      ingress = 3000,
    },
  },

  autoupdater = {
    -- Default branch (optional), can be overridden by setting GLUON_AUTOUPDATER_BRANCH when building.
    -- Set GLUON_AUTOUPDATER_ENABLED to enable the autoupdater by default for newly installed nodes.
    branch = 'stable',

    -- List of branches. You may define multiple branches.
    branches = {
      stable = {
        name = 'stable',

        -- List of mirrors to fetch images from. IPv6 required!
        mirrors = {'http://1.updates.services.ffhl/stable/sysupgrade'},

        -- Number of good signatures required.
        -- Have multiple maintainers sign your build and only
        -- accept it when a sufficient number of them have
        -- signed it.
        good_signatures = 0,

        -- List of public keys of maintainers.
        pubkeys = {
        },
      },
    },
  },
}
+29 −0
Original line number Diff line number Diff line
##	gluon site.mk makefile example

##	DEFAULT_GLUON_RELEASE
#		version string to use for images
#		gluon relies on
#			opkg compare-versions "$1" '>>' "$2"
#		to decide if a version is newer or not.

DEFAULT_GLUON_RELEASE := 0.6+exp$(shell date '+%Y%m%d')

# Variables set with ?= can be overwritten from the command line

##	GLUON_RELEASE
#		call make with custom GLUON_RELEASE flag, to use your own release version scheme.
#		e.g.:
#			$ make images GLUON_RELEASE=23.42+5
#		would generate images named like this:
#			gluon-ff%site_code%-23.42+5-%router_model%.bin

GLUON_RELEASE ?= $(DEFAULT_GLUON_RELEASE)

# Default priority for updates.
GLUON_PRIORITY ?= 0

# Region code required for some images; supported values: us eu
GLUON_REGION ?= eu

# Languages to include
GLUON_LANGS ?= en de

contrib/depdot.sh

0 → 100755
+58 −0
Original line number Diff line number Diff line
#!/usr/bin/env bash

# Script to output the dependency graph of Gluon's packages
# Limitations:
#  * Doesn't show dependencies through virtual packages correctly

set -e
shopt -s nullglob


pushd "$(dirname "$0")/.." >/dev/null


escape_name() {
	echo -n "_$1" | tr -c '[:alnum:]' _
}

print_node() {
	echo "$(escape_name "$1") [label=\"$1\", shape=box];"
}

print_dep() {
	echo "$(escape_name "$1") -> $(escape_name "$2");"
}

print_package() {
	local package="$1" depends="$2"
	# shellcheck disable=SC2086
	set -- $depends

	print_node "$package"
	for dep in "$@"; do
		print_node "$dep"
		print_dep "$package" "$dep"
	done
}

make -C openwrt -s prepare-tmpinfo

echo 'digraph G {'

cat ./openwrt/tmp/info/.packageinfo-feeds_gluon_base_* | while read -r key value; do
	case "$key" in
	'Package:')
		package="$value"
		;;
	'Depends:')
		depends="${value//+/}"
		;;
	'@@')
		print_package "$package" "$depends"
		;;
	esac
done | sort -u

popd >/dev/null

echo '}'
+47 −0
Original line number Diff line number Diff line
FROM debian:bookworm-slim

ARG TARGETOS
ARG TARGETARCH

ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    ca-certificates \
    clang \
    ecdsautils \
    file \
    gawk \
    git \
    libelf-dev \
    libncurses5-dev \
    libnss-unknown \
    libssl-dev \
    llvm \
    lua-check \
    openssh-client \
    python3 \
    python3-dev \
    python3-pyelftools \
    python3-setuptools \
    qemu-utils \
    rsync \
    shellcheck \
    swig \
    time \
    unzip \
    wget \
    zlib1g-dev \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

RUN mkdir /tmp/ec &&\
    wget -O /tmp/ec/ec-${TARGETOS}-${TARGETARCH}.tar.gz https://github.com/editorconfig-checker/editorconfig-checker/releases/download/2.7.0/ec-${TARGETOS}-${TARGETARCH}.tar.gz &&\
    tar -xvzf /tmp/ec/ec-${TARGETOS}-${TARGETARCH}.tar.gz &&\
    mv bin/ec-${TARGETOS}-${TARGETARCH} /usr/local/bin/editorconfig-checker &&\
    rm -rf /tmp/ec

RUN useradd -m -d /gluon -u 100 -g 100 -o gluon
USER gluon

VOLUME /gluon
WORKDIR /gluon

contrib/i18n-scan.pl

0 → 100755
+128 −0
Original line number Diff line number Diff line
#!/usr/bin/perl

use strict;
use warnings;
use Text::Balanced qw(extract_bracketed extract_delimited extract_tagged);

@ARGV >= 1 || die "Usage: $0 <source directory>\n";


my %stringtable;

sub dec_lua_str
{
	my $s = shift;
	$s =~ s/[\s\n]+/ /g;
	$s =~ s/\\n/\n/g;
	$s =~ s/\\t/\t/g;
	$s =~ s/\\(.)/$1/g;
	$s =~ s/^ //;
	$s =~ s/ $//;
	return $s;
}

sub dec_tpl_str
{
	my $s = shift;
	$s =~ s/-$//;
	$s =~ s/[\s\n]+/ /g;
	$s =~ s/^ //;
	$s =~ s/ $//;
	$s =~ s/\\/\\\\/g;
	return $s;
}


if( open F, "find @ARGV -type f '(' -name '*.html' -o -name '*.lua' ')' |" )
{
	while( defined( my $file = readline F ) )
	{
		chomp $file;

		if( open S, "< $file" )
		{
			local $/ = undef;
			my $raw = <S>;
			close S;


			my $text = $raw;

			while( $text =~ s/ ^ .*? (?:translate|translatef|_) [\n\s]* \( /(/sgx )
			{
				( my $code, $text ) = extract_bracketed($text, q{('")});

				$code =~ s/\\\n/ /g;
				$code =~ s/^\([\n\s]*//;
				$code =~ s/[\n\s]*\)$//;

				my $res = "";
				my $sub = "";

				if( $code =~ /^['"]/ )
				{
					while( defined $sub )
					{
						( $sub, $code ) = extract_delimited($code, q{'"}, q{\s*(?:\.\.\s*)?});

						if( defined $sub && length($sub) > 2 )
						{
							$res .= substr $sub, 1, length($sub) - 2;
						}
						else
						{
							undef $sub;
						}
					}
				}
				elsif( $code =~ /^(\[=*\[)/ )
				{
					my $stag = quotemeta $1;
					my $etag = $stag;
					$etag =~ s/\[/]/g;

					( $res ) = extract_tagged($code, $stag, $etag);

					$res =~ s/^$stag//;
					$res =~ s/$etag$//;
				}

				$res = dec_lua_str($res);
				$stringtable{$res}++ if $res;
			}


			$text = $raw;

			while( $text =~ s/ ^ .*? <% -? [:_] /<%/sgx )
			{
				( my $code, $text ) = extract_tagged($text, '<%', '%>');

				if( defined $code )
				{
					$code = dec_tpl_str(substr $code, 2, length($code) - 4);
					$stringtable{$code}++;
				}
			}
		}
	}

	close F;
}


if( open C, "| msgcat -" )
{
	printf C "msgid \"\"\nmsgstr \"Content-Type: text/plain; charset=UTF-8\"\n\n";

	foreach my $key ( sort keys %stringtable )
	{
		if( length $key )
		{
			$key =~ s/"/\\"/g;
			printf C "msgid \"%s\"\nmsgstr \"\"\n\n", $key;
		}
	}

	close C;
}

contrib/lsupgrade.sh

0 → 100755
+48 −0
Original line number Diff line number Diff line
#!/usr/bin/env bash

set -e
# Script to list all upgrade scripts in a clear manner
# Limitations:
#  * Does only show scripts of packages whose `files'/`luasrc' directories represent the whole image filesystem (which are all Gluon packages)


SUFFIX1=files/lib/gluon/upgrade
SUFFIX2=luasrc/lib/gluon/upgrade


shopt -s nullglob


if tty -s <&1; then
	RED="$(echo -e '\x1b[01;31m')"
	GREEN="$(echo -e '\x1b[01;32m')"
	BLUE="$(echo -e '\x1b[01;34m')"
	RESET="$(echo -e '\x1b[0m')"
else
	RED=
	GREEN=
	BLUE=
	RESET=
fi


pushd "$(dirname "$0")/.." >/dev/null

find ./package packages -name Makefile | grep -v '^packages/packages/' | while read -r makefile; do
	dir="$(dirname "$makefile")"

	pushd "$dir" >/dev/null

	repo="$(dirname "$dir" | cut -d/ -f 2)"
	dirname="$(dirname "$dir" | cut -d/ -f 3-)"
	package="$(basename "$dir")"

	for file in "${SUFFIX1}"/* "${SUFFIX2}"/*; do
		basename="$(basename "${file}")"
		suffix="$(dirname "${file}")"
		printf "%s\t%s\n" "${basename}" "${BLUE}${repo}${RESET}/${dirname}${dirname:+/}${RED}${package}${RESET}/${suffix}/${GREEN}${basename}${RESET}"
	done
	popd >/dev/null
done | sort | cut -f2-

popd >/dev/null

contrib/push_pkg.sh

0 → 100755
+149 −0
Original line number Diff line number Diff line
#!/bin/sh

set -e

topdir="$(realpath "$(dirname "${0}")/../openwrt")"

# defaults to qemu run script
ssh_host=localhost
build_only=0
preserve_config=1

print_help() {
	echo "$0 [OPTIONS] PACKAGE_DIR [PACKAGE_DIR] ..."
	echo ""
	echo " -h          print this help"
	echo " -r HOST     use a remote machine as target machine. By default if this"
	echo "             option is not given, push_pkg.sh will use a locally"
	echo "             running qemu instance started by run_qemu.sh."
	echo " -p PORT     use PORT as ssh port (default is 22)"
	echo " -b          build only, do not push"
	echo " -P          do not preserve /etc/config. By default, if a package"
	echo "             defines a config file in /etc/config, this config file"
	echo "             will be preserved. If you specify this flag, the package"
	echo "             default will be installed instead."
	echo ""
	echo ' To change gluon variables, run e.g. "make config GLUON_MINIFY=0"'
	echo ' because then the gluon logic will be triggered, and openwrt/.config'
	echo ' will be regenerated. The variables from openwrt/.config are already'
	echo ' automatically used for this script.'
	echo
}

while getopts "p:r:hbP" opt
do
	case $opt in
		P) preserve_config=0;;
		p) ssh_port="${OPTARG}";;
		r) ssh_host="${OPTARG}"; [ -z "$ssh_port" ] && ssh_port=22;;
		b) build_only=1;;
		h) print_help; exit 0;;
		*) ;;
	esac
done
shift $(( OPTIND - 1 ))

[ -z "$ssh_port" ] && ssh_port=2223

if [ "$build_only" -eq 0 ]; then
	remote_info=$(ssh -p "${ssh_port}" "root@${ssh_host}" '
		source /etc/os-release
		printf "%s\\t%s\\n" "$OPENWRT_BOARD" "$OPENWRT_ARCH"
	')
	REMOTE_OPENWRT_BOARD="$(echo "$remote_info" | cut -f 1)"
	REMOTE_OPENWRT_ARCH="$(echo "$remote_info" | cut -f 2)"

	# check target
	if ! grep -q "CONFIG_TARGET_ARCH_PACKAGES=\"${REMOTE_OPENWRT_ARCH}\"" "${topdir}/.config"; then
		echo "Configured OpenWrt Target is not matching with the target machine!" 1>&2
		echo
		printf "%s" "    Configured architecture: " 1>&2
		grep "CONFIG_TARGET_ARCH_PACKAGES" "${topdir}/.config" 1>&2
		echo "Target machine architecture: ${REMOTE_OPENWRT_ARCH}" 1>&2
		echo 1>&2
		echo "To switch the local with the run with the corresponding GLUON_TARGET:"  1>&2
		echo "  make GLUON_TARGET=... config" 1>&2
		exit 1
	fi
fi

if [ $# -lt 1 ]; then
	echo ERROR: Please specify a PACKAGE_DIR. For example:
	echo
	echo " \$ $0 package/gluon-core"
	exit 1
fi

while [ $# -gt 0 ]; do

	pkgdir="$1"; shift
	echo "Package: ${pkgdir}"

	if ! [ -f "${pkgdir}/Makefile" ]; then
		echo "ERROR: ${pkgdir} does not contain a Makefile"
		exit 1
	fi

	if ! grep -q BuildPackage "${pkgdir}/Makefile"; then
		echo "ERROR: ${pkgdir}/Makefile does not contain a BuildPackage command"
		exit 1
	fi

	opkg_packages="$(make TOPDIR="${topdir}" -C "${pkgdir}" DUMP=1 | awk '/^Package: / { print $2 }')"

	search_package() {
		find "$2" -name "$1_*.ipk" -printf '%f\n'
	}

	make TOPDIR="${topdir}" -C "${pkgdir}" clean
	make TOPDIR="${topdir}" -C "${pkgdir}" compile

	if [ "$build_only" -eq 1 ]; then
		continue
	fi

	# IPv6 addresses need brackets around the ${ssh_host} for scp!
	if echo "${ssh_host}" | grep -q :; then
		BL=[
		BR=]
	fi

	for pkg in ${opkg_packages}; do

		for feed in "${topdir}/bin/packages/${REMOTE_OPENWRT_ARCH}/"*/ "${topdir}/bin/targets/${REMOTE_OPENWRT_BOARD}/packages/"; do
			printf "%s" "searching ${pkg} in ${feed}: "
			filename=$(search_package "${pkg}" "${feed}")
			if [ -n "${filename}" ]; then
				echo found!
				break
			else
				echo not found
			fi
		done

		if [ "$preserve_config" -eq 0 ]; then
			opkg_flags=" --force-maintainer"
		fi

		# shellcheck disable=SC2029
		if [ -n "$filename" ]; then
			scp -O -P "${ssh_port}" "$feed/$filename" "root@${BL}${ssh_host}${BR}:/tmp/${filename}"
			ssh -p "${ssh_port}" "root@${ssh_host}" "
				set -e
				echo Running opkg:
				opkg install --force-reinstall ${opkg_flags} '/tmp/${filename}'
				rm '/tmp/${filename}'
				gluon-reconfigure
			"
		else
			# Some packages (e.g. procd-seccomp) seem to contain BuildPackage commands
			# which do not generate *.ipk files. Till this point, I am not aware why
			# this is happening. However, dropping a warning if the corresponding
			# *.ipk is not found (maybe due to other reasons as well), seems to
			# be more reasonable than aborting. Before this commit, the command
			# has failed.
			echo "Warning: ${pkg}*.ipk not found! Ignoring." 1>&2
		fi

	done
done

contrib/run_qemu.sh

0 → 100755
+15 −0
Original line number Diff line number Diff line
#!/bin/sh

# Note: You can exit the qemu instance by first pressing "CTRL + a" then "c".
#       Then you enter the command mode of qemu and can exit by typing "quit".

qemu-system-x86_64 \
	-d 'cpu_reset' \
	-enable-kvm \
	-gdb tcp::1234 \
	-nographic \
	-netdev user,id=wan,hostfwd=tcp::2223-10.0.2.15:22 \
	-device virtio-net-pci,netdev=wan,addr=0x06,id=nic1 \
	-netdev user,id=lan,hostfwd=tcp::6080-192.168.1.1:80,hostfwd=tcp::2222-192.168.1.1:22,net=192.168.1.100/24 \
	-device virtio-net-pci,netdev=lan,addr=0x05,id=nic2 \
	"$@"
+48 −21
Original line number Diff line number Diff line
#!/bin/sh

if [ $# -eq 0 -o "-h" = "$1" -o "-help" = "$1" -o "--help" = "$1" ]; then
set -e

if [ $# -ne 2 ] || [ "-h" = "$1" ] || [ "--help" = "$1" ] || [ ! -r "$1" ] || [ ! -r "$2" ]; then
	cat <<EOHELP
Usage: $0 <secret> <manifest>

sign.sh adds lines to a manifest to indicate the approval
of the integrity of the firmware as required for automated
updates. The first argument <secret> references a file harboring
the private key of a public-private key pair of a developer
that referenced by its public key in the site configuration.
The script may be performed multiple times to the same document
to indicate an approval by multiple developers.

See also
 * ecdsautils on https://github.com/freifunk-gluon/ecdsautils

EOHELP
	exit 1
fi

SECRET=$1
SECRET="$1"

manifest="$2"
upper="$(mktemp)"
lower="$(mktemp)"

trap 'rm -f "$upper" "$lower"' EXIT

manifest=$2
upper=$(mktemp)
lower=$(mktemp)
awk 'BEGIN    {
	sep = 0
}

awk "BEGIN    { sep=0 }
     /^---\$/ { sep=1; next }
              { if(sep==0) print > \"$upper\";
                else       print > \"$lower\"}" \
    $manifest
/^---$/ {
	sep = 1;
	next
}

ecdsasign $upper < $SECRET >> $lower
{
	if(sep == 0) {
		print > "'"$upper"'"
	} else {
		print > "'"$lower"'"
	}
}' "$manifest"

cat  $upper  > $manifest
echo ---    >> $manifest
cat  $lower >> $manifest
ecdsasign "$upper" < "$SECRET" >> "$lower"

rm -f $upper $lower
(
	cat  "$upper"
	echo ---
	cat  "$lower"
) > "$manifest"

contrib/sigtest.sh

0 → 100755
+50 −0
Original line number Diff line number Diff line
#!/bin/sh

if [ $# -eq 0 ] || [ "-h" = "$1" ] || [ "-help" = "$1" ] || [ "--help" = "$1" ]; then
	cat <<EOHELP
Usage: $0 <public> <signed manifest>

sigtest.sh checks if a manifest is signed by the public key <public>. There is
no output, success or failure is indicated via the return code.

See also:
 * ecdsautils in https://github.com/freifunk-gluon/ecdsautils
 * https://gluon.readthedocs.io/en/latest/features/autoupdater.html

EOHELP
	exit 1
fi

public="$1"
manifest="$2"
upper="$(mktemp)"
lower="$(mktemp)"
ret=1

awk 'BEGIN    {
	sep = 0
}

/^---$/ {
	sep = 1;
	next
}

{
	if(sep == 0) {
		print > "'"$upper"'"
	} else {
		print > "'"$lower"'"
	}
}' "$manifest"

while read -r line
do
	if ecdsaverify -s "$line" -p "$public" "$upper"; then
		ret=0
		break
	fi
done < "$lower"

rm -f "$upper" "$lower"
exit $ret
+10 −168
Original line number Diff line number Diff line
# Makefile for Sphinx documentation
# Minimal makefile for Sphinx documentation
#

# You can set these variables from the command line.
SPHINXOPTS    =
SPHINXOPTS    = -W --keep-going
SPHINXBUILD   = sphinx-build
PAPER         =
SOURCEDIR     = .
BUILDDIR      = _build

# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif

# Internal variables.
PAPEROPT_a4     = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .

.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext

# Put it first so that "make" without argument is like "make help".
help:
	@echo "Please use \`make <target>' where <target> is one of"
	@echo "  html       to make standalone HTML files"
	@echo "  dirhtml    to make HTML files named index.html in directories"
	@echo "  singlehtml to make a single large HTML file"
	@echo "  pickle     to make pickle files"
	@echo "  json       to make JSON files"
	@echo "  htmlhelp   to make HTML files and a HTML help project"
	@echo "  qthelp     to make HTML files and a qthelp project"
	@echo "  devhelp    to make HTML files and a Devhelp project"
	@echo "  epub       to make an epub"
	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
	@echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
	@echo "  text       to make text files"
	@echo "  man        to make manual pages"
	@echo "  texinfo    to make Texinfo files"
	@echo "  info       to make Texinfo files and run them through makeinfo"
	@echo "  gettext    to make PO message catalogs"
	@echo "  changes    to make an overview of all changed/added/deprecated items"
	@echo "  xml        to make Docutils-native XML files"
	@echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
	@echo "  linkcheck  to check all external links for integrity"
	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"

clean:
	rm -rf $(BUILDDIR)/*

html:
	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
	@echo
	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."

dirhtml:
	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
	@echo
	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."

singlehtml:
	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
	@echo
	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."

pickle:
	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
	@echo
	@echo "Build finished; now you can process the pickle files."

json:
	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
	@echo
	@echo "Build finished; now you can process the JSON files."

htmlhelp:
	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
	@echo
	@echo "Build finished; now you can run HTML Help Workshop with the" \
	      ".hhp project file in $(BUILDDIR)/htmlhelp."

qthelp:
	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
	@echo
	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Gluon.qhcp"
	@echo "To view the help file:"
	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Gluon.qhc"

devhelp:
	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
	@echo
	@echo "Build finished."
	@echo "To view the help file:"
	@echo "# mkdir -p $$HOME/.local/share/devhelp/Gluon"
	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Gluon"
	@echo "# devhelp"

epub:
	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
	@echo
	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."

latex:
	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
	@echo
	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
	@echo "Run \`make' in that directory to run these through (pdf)latex" \
	      "(use \`make latexpdf' here to do that automatically)."

latexpdf:
	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
	@echo "Running LaTeX files through pdflatex..."
	$(MAKE) -C $(BUILDDIR)/latex all-pdf
	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."

latexpdfja:
	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
	@echo "Running LaTeX files through platex and dvipdfmx..."
	$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."

text:
	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
	@echo
	@echo "Build finished. The text files are in $(BUILDDIR)/text."

man:
	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
	@echo
	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."

texinfo:
	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
	@echo
	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
	@echo "Run \`make' in that directory to run these through makeinfo" \
	      "(use \`make info' here to do that automatically)."

info:
	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
	@echo "Running Texinfo files through makeinfo..."
	make -C $(BUILDDIR)/texinfo info
	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."

gettext:
	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
	@echo
	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."

changes:
	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
	@echo
	@echo "The overview file is in $(BUILDDIR)/changes."

linkcheck:
	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
	@echo
	@echo "Link check complete; look for any errors in the above output " \
	      "or in $(BUILDDIR)/linkcheck/output.txt."

doctest:
	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
	@echo "Testing of doctests in the sources finished, look at the " \
	      "results in $(BUILDDIR)/doctest/output.txt."
	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

xml:
	$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
	@echo
	@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
.PHONY: help Makefile

pseudoxml:
	$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
	@echo
	@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+3 −0
Original line number Diff line number Diff line
.strike {
	text-decoration: line-through;
}
+102 −175
Original line number Diff line number Diff line
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Gluon documentation build configuration file, created by
# sphinx-quickstart on Wed Jan 29 00:45:53 2014.
# Configuration file for the Sphinx documentation builder.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# This file does only contain a selection of the most common options. For a
# full list see the documentation:
# http://www.sphinx-doc.org/en/master/config

import sys
import os
# -- Path setup --------------------------------------------------------------

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))

# -- General configuration ------------------------------------------------

# -- Project information -----------------------------------------------------

project = 'Gluon'
copyright = 'Project Gluon'
author = 'Project Gluon'

# The short X.Y version
version = '2023.2.5'
# The full version, including alpha/beta/rc tags
release = version


# -- General configuration ---------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
    'sphinx.ext.mathjax',
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# The suffix of source filenames.
source_suffix = '.rst'

# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = {'.rst': 'restructuredtext'}

# The master toctree document.
master_doc = 'index'

# General information about the project.
project = 'Gluon'
copyright = '2014, Project Gluon'

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '2014.3'
# The full version, including alpha/beta/rc tags.
release = '2014.3'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None

# There are two options for replacing |today|: either, you set today to some
# 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'
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = 'en'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']

# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None

# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True

# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True

# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
pygments_style = None

# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# Don't highlight code blocks unless requested explicitly
highlight_language = 'none'

# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# Ignore links to the config mode, as well as anchors on on hackint, which are
# used to mark channel names and do not exist. Regular links are not effected.
linkcheck_ignore = [
    'http://192.168.1.1',
    'https://chat.hackint.org'
]


# -- Options for HTML output ----------------------------------------------
# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
#html_theme = 'default'
#
html_theme = 'sphinx_rtd_theme'

# 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 = {}

# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []

# The name for this set of Sphinx documents.  If None, it defaults to
# "<project> v<release> documentation".
#html_title = None

# A shorter title for the navigation bar.  Default is the same as html_title.
#html_short_title = None

# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None

# The name of an image file (within the static path) to use as favicon of the
# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
#html_static_path = ['_static']

# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []

# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'

# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
#
html_static_path = ['_static']

# Custom sidebar templates, maps document names to template names.
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# The default sidebars (for documents that don't match any pattern) are
# defined by theme itself.  Builtin themes are using these templates by
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
# 'searchbox.html']``.
#
# html_sidebars = {}

# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}

# If false, no module index is generated.
#html_domain_indices = True
# These paths are either relative to html_static_path
# or fully qualified paths (eg. https://...)
html_css_files = ['css/custom.css']

# If false, no index is generated.
#html_use_index = True

# If true, the index is split into individual pages for each letter.
#html_split_index = False

# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True

# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True

# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True

# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it.  The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''

# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# -- Options for HTMLHelp output ---------------------------------------------

# Output file base name for HTML help builder.
htmlhelp_basename = 'Gluondoc'


# -- Options for LaTeX output ---------------------------------------------
# -- Options for LaTeX output ------------------------------------------------

latex_elements = {
    # The paper size ('letterpaper' or 'a4paper').
    #
    # 'papersize': 'letterpaper',

    # The font size ('10pt', '11pt' or '12pt').
    #
    # 'pointsize': '10pt',

    # Additional stuff for the LaTeX preamble.
    #
    # 'preamble': '',

    # Latex figure (float) alignment
    #
    # 'figure_align': 'htbp',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
#  author, documentclass [howto, manual, or own class]).
latex_documents = [
  ('index', 'Gluon.tex', 'Gluon Documentation',
    (master_doc, 'Gluon.tex', 'Gluon Documentation',
    'Project Gluon', 'manual'),
]

# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None

# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False

# If true, show page references after internal links.
#latex_show_pagerefs = False

# If true, show URL addresses after external links.
#latex_show_urls = False

# Documents to append as an appendix to all manuals.
#latex_appendices = []

# If false, no module index is generated.
#latex_domain_indices = True


# -- Options for manual page output ---------------------------------------
# -- Options for manual page output ------------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
    ('index', 'gluon', 'Gluon Documentation',
     ['Project Gluon'], 1)
    (master_doc, 'gluon', 'Gluon Documentation',
    [author], 1)
]

# If true, show URL addresses after external links.
#man_show_urls = False


# -- Options for Texinfo output -------------------------------------------
# -- Options for Texinfo output ----------------------------------------------

# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
#  dir menu entry, description, category)
texinfo_documents = [
  ('index', 'Gluon', 'Gluon Documentation',
   'Project Gluon', 'Gluon', 'One line description of project.',
    (master_doc, 'Gluon', 'Gluon Documentation',
    author, 'Gluon', 'One line description of project.',
    'Miscellaneous'),
]

# Documents to append as an appendix to all manuals.
#texinfo_appendices = []

# If false, no module index is generated.
#texinfo_domain_indices = True
# -- Options for Epub output -------------------------------------------------

# Bibliographic Dublin Core info.
epub_title = project

# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#
# epub_identifier = ''

# A unique identification for the text.
#
# epub_uid = ''

# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False
# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']
Original line number Diff line number Diff line
@@ -15,10 +15,15 @@ The `main repo`_ does have issues enabled.
IRC
---

Gluon's developers frequent `#gluon on hackint`_. You're welcome to join us!
Gluon's developers frequent the IRC chatroom `#gluon`_ on `hackint`_.
There is a `webchat`_ that allows for easy access from within your
web browser. You're welcome to join us!

.. _#gluon on hackint: irc://irc.hackint.org/#gluon
.. _#gluon: ircs://irc.hackint.org/#gluon
.. _hackint: https://hackint.org/
.. _webchat: https://chat.hackint.org/?join=gluon

.. _working-with-repositories:

Working with repositories
-------------------------
@@ -32,23 +37,9 @@ rerun

`make update` also applies the patches that can be found in the directories found in
`patches`; the resulting branch will be called `patched`, while the commit specified in `modules`
can be refered to by the branch `base`.
can be referred to by the branch `base`.

::

	make unpatch

sets the repositories to the `base` branch,

::

	make patch

re-applies the patches by resetting the `patched` branch to `base` and calling `git am`
for the patch files. Calling `make` or a similar command after calling `make unpatch`
is generally not a good idea.

After new patches have been commited on top of the patched branch (or existing commits
After new patches have been committed on top of the `patched` branch (or existing commits
since the base commit have been edited or removed), the patch directories can be regenerated
using

@@ -61,3 +52,34 @@ and you can try rebasing it onto the new `base` branch yourself and after that c

Always call `make update-patches` after making changes to a module repository as `make update` will overwrite your
commits, making `git reflog` the only way to recover them!

::

  make refresh-patches

In order to refresh patches when updating feeds or the OpenWrt base, `make refresh-patches` applies and updates all of their patches without installing feed packages to the OpenWrt build system.

This command speeds up the maintenance of updating OpenWrt and feeds.

Development Guidelines
----------------------
Lua should be used instead of sh whenever sensible. The following criteria
should be considered:

- Is the script doing more than just executing external commands? if so, use Lua
- Is the script parsing/editing json-data? If so, use Lua for speed
- When using sh, use jsonfilter instead of json_* functions for speed

Code formatting may sound like a topic for the pedantic, however it helps if
the code in the project is formatted in the same way. The following basic rules
apply:

- use tabs instead of spaces
- trailing whitespace characters must be eliminated
- files need to end with a final newline
- newlines need to have Unix line endings (lf)

To that end we provide a ``.editorconfig`` configuration, which is supported by most
of the editors out there.

If you add Lua scripts to gluon, check formatting with ``luacheck``.

docs/dev/build.rst

0 → 100644
+104 −0
Original line number Diff line number Diff line
Build system
============

This page explains internals of the Gluon build system. It is currently very
incomplete; please contribute if you can!

Feed management
---------------

Rather that relying on the *feed.conf* mechanism of OpenWrt directly, Gluon
manages its feeds (*"modules"*) using a collection of scripts. This solution was
selected for multiple reasons:

- Feeds lists from Gluon base and the site repository are combined
- Patchsets are applied to downloaded feed repositories automatically

The following variables specifically affect the feed management:

GLUON_FEEDS
    List of base feeds; defined in file *modules* in Gluon base

GLUON_SITE_FEED
    List of site feeds; defined in file *modules* in site config

\*_REPO, \*_BRANCH, \*_COMMIT
    Git repository URL, branch and
    commit ID of the feeds to use. The branch name may be omitted; the default
    branch will be used in this case.

GLUON_BASE_FEEDS
    Additional feed definitions to be added to *feeds.conf*
    verbatim. By default, this contains a reference to the Gluon base packages;
    when using the Gluon build system to build a non-Gluon system, the variable
    can be set to the empty string.

Helper scripts
--------------

Several tasks of the build process have been separated from the Makefile into
external scripts, which are stored in the *scripts* directory. This was done to
ease maintenance of these scripts and the Makefile, by avoiding a lot of escaping.
These scripts are either bash or Lua scripts that run on the build system.

default_feeds.sh
    Defines the constant ``DEFAULT_FEEDS`` with the names of all feeds listed in
    *openwrt/feeds.conf.default*. This script is only used as an include by other
    scripts.

feeds.sh
    Creates the *openwrt/feeds.conf* file from ``FEEDS`` and ``DEFAULT_FEEDS``. The
    feeds from ``FEEDS`` are linked to the matching subfolder of *packages/* and not
    explicitly defined feeds of ``DEFAULT_FEEDS`` are setup as dummy (src-dummy).
    This *openwrt/feeds.conf* is used to reinstall all packages of all feeds with
    the *openwrt/scripts/feeds* tool.

modules.sh
    Defines the constants ``GLUON_MODULES`` and ``FEEDS`` by reading the *modules*
    files of the Gluon repository root and the site configuration. The returned
    variables look like:

    - ``FEEDS``: "*feedA feedB ...*"
    - ``GLUON_MODULES``: "*openwrt packages/feedA packages/feedB ...*"

    This script is only used as an include by other scripts.

patch.sh
    (Re-)applies the patches from the *patches* directory to all ``GLUON_MODULES``
    and checks out the files to the filesystem.
    This is done for each repo by:

    - creating a temporary clone of the repo to patch
      - only branch *base* is used
    - applying all patches via *git am* on top of this temporary *base* branch
      - this branch is named *patched*
    - copying the temporary clone to the *openwrt* (for OpenWrt Base) or
      *packages* (for feeds) folder
      - *git fetch* is used with the temporary clone as source
      - *git checkout* is called to update the filesystem
    - updating all git submodules

    This solution with a temporary clone ensures that the timestamps of checked
    out files are not changed by any intermediate patch steps, but only when
    updating the checkout with the final result. This avoids triggering unnecessary
    rebuilds.

update.sh
    Sets up a working clone of the ``GLUON_MODULES`` (external repos) from the external
    source and installs it into *packages/* directory. It simply tries to set the *base*
    branch of the cloned repo to the correct commit. If this fails it fetches the
    upstream branch and tries again to set the local *base* branch.

getversion.sh
    Used to determine the version numbers of the repositories of Gluon and the
    site configuration, to be included in the built firmware images as
    */lib/gluon/gluon-version* and */lib/gluon/site-version*.

    By default, this uses ``git describe`` to generate a version number based
    on the last git tag. This can be overridden by putting a file called
    *.scmversion* into the root of the respective repositories.

    A command like ``rm -f .scmversion; echo "$(./scripts/getversion.sh .)" > .scmversion``
    can be used before applying local patches to ensure that the reported
    version numbers refer to an upstream commit ID rather than an arbitrary
    local one after ``git am``.

docs/dev/configmode.rst

deleted100644 → 0
+0 −92
Original line number Diff line number Diff line
Config Mode
===========

As of 2014.4 `gluon-config-mode` consists of several modules.

gluon-config-mode-core
    This modules provides the core functionality for the config mode.
    All modules must depend on it.

gluon-config-mode-hostname
    Provides a hostname field.

gluon-config-mode-autoupdater
    Informs whether the autoupdater is enabled.

gluon-config-mode-mesh-vpn
    Allows toggling of mesh-vpn-fastd and setting a bandwidth limit.

gluon-config-mode-geo-location
    Enables the user to set the geographical location of the node.

gluon-config-mode-contact-info
    Adds a field where the user can provide contact information.

In order to get a config mode close to the one found in 2014.3.x you may add
these modules to your `site.mk`:
gluon-config-mode-hostname,
gluon-config-mode-autoupdater,
gluon-config-mode-mesh-vpn,
gluon-config-mode-geo-location,
gluon-config-mode-contact-info

Writing Config Mode Modules
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Config mode modules are located at `/lib/gluon/config-mode/wizard` and
`/lib/gluon/config-mode/reboot`. Modules are named like `0000-name.lua` and
are executed in lexical order. If you take the standard set of modules, the
order is, for wizard modules:

  - 0050-autoupdater-info
  - 0100-hostname
  - 0300-mesh-vpn
  - 0400-geo-location
  - 0500-contact-info

While for reboot modules it is:

  - 0100-mesh-vpn
  - 0900-msg-reboot

Wizards
-------

Wizard modules return a UCI section. A simple module capable of changing the
hostname might look like this::

  local cbi = require "luci.cbi"
  local uci = luci.model.uci.cursor()

  local M = {}

  function M.section(form)
    local s = form:section(cbi.SimpleSection, nil, nil)
    local o = s:option(cbi.Value, "_hostname", "Hostname")
    o.value = uci:get_first("system", "system", "hostname")
    o.rmempty = false
    o.datatype = "hostname"
  end

  function M.handle(data)
    uci:set("system", uci:get_first("system", "system"), "hostname", data._hostname)
    uci:save("system")
    uci:commit("system")
  end

  return M

Reboot page
-----------

Reboot modules return a function that will be called when the page is to be
rendered or nil (i.e. the module is skipped)::

  if no_hello_world_today then
    return nil
  else
    return function ()
      luci.template.render_string("Hello World!")
    end
  end

docs/dev/debugging.rst

0 → 100644
+51 −0
Original line number Diff line number Diff line
Debugging
=========


.. _dev-debugging-kernel-oops:

Kernel Oops
-----------

Sometimes a running Linux kernel detects an error during runtime that can't
be corrected.
This usually generates a stack trace that points to the location in the code
that caused the oops.

Linux kernels in Gluon (and OpenWrt) are stripped.
That means they do not contain any debug symbols.
On one hand this leads to a smaller binary and faster loading times on the
target.
On the other hand this means that in a case of a stack trace the unwinder
can only print memory locations and no further debugging information.

Gluon stores a compressed kernel with debug symbols for every target
in the directory `output/debug/`.
These kernels should be kept along with the images as long as the images
are in use.
This allows the developer to analyse a stack trace later.

Decoding Stacktraces
....................

The tooling is contained in the kernel source tree in the file
`decode_stacktrace.sh <https://github.com/torvalds/linux/blob/master/scripts/decode_stacktrace.sh>`__.
This file and the needed source tree are available in the directory: ::

  openwrt/build_dir/target-<architecture>/linux-<architecture>/linux-<version>/

.. note::
  Make sure to use a kernel tree that matches the version and patches
  that was used to build the kernel.
  If in doubt just re-build the images for the target.

Some more information on how to use this tool can be found at
`LWN <https://lwn.net/Articles/592724/>`__.

Obtaining Stacktraces
.....................

On many targets stack traces can be read from the following
location after reboot: ::

  /sys/kernel/debug/crashlog
Original line number Diff line number Diff line
Adding support for new hardware
===============================
Adding hardware support
=======================
This page will give a short overview on how to add support
for new hardware to Gluon.

Hardware requirements
---------------------
Having an ath9k (or ath10k) based WLAN adapter is highly recommended,
Having an ath9k, ath10k or mt76 based WLAN adapter is highly recommended,
although other chipsets may also work. VAP (multiple SSID) support
is a requirement. At the moment, Gluon's scripts can't handle devices
without WLAN adapters (although such environments may also be interesting,
e.g. for automated testing in virtual machines).

.. _hardware-adding-profiles:

Adding profiles
---------------
The vast majority of devices with ath9k WLAN uses the ar71xx target of OpenWrt.
If the hardware you want to add support for is also ar71xx, adding a new profile
is enough.

Profiles are defined in ``targets/<target>-<subtarget>/profiles.mk``. There are two macros
used to define which images are generated: ``GluonProfile`` and ``GluonModel``. The following examples
are taken from ``profiles.mk`` of the ``ar71xx-generic`` target::

    $(eval $(call GluonProfile,TLWR1043))
    $(eval $(call GluonModel,TLWR1043,tl-wr1043nd-v1-squashfs,tp-link-tl-wr1043n-nd-v1))
    $(eval $(call GluonModel,TLWR1043,tl-wr1043nd-v2-squashfs,tp-link-tl-wr1043n-nd-v2))

The ``GluonProfile`` macro takes at least one parameter, the profile name as it is
defined in the Makefiles of OpenWrt (``openwrt/target/linux/<target>/<subtarget>/profiles/*``
and ``openwrt/target/linux/<target>/image/Makefile``). If the target you are on doesn't define
profiles (e.g. on x86), just add a single profile called ``Generic`` or similar.

It may optionally take a second parameter which defines additional packages to include for the profile
(e.g. ath10k). The additional packages defined in ``openwrt/target/linux/<target>/<subtarget>/profiles/*``
aren't used.

The ``GluonModel`` macro takes three parameters: The profile name, the suffix of the image file
generated by OpenWrt (without the file extension), and the final image name of the Gluon image.
The final image name must be the same that is returned by the following command.

::

    lua -e 'print(require("platform_info").get_image_name())'


This is just for the autoupdater can work. The command has to be executed _on_ the target (eg. the hardware router with a flashed image). So you'll first have to build an image with a guessed name, and afterwards build a new, correctly named image. On targets which aren't supported by the autoupdater,
``require("platform_info").get_image_name()`` will just return ``nil`` and the final image name
may be defined arbitrarily.

On devices with multiple WLAN adapters, care must also be taken that the primary MAC address is
configured correctly. ``/lib/gluon/core/sysconfig/primary_mac`` should contain the MAC address which
can be found on a label on most hardware; if it does not, ``/lib/gluon/upgrade/core/initial/001-sysconfig``
in ``gluon-core`` might need a fix. (There have also been cases in which the address was incorrect
even on devices with only one WLAN adapter, in these cases an OpenWrt bug was the cause).

Adding support for new hardware targets
---------------------------------------
Adding a new target is much more complex than adding a new profile. There are two basic steps
required for adding a new target:

Adjust packages
'''''''''''''''
One package that definitely needs adjustments for every new target added is ``lua-platform-info``. Just
start with a copy of an existing platform info script, adjust it for the new target, and add the new target
to the list of supported targets in the package Makefile.

On many targets, Gluon's network setup scripts (mainly in the packages ``gluon-core`` and ``gluon-mesh-batman-adv-core``)
won't run correctly without some adjustments, so better double check that everything is fine there (and the files
``primary_mac``, ``lan_ifname`` and ``wan_ifname`` in ``/lib/gluon/core/sysconfig/`` contain sensible values).

Add support to the build system
'''''''''''''''''''''''''''''''
A directory for the new target must be created under ``targets``, and it must be added
to ``targets/targets.mk``. In the new target directory, four files must be created:

* config
* kernel-config
* kernel-vermagic
* profiles.mk

The file ``config`` can be used to add additional, target-specific options to the OpenWrt config. If such options
aren't necessary, it can be left empty. For ``profiles.mk``, see :ref:`hardware-adding-profiles`.

The files ``kernel-config`` and ``kernel-vermagic`` must have the correct content so kernel modules from the upstream repositories
can be easily installed. The OpenWrt version a Gluon release is based on is defined by the upstream package repo URL in ``include/gluon.mk``
(in the variable ``CONFIG_VERSION_REPO``); at the time this documentation was written, this was ``barrier_breaker/14.07-rc3``; whenever
the package repo is updated, all ``kernel-config`` and ``kernel-vermagic`` files must be updated as well.

The file ``kernel-vermagic`` just contains a hash which is part of the version number of the kernel package. So in the case of ``ar71xx-generic`` on
``barrier_breaker/14.07-rc3``, we look in the directory ``https://downloads.openwrt.org/barrier_breaker/14.07-rc3/ar71xx/generic/packages/`` and
find that the kernel package is called ``kernel_3.10.49-1-94831e5bcf361d1c03e87a15e152b0e8_ar71xx.ipk``. This makes the ``kernel-vermagic`` the
string ``94831e5bcf361d1c03e87a15e152b0e8``.

For ``kernel-config``, the OpenWrt image builder must be downloaded. Again, for ``ar71xx-generic`` on
``barrier_breaker/14.07-rc3``, we download ``OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2.tar.bz2``
from ``https://downloads.openwrt.org/barrier_breaker/14.07-rc3/ar71xx/generic/``. After unpacking it, we use the file
``OpenWrt-ImageBuilder-ar71xx_generic-for-linux-x86_64/build_dir/target-mips_34kc_uClibc-0.9.33.2/linux-ar71xx_generic/linux-3.10.49/.config``
as our ``kernel-config``.

After this, is should be sufficient to call ``make GLUON_TARGET=<target>-<subtarget>`` to build the images for the new target.
with simultaneous AP + Mesh Point (802.11s) operation is required.

Device checklist
----------------
The description of pull requests adding device support must include the
`device integration checklist
<https://github.com/freifunk-gluon/gluon/wiki/Device-Integration-checklist>`_.
The checklist ensures that core functionality of Gluon is well supported on the
device.

.. _device-class-definition:

Device classes
--------------
All supported hardware is categorized into "device classes". This allows to
adjust the feature set of Gluon to the different hardware's capabilities via
``site.mk`` without having to list individual devices.

There are currently two devices classes defined: "standard" and "tiny". The
"tiny" class contains all devices that do not meet the following requirements:

- At least 7 MiB of usable firmware space
- At least 64 MiB of RAM (128MiB for devices with ath10k radio)

Target configuration
--------------------
Gluon's hardware support is based on OpenWrt's. For each supported target,
a configuration file exists at ``targets/<target>-<subtarget>`` (or just
``target/<target>`` for targets without subtargets) that contains all
Gluon-specific settings for the target. The generic configuration
``targets/generic`` contains settings that affect all targets.

All targets must be listed in ``target/targets.mk``.

The target configuration language is based on Lua, so Lua's syntax for variables
and control structures can be used.

Device definitions
~~~~~~~~~~~~~~~~~~
To configure a device to be built for Gluon, the ``device`` function is used.
In the simplest case, only two arguments are passed, for example:

.. code-block:: lua

  device('tp-link-tl-wdr3600-v1', 'tplink_tl-wdr3600-v1')

The first argument is the device name in Gluon, which is part of the output
image filename, and must correspond to the model string looked up by the
autoupdater. The second argument is the corresponding device profile name in
OpenWrt, as found in ``openwrt/target/linux/<target>/image/*``.

A table of additional settings can be passed as a third argument:

.. code-block:: lua

  device('ubiquiti-edgerouter-x', 'ubnt_edgerouter-x', {
    factory = false,
    packages = {'-hostapd-mini'},
    manifest_aliases = {
      'ubnt-erx',
    },
  })

The supported additional settings are described in the following sections.

Suffixes and extensions
~~~~~~~~~~~~~~~~~~~~~~~
For many targets, OpenWrt generates images with the suffixes
``-squashfs-factory.bin`` and ``-squashfs-sysupgrade.bin``. For devices with
different image names, is it possible to override the suffixes and extensions
using the settings ``factory``, ``factory_ext``, ``sysupgrade`` and
``sysupgrade_ext``, for example:

.. code-block:: lua

  {
    factory = '-squashfs-combined',
    factory_ext = '.img.gz',
    sysupgrade = '-squashfs-combined',
    sysupgrade_ext = '.img.gz',
  }

Only settings that differ from the defaults need to be passed. ``factory`` and
``sysupgrade`` can be set to ``false`` when no such images exist.

For some device types, there are multiple factory images with different
extensions. ``factory_ext`` can be set to a table of strings to account for this
case:

.. code-block:: lua

  {
    factory_ext = {'.img.gz', '.vmdk', '.vdi'},
  }

TODO: Extra images

Aliases and manifest aliases
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sometimes multiple devices exist that use the same OpenWrt images. To make it
easier to find these images, the ``aliases`` setting can be used to define
additional device names. Gluon will create symlinks for these names in the
image output directory.

.. code-block:: lua

  device('aruba-ap-303', 'aruba_ap-303', {
    factory = false,
    aliases = {'aruba-instant-on-ap11'},
  })

The aliased name will also be added to the autoupdater manifest, allowing upgrade
images to be found under the different name on targets that perform model name
detection at runtime.

It is also possible to add alternative names to the autoupdater manifest without
creating a symlink by using ``manifest_aliases`` instead of ``aliases``, which
should be done when the alternative name does not refer to a separate device.
This is particularly useful to allow the autoupdater to work when the model name
changed between Gluon versions.

Package lists
~~~~~~~~~~~~~
Gluon generates lists of packages that are installed in all images based on a
default list and the features and packages specified in the site configuration.

In addition, OpenWrt defines additional per-device package lists. These lists
may be modified in Gluon's device definitions, for example to include additional
drivers and firmware, or to remove unneeded software. Packages to remove are
prefixed with a ``-`` character.

For many ath10k-based devices, this is used to replace the "CT" variant of
ath10k with the mainline-based version:

.. code-block:: lua

  local ATH10K_PACKAGES_QCA9880 = {
    'kmod-ath10k',
    '-kmod-ath10k-ct',
    '-kmod-ath10k-ct-smallbuffers',
    'ath10k-firmware-qca988x',
    '-ath10k-firmware-qca988x-ct',
  }
  device('openmesh-a40', 'openmesh_a40', {
    packages = ATH10K_PACKAGES_QCA9880,
    factory = false,
  })

This example also shows how to define a local variable, allowing the package
list to be reused for multiple devices.

Device flags
~~~~~~~~~~~~

The settings ``class``, ``deprecated`` or ``broken`` should be set according to
the device support status. The default values are as follows:

.. code-block:: lua

  {
    class = 'standard',
    deprecated = false,
    broken = false,
  }

- Device classes are described in :ref:`device-class-definition`
- Broken devices are untested or do not meet our requirements as given by the
  device checklist
- Deprecated devices are slated for removal in a future Gluon version due to
  hardware constraints

Global settings
~~~~~~~~~~~~~~~
There is a number of directives that can be used outside of a ``device()``
definition:

- ``include('filename')``: Include another file with global settings
- ``config(key, value)``: Set a config symbol in OpenWrt's ``.config``. Value
  may be a string, number, boolean, or nil. Booleans and nil are used for
  tristate symbols, where nil sets the symbol to ``m``.
- ``try_config(key, value)``: Like ``config()``, but do not fail if setting
  the symbol is not possible (usually because its dependencies are not met)
- ``packages { 'package1', '-package2', ... }``: Define a list of packages to
  add or remove for all devices of a target. Package lists passed to multiple
  calls of ``packages`` will be aggregated.
- ``defaults { key = value, ... }``: Set default values for any of the
  additional settings that can be passed to ``device()``.

Helper functions
~~~~~~~~~~~~~~~~
The following helpers can be used in the target configuration:

- ``env.KEY`` allows to access environment variables
- ``istrue(value)`` returns true if the passed string is a positive number
  (often used with ``env``, for example ``if istrue(env.GLUON_DEBUG) then ...``)

Hardware support in packages
----------------------------
In addition to the target configuration files, some device-specific changes may
be required in packages.

gluon-core
~~~~~~~~~~
- ``/lib/gluon/upgrade/010-primary-mac``: Override primary MAC address selection

  Usually, the primary (label) MAC address is defined in OpenWrt's Device Trees.
  For devices or targets where this is not the case, it is possible to specify
  what interface to take the primary MAC address from in ``010-primary-mac``.

- ``/lib/gluon/upgrade/020-interfaces``: Override LAN/WAN interface assignment

  On PoE-powered devices, the PoE input port should be "WAN".

- ``/usr/lib/lua/gluon/platform.lua``: Contains a list of outdoor devices

gluon-setup-mode
~~~~~~~~~~~~~~~~
- ``/lib/gluon/upgrade/320-setup-ifname``: Contains a list of devices that use
  the WAN port for the config mode

  On PoE-powered devices, the PoE input port should be used for the config
  mode. This is handled correctly by default for outdoor devices listed in
  ``platform.lua``.

libplatforminfo
~~~~~~~~~~~~~~~
When adding support for a new target to Gluon, it may be necessary to adjust
libplatforminfo to define how autoupdater image names are derived from the
model name.
+18 −0
Original line number Diff line number Diff line
MAC addresses
=============

Many devices don't have enough unique MAC addresses assigned by the vendor
(in batman-adv, each mesh interface needs an own MAC address that must be unique
mesh-wide).

Gluon tries to solve this issue by using a hash of the primary MAC address as a
45 bit MAC address prefix. The resulting 8 addresses are used as follows:

* 0: client0; WAN
* 1: mesh0
* 2: owe0
* 3: wan_radio0 (private WLAN); batman-adv primary address
* 4: client1; LAN
* 5: mesh1
* 6: owe1
* 7: wan_radio1 (private WLAN); mesh VPN

docs/dev/packages.rst

0 → 100644
+215 −0
Original line number Diff line number Diff line
Package development
###################

Gluon packages are OpenWrt packages and follow the same rules described at https://openwrt.org/docs/guide-developer/packages.

Development workflow
====================

When you are developing packages, it often happens that you iteratively want to deploy
and verify the state your development. There are two ways to verify your changes:

1)
  One way is to rebuild the complete firmware, flash it, configure it and verify your
  development then. This usually takes at least a few minutes to get your changes
  working so you can test them. Especially if you iterate a lot, this becomes tedious.

2)
  Another way is to rebuild only the package you are currently working on and
  to deploy this package to your test system. Here not even a reboot is required.
  This makes iterating relatively fast. Your test system could be real hardware or
  even a qemu in most cases.

Gluon provides scripts to enhance workflow 2). Here is an example illustrating
the workflow using these scripts:

.. code-block:: shell

  # start a local qemu instance
  contrib/run_qemu.sh output/images/factory/[...]-x86-64.img

  # apply changes to the desired package
  vi package/gluon-ebtables/files/etc/init.d/gluon-ebtables

  # rebuild and push the package to the qemu instance
  contrib/push_pkg.sh package/gluon-ebtables/

  # test your changes
  ...

  # do more changes
  ...

  # rebuild and push the package to the qemu instance
  contrib/push_pkg.sh package/gluon-ebtables/

  # test your changes
  ...

  (and so on...)

  # see help of the script for more information
  contrib/push_pkg.sh -h
  ...

Features of ``push_pkg.sh``:

* Works with compiled and non-compiled packages.

  * This means it can be used in the development of C-code, Lua-Code and mostly any other code.

* Works with native OpenWrt and Gluon packages.
* Pushes to remote machines or local qemu instances.
* Pushes multiple packages in one call if desired.
* Performs site.conf checks.

Implementation details of ``push_pkg.sh``:

* First, the script builds an opkg package using the OpenWrt build system.
* This package is pushed to a *target machine* using scp:

  * By default the *target machine* is a locally running x86 qemu started using ``run_qemu.sh``.
  * The *target machine* can also be remote machine. (See the cli switch ``-r``)
  * Remote machines are not limited to a specific architecture. All architectures supported by gluon can be used as remote machines.

* Finally opkg is used to install/update the packages in the target machine.

  * While doing this, it will not override ``/etc/config`` with package defaults by default. (See the cli switch ``-P``).
  * While doing this, opkg calls the ``check_site.lua`` from the package as post_install script to validate the ``site.conf``. This means that the ``site.conf`` of the target machine is used for this validation.

Note that:

* ``push_pkg.sh`` does neither build nor push dependencies of the packages automatically. If you want to update dependencies, you must explicitly specify them to be pushed.
* If you add new packages, you must run ``make update config GLUON_TARGET=...``.
* You can change the gluon target of the target machine via ``make config GLUON_TARGET=...``.
* If you want to update the ``site.conf`` of the target machine, use ``push_pkg.sh package/gluon-site/``.
* Sometimes when things break, you can heal them by compiling a package with its dependencies: ``cd openwrt; make package/gluon-ebtables/clean; make package/gluon-ebtables/compile; cd ..``.
* You can exit qemu by pressing ``CTRL + a`` and ``c`` afterwards.

Gluon package makefiles
=======================

As many packages share the same or a similar structure, Gluon provides a ``package/gluon.mk`` that
can be included for common definitions. This file replaces OpenWrt's ``$(INCLUDE_DIR)/package.mk``;
it is usually included as ``include ../gluon.mk`` from Gluon core packages, or as
``include $(TOPDIR)/../package/gluon.mk`` from feeds.

Provided macros
***************

* *GluonBuildI18N* (arguments: *<source directory>*)

  Converts the *.po* files for all enabled languages from the given source directory to
  the binary *.lmo* format and stores them in ``$(PKG_BUILD_DIR)/i18n``.

* *GluonInstallI18N*

  Install *.lmo* files from ``$(PKG_BUILD_DIR)/i18n`` to ``/lib/gluon/web/i18n`` in the
  package install directory.

* *GluonSrcDiet* (arguments: *<source directory>*, *<destination directory>*)

  Copies a directory tree, processing all files in it using *LuaSrcDiet*. The directory
  tree should only contain Lua files.

* *GluonCheckSite* (arguments: *<source file>*)

  Intended to be used in a package postinst script. It will use the passed Lua
  snippet to verify package-specific site configuration.

* *BuildPackageGluon* (replaces *BuildPackage*)

  Extends the *Package/<name>* definition with common defaults, sets the package
  install script to the common *Gluon/Build/Install*, and automatically creates
  a postinst script using *GluonCheckSite* if a ``check_site.lua`` is found in the
  package directory.

Default build steps
*******************

These defaults greatly reduce the boilerplate in each package, but they can also
be confusing because of the many implicit behaviors depending on files in the
package directory. If any part of *Gluon/Build/Compile* or *Gluon/Build/Install*
does not work as intended for a package, the compile and install steps can
always be replaced or extended.

*Build/Compile* is set to *Gluon/Build/Compile* by default, which will

* run OpenWrt standard default commands (*Build/Compile/Default*) if a ``src/Makefile``
  or ``src/CMakeLists.txt`` is found
* run *GluonSrcDiet* on all files in the ``luasrc`` directory
* run *GluonBuildI18N* if a ``i18n`` directory is found

*Package/<name>* defaults to *Gluon/Build/Install* for packages defined using
*BuildPackageGluon*, which will

* copy all files from ``$(PKG_INSTALL_DIR)`` into the package if ``$(PKG_INSTALL)`` is 1
* copy all files from ``files`` into the package
* copy all Lua files built from ``luasrc`` into the package
* installs ``$(PKG_BUILD_DIR)/respondd.so`` to ``/usr/lib/respondd/$(PKG_NAME).so`` if ``src/respondd.c`` exists
* installs compiled i18n *.lmo* files

Feature flags
=============

Feature flags provide a convenient way to define package selections without
making it necessary to list each package explicitly. The list of features to
enable for a Gluon build is determined by the evaluated image-customization.lua file
in the root-directory of the Site repository.

The main feature flag definition file is ``package/features``, but each package
feed can provide additional definitions in a file called ``features`` at the root
of the feed repository.

Each flag *$flag* will include the package the name *gluon-$flag* by default.
The feature definition file can modify the package selection by adding or removing
packages when certain combinations of flags are set.

Feature definitions use Lua syntax. Two basic functions are defined:

* *feature(name, pkgs)*: Defines a new feature. *feature()* expects a feature
  (flag) name and a list of packages to add or remove when the feature is
  enabled.

  * Defining a feature using *feature* replaces the default definition of
    just including *gluon-$flag*.
  * A package is removed when the package name is prefixed with a ``-`` (after
    the opening quotation mark).

* *when(expr, pkgs)*: Adds or removes packages when a given logical expression
  of feature flags is satisfied.

  * *expr* is a logical expression composed of feature flag names (each prefixed
    with an underscore before the opening quotation mark), logical operators
    (*and*, *or*, *not*) and parentheses.
  * Referencing a feature flag in *expr* has no effect on the default handling
    of the flag. When no *feature()* entry for a flag exists, it will still
    add *gluon-$flag* by default.
  * *pkgs* is handled as for *feature()*.

Example::

    feature('web-wizard', {
      'gluon-config-mode-hostname',
      'gluon-config-mode-geo-location',
      'gluon-config-mode-contact-info',
      'gluon-config-mode-outdoor',
    })

    when(_'web-wizard' and _'mesh-vpn-fastd' or _'mesh-vpn-wireguard'), {
      'gluon-config-mode-mesh-vpn',
    })

    feature('no-radvd', {
      '-gluon-radvd',
    })


This will

* disable the inclusion of the (non-existent) packages *gluon-web-wizard* and *gluon-no-radvd* when their
  corresponding feature flags are evaluated as selected in the image-customization.lua file
* enable four additional config mode packages when the *web-wizard* feature is enabled
* enable *gluon-config-mode-mesh-vpn* when both *web-wizard* and one
  of *mesh-vpn-fastd* and *mesh-vpn-wireguard* are enabled
* disable the *gluon-radvd* package when *gluon-no-radvd* is enabled
+36 −0
Original line number Diff line number Diff line
gluon.site library
==================

The *gluon.site* library allows convenient access to the site configuration
from Lua scripts. Example:

.. code-block:: lua

  local site = require 'gluon.site'
  print(site.wifi24.ap.ssid())

The *site* object in this example does not directly represent the *site.conf* data structure;
instead, it is wrapped in a way that makes it more convenient to access deeply nested elements.
To access the underlying values, they must be unwrapped using the function call notation
(the ``()`` after ``site.wifi24.ap.ssid`` in the example).

The wrapper objects have two advantages over simple Lua tables:

* Accessing non-existing values is never an error: ``site.wifi24.ap.ssid()`` will simply
  return *nil* if ``site.wifi24`` or ``site.wifi24.ap`` do not exist
* Default values: A default value can be passed to the unwrapping function call:

  .. code-block:: lua

    print(site.wifi24.ap.ssid('Default'))

  will return *'Default'* instead of *nil* when the value is unset.

  Note that *nil* values and unset values are equivalent in Lua.

A simple way to access the whole site configuration as a simple table
is to unwrap the top-level site object:

.. code-block:: lua

  local site_table = site()

docs/dev/upgrade.rst

0 → 100644
+41 −0
Original line number Diff line number Diff line
Upgrade scripts
===============

Basics
------

After each sysupgrade (including the initial installation), Gluon will execute all scripts
under ``/lib/gluon/upgrade``. These scripts' filenames usually begin with a 3-digit number
specifying the order of execution. Note that the script files need to be executable.

To get an overview of the ordering of all scripts of all packages, the helper script ``contrib/lsupgrade.sh``
in the Gluon repository can be used, which will print all upgrade scripts' filenames and directories. If executed
on a TTY, the filename will be highlighted in green, the repository in blue and the package in red.

Best practices
--------------

* Most upgrade scripts are written in Lua. This allows using lots of helper functions provided
  by Gluon, e.g. to access the site configuration or edit UCI configuration files.

* Whenever possible, scripts shouldn't check if they are running for the first time, but just edit configuration
  files to achieve a valid configuration (without overwriting configuration changes made by the user where desirable).
  This allows using the same code to create the initial configuration and upgrade configurations on upgrades.

* If it is unavoidable to run different code during the initial installation, the ``sysconfig.gluon_version`` variable
  can be checked. This variable is ``nil`` during the initial installation and contains the previously installed Gluon
  version otherwise.

Script ordering
---------------

These are some guidelines for the script numbers:

* ``0xx``: Basic ``sysconfig`` setup
* ``1xx``: Basic system setup (including basic network configuration)
* ``2xx``: Wireless setup
* ``3xx``: Advanced network and system setup
* ``4xx``: Extended network and system setup (e.g. mesh VPN and next-node)
* ``5xx``: Miscellaneous (everything not fitting into any other category)
* ``6xx`` .. ``8xx``: Currently unused
* ``9xx``: Upgrade finalization

docs/dev/uplink.rst

0 → 100644
+55 −0
Original line number Diff line number Diff line
Uplink support
==============

As the WAN port of a node will be connected to a user's private network, it
is essential that the node only uses the WAN when it is absolutely necessary.
There are two cases in which the WAN port is used:

* Mesh VPN (package ``gluon-mesh-vpn-fastd``)
* DNS to resolve the VPN servers' addresses (package ``gluon-wan-dnsmasq``)

After the VPN connection has been established, the node should be able to reach
the mesh's DNS servers and use these for all other name resolution.

If a device has only a single Ethernet port (or group of ports), it will be
used as an uplink port even when it is not labeled as "WAN" by default. This
behavior can be controlled using the ``interfaces.single.default_roles``
site.conf option. It is also possible to alter the interface assignment after
installation by modifying ``/etc/config/gluon`` and running
``gluon-reconfigure``.

Routing tables
~~~~~~~~~~~~~~
As a node may get IPv6 default routes both over the WAN and the mesh, Gluon
uses two routing tables for IPv6. As all normal traffic should go over the mesh,
the mesh routes are added to the default table (table 0). All routes on the WAN interface
are put into table 1 (see ``/lib/gluon/upgrade/110-network`` in ``gluon-core``).

There is also an *ip -6 rule* which routes all IPv6 traffic with a packet mark with the
bit 1 set though table 1.


libpacketmark
~~~~~~~~~~~~~
*libpacketmark* is a library which can be loaded with ``LD_PRELOAD`` and will set the packet mark of all
sockets created by a process in accordance with the ``LIBPACKETMARK_MARK`` environment variable. This allows setting
the packet mark for processes which don't support this themselves. The process must run as root (or at least
with ``CAP_NET_ADMIN``) for this to work.

Unfortunately there's no nice way to set the packet mark via iptables for outgoing packets. The iptables will
run after the packet has been created, to even when the packet mark is changed and the packet is re-routed, the
source address won't be rewritten to the default source address of the newly chosen route. *libpacketmark* avoids
this issue as the packet mark will already be set when the packet is created.

gluon-wan-dnsmasq
~~~~~~~~~~~~~~~~~
To separate the DNS servers in the mesh from the ones on the WAN, the ``gluon-wan-dnsmasq`` package provides
a secondary DNS daemon which runs on ``127.0.0.1:54``. It will automatically use all DNS servers explicitly
configured in ``/etc/config/gluon-wan-dnsmasq`` or received via DNS/RA on the WAN port. It is important that
no DNS servers for the WAN interface are configured in ``/etc/config/network`` and that ``peerdns`` is set to 0
so the WAN DNS servers aren't leaked to the primary DNS daemon.

*libpacketmark* is used to make the secondary DNS daemon send its requests over the WAN interface.

The package ``gluon-mesh-vpn-fastd`` provides an iptables rule which will redirect all DNS requests from processes running
with the primary group ``gluon-mesh-vpn`` to ``127.0.0.1:54``, thus making fastd use the secondary DNS daemon.
+92 −0
Original line number Diff line number Diff line
Config Mode
===========

The `Config Mode` consists of several modules that provide a range of different
configuration options:

gluon-config-mode-core
    This modules provides the core functionality for the config mode.
    All modules must depend on it.

gluon-config-mode-hostname
    Provides a hostname field.

:doc:`gluon-config-mode-autoupdater <../../features/autoupdater>`
    Informs whether the autoupdater is enabled.

:doc:`gluon-config-mode-mesh-vpn <../../features/vpn>`
    Allows toggling of installed mesh-vpn technology and setting a bandwidth limit.

gluon-config-mode-geo-location
    Enables the user to set the geographical location of the node.

:doc:`../../package/gluon-config-mode-geo-location-osm`
    Lets the user click on a map to select the geographical location through a OSM map

gluon-config-mode-contact-info
    Adds a field where the user can provide contact information.

:doc:`../../package/gluon-web-cellular`
    Adds advanced options to enter WWAN config.

:doc:`../../package/gluon-web-network`
    Adds option to configure used role on interfaces

Most of the configuration options are described in :ref:`user-site-config_mode`

Writing Config Mode modules
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Config mode modules are located at ``/lib/gluon/config-mode/wizard`` and
``/lib/gluon/config-mode/reboot``. Modules are named like ``0000-name.lua`` and
are executed in lexical order. In the standard package set, the
order is, for wizard modules:

  - 0050-autoupdater-info
  - 0100-hostname
  - 0300-mesh-vpn
  - 0400-geo-location
  - 0500-contact-info

The reboot module order is:

  - 0100-mesh-vpn
  - 0900-msg-reboot

All modules are run in the gluon-web model context and have access to the same
variables as "full" gluon-web modules.

Wizards
-------

Wizard modules must return a function that is provided with the wizard form and an
UCI cursor. The function can create configuration sections in the form:

.. code-block:: lua

  return function(form, uci)
    local s = form:section(Section)
    local o = s:option(Value, "hostname", "Hostname")
    o.default = uci:get_first("system", "system", "hostname")
    o.datatype = "hostname"

    function o:write(data)
      uci:set("system", uci:get_first("system", "system"), "hostname", data)
    end

    return {'system'}
  end

The function may return a table of UCI packages to commit after the individual
fields' `write` methods have been executed. This is done to avoid committing the
packages repeatedly when multiple wizard modules modify the same package.

Reboot page
-----------

Reboot modules are simply executed when the reboot page is
rendered:

.. code-block:: lua

  renderer.render_string("Hello World!")
+124 −0
Original line number Diff line number Diff line
Controllers
===========

Controllers live in the ``controller`` subdirectory of a gluon-web application
(``/lib/gluon/config-mode/controller`` for the config mode,
``/lib/gluon/status-page/controller`` for the status page). They define which pages ("routes")
exist under the application base URL, and what code is run when these pages are requested.

Controller scripts usually start with a *package* declaration, followed by calls
to the *entry* function, which each define one route:

.. code-block:: lua

  package 'gluon-web-admin'

  entry({"admin"}, alias("admin", "info"), _("Advanced settings"), 10)
  entry({"admin", "info"}, template("admin/info"), _("Information"), 1)

*package* defines the translation namespace for the titles of the defined
pages as well as the referenced views and models. The entry function expects 4
arguments:

  - `path`: Components of the path to define a route for.

    The above example defines routes for the paths ``admin`` and ``admin/info``.

  - `target`: Dispatcher for the route. See the following section for details.
  - `title`: Page title (also used in navigation). The underscore function is used
    to mark the strings as translatable for ``i18n-scan.pl``.

  - `order`: Sort index in navigation (defaults to 100)

Navigation indexes are automatically generated for each path level. Pages can be
hidden from the navigation by setting the `hidden` property of the node object
returned by `entry`:

.. code-block:: lua

  entry({"hidden"}, alias("foo"), _("I'm hidden!")).hidden = true


Dispatchers
-----------

  - *alias* (*path*, ...): Redirects to a different page. The path components are
    passed as individual arguments.
  - *call* (*func*, ...): Runs a Lua function for custom request handling. The given
    function is called with the HTTP object and the template renderer as first
    two arguments, followed by all additional arguments passed to `call`.
  - *template* (*view*): Renders the given view. See :doc:`view`.
  - *model* (*name*): Displays and evaluates a form as defined by the given model. See the
    :doc:`model` page for an explanation of gluon-web models.


.. _web-controller-http:

The HTTP object
---------------

The HTTP object provides information about the HTTP requests and allows to add
data to the reply. Using it directly is rarely necessary when gluon-web
models and views are used.

Useful functions:

  - *getenv* (*key*): Returns a value from the CGI environment passed by the webserver.
  - *formvalue* (*key*): Returns a value passed in a query string or in the content
    of a POST request. If multiple values with the same name have been passed, only
    the first is returned.
  - *formvaluetable* (*key*): Similar to *formvalue*, but returns a table of all
    values for the given key.
  - *status* (*code*, *message*): Writes the HTTP status to the reply. Has no effect
    if a status has already been sent or non-header data has been written.
  - *header* (*key*, *value*): Adds an HTTP header to the reply to be sent to
    the client. Has no effect when non-header data has already been written.
  - *prepare_content* (*mime*): Sets the *Content-Type* header to the given MIME
    type
  - *write* (*data*, ...): Sends the given data to the client. If headers have not
    been sent, it will be done before the data is written.


HTTP functions are called in method syntax, for example:

.. code-block:: lua

  http:write('Output!')


.. _web-controller-template-renderer:

The template renderer
---------------------

The template renderer allows to render templates (views). The most useful functions
are:

  - *render* (*view*, *scope*, *pkg*): Renders the given view, optionally passing a table
    with additional variables to make available in the template. The passed package
    defines the translation namespace.
  - *render_string* (*str*, *scope*, *pkg*): Same as *render*, but the template is passed
    directly instead of being loaded from the view directory.

The renderer functions are called in property syntax, for example:

.. code-block:: lua

  renderer.render('layout')


Differences from LuCI
---------------------

  - Controllers must not use the *module* function to define a Lua module (*gluon-web*
    will set up a proper environment for each controller itself)
  - Entries are defined at top level, not inside an *index* function
  - The *alias* dispatcher triggers an HTTP redirect instead of directly running
    the dispatcher of the aliased route.
  - The *call* dispatcher is passed a function instead of a string with a function
    name.
  - The *cbi* dispatcher of LuCI has been renamed to *model*.
  - The HTTP POST handler support the multipart/form-data encoding only, so
    ``enctype="multipart/form-data"`` must be included in all *<form>* HTML
    elements.
  - Other dispatchers like *form* are not provided.

docs/dev/web/i18n.rst

0 → 100644
+109 −0
Original line number Diff line number Diff line
Internationalization support
============================

General guidelines
------------------

* All config mode packages must be fully translatable, with complete English and German texts.
* All new expert mode packages must be fully translatable. English texts are required.
* German translations are recommended. Other supported languages, especially French, are
  nice-to-have, but not required. If you don't know a language well, rather leave the translation
  blank, so it is obvious that there is no proper translation yet.
* Existing expert mode packages should be made translatable as soon as possible.
* The "message IDs" (which are the arguments to the *translate* function) should be the
  English texts.

i18n support in Gluon
---------------------

Internationalization support is available in all components (models, view and
controllers) of *gluon-web*-based packages. Strings are translated using the *translate*,
*_translate* and *translatef* functions (*translate* for static strings, *translatef*
for printf-like formatted string; *_translate* works the same as *translate*, but
will return *nil* instead of the original string when no translation is available).

In views, the special tags ``<%:...%>`` can be used to translate the contained string.

Example from the *gluon-config-mode-geo-location* package:

.. code-block:: lua

  local share_location = s:option(Flag, "location", translate("Show node on the map"))

Note that translations are *namespaced*: each package will only use its own
translation strings by default. For this purpose, the package name must by
specified in a package's controller. It is possible to access a different
translation package using the *i18n* function from models and view, which is
necessary when strings from the site configuration are used, or packages do not
have their own controller (which is the case for config mode wizard components).

.. code-block:: lua

  local site_i18n = i18n 'gluon-site'
  local msg = site_i18n._translate('gluon-config-mode:welcome')

Adding translation templates to Gluon packages
----------------------------------------------

The i18n support is based on the standard gettext system. For each translatable package,
a translation template with extension ``.pot`` can be created using the *i18n-scan.pl*
script in the ``contrib`` directory:

.. code-block:: sh

  cd package/gluon-web-mesh-vpn-fastd
  mkdir i18n
  cd i18n
  ../../../contrib/i18n-scan.pl ../files ../luasrc > gluon-web-mesh-vpn-fastd.pot

The same command can be run again to update the template.

In addition, the Makefile must be adjusted. Instead of OpenWrt's default *package.mk*,
the Gluon version (``../gluon.mk`` for core packages) must be used. The i18n files must be installed
and PKG_CONFIG_DEPENDS must be added::

  ...
  include ../gluon.mk

  PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG)
  ...
  define Build/Compile
    $(call GluonBuildI18N,gluon-web-mesh-vpn-fastd,i18n)
  endef

  define Package/gluon-web-mesh-vpn-fastd/install
    ...
    $(call GluonInstallI18N,gluon-web-mesh-vpn-fastd,$(1))
  endef
  ...


Adding translations
-------------------

A new translation file for a template can be added using the *msginit* command:

.. code-block:: sh

  cd package/gluon-web-mesh-vpn-fastd/i18n
  msginit -l de

This will create the file *de.po* in which the translations can be added.

The translation file can be updated to a new template version using the *msgmerge* command:

.. code-block:: sh

  msgmerge -U de.po gluon-web-mesh-vpn-fastd.pot

After the merge, the translation file should be checked for "fuzzy matched" entries where
the original English texts have changed. All entries from the translation file should be
translated in the *.po* file (or removed from it, so the original English texts are displayed
instead).

Adding support for new languages
--------------------------------

A list of all languages supported by *gluon-web* can be found in ``package/gluon.mk``.
New languages just need to be added to *GLUON_SUPPORTED_LANGS*, and a human-readable
language name must be defined.

docs/dev/web/model.rst

0 → 100644
+153 −0

File added.

Preview size limit exceeded, changes collapsed.

docs/dev/web/view.rst

0 → 100644
+60 −0

File added.

Preview size limit exceeded, changes collapsed.

Original line number Diff line number Diff line
@@ -8,7 +8,7 @@ If you select this package, add a list of authorized keys to ``site.conf`` like

  {
    authorized_keys = { 'ssh-rsa AAA.... user1@host',
                        'ssh-rsa AAA.... user2@host },
                        'ssh-rsa AAA.... user2@host' },
    hostname_prefix = ...
    ...

+34 −0

File added.

Preview size limit exceeded, changes collapsed.

docs/features/tls.rst

0 → 100644
+10 −0

File added.

Preview size limit exceeded, changes collapsed.

docs/features/vpn.rst

0 → 100644
+250 −0

File added.

Preview size limit exceeded, changes collapsed.

+74 −73

File changed.

Preview size limit exceeded, changes collapsed.

+148 −0

File added.

Preview size limit exceeded, changes collapsed.

docs/requirements.txt

0 → 100644
+2 −0

File added.

Preview size limit exceeded, changes collapsed.

File changed.

Preview size limit exceeded, changes collapsed.

docs/user/mtu.rst

0 → 100644
+225 −0

File added.

Preview size limit exceeded, changes collapsed.

+889 −147

File changed.

Preview size limit exceeded, changes collapsed.

docs/user/x86.rst

0 → 100644
+34 −0

File added.

Preview size limit exceeded, changes collapsed.

include/Makefile.image

deleted100644 → 0
+0 −7

File deleted.

Preview size limit exceeded, changes collapsed.

include/Makefile.target

deleted100644 → 0
+0 −11

File deleted.

Preview size limit exceeded, changes collapsed.

include/config

deleted100644 → 0
+0 −18

File deleted.

Preview size limit exceeded, changes collapsed.

include/gluon.mk

deleted100644 → 0
+0 −67

File deleted.

Preview size limit exceeded, changes collapsed.

include/package.mk

deleted100644 → 0
+0 −8

File deleted.

Preview size limit exceeded, changes collapsed.

include/toplevel.mk

deleted100644 → 0
+0 −66

File deleted.

Preview size limit exceeded, changes collapsed.

include/verbose.mk

deleted100644 → 0
+0 −67

File deleted.

Preview size limit exceeded, changes collapsed.

+12 −14

File changed.

Preview size limit exceeded, changes collapsed.

package/features

0 → 100644
+56 −0

File added.

Preview size limit exceeded, changes collapsed.