Guide to contributing to the
Telodendria is an open source project. As such, it welcomes contributions. There are many ways you can contribute, and any way you can is greatly appreciated. This page contains some of the ways you can help out.
Please reach out to the Matrix rooms mentioned at the top of telodendria(7). All issue tracking takes place in those rooms. Start by reaching out to the general room, and if you think there's a legitimate problem with Telodendria itself, then stick the issue in the issues room, where it can be discussed further. Issues usually remain in the Matrix rooms, but severe enough issues may be put in a TODO file in the cvs(1) repository so that they don't get lost.
The primary language used to write Telodendria code is ANSI C. Other languages you'll find in the Telodendria repository include shell scripts, mdoc(7), and a little bit of HTML and CSS. If you have any experience with any of these languages, your contributions are valuable! Please follow the guidelines on this page to ensure the contribution workflow goes as smoothly as possible.
Getting the Code
If you'd like to hack on Telodendria, you'll need the following tools in addition to a C compiler and POSIX shell:
- For checking out and updating your local copy of the source code.
- For formatting your code before generating patches.
- For applying patches to your local copy of the source code.
All of these tools are built into OpenBSD. While you don't have to use OpenBSD to develop Telodendria, it may make the process a bit easier. In fact, these tools where chosen precisely because they were built into my operating system of choice.
You can download an official release tarball from the website if you would really like, but the preferred way to get the source code for development is to check it out from CVS. This makes generating patches a lot easier.
$ cvs -d email@example.com:/cvs checkout -P Telodendria $ cd Telodendria
If you already checked out the code previously, make sure you update your local copy before you start developing:
$ cvs -q update -dP
You should now have the latest source code. Follow the
CODE STYLE as you make your changes. If
the cvs(1) command fails with a "Connection refused" error
message, try setting the
variable to "ssh", like this:
$ export CVS_RSH=ssh
Then run the checkout command again. Some versions of CVS on some systems don't use SSH to checkout by default, so if yours doesn't, you might want to put the above line into your shell init script.
Telodendria aims at remaining as minimal as possible. This doesn't just mean minimal code, it also means a minimal development process, which is why Telodendria doesn't use GitHub, GitLab, or even SourceHut. Instead, the contribution workflow operates on submitting patch files to a public Matrix room, sort of like the OpenBSD project operates on patch files sent to a public mailing list.
If you're not used to manually creating and submitting patches instead of just opening a "pull request," you should be pleased to hear that submitting patches is fairly easy to do if you've got the CVS sources checked out. In fact, I find it easier than having to make a GitHub account, forking a project's repository, and then making a pull request for it. Once you have made your changes in your local copy of the code, and you've configured your environment properly as noted in the manual for td(8), just run the patch recipe:
$ td patch
This will automatically generate a patch file for all your
changes, and then open it in your preferred editor. You can also generate a
patch file for only certain files and directories. To do that, set
PATCHSET, like this:
# Only write a patch for README.txt and the files in docs/ $ PATCHSET="README.txt docs/" td patch
As you'll notice, the top of the patch file should have some email-style headers that look like this:
From: Jordan Bancino <@jordan:bancino.net> Date: Fri Jul 29 03:21:21 PM EDT 2022 Subject: Document Patch Procedure
As much information should be filled out for you, such as the date. An attempt to fill out the From header was also made by td(8), but the information there can be modifed as necessary. Consult the manual for td(8) for more details. The Subject should very briefly describe what the patch is about.
You'll also notice these lines in the patch:
[ ] I have read the Telodendria Project development certificate of origin, and certify that I have permission to submit this patch under the conditions specified in it.
This is a checkbox that tells me whether or not you actually have the rights to submit your patch, and that once you submit your patch, your code is bound by the Telodendria project license, which you can and should view in telodendria(7). The full text of the developer certificate of origin is as follows:
- The contribution was created in whole or in part by me, and I have the right to submit it under the open source licenses of the Telodendria project; or
- The contribution is based upon a previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the Telodendria project license; or
- The contribution whas provided directly to me by some other person who certified (1), (2), or (3), and I have not modifed it.
- I understand and agree that this project and the contribution are made public and that a record of the contribution—including all personal information I submit with it—is maintained indefinitely and may be redistributed consistent with this project or the open source licenses involved.
If you agree to the above, fill in the square brackets with an 'x', and then after the headers, but before the checkbox, write a more thorough description of the patch and why it was created. Then, send the resulting patch file to the public Matrix room using send-patch(1).
Try to keep your patches on topic—make one patch file per feature or bug fix being implemented. It is okay if your patches depend on previous patches, just indicate that in the patch description. Note that it may take a while for patches to be committed, and some patches may not be comitted at all. In either case, all sent patches are queued from the Matrix room into the public patch directory, so they can be referenced easier in the future. If you want to reference a submitted patch in a Matrix message, email, or other digital medium, it might be a good idea to link to it in the public patch directory.
The public patch directory works as follows: when you send your patch to the Matrix room, it is downloaded by Telodendria Bot and placed in the ingress/ directory, named as the message ID. Then, it is assigned a patch ID and copied to the p/ directory as just "%d.patch", where "%d" is obviously the patch ID. This is a permanent link that will always reference your patch. Then, your patch will be symlinked into the queue/ directory. I have a script that automatically ingresses patches and queues them for me, and I use this to review patches. If your patch is accepted, the queue symlink will be moved to accepted/ and the submitted patch will be committed to the official CVS repository. If your patch is rejected for some reason, its symlink will be moved to the rejected/ directory. Regardless of the state of your patch, it will always remain permalinked in the p/ directory, and when it is accepted or rejected, Telodendria Bot will send a message to the Matrix room.
You're always welcome to inquire about rejected patches, and request that they be reviewed again, or you can use them as a starting point for future patches.
The public patch directory is located at https://telodendria.io/patches/
In general, these are the conventions used by the code base. This guide may be slightly outdated or subject to change, but it should be a good start. The source code itself is always the absolute source of truth, so as long as you make your code look like the code surrounding it, you should be fine.
- All function, enumeration, structure, and header names are CamelCase. This is preferred to snake_case because it is more compact.
- All variable names are lowerCamelCase. This is preferred to snake_case because it is more compact.
- enumerations and structures are always typedef-ed to their same name. The typedef should occur in the public API header, and the actual declaration should live in the implementation file.
- A feature of the code base lives in a single C source file that has a matching header. The header file should only export public symbols; everything else in the C source should be static.
- Except where absolutely necessary, global variables are forbidden to prevent problems with threads and whatnot. Every variable a function needs should be passed to it either through a structure, or as a separate argument.
- Anywhere curly braces are optional, there still must be curly braces. This makes it easier to add on to the code later, and just makes things a bit less ambiguous.
As far as actually formatting the code goes, such as where to put brackets, and whether or not to use tabs or spaces, use indent(1) to take care of all of that. The root of the CVS repository has a .indent.pro that should automatically be loaded by indent(1) to set the correct rules. If you don't have a working indent(1), then just indicate in your patch that I should run my indent(1) on the code after applying it. Although in reality, I'll likely run my own indent(1) on the code anyway, just to make sure the spacing is consistent, if nothing else.
This project places a strong emphasis on documentation. Well-documented code is fundamental to a successful project, so when you are writing code, please also make sure it is documented appropriately.
- If you are adding a header, make sure you add a man page that documents all the functions in the header.
- If you're adding a function, make sure you add documentation for it to the appropriate man page for the header that your function resides in. Do note that you do not have to document static functions, only public API functions.
If your patch does not also include proper documentation, it will likely be rejected.