diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 923f89af5a..ff78ea4c2e 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -10,7 +10,7 @@ jobs: include: - os: ubuntu-latest name: Linux - container: wpilib/roborio-cross-ubuntu:2021-18.04 + container: wpilib/roborio-cross-ubuntu:2021-20.04 flags: "" - os: macos-latest name: macOS @@ -26,6 +26,12 @@ jobs: if [ "$RUNNER_OS" == "macOS" ]; then brew install opencv fi + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install jinja + run: python -m pip install jinja2 - name: configure run: mkdir build && cd build && cmake ${{ matrix.flags }} .. - name: build diff --git a/.github/workflows/lint-format.yml b/.github/workflows/lint-format.yml index 2fd5e9de57..b227fc5a35 100644 --- a/.github/workflows/lint-format.yml +++ b/.github/workflows/lint-format.yml @@ -63,6 +63,8 @@ jobs: sudo apt-get install -y clang-tidy-12 clang-format-12 - name: Install wpiformat run: pip3 install wpiformat + - name: Install jinja + run: python -m pip install jinja2 - name: Create compile_commands.json run: mkdir build-cmake && cd build-cmake && cmake -DWITH_OLD_COMMANDS=ON -DWITH_EXAMPLES=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=YES .. - name: List changed files diff --git a/.github/workflows/sanitizers.yml b/.github/workflows/sanitizers.yml index f0022b0a5e..1f4ff8f5d2 100644 --- a/.github/workflows/sanitizers.yml +++ b/.github/workflows/sanitizers.yml @@ -16,7 +16,7 @@ jobs: flags: "-DCMAKE_BUILD_TYPE=Ubsan" name: "${{ matrix.name }}" runs-on: ubuntu-latest - container: wpilib/roborio-cross-ubuntu:2021-18.04 + container: wpilib/roborio-cross-ubuntu:2021-20.04 steps: - uses: actions/checkout@v2 - name: Install Dependencies @@ -27,6 +27,12 @@ jobs: --install /usr/bin/gcc gcc /usr/bin/gcc-11 11 \ --slave /usr/bin/g++ g++ /usr/bin/g++-11 sudo update-alternatives --set gcc /usr/bin/gcc-11 + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install jinja + run: python -m pip install jinja2 - name: configure run: mkdir build && cd build && cmake ${{ matrix.flags }} .. - name: build diff --git a/build.gradle b/build.gradle index dec75ba7ba..7cc068e31a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,14 @@ import edu.wpi.first.toolchain.* +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'com.hubspot.jinjava:jinjava:2.5.8' + } +} + plugins { id 'base' id 'edu.wpi.first.wpilib.versioning.WPILibVersioningPlugin' version '4.1.0' diff --git a/wpimath/build.gradle b/wpimath/build.gradle index 2e002ca461..6815cbd668 100644 --- a/wpimath/build.gradle +++ b/wpimath/build.gradle @@ -1,3 +1,6 @@ +import com.hubspot.jinjava.Jinjava; +import com.hubspot.jinjava.JinjavaConfig; + ext { useJava = true useCpp = true @@ -66,9 +69,8 @@ dependencies { api "com.fasterxml.jackson.core:jackson-databind:2.10.0" } -def wpilibNumberFileInput = file("src/generate/GenericNumber.java.in") -def natFileInput = file("src/generate/Nat.java.in") -def natGetterInput = file("src/generate/NatGetter.java.in") +def wpilibNumberFileInput = file("src/generate/GenericNumber.java.jinja") +def natFileInput = file("src/generate/Nat.java.jinja") def wpilibNumberFileOutputDir = file("$buildDir/generated/java/edu/wpi/first/math/numbers") def wpilibNatFileOutput = file("$buildDir/generated/java/edu/wpi/first/math/Nat.java") def maxNum = 20 @@ -86,10 +88,17 @@ task generateNumbers() { } wpilibNumberFileOutputDir.mkdirs() + def config = new JinjavaConfig() + def jinjava = new Jinjava(config) + + def template = wpilibNumberFileInput.text + for(i in 0..maxNum) { def outputFile = new File(wpilibNumberFileOutputDir, "N${i}.java") - def read = wpilibNumberFileInput.text.replace('${num}', i.toString()) - outputFile.write(read) + def replacements = new HashMap() + replacements.put("num", i) + def output = jinjava.render(template, replacements) + outputFile.write(output) } } } @@ -97,7 +106,7 @@ task generateNumbers() { task generateNat() { description = "Generates Nat.java" group = "WPILib" - inputs.files([natFileInput, natGetterInput]) + inputs.file natFileInput outputs.file wpilibNatFileOutput dependsOn generateNumbers @@ -106,19 +115,16 @@ task generateNat() { wpilibNatFileOutput.delete() } - def template = natFileInput.text + "\n" + def config = new JinjavaConfig() + def jinjava = new Jinjava(config) - def importsString = ""; + def template = natFileInput.text - for(i in 0..maxNum) { - importsString += "import edu.wpi.first.math.numbers.N${i};\n" - template += natGetterInput.text.replace('${num}', i.toString()) + "\n" - } - template += "}\n" // Close the class body + def replacements = new HashMap() + replacements.put("nums", 0..maxNum) - template = template.replace('{{REPLACEWITHIMPORTS}}', importsString) - - wpilibNatFileOutput.write(template) + def output = jinjava.render(template, replacements) + wpilibNatFileOutput.write(output) } } diff --git a/wpimath/generate_numbers.py b/wpimath/generate_numbers.py index 14c9cb7cd8..c52ddb4fd3 100644 --- a/wpimath/generate_numbers.py +++ b/wpimath/generate_numbers.py @@ -1,5 +1,26 @@ +# Copyright (c) FIRST and other WPILib contributors. +# Open Source Software; you can modify and/or share it under the terms of +# the WPILib BSD license file in the root directory of this project. + import os import sys +from jinja2 import Environment, FileSystemLoader + + +def output(outPath, outfn, contents): + if not os.path.exists(outPath): + os.makedirs(outPath) + + outpathname = f"{outPath}/{outfn}" + + if os.path.exists(outpathname): + with open(outpathname, "r") as f: + if f.read() == contents: + return + + # File either doesn't exist or has different contents + with open(outpathname, "w") as f: + f.write(contents) def main(): @@ -8,51 +29,21 @@ def main(): dirname, _ = os.path.split(os.path.abspath(__file__)) cmake_binary_dir = sys.argv[1] - with open(f"{dirname}/src/generate/GenericNumber.java.in", - "r") as templateFile: - template = templateFile.read() - rootPath = f"{cmake_binary_dir}/generated/main/java/edu/wpi/first/math/numbers" + env = Environment(loader=FileSystemLoader(f"{dirname}/src/generate"), + autoescape=False, + keep_trailing_newline=True) - if not os.path.exists(rootPath): - os.makedirs(rootPath) + template = env.get_template("GenericNumber.java.jinja") + rootPath = f"{cmake_binary_dir}/generated/main/java/edu/wpi/first/math/numbers" - for i in range(MAX_NUM + 1): - new_contents = template.replace("${num}", str(i)) + for i in range(MAX_NUM + 1): + contents = template.render(num=i) + output(rootPath, f"N{i}.java", contents) - if os.path.exists(f"{rootPath}/N{i}.java"): - with open(f"{rootPath}/N{i}.java", "r") as f: - if f.read() == new_contents: - continue - - # File either doesn't exist or has different contents - with open(f"{rootPath}/N{i}.java", "w") as f: - f.write(new_contents) - - with open(f"{dirname}/src/generate/Nat.java.in", "r") as templateFile: - template = templateFile.read() - outputPath = f"{cmake_binary_dir}/generated/main/java/edu/wpi/first/math/Nat.java" - with open(f"{dirname}/src/generate/NatGetter.java.in", - "r") as getterFile: - getter = getterFile.read() - - importsString = "" - - for i in range(MAX_NUM + 1): - importsString += f"import edu.wpi.first.math.numbers.N{i};\n" - template += getter.replace("${num}", str(i)) - - template += "}\n" - - template = template.replace('{{REPLACEWITHIMPORTS}}', importsString) - - if os.path.exists(outputPath): - with open(outputPath, "r") as f: - if f.read() == template: - return 0 - - # File either doesn't exist or has different contents - with open(outputPath, "w") as f: - f.write(template) + template = env.get_template("Nat.java.jinja") + rootPath = f"{cmake_binary_dir}/generated/main/java/edu/wpi/first/math" + contents = template.render(nums=range(MAX_NUM + 1)) + output(rootPath, "Nat.java", contents) if __name__ == "__main__": diff --git a/wpimath/src/generate/GenericNumber.java.in b/wpimath/src/generate/GenericNumber.java.in deleted file mode 100644 index 3bdc1b6ba2..0000000000 --- a/wpimath/src/generate/GenericNumber.java.in +++ /dev/null @@ -1,34 +0,0 @@ -/*----------------------------------------------------------------------------*/ -/* Copyright (c) 2019 FIRST. All Rights Reserved. */ -/* Open Source Software - may be modified and shared by FRC teams. The code */ -/* must be accompanied by the FIRST BSD license file in the root directory of */ -/* the project. */ -/*----------------------------------------------------------------------------*/ - -package edu.wpi.first.math.numbers; - -import edu.wpi.first.math.Nat; -import edu.wpi.first.math.Num; - -/** - * A class representing the number ${num}. -*/ -public final class N${num} extends Num implements Nat { - private N${num}() { - } - - /** - * The integer this class represents. - * - * @return The literal number ${num}. - */ - @Override - public int getNum() { - return ${num}; - } - - /** - * The singleton instance of this class. - */ - public static final N${num} instance = new N${num}(); -} diff --git a/wpimath/src/generate/GenericNumber.java.jinja b/wpimath/src/generate/GenericNumber.java.jinja new file mode 100644 index 0000000000..5e4be85aeb --- /dev/null +++ b/wpimath/src/generate/GenericNumber.java.jinja @@ -0,0 +1,31 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package edu.wpi.first.math.numbers; + +import edu.wpi.first.math.Nat; +import edu.wpi.first.math.Num; + +/** + * A class representing the number {{ num }}. +*/ +public final class N{{ num }} extends Num implements Nat { + private N{{ num }}() { + } + + /** + * The integer this class represents. + * + * @return The literal number {{ num }}. + */ + @Override + public int getNum() { + return {{ num }}; + } + + /** + * The singleton instance of this class. + */ + public static final N{{ num }} instance = new N{{ num }}(); +} diff --git a/wpimath/src/generate/Nat.java.in b/wpimath/src/generate/Nat.java.in deleted file mode 100644 index 2719df0c39..0000000000 --- a/wpimath/src/generate/Nat.java.in +++ /dev/null @@ -1,27 +0,0 @@ -/*----------------------------------------------------------------------------*/ -/* Copyright (c) 2019 FIRST. All Rights Reserved. */ -/* Open Source Software - may be modified and shared by FRC teams. The code */ -/* must be accompanied by the FIRST BSD license file in the root directory of */ -/* the project. */ -/*----------------------------------------------------------------------------*/ - -package edu.wpi.first.math; - -//CHECKSTYLE.OFF: ImportOrder -{{REPLACEWITHIMPORTS}} -//CHECKSTYLE.ON - -/** - * A natural number expressed as a java class. - * The counterpart to {@link Num} that should be used as a concrete value. - * - * @param The {@link Num} this represents. - */ -@SuppressWarnings({"MethodName", "unused"}) -public interface Nat { - /** - * The number this interface represents. - * - * @return The number backing this value. - */ - int getNum(); diff --git a/wpimath/src/generate/Nat.java.jinja b/wpimath/src/generate/Nat.java.jinja new file mode 100644 index 0000000000..31451d2612 --- /dev/null +++ b/wpimath/src/generate/Nat.java.jinja @@ -0,0 +1,32 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package edu.wpi.first.math; + +//CHECKSTYLE.OFF: ImportOrder +{% for num in nums %} +import edu.wpi.first.math.numbers.N{{ num }}; +{%- endfor %} +//CHECKSTYLE.ON + +/** + * A natural number expressed as a java class. + * The counterpart to {@link Num} that should be used as a concrete value. + * + * @param The {@link Num} this represents. + */ +@SuppressWarnings({"MethodName", "unused"}) +public interface Nat { + /** + * The number this interface represents. + * + * @return The number backing this value. + */ + int getNum(); +{% for num in nums %} + static Nat N{{ num }}() { + return N{{ num }}.instance; + } +{% endfor %} +} diff --git a/wpimath/src/generate/NatGetter.java.in b/wpimath/src/generate/NatGetter.java.in deleted file mode 100644 index d268fab425..0000000000 --- a/wpimath/src/generate/NatGetter.java.in +++ /dev/null @@ -1,3 +0,0 @@ - static Nat N${num}() { - return N${num}.instance; - }