From d6c7135b0a16497b574bf7185e0a089b70a03e18 Mon Sep 17 00:00:00 2001 From: Henry Huang <69825683+hhenry01@users.noreply.github.com> Date: Wed, 22 Nov 2023 15:05:01 -0800 Subject: [PATCH] Plantuml Infrastructure (#212) * Add dependencies * Complete template and examples * Update template.puml * Update README for Plantuml Rendering * Move to /diagrams/ * Move diagrams to diagrams/src * Update gitignore * Add export settings * Update export documentation --------- Co-authored-by: Patrick Creighton --- .devcontainer/Dockerfile | 2 +- .devcontainer/base-dev/base-dev.Dockerfile | 16 ++++ .devcontainer/devcontainer.json | 1 + .gitignore | 20 ++-- diagrams/README.md | 65 +++++++++++++ diagrams/src/sequence_diagram_ex.puml | 37 ++++++++ diagrams/src/state_diagram_ex.puml | 104 +++++++++++++++++++++ diagrams/template.puml | 67 +++++++++++++ sailbot.code-workspace | 6 ++ 9 files changed, 308 insertions(+), 10 deletions(-) create mode 100644 diagrams/README.md create mode 100644 diagrams/src/sequence_diagram_ex.puml create mode 100644 diagrams/src/state_diagram_ex.puml create mode 100644 diagrams/template.puml diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 68246aba6..914531544 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM ghcr.io/ubcsailbot/sailbot_workspace/dev:jupyter +FROM ghcr.io/ubcsailbot/sailbot_workspace/dev:plantuml2 # Copy configuration files (e.g., .vimrc) from config/ to the container's home directory ARG USERNAME=ros diff --git a/.devcontainer/base-dev/base-dev.Dockerfile b/.devcontainer/base-dev/base-dev.Dockerfile index 79d182bb6..5bc1b10c5 100644 --- a/.devcontainer/base-dev/base-dev.Dockerfile +++ b/.devcontainer/base-dev/base-dev.Dockerfile @@ -157,6 +157,22 @@ RUN chmod +x /sbin/update-bashrc \ && /bin/bash -c /sbin/update-bashrc \ && rm /sbin/update-bashrc +# plantuml diagram support +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + default-jre graphviz \ + && wget https://github.com/plantuml/plantuml/releases/download/v1.2023.12/plantuml-asl-1.2023.12.jar \ + && mv plantuml-asl-1.2023.12.jar /usr/local/bin/plantuml-asl-1.2023.12.jar \ + && echo "#!/bin/bash\njava -jar /usr/local/bin/plantuml-asl-1.2023.12.jar \$*" > /usr/local/bin/plantuml.sh \ + && chmod +x /usr/local/bin/plantuml.sh \ + && apt-get autoremove -y \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/{apt,dpkg,cache,log} /tmp/* /var/tmp/* +ENV DEBIAN_FRONTEND= + +ENV PLANTUML_TEMPLATE_PATH="/workspaces/sailbot_workspace/diagrams/template.puml" + # install some clang tools and googletest for network systems ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update \ diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 56b696c10..ba1b160da 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -70,6 +70,7 @@ "github.copilot", "github.vscode-github-actions", "Gruntfuggly.todo-tree", + "jebbs.plantuml", "jeff-hykin.better-cpp-syntax", "KevinRose.vsc-python-indent", "llvm-vs-code-extensions.vscode-clangd", diff --git a/.gitignore b/.gitignore index 5c59ad0e8..70e79bd47 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,19 @@ # ros -build/ -install/ -log/ +/build/ +/install/ +/log/ # vcstool packages -src/* -!src/global_launch -!src/polaris.repos +/src/* +!/src/global_launch +!/src/polaris.repos # configuration files -.devcontainer/config/* -!.devcontainer/config/README.md +/.devcontainer/config/* +!/.devcontainer/config/README.md # clangd .cache/ -compile_commands.json # microsoft c/c++ intellisense (disabled in favor of clangd) /.vscode/c_cpp_properties.json @@ -23,3 +22,6 @@ compile_commands.json __pycache__/ .mypy_cache/ .pytest_cache/ + +# exported plantuml diagrams +/diagrams/out/ diff --git a/diagrams/README.md b/diagrams/README.md new file mode 100644 index 000000000..4a2917697 --- /dev/null +++ b/diagrams/README.md @@ -0,0 +1,65 @@ +# PlantUML + +## Overview + +The simplest way to describe PlantUML is "diagrams written with code". The main benefit of using PlantUML instead of +making diagrams in GUI-based software like draw.io or Visio is the ability to version control diagrams. Since they are +rendered based on plain text descriptions, Git can easily track edit histories. Another benefit is the easy propagation +of an organization specific diagram style. By including [template.puml](template.puml) in other puml files, we can have +a consistent style across sailbot_workspace. Simply add `!include %getenv("PLANTUML_TEMPLATE_PATH")` to your file. + +## How To + +### Render In VSCode (Simplest Way to View) + +When you have a `.puml` file open in VSCode, there will be an icon in the top right of the tab with a magnifying glass. +Simply click it and the diagram will render to the side. Usually, it automatically updates whenever you make a change to +the `.puml` file. Occasionally, you'll need to run `PlantUML: Preview Current Diagram` in the VSCode command palette +(`ctrl+shift+p`) to manually update the rendered diagram. + +### Export As Image + +Exporting as an image is required for viewing PlantUML diagrams on services like Google Drive and Confluence. + +If simply copying an image suffices, then [render in VSCode](#render-in-vscode-simplest-way-to-view), hover over the +rendered diagram and click the copy icon to the left of the help button. You can also export it as a PNG +by opening the VSCode command palette (`ctrl+shift+p`) and running one of the +`PlantUML: Export <...>` commands. The exported diagram(s) can be found under `diagrams/out/`. + +### Create a Diagram + +PlantUML supports various diagram types. This section goes over a few types in use by the Sailbot Software Team and +describes their use cases. For a full list, see the [PlantUML website](https://plantuml.com/). Examples of the diagrams +described below can be found under [src/](src/). + +#### [Sequence Diagram](https://plantuml.com/sequence-diagram) + +Use when describing the control sequence/flow of a module or algorithm. Its usecase is similar to flow diagrams +[PlantUML calls these activity diagrams](https://plantuml.com/activity-diagram-beta), but has some key advantages: + +- Clearly organize different modules and reduces. Each module and resource can have their own category in a diagram, and +can be grouped with related modules and resources. +- Explicitly show resource usage. When a flow accesses a resource persistent across sequences, accesses can be shown +and described as part of the flow. For example, showing reads, write/appends, allocations, and clears. +- Represent simultaneous control flows. When exploiting parallelism and asynchronous operations, multiple modules can +be shown as active and described in a diagram at once. + +The primary limitation of sequences diagrams is non-trivial branching (ex. if/else flows). Sequence diagrams are +clearest when the control flow has one possible path. To handle non-trivial branching, consider: + +- Splitting branches into their own sequences/subsequences. Dedicate a sequence/subsequence to when a branch is true and +another where the branch is false. +- Using a [flow/activity diagram](https://plantuml.com/activity-diagram-beta). + +#### [State Diagram](https://plantuml.com/state-diagram) + +Primarily used for state machines, but can also be used to show how nodes in a system are connected (ex. ROS topics, +publishers, subscribers). + +## Resources + +- The [PlantUML website](https://plantuml.com/) is an excellent resource for how to create diagrams. Each tutorial page +is relatively short and goes over every diagram specific feature and some basic styling. +- For more advanced styling, comprehensive documentation can be found +[here](https://plantuml-documentation.readthedocs.io/en/latest/formatting/all-skin-params.html). +- The [src/](src/) folder contains some basic diagram examples that utilize the template. diff --git a/diagrams/src/sequence_diagram_ex.puml b/diagrams/src/sequence_diagram_ex.puml new file mode 100644 index 000000000..1b9fda52d --- /dev/null +++ b/diagrams/src/sequence_diagram_ex.puml @@ -0,0 +1,37 @@ +@startuml sequence_diagram_ex +title Common Sequence + +!include %getenv("PLANTUML_TEMPLATE_PATH") + +autonumber + +!startsub PARTICIPANTS +box "Common Sequence" +participant CanTransceiver as can +participant CanTransceiverRosIntf as ros_intf +end box +== Inbound == +!endsub PARTICIPANTS + +-> can : Inbound Sensor(s) [CAN] + +!startsub SEQUENCE + +activate can +can -> can : Convert from CAN to ROS +can -> can : Filter Sensor(s) +can -> ros_intf --++ : Transmit Sensor(s) [ROS] +ros_intf -> : Publish sensor(s) to Software ROS Network +deactivate ros_intf + +== Outbound == + +ros_intf <- ++ : Command(s) from Software ROS Network (ex. Desired Heading) +can <- ros_intf --++ : Transmit Command(s) [ROS] +can -> can : Convert Command(s) from ROS to CAN +!endsub SEQUENCE + +<- can : Outbound Command(s) [CAN] +deactivate can + +@enduml diff --git a/diagrams/src/state_diagram_ex.puml b/diagrams/src/state_diagram_ex.puml new file mode 100644 index 000000000..c7570863a --- /dev/null +++ b/diagrams/src/state_diagram_ex.puml @@ -0,0 +1,104 @@ +@startuml state_diagram_ex +title Digital Watch + +!include %getenv("PLANTUML_TEMPLATE_PATH") + +State Regular + +State StopWatch { + state PauseStopWatch + state StartStopWatch +} +note top of StopWatch + B1: Unused + B2: Continue + B3: Pause +endnote + +State Timer { + State RunTimer { + State PauseTimer + State StartTimer + } + note left of RunTimer + B1: Adjust + B2: Continue + B3: Pause + end note + State SetTimer { + State SetSecondTimer + State SetMinuteTimer + State SetHourTimer + } + note bottom of SetTimer + B1: Adjust + B2: Increment + B3: Decrement + + Increment and Decrement + in each Set{X}Timer + substate increments or + decrements each counter + register X. + end note +} + +State SetTime { + State SetSecond + State SetMinute + State SetHour + State SetDay + State SetWeekday + State SetMonth + State SetTimeType : Cycle through enums\n24H, AM, PM +} +note top of SetTime + B1: Adjust + B2: Increment + B3: Decrement + + Increment and Decrement + in each Set{X} + substate increments or + decrements each counter + register X. +end note + +[*]-->Regular +note on link + Four Button Digital Watch + B0: Mode Select + B1: Unused / Adjust (depends on mode) + B2: Continue / Increment (depends on mode) + B3: Pause / Decrement (depends on mode) +end note +Regular-up->Regular : Increment all time tracking registers + +Regular-down->PauseStopWatch : Mode Select +PauseStopWatch-up->StartStopWatch : Continue +StartStopWatch->StartStopWatch : Increment seconds, minutes, hours +StartStopWatch-down->PauseStopWatch : Pause +PauseStopWatch->PauseStopWatch : Pause / reset seconds, minutes, hours to 0 + +StopWatch-down->RunTimer : Mode Select +PauseTimer-up->StartTimer : Continue +PauseTimer-->PauseTimer : Pause / reset seconds, minutes, hours to 0 +StartTimer-down->PauseTimer : Pause +StartTimer->StartTimer : Decrement seconds, minutes, hours +PauseTimer-down->SetSecondTimer : Adjust Timer +SetSecondTimer-right->SetMinuteTimer : Adjust Timer +SetMinuteTimer-up->SetHourTimer : Adjust Timer +SetHourTimer-left->SetSecondTimer : Adjust Timer +SetTimer-up->PauseTimer : Mode Select + +RunTimer-right->SetTimeType : Mode Select +SetTimeType-left->SetSecond : Adjust Time +SetSecond-up->SetMinute : Adjust Time +SetMinute-up->SetHour : Adjust Time +SetHour-up->SetWeekday : Adjust Time +SetWeekday-right->SetDay : Adjust Time +SetDay-down->SetMonth : Adjust Time +SetMonth-down->SetTimeType : Adjust Time +SetTime-up->Regular : Mode Select + +@enduml diff --git a/diagrams/template.puml b/diagrams/template.puml new file mode 100644 index 000000000..6837788f2 --- /dev/null +++ b/diagrams/template.puml @@ -0,0 +1,67 @@ +@startuml template +' Colors picked to (try to) match docs site +' See sailbot_workspace/src/docs/docs/stylesheets/extra.css +!$SAILBOT_LIGHT_BLUE = "#73a3c7" +!$SAILBOT_BLUE = "#1665a2" +!$SAILBOT_DARK_BLUE = "#0d3d61" +!$MAX_MESSAGE_SIZE = 150 +!$PADDING = 20 + +' autonumber ' autonumber breaks state diagrams so don't put in template +hide empty description + +!procedure $set_sequence_participant_skinparams($participant) + !$BackgroundColor = $participant + "BackgroundColor" + !$BorderColor = $participant + "BorderColor" + !$FontColor = $participant + "FontColor" + !$Padding = $participant + "Padding" + + $BackgroundColor $SAILBOT_DARK_BLUE + $BorderColor White + $FontColor White + $Padding $PADDING +!endprocedure + +skinparam { + BoxPadding 10 + MaxMessageSize $MAX_MESSAGE_SIZE + Note { + BackgroundColor $SAILBOT_BLUE + BorderColor Grey + FontColor White + Shadowing true + } + Sequence { + BoxBackgroundColor $SAILBOT_LIGHT_BLUE + Group { + BackgroundColor White + BodyBackgroundColor PowderBlue + FontColor OrangeRed + } + LifeLine { + BackgroundColor $SAILBOT_DARK_BLUE + BorderColor White + } + MessageAlign center + } + State { + BackgroundColor $SAILBOT_DARK_BLUE + FontColor White + } + Title { + BackgroundColor LightSteelBlue + BorderColor $SAILBOT_DARK_BLUE + FontSize 28 + } + + $set_sequence_participant_skinparams("Actor") + $set_sequence_participant_skinparams("Boundary") + $set_sequence_participant_skinparams("Collections") + $set_sequence_participant_skinparams("Control") + $set_sequence_participant_skinparams("Database") + $set_sequence_participant_skinparams("Entity") + $set_sequence_participant_skinparams("Participant") + $set_sequence_participant_skinparams("Queue") +} + +@enduml diff --git a/sailbot.code-workspace b/sailbot.code-workspace index 6a9ea5ef9..3ab5db662 100644 --- a/sailbot.code-workspace +++ b/sailbot.code-workspace @@ -255,6 +255,12 @@ "tag:yaml.org,2002:python/name:materialx.emoji.to_svg", "tag:yaml.org,2002:python/name:pymdownx.superfences.fence_code_format" ], + + // PlantUML diagrams extension + "plantuml.exportFormat": "png", + "plantuml.exportIncludeFolderHeirarchy": false, + "plantuml.exportOutDir": "diagrams/out", + "plantuml.exportSubFolder": false, }, "launch": { // Use IntelliSense to learn about possible attributes.