https://github.com/mcandre/lichen Skip to content Toggle navigation Sign in * Product + Actions Automate any workflow + Packages Host and manage packages + Security Find and fix vulnerabilities + Codespaces Instant dev environments + Copilot Write better code with AI + Code review Manage code changes + Issues Plan and track work + Discussions Collaborate outside of code Explore + All features + Documentation + GitHub Skills + Blog * Solutions For + Enterprise + Teams + Startups + Education By Solution + CI/CD & Automation + DevOps + DevSecOps Resources + Learning Pathways + White papers, Ebooks, Webinars + Customer Stories + Partners * Open Source + GitHub Sponsors Fund open source developers + The ReadME Project GitHub community articles Repositories + Topics + Trending + Collections * Pricing Search or jump to... Search code, repositories, users, issues, pull requests... Search [ ] Clear Search syntax tips Provide feedback We read every piece of feedback, and take your input very seriously. [ ] [ ] Include my email address so I can be contacted Cancel Submit feedback Saved searches Use saved searches to filter your results more quickly Name [ ] Query [ ] To see all available qualifiers, see our documentation. Cancel Create saved search Sign in Sign up You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session. Dismiss alert {{ message }} mcandre / lichen Public * Notifications * Fork 0 * Star 4 the sed build system 4 stars 0 forks Activity Star Notifications * Code * Issues 0 * Pull requests 0 * Actions * Projects 0 * Security * Insights Additional navigation options * Code * Issues * Pull requests * Actions * Projects * Security * Insights mcandre/lichen This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository. main Switch branches/tags [ ] Branches Tags Could not load branches Nothing to show {{ refName }} default View all branches Could not load tags Nothing to show {{ refName }} default View all tags Name already in use A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch? Cancel Create 1 branch 0 tags Code * Local * Codespaces * Clone HTTPS GitHub CLI [https://github.com/m] Use Git or checkout with SVN using the web URL. [gh repo clone mcandr] Work fast with our official CLI. Learn more about the CLI. * Open with GitHub Desktop * Download ZIP Sign In Required Please sign in to use Codespaces. Launching GitHub Desktop If nothing happens, download GitHub Desktop and try again. Launching GitHub Desktop If nothing happens, download GitHub Desktop and try again. Launching Xcode If nothing happens, download Xcode and try again. Launching Visual Studio Code Your codespace will open once ready. There was a problem preparing your codespace, please try again. Latest commit @mcandre mcandre document more future research ... eac04a6 Dec 28, 2023 document more future research eac04a6 Git stats * 2 commits Files Permalink Failed to load latest commit information. Type Name Latest commit message Commit time example works December 28, 2023 02:11 README.md document more future research December 28, 2023 02:19 View code [ ] lichen: the sed build system ABOUT EXAMPLE REQUIREMENTS CONFIGURATION Shebang! Don't cross the streams! Validation Creating Simple Tasks Creating Complex Taks Usage Menu Further Research SEE ALSO README.md lichen: the sed build system For sedists, or perhaps sadists. ABOUT While C enjoys make, and Java her Maven, it has come to our attention that sed up to now, has had no build system of its own. Let us correct this oversight. Enter, the sed build system, designed for sed projects, and written itself in GNU sed. EXAMPLE $ cd example $ ./lichen help usage: ... tasks: * help * test * lint test info: pass lint warn: strange permissions: ./bad.sed (Control+D) $ Here, we see our sed build system operating as a REPL. We invite the user to enter task names, one per line. When you're finished, press Control+D to terminate the lichen session. REQUIREMENTS * a UNIX environment with coreutils / base / macOS / WSL / etc. * GNU sed 4.2+ CONFIGURATION Let's open example/lichen for reading. Shebang! At the top, we have a not strictly POSIX compliant, multi-argument shebang: #!/usr/bin/env gsed -nE -f It may break on some fringe UNIX implementations, but it is necessary for the system to work. The -n sed flag in the shebang, hides some REPL input mirroring. Try temporarily removing n in -nE, and you'll quickly experience this noisy behavior. The -E sed flag enables ERE syntax, a more modern and capable regular expression language. The -f flag instructs sed to load the the file as a series of editing commands. Don't cross the streams! Next, we have a warning against output formats matching input patterns. # Warning: Ensure none of the output formats match any of the input patterns. This is because sed will apply all the sed editing commands that eventually match the transformed user input line. If the name of a build task accidentally matches the output text block of a running task, then we may see the computer go crazy! In order to avoid cross-contamination between tasks, we must tune the output format so that no output block will trigger further processing by another sed editing command. The easiest way to do this is to introduce a uniquely spicy prefix for each task's output. For example, our unit tests feature an info: log level prefix, and we will take pains to avoid creating a task called info. Even if we did, the colon delimiter (:) in the output prefix, catches most of these kinds of accidents. By the way, avoid colons in task names. Better yet, limit task names to alphanumerics, ideally lowercase for simplicity and typing speed. Validation We have a beefy validation command: /^(test|lint|help)$/!s/(.+)/error: no such task: \1/p The validation pattern uses a hardcoded group (test|lint|help), permitting any of three tasks test, lint, help through the build system. If the user input line does not match exactly one of these entries, then lichen emits a validation error. In the event that the task names grow, shrink, or rename, then this list must be updated to reflect the change. Creating Simple Tasks In lichen, a task is created by writing a sed editing command. For example, we have a rather droll, NO-OP unit test suite: s/^test$/echo 'info: pass'/ep Naturally, this test suite is bereft of meaning. It states that it passes, without performing any significant checks. But this is merely a placeholder. You will want to replace echo 'info: pass' with some shell commands that test your own sed application. The input pattern ^test$ matches the user REPL line test. When the user invokes the test this way, the e flag in /ep instructs sed to execute the output pattern as a shell command: echo 'info: pass'. The -n sed flag in the shebang aggressively disables too much output. So the p flag in /ep at the end of the editing command, counteracts -n, turning output back on, but only for the REPL lines that match our patterns. Optionally, remove a p to silence command results. After the test task, we have a more intricate lint task: Creating Complex Taks s/^lint$/find . -iname '*.sed' -not -perm 0644 -exec echo 'warn: strange permissions:' '{}' \\;/ep This rudimentary lint task uses the classic UNIX find utility to look for sed script filenames matching *.sed in the currend directory and below. Any sed scripts that both feature a .sed file extension and have chmod file permissions other than 0644 (octal), will generate a linter warning. That's just a good habit to follow in UNIX, reserving file extensions on scripts for libraries, and reserving extensionless, executable chmod bits for applications. The practice applies to shell scripts, sed files, awk, Perl, Python, Ruby, and essentially any interpreted programming language script. The metadata about the script should help to reinforce the intent of the script, in case the author is unavailable. A shebang should also be present in executable application scripts and removed from library scripts for the same reason. We leave implementation of sed shebang linter checks to other systems. Getting back to sed, review the precise syntax for this example lint task. Notice that the \; usually indicated for terminating UNIX find commands, is escaped as \\;. Many sed editing command characters such as forward slash (/), back slash (\), caret (^), and dollar ($), just to name a few of these, will require additional back slashes. Throw in escapes for any quoting, and the commands can get messy in a hurry. When a command gets too hairy to manage directly in a lichen script, then chop it up into short .lichen.d/