├── .gitattributes ├── .github ├── alfons-banner.png ├── alfons-logo-64x.png ├── alfons-logo.svg ├── dependency-graph ├── dependency-graph.png └── workflows │ └── main.yml ├── .gitignore ├── Alfons.moon ├── Alfons.yue ├── LICENSE ├── README.md ├── alfons.lua ├── alfons ├── env.moon ├── file.moon ├── getopt.moon ├── help.moon ├── init.moon ├── look.moon ├── parser.moon ├── provide.moon ├── setfenv.moon ├── tasks │ ├── fetch.lua │ ├── fetch.moon │ ├── teal.lua │ └── teal.moon ├── version.moon └── wildcard.moon ├── bin ├── alfons.moon ├── completion.bash ├── completion.fish └── completion.zsh ├── docs ├── README.md ├── api.md ├── arguments.md ├── autocompletion.md ├── branding.md ├── build.md ├── documenting.md ├── environment.md ├── loading.md ├── provide.md ├── recipes.md ├── teal.md ├── tutorial.md └── watch.md ├── rock-dev.yml ├── rock.yml ├── rockspecs ├── alfons-4.0-1.rockspec ├── alfons-4.0.1-1.rockspec ├── alfons-4.0.2-1.rockspec ├── alfons-4.1-1.rockspec ├── alfons-4.1.1-1.rockspec ├── alfons-4.1.3-1.rockspec ├── alfons-4.1.4-1.rockspec ├── alfons-4.2-1.rockspec ├── alfons-4.2.1-1.rockspec ├── alfons-4.2.2-1.rockspec ├── alfons-4.3-1.rockspec ├── alfons-4.4-1.rockspec ├── alfons-4.4.1-1.rockspec ├── alfons-5.0.0-1.rockspec ├── alfons-5.0.1-1.rockspec ├── alfons-5.0.2-1.rockspec ├── alfons-5.1-1.rockspec ├── alfons-5.2-1.rockspec ├── alfons-5.2.1-1.rockspec ├── alfons-5.2.2-1.rockspec ├── alfons-5.3-1.rockspec ├── alfons-5.3.1-1.rockspec ├── alfons-dev-5.0.2-1.rockspec ├── alfons-dev-5.1-1.rockspec ├── alfons-dev-5.2-1.rockspec └── alfons-dev-5.2.1-1.rockspec └── test ├── alfons ├── dusubalf.moon ├── graph-proof │ ├── a.moon │ ├── b.moon │ ├── c.moon │ ├── d.moon │ ├── e.moon │ ├── f.moon │ └── main.moon ├── lua.lua ├── main.moon ├── predet.moon ├── predet2.moon ├── sidea.moon ├── sideb.moon ├── storea.moon ├── storeb.moon ├── subalf.moon ├── teal-table.tl └── teal.tl ├── graph-proof.moon ├── lua.moon ├── predet.moon ├── runString.moon ├── store.moon └── teal.moon /.gitattributes: -------------------------------------------------------------------------------- 1 | alfons.lua linguist-generated 2 | test/alfons/lua.lua -linguist-detectable -------------------------------------------------------------------------------- /.github/alfons-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daelvn/alfons/18d688f0755445134e41829a70e3296b39fed82c/.github/alfons-banner.png -------------------------------------------------------------------------------- /.github/alfons-logo-64x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daelvn/alfons/18d688f0755445134e41829a70e3296b39fed82c/.github/alfons-logo-64x.png -------------------------------------------------------------------------------- /.github/alfons-logo.svg: -------------------------------------------------------------------------------- 1 | alfons-logo -------------------------------------------------------------------------------- /.github/dependency-graph: -------------------------------------------------------------------------------- 1 | 5Zhbb5swFMc/DdL2sCrYQNLXptlFWrVJeVj76MIJeDWYOaYh+/Qz5RAuVm9LIlL1JfL54+PL//xMLBw6T8sviuXJlYxAOGQSlQ69dAiZudT8VsK2FrzArYVY8aiWOsKS/wUUJ6gWPIJ1r6OWUmie98VQZhmEuqcxpeSm320lRX/WnMVgCcuQCVv9xSOd4LbItNW/Ao+TZmY3OK+fpKzpjDtZJyySm45EFw6dKyl13UrLOYjKu8aXOu/zI093C1OQ6ZckzKa+t7xmf+5W6Tc/F/yKFsEnHOWeiQI3/CFlPPuIS9bbxgez+rxq5kqGsDamXmwSrmGZs7CSN6b4Rkt0KkzkmuYtC+9iJYss+lFowTNAHScEpaF8dCfuzh/DFcgUtNqaLphAG0uRKbeJN50KoZR0iuOhxpCJeDdya5tpoHOvcHFm2QWRoQhDqXQiY5kxsWjViwdroBp1YqK2z3cpc7TqN2i9xSPBCi37BkPJ9XWVfuZjdIODVe3LshtsmyAz2+0kVeFNM14VtGkPUZNX76/a1NMlMx7IQoXwhFcEDzFTMejnyLQRUCCY5vf9dRy8oMQ6Fswqcb+Az5yGA1BPJn3qd/FY1J+/FeoPSC/dk0pM/Sm5mbl9oQWTM9cjM3+Kv/3XWzCoYH12cIxBEXeL+v+6Ugv+29HhH77yR4e/uZ+8K/q9Y9E/Ku+exXs4Ou+ed2q803fIu38U3smwtsOiHZl33+I9Gp13d+jJbGzeyVvh/QTu9IHzsjs92fM87VXRwMIeRseeBKeGvWt5cqLYHxDf6Qvx3ff6s1dlpha+q9HxtW4px8PXhO2nsvqfsP3eSBf/AA== -------------------------------------------------------------------------------- /.github/dependency-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daelvn/alfons/18d688f0755445134e41829a70e3296b39fed82c/.github/dependency-graph.png -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: CI 4 | 5 | # Controls when the action will run. Triggers the workflow on push or pull request 6 | # events but only for the master branch 7 | on: 8 | push: 9 | branches: [master] 10 | pull_request: 11 | branches: [master] 12 | 13 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 14 | jobs: 15 | # This workflow contains a single job called "build" 16 | build: 17 | # The type of runner that the job will run on 18 | runs-on: ubuntu-latest 19 | 20 | # Steps represent a sequence of tasks that will be executed as part of the job 21 | steps: 22 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 23 | - uses: actions/checkout@v2 24 | 25 | # Install glibc and yaml 26 | - name: Install libyaml 27 | run: | 28 | sudo apt install libyaml-dev 29 | 30 | # Lua 31 | - name: Install Lua/LuaJIT 32 | uses: leafo/gh-actions-lua@v8.0.0 33 | with: 34 | luaVersion: 5.1 35 | 36 | - name: Install LuaRocks 37 | uses: leafo/gh-actions-luarocks@v4 38 | with: 39 | # The version of LuaRocks to install, must be available on https://luarocks.github.io/luarocks/releases/ 40 | luaRocksVersion: 3.5.0 41 | 42 | # Runs a single command using the runners shell 43 | - name: Install dependencies 44 | run: | 45 | luarocks install moonscript 46 | luarocks install filekit 47 | luarocks install lpath 48 | luarocks install ansikit 49 | luarocks install http 50 | luarocks install rockbuild 51 | luarocks install amalg 52 | 53 | # Compile MoonScript 54 | - name: Compile 55 | run: | 56 | moonc alfons/ 57 | moonc bin/ 58 | 59 | # Pack into single script 60 | - name: Pack 61 | run: | 62 | amalg.lua -o alfons.lua -s bin/alfons.lua alfons.setfenv alfons.env alfons.file alfons.getopt alfons.provide alfons.version alfons.init alfons.look 63 | 64 | # Runs a set of commands using the runners shell 65 | - name: rockbuild -m 66 | run: | 67 | rockbuild -m "$GITHUB_SHA" 68 | 69 | # Upload artifacts 70 | - uses: actions/upload-artifact@v2 71 | with: 72 | name: alfons 73 | path: alfons.lua 74 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode -------------------------------------------------------------------------------- /Alfons.moon: -------------------------------------------------------------------------------- 1 | tasks: 2 | --- @task make Install a local version of a version 3 | --- @option make [v] Current version 4 | make: => sh "rockbuild -m --delete #{@v}" if @v 5 | --- @task release Create and upload a release of Alfons using %{magenta}`rockbuild`%{reset}. 6 | --- @option release [v] Current version 7 | release: => sh "rockbuild -m -t #{@v} u" if @v 8 | --- @task compile Compile all MoonScript files 9 | compile: => 10 | sh "moonc #{file}" for file in wildcard "alfons/**.moon" 11 | sh "moonc bin/alfons.moon" 12 | --- @task clean Clean all built files 13 | clean: => 14 | show "Cleaning files" 15 | for file in wildcard "**.lua" 16 | continue if (file\match "alfons.lua") and not (file\match "bin") 17 | continue if (file\match "tasks") 18 | delete file 19 | --- @task pack Pack an Alfons build using amalg.lua 20 | --- @option pack [output o] Output file (Default: %{green}"alfons.lua"%{reset}) 21 | --- @option pack [entry s] Entry file (Default: %{green}"bin/alfons.lua"%{reset}) 22 | pack: => 23 | show "Packing using amalg.lua" 24 | @o or= @output or "alfons.lua" 25 | @s or= @entry or "bin/alfons.lua" 26 | modules = for file in wildcard "./alfons/*.moon" do "alfons.#{filename file}" 27 | tasks = for file in wildcard "./alfons/tasks/*.moon" do "alfons.tasks.#{filename file}" 28 | show "amalg.lua -o #{@o} -s #{@s} #{table.concat modules, ' '} #{table.concat tasks, ' '}" 29 | sh "amalg.lua -o #{@o} -s #{@s} #{table.concat modules, ' '} #{table.concat tasks, ' '}" 30 | --- @task produce Generate %{green}`alfons.lua`%{reset} 31 | produce: => 32 | tasks.compile! 33 | tasks.pack! 34 | tasks.clean! 35 | --- @task test Run an Alfons test 36 | --- @option test [n] Name of the test to run 37 | test: => sh "moon test/#{@n or ''}.moon" 38 | -- dummy tasks 39 | hello: => print "hello!" 40 | shello: => sh "echo 'hello!'" 41 | args: => 42 | inspect = require "inspect" 43 | print inspect args 44 | print inspect @ 45 | print inspect store 46 | print inspect calls! 47 | reargs: => tasks.args! 48 | wild: => 49 | for file in wildcard "./**.moon" 50 | print file 51 | where: => 52 | inspect = require 'inspect' 53 | print inspect debug.getinfo 1 54 | cmdread: => 55 | show cmdread "echo 'hi'" 56 | reduce: => 57 | t = {1, 2, 3} 58 | reduced = reduce t, ((acc, e) -> 59 | print 'accv', acc.v 60 | print 'e', e 61 | return {v: acc.v + e} 62 | ), { v: 0 } 63 | show reduced.v 64 | -------------------------------------------------------------------------------- /Alfons.yue: -------------------------------------------------------------------------------- 1 | tasks: 2 | test: => "Hello from Yuescript!" |> show 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Alfons 5 2 | 3 | 4 | ![GitHub stars](https://img.shields.io/github/stars/daelvn/alfons?style=flat-square) 5 | ![GitHub tag (latest SemVer pre-release)](https://img.shields.io/github/v/tag/daelvn/alfons?include_prereleases&label=release&style=flat-square) 6 | ![LuaRocks](https://img.shields.io/luarocks/v/daelvn/alfons?style=flat-square) 7 | 8 | 9 | 10 | 11 | > Alfons 5 is a rewrite of the original Alfons, written to be much more modular and usable. For the old Alfons 3, see the [`three`](https://github.com/daelvn/alfons/tree/three) GitHub branch. 12 | 13 | Alfons is a task runner to help you manage your project. It's inspired by the worst use cases of Make (this means using `make` instead of shell scripts), it will read an Alfonsfile, extract the exported functions and run the tasks in order. I would tell you that there is no real reason to use this thing, but it's becoming surprisingly useful, so actually try it out. 14 | 15 | > [!TIP] 16 | > Check out the 5.2 update! 17 | > Shell autocompletions, help messages, Taskfile documentations and extra environment functions have been added. 18 | 19 | ## Table of contents 20 | 21 | - [Alfons 5](#alfons-5) 22 | - [Table of contents](#table-of-contents) 23 | - [Changelog](#changelog) 24 | - [5.3](#53) 25 | - [5.2](#52) 26 | - [5](#5) 27 | - [4.4](#44) 28 | - [4.3](#43) 29 | - [4.2](#42) 30 | - [4.1](#41) 31 | - [Usage](#usage) 32 | - [Defining tasks](#defining-tasks) 33 | - [Calling tasks](#calling-tasks) 34 | - [Arguments](#arguments) 35 | - [Migrating from Alfons 3](#migrating-from-alfons-3) 36 | - [Missing functions](#missing-functions) 37 | - [Importable tasks](#importable-tasks) 38 | - [Installing](#installing) 39 | - [Extra features](#extra-features) 40 | - [Projects using Alfons](#projects-using-alfons) 41 | - [License](#license) 42 | - [Goodbye?](#goodbye) 43 | 44 | ## Changelog 45 | 46 | ### 5.3 47 | 48 | - **5.3.1** (02.09.2024) Fixed argument parser bug. `alfons --a --b` is now `a = true; b = true` instead of `a = "--b"`. 49 | - **5.3** (09.08.2024) Added [Yuescript](https://yuescript.org) support. Added a few functions. 50 | 51 | - **Yuescript support.** You can now use `Alfons.yue` files (or any taskfile that ends in `.yue`) to load in Yuescript tasks. 52 | - **Additions to the environment.** 53 | - `values`: Get the values of a table as an array 54 | - `entries`: Turns a table into an array of key-value tuples 55 | - `fromEntries`: Reverses the process of `entries` 56 | 57 | ### 5.2 58 | 59 | - **5.2.2** (09.08.2024) Fixed the `reduce` implementation 60 | - **5.2** (08.06.2024) Implemented Taskfile documentation, help messages and autocompletion 61 | 62 | - **Taskfile documentation.** You can now document your Taskfiles for automatic help messages and shell completion. 63 | - Check [the documentation](docs/documenting.md) for more info. 64 | - **Help messages.** You can now display a help message with `--help`, or even get help for a specific task with `--help [task]`. 65 | - This help message can be automatically generated from the detected tasks in the Taskfile. 66 | - It works best when you document your Taskfile, so you can add descriptions and options. 67 | - **Shell autocompletion.** Shell autocompletion is now available in Zsh, Bash and Fish flavors. 68 | - The Zsh and Fish flavors are by far the most complete, since Zsh's and Fish's completion systems are slightly more capable. 69 | - Bash is only able to list tasks, and sometimes options or flags for those tasks. Use Zsh. 70 | - Check [the documentation](docs/autocompletion.md) for more info and install instructions. 71 | - **Additions to the environment.** 72 | - `lines`: Split a string into lines 73 | - `split`: Split any string by any pattern 74 | - `sanitize`: Neutralizes pattern magic characters in strings 75 | - `keys`: Get the keys of a table as an array 76 | - `slice`: Creates a slice of an array 77 | - `map`, `reduce`, `filter` do to arrays what you would expect 78 | - `contains` has been rewritten 79 | 80 | ### 5 81 | 82 | - **5.0.2** (23.01.2023) Rolled back test mode 83 | - **5.0.1** (23.01.2023) Fixed rockspec dependencies 84 | - **5.0** (23.01.2023) Switched out [filekit](https://github.com/daelvn/filekit) in favor of [lpath](https://github.com/starwing/lpath). 85 | 86 | I am back to life and filekit errored on me. Filekit is terribly inefficient anyway and I don't know why I ever made it. Now I am using an actually good filesystem library. It's a breaking change, though. 87 | 88 | - **Compatibility with ComputerCraft has been removed.** Alfons 5 is not compatible with it. 89 | - **Replaced filekit with lpath** 90 | - `fs` in the environment no longer points to `filekit`, but to `path.fs` 91 | - `path`, `fsinfo` and `env` have been added to the environment, corresponding to `path`, `path.info` and `path.env` respectively. 92 | - Additions to the environment 93 | - `safeOpen`: Open IO handles safely 94 | - `listAll`: Returns a list of all files and directories recursively. 95 | - `copy`: Recursive file copy 96 | - `delete`: Recursive delete 97 | - `isEmpty`: Checks if a directory is empty 98 | - Changes to the environment 99 | - All FS operations don't deal in absolute paths anymore 100 | - `wildcard` and `iwildcard` may exhibit slightly different behavior. 101 | 102 | ### 4.4 103 | 104 | - **4.4** (04.02.2021) Added [`exists`](docs/environment.md) and **Experimental Teal Support**. 105 | 106 | Some critical bugs in the loading of taskfiles and the invocation of tasks have been fixed. 107 | 108 | ### 4.3 109 | 110 | - **4.3** (26.01.2021) Added [`calls`](docs/arguments.md#calls) and [`npairs`](docs/provide.md#npairs). 111 | 112 | ### 4.2 113 | 114 | - **4.2** (02.10.2020) Internal overhaul. 115 | 116 | Alfons 4.2 changes the whole way that Alfons works on the inside. Please refer to [Loading](docs/loading.md) and [API](docs/api.md) for the most notable work. 117 | 118 | ### 4.1 119 | 120 | - **4.1.4** (12.09.2020) - Bugfix on `default` task. 121 | - **4.1.3** (11.09.2020) - Funny Homestuck Number update. Fix `inotify` dependency. 122 | - **4.1.2** (29.08.2020) - More bugfixes 123 | - **4.1.1** (27.08.2020) - Bugfixes 124 | - **4.1** (27.08.2020) - Added [`uses`](docs/arguments.md) 125 | 126 | ## Usage 127 | 128 | Run `alfons` in a directory with an `Alfons.lua` or `Alfons.moon` file. Using MoonScript (obviously) requires installing MoonScript via LuaRocks. 129 | 130 | To see the documentation, check out the [`docs/`](docs/) folder of this repo. 131 | 132 | To get started using Alfons, check out the [Tutorial](docs/tutorial.md) or the [Recipes](docs/recipes.md). 133 | 134 | ### Defining tasks 135 | 136 | Tasks are obtained by either returning a table `{tasks={}}` where the empty table is a list of named functions, or by exporting globals. The preferred mode for Lua is exporting globals, and the preferred mode for MoonScript is returning a table, although both work in both languages. 137 | 138 | **Lua:** 139 | 140 | ```lua 141 | -- Exporting globals 142 | function always(self) print(self.name) end 143 | -- Returning table 144 | return { tasks = { 145 | always = function(self) print(self.name) end 146 | }} 147 | ``` 148 | 149 | **MoonScript** 150 | 151 | ```moon 152 | -- Exporting globals 153 | export always ==> print @name 154 | -- Returning table 155 | tasks: 156 | always: => @name 157 | ``` 158 | 159 | ### Calling tasks 160 | 161 | From the command line, simply pass the name of the task you wish to run. Alternatively, use `tasks.TASK` to call `TASK` if it's loaded. 162 | 163 | **Lua:** 164 | 165 | ```lua 166 | function test (self) 167 | print("I am " .. self.name .. " and " .. self.caller .. " called me.") 168 | end 169 | 170 | function call (self) 171 | tasks.test{caller = self.name} 172 | end 173 | ``` 174 | 175 | **MoonScript:** 176 | 177 | ```moon 178 | tasks: 179 | test: => print "I am #{@name} and #{@caller} called me." 180 | call: => tasks.test caller: @name 181 | ``` 182 | 183 | ### Arguments 184 | 185 | Arguments are passed in the `self` table of every function, which contains a field called `name` which is, well, uh, its own name. You can also use the `args` table to see the whole tree of arguments. Feel free to play with and abuse this! 186 | 187 | ### Migrating from Alfons 3 188 | 189 | Some functions are either not implemented or not yet ported. 190 | 191 | #### Missing functions 192 | 193 | `moonc`, `git`, `clone` and `toflags` do not exist anymore. The first three may be implemented at a later time, and the last won't be implemented due to the changes in Alfons' argument system. For now, you will have to use their command-line counterparts, so `moonc file` becomes `sh "moonc #{file}"` and such. 194 | 195 | #### Importable tasks 196 | 197 | `fetch`/`fetchs` is now just `fetch`, and `ms-compile` has been removed and will probably not come back. Write a compile task manually. This should work as a dropin replacement: 198 | 199 | **Lua:** 200 | 201 | ```lua 202 | compile = function() 203 | for file in wildcard "**.moon" do sh "moonc ".. file end 204 | end 205 | ``` 206 | 207 | **MoonScript:** 208 | 209 | ```moon 210 | compile: => sh "moonc #{file}" for file in wildcard "**.moon" 211 | ``` 212 | 213 | ## Installing 214 | 215 | ~~Since this is not upstream yet, you can't install through the LuaRocks server. However, you can install Alfons using itself.~~ 216 | 217 | Alfons 4 is now available on LuaRocks! 218 | 219 | ```sh 220 | $ luarocks install alfons 221 | ``` 222 | 223 | ### Extra features 224 | 225 | The preincluded task `fetch` depends on [lua-http](https://github.com/daurnimator/lua-http) to be used. The `watch` function depends on [linotify](https://github.com/hoelzro/linotify) and will not work on platforms other than Linux. 226 | 227 | ```sh 228 | $ luarocks install http # lua-http 229 | $ luarocks install inotify # linotify 230 | ``` 231 | 232 | ## Projects using Alfons 233 | 234 | - [Moonbuild](https://github.com/natnat-mc/moonbuild) by the one and only [Codinget](https://github.com/natnat-mc) 235 | - [awlua](https://github.com/Le0Developer/awluas) by [Le0Developer](https://github.com/Le0Developer) 236 | - [VNDS-LOVE](https://github.com/ajusa/VNDS-LOVE) by [ajusa](https://github.com/ajusa) 237 | 238 | Thanks for using the project \<3. 239 | 240 | ## License 241 | 242 | Throwing it to the public domain. Check out the [license](https://github.com/daelvn/alfons/blob/rewrite/LICENSE.md). 243 | 244 | ## Goodbye? 245 | 246 | goodbye. 247 | -------------------------------------------------------------------------------- /alfons/env.moon: -------------------------------------------------------------------------------- 1 | -- alfons.env 2 | -- Loading and custom environment 3 | import style from require "ansikit.style" 4 | setfenv or= require "alfons.setfenv" 5 | path = require "path" 6 | fs or= require "path.fs" 7 | env = require "path.env" 8 | fsinfo = require "path.info" 9 | unpack or= table.unpack 10 | 11 | -- forward-declare environment 12 | local ENVIRONMENT 13 | 14 | -- environment for alfons files 15 | ENVIRONMENT = { 16 | :_VERSION 17 | :assert, :error, :pcall, :xpcall 18 | :tonumber, :tostring 19 | :select, :type, :pairs, :ipairs, :next, :unpack 20 | :require 21 | :print, :style -- from ansikit 22 | :io, :math, :string, :table, :os 23 | :fs -- fs is either CC/fs or lpath.fs 24 | :path, :env, :fsinfo -- lpath, lpath.env and lpath.info respectively 25 | } 26 | 27 | -- load in environment 28 | -- loadEnv content:string, env:table -> fn:function | nil, err:string 29 | loadEnv = (content, env) -> 30 | local fn 31 | switch _VERSION 32 | -- use loadstring on 5.1 33 | when "Lua 5.1" 34 | fn, err = loadstring content 35 | unless fn 36 | return nil, "Could not load Alfonsfile content (5.1): #{err}" 37 | setfenv fn, env 38 | -- use load otherwise 39 | when "Lua 5.2", "Lua 5.3", "Lua 5.4" 40 | fn, err = load content, "Alfons", "t", env 41 | unless fn 42 | return nil, "Could not load Alfonsfile content (5.2+): #{err}" 43 | -- return 44 | return fn 45 | 46 | { 47 | :ENVIRONMENT 48 | :loadEnv 49 | } -------------------------------------------------------------------------------- /alfons/file.moon: -------------------------------------------------------------------------------- 1 | -- alfons.file 2 | -- Gets the contents of a taskfile 3 | safeOpen = (path, mode) -> 4 | a, b = io.open path, mode 5 | return a and a or {error: b} 6 | 7 | readMoon = (file) -> 8 | local content 9 | with safeOpen file, "r" 10 | -- check that we could open correctly 11 | if .error 12 | return nil, "Could not open #{file}: #{.error}" 13 | -- read and compile 14 | import to_lua from require "moonscript.base" 15 | content, err = to_lua \read "*a" 16 | -- check that we could compile correctly 17 | unless content 18 | return nil, "Could not read or parse #{file}: #{err}" 19 | \close! 20 | -- return 21 | return content 22 | 23 | readFile = (file) -> 24 | local content 25 | with safeOpen file, "r" 26 | -- check that we could open correctly 27 | if .error 28 | return nil, "Could not open #{file}: #{.error}" 29 | -- read and compile 30 | content = \read "*a" 31 | -- check that we could compile correctly 32 | unless content 33 | return nil, "Could not read #{file}: #{content}" 34 | \close! 35 | -- return 36 | return content 37 | 38 | readLua = readFile 39 | 40 | -- REQUIRES "tl" MODULE 41 | readTeal = (file) -> 42 | local content 43 | with safeOpen file, "r" 44 | -- check that we could open correctly 45 | if .error 46 | return nil, "Could not open #{file}: #{.error}" 47 | -- read and compile 48 | import init_env, gen from require "tl" 49 | gwe = init_env true, false -- lax:true, compat:false 50 | content = gen (\read "*a"), gwe 51 | -- check that we could compile correctly 52 | unless content 53 | return nil, "Could not read #{file}: #{content}" 54 | \close! 55 | -- return 56 | return content 57 | 58 | -- REQUIRES "yue" MODULE 59 | readYue = (file) -> 60 | local content 61 | with safeOpen file, "r" 62 | -- check that we could open correctly 63 | if .error 64 | return nil, "Could not open #{file}: #{.error}" 65 | -- read and compile 66 | import to_lua from require "yue" 67 | content = to_lua \read "*a" 68 | -- check that we could compile correctly 69 | unless content 70 | return nil, "Could not read #{file}: #{content}" 71 | \close! 72 | -- return 73 | return content 74 | 75 | { :readMoon, :readLua, :readTeal, :readYue, :readFile } 76 | -------------------------------------------------------------------------------- /alfons/getopt.moon: -------------------------------------------------------------------------------- 1 | -- alfons.getopt 2 | -- Alfons needs its own getopt because of how it calls tasks. 3 | getopt = (argl) -> 4 | args = { 5 | commands: {} 6 | } 7 | flags = { 8 | stop: false 9 | command: false 10 | wait: false 11 | } 12 | push = (o, v) -> 13 | if flags.command 14 | args[flags.command][o] = v 15 | else 16 | args[o] = v 17 | -- loop args 18 | for arg in *argl 19 | -- stop parsing 20 | if arg == "--" 21 | flags.stop = true 22 | -- add to args if stopped 23 | if flags.stop 24 | table.insert args, arg 25 | continue 26 | -- set as value for last if waiting 27 | if flags.wait 28 | -- test next arg 29 | if arg\match "^%-%-" 30 | -- next argument is another long flag 31 | -- set waiting flag to current arg, wait for next value 32 | push (flags.wait\gsub "%-", "_"), true 33 | flags.wait = arg\match "^%-%-([a-za-z0-9%-_]+)" 34 | else 35 | -- next argument is not a long flag 36 | -- proceed normally 37 | push (flags.wait\gsub "%-", "_"), arg 38 | flags.wait = false 39 | continue 40 | -- change command 41 | unless arg\match "^%-%-?" 42 | args[arg] = {} 43 | flags.command = arg 44 | table.insert args.commands, arg 45 | continue 46 | -- add short opt 47 | if flag = arg\match "^%-(%w)$" 48 | flags.wait = flag 49 | continue 50 | -- add multiple flags 51 | if flagl = arg\match "^%-(%w+)$" 52 | for chr in flagl\gmatch "." 53 | push chr, true 54 | continue 55 | -- add option with value 56 | if arg\match "^%-%-?([a-za-z0-9%-_]+)=(.+)$" 57 | opt, value = arg\match "^%-%-?([a-zA-Z0-9%-_]+)=(.+)" 58 | push (opt\gsub "%-", "_"), value 59 | continue 60 | -- add option with next value 61 | if opt = arg\match "^%-%-([a-zA-Z0-9%-_]+)$" 62 | flags.wait = opt\gsub "%-", "_" 63 | -- push if waiting 64 | if flags.wait 65 | push (flags.wait\gsub "%-", "_"), true 66 | -- return result 67 | args 68 | 69 | -- 70 | { :getopt } 71 | -------------------------------------------------------------------------------- /alfons/help.moon: -------------------------------------------------------------------------------- 1 | -- alfons.help 2 | -- Displays help messages 3 | import style from require "ansikit.style" 4 | import map, reduce from require "alfons.provide" 5 | unpack or= table.unpack 6 | 7 | Node = (type, content, options) -> 8 | node = { :type, :content } 9 | if options then for k, v in pairs options do node[k] = v 10 | return node 11 | Paragraph = (content) -> Node 'paragraph', content 12 | Columns = (options, content) -> Node 'columns', content, options 13 | Row = (content) -> Node 'row', content 14 | Cell = (content, options) -> Node 'cell', content, options 15 | Cells = (arr) -> map arr, (cell) -> Cell cell[2], cell[1] 16 | Spacer = (length) -> Node 'spacer', '', :length 17 | 18 | -- sections: { 19 | -- { type: 'paragraph', content: 'Options:' } 20 | -- { type: 'columns', padding: 2, content: { 21 | -- { type: 'row', content: { 22 | -- { type: 'cell', } 23 | -- }} 24 | -- } } 25 | -- } 26 | generateHelp = (sections, options={}) -> 27 | final = "" 28 | for section in *sections 29 | final ..= string.rep ' ', options.padding or 0 30 | switch section.type 31 | when 'paragraph' 32 | final ..= (style section.content) .. '\n' 33 | when 'spacer' 34 | final ..= string.rep '\n', section.length or 1 35 | when 'columns' 36 | -- find maximum width of each column 37 | columns = section.content 38 | lengths = {} 39 | for row_index, row in ipairs columns 40 | for cell_index, cell in ipairs row.content 41 | lengths[cell_index] = 0 unless lengths[cell_index] 42 | if (string.len cell.content) > lengths[cell_index] 43 | lengths[cell_index] = string.len cell.content 44 | -- recursively generate section 45 | for row_index, row in ipairs columns 46 | final ..= string.rep ' ', section.padding 47 | for cell_index, cell in ipairs row.content 48 | cell_length = (string.len cell.content) 49 | needed_length = lengths[cell_index] 50 | content = style (cell.color or '') .. (cell.content .. (string.rep ' ', needed_length - cell_length)) 51 | final ..= content .. ' ' 52 | final ..= '\n' 53 | return final 54 | 55 | { 56 | :Node, :Paragraph, :Spacer, :Columns, :Row, :Cell, :Cells, 57 | :generateHelp 58 | } 59 | -------------------------------------------------------------------------------- /alfons/init.moon: -------------------------------------------------------------------------------- 1 | -- alfons.init 2 | -- API for running taskfiles 3 | import ENVIRONMENT, loadEnv from require "alfons.env" 4 | import getopt from require "alfons.getopt" 5 | import look from require "alfons.look" 6 | provide = require "alfons.provide" 7 | unpack or= table.unpack 8 | 9 | -- forward-declare all locals 10 | local * 11 | 12 | -- util 13 | sanitize = (pattern) -> pattern\gsub "[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%0" if pattern 14 | 15 | -- prefix for modules 16 | -- FIXME roll back from test 17 | --PREFIX = "test.alfons." 18 | PREFIX = "alfons.tasks." 19 | 20 | -- initialize a new environment 21 | initEnv = (run, base=ENVIRONMENT, genv, modname="main", pretty=false, debug_mode=false) -> 22 | -- create table to be the actual environment 23 | env, envmt = {}, {} 24 | env.tasks, tasksmt = {}, {} 25 | setmetatable env, envmt 26 | setmetatable env.tasks, tasksmt 27 | if debug_mode 28 | base.debug = debug 29 | -- set envmt.__index to access environment and provided functions 30 | envmt.__index = (k) => 31 | if genv and k == "__ran" 32 | return (getmetatable genv[modname]).__ran 33 | elseif genv and k == "store" 34 | return (getmetatable genv).store 35 | else 36 | base[k] or provide[k] 37 | -- set envmt.__newindex to get new tasks 38 | envmt.__newindex = (k, v) => 39 | error "Task '#{k}' is not a function." if "function" != type v 40 | @tasks[k] = (t={}) -> run k, v, t 41 | -- set tasksmt.__index to give friendly messages 42 | tasksmt.__index = (k) => (rawget @, k) or do 43 | for scope, t in pairs genv 44 | for name, task in pairs t.tasks 45 | return task if k == name 46 | -- else 47 | if pretty 48 | provide.printError "Task '#{k}' does not exist." 49 | os.exit 1 50 | else 51 | error "Task '#{k}' does not exist." 52 | -- set __ran value to 0 53 | envmt.__ran = 0 54 | return env 55 | 56 | -- runs a taskfile 57 | runString = (content, environment=ENVIRONMENT, runAlways=true, child=0, genv={}, rqueue={}, pretty=false, debug_mode=false) -> 58 | return nil, "Taskfile content must be a string" unless "string" == type content 59 | -- if content has no newlines and starts with 'alfons.tasks', use look. 60 | local modname 61 | if (not content\match "\n") and (content\match "^#{sanitize PREFIX}") 62 | modname = content 63 | content, contentErr = look content 64 | if contentErr then return nil, contentErr 65 | else 66 | modname = "main" 67 | -- if modname already exists, return genv[modname] 68 | return genv[modname] if genv[modname] 69 | -- add run function 70 | -- run a single task with the proper arguments 71 | run = (name, task, argl) -> 72 | (getmetatable genv[modname]).__ran += 1 73 | --print "ran tasks for #{modname}", (getmetatable genv[modname]).__ran 74 | self = setmetatable {}, __index: argl 75 | self.name = name 76 | self.task = -> run name, task, argl 77 | callstack = (getmetatable genv).store.callstack 78 | table.insert callstack, name 79 | if (('function' != type task) and ('table' != type task)) 80 | provide.printError "Task #{name} is not callable. Please check that it is a function." 81 | provide.printError "The task may be running on its own without calling it." 82 | os.exit 1 83 | -- Create error reporter 84 | errorHandler = (err) -> 85 | rewrite = err\gsub "%[string \"Alfons\"%]", "Taskfile (#{modname}:#{child})" 86 | provide.printError "Error in task `#{name}`:\n #{rewrite}" 87 | provide.printError " Callstack:\n (root)" 88 | provide.printError " " .. table.concat callstack, '\n ' 89 | os.exit 1 90 | ret = xpcall (() -> task self), errorHandler 91 | table.remove callstack, #callstack 92 | return ret 93 | -- reset genv metatable 94 | setmetatable genv, {store: {callstack: {}}} unless getmetatable genv 95 | -- initialize environment 96 | env = initEnv run, environment, genv, modname, pretty, debug_mode 97 | genv[modname] = env 98 | -- load file 99 | alf, alfErr = loadEnv content, env 100 | if alfErr then return nil, "Could not load Taskfile #{child}: #{alfErr}" 101 | -- return with wrapper 102 | return (...) -> 103 | -- argument handling 104 | argl = {...} 105 | args = getopt argl 106 | rawset env, "args", args 107 | -- add utils 108 | rawset env, "uses", (cmdmd) -> provide.contains (args.commands or {}), cmdmd 109 | rawset env, "exists", (wants) -> 110 | for scope, t in pairs genv 111 | for name, task in pairs t.tasks 112 | return true if wants == name 113 | return false 114 | rawset env, "calls", (cmdmd) -> 115 | -- get currently running task 116 | callstack = (getmetatable genv).store.callstack 117 | current = callstack[#callstack] 118 | -- iterate command list and grab non-existing tasks 119 | on = false 120 | subcommands = {} 121 | i = 0 122 | for cmd in *args.commands 123 | i += 1 124 | if on 125 | break if rawget env.tasks, cmd 126 | subcommands[#subcommands+1] = cmd 127 | args.commands[i] = nil 128 | else 129 | on = true if cmd == current 130 | -- remove taken commands 131 | args.commands = [e for i, e in provide.npairs args.commands] 132 | -- return 133 | return subcommands 134 | -- run 135 | list = alf args 136 | tasks = list and (list.tasks and list.tasks or {}) or {} 137 | -- wrap tasks and put into environment 138 | for k, v in pairs tasks do env.tasks[k] = (t={}) -> run k, v, t 139 | -- add finalize tasks to the queue 140 | if fintask = (rawget env.tasks, "finalize") 141 | rqueue[#rqueue+1] = fintask 142 | -- add function for subloading 143 | rawset env, "load", (mod) -> 144 | -- add prefix to mod 145 | -- TODO add configurable prefix 146 | mod = PREFIX .. mod 147 | -- avoid mutual loading 148 | return genv[mod] if genv[mod] 149 | -- wrap 150 | subalf, subalfErr = runString mod, env, runAlways, child+1, genv, rqueue 151 | if subalfErr then error subalfErr 152 | subenv = subalf unpack argl 153 | -- add tasks to main task table 154 | -- direction: down/below 155 | --tasksmt = getmetatable env.tasks 156 | --fallback = tasksmt.__index 157 | --tasksmt.__index = (k) => (rawget @, k) or subenv.tasks[k] or fallback k 158 | tasksmt = getmetatable env.tasks 159 | tasksmt.__index = (k) => (rawget @, k) or do 160 | for scope, t in pairs genv 161 | for name, task in pairs t.tasks 162 | return task if k == name 163 | -- else 164 | if pretty 165 | provide.printError "Task '#{k}' does not exist." 166 | os.exit 1 167 | else 168 | error "Task '#{k}' does not exist." 169 | -- make the main tasks table accessible to the subloaded task table 170 | -- direction: up/above 171 | --subtasksmt = getmetatable subenv.tasks 172 | --subfallback = subtasksmt.__index 173 | --subtasksmt.__index = (k) => (rawget @, k) or env.tasks[k] or subfallback k 174 | subtasksmt = getmetatable subenv.tasks 175 | subtasksmt.__index = (k) => (rawget @, k) or do 176 | for scope, t in pairs genv 177 | for name, task in pairs t.tasks 178 | return task if k == name 179 | -- else 180 | if pretty 181 | provide.printError "Task '#{k}' does not exist." 182 | os.exit 1 183 | else 184 | error "Task '#{k}' does not exist." 185 | -- run always task 186 | if runAlways and (rawget env.tasks, "always") 187 | (rawget env.tasks, "always")! 188 | (getmetatable genv[modname]).__ran -= 1 189 | -- add trigger for default and finalize tasks 190 | rawset env, "finalize", -> 191 | -- default 192 | for scope, t in pairs genv 193 | --print "ran for #{scope}", t.__ran 194 | (rawget t.tasks, "default")! if (rawget t.tasks, "default") and t.__ran < 1 195 | -- finalize 196 | rqueue[i]! for i=#rqueue, 1, -1 197 | -- return 198 | return env 199 | 200 | { :runString, :initEnv } 201 | -------------------------------------------------------------------------------- /alfons/look.moon: -------------------------------------------------------------------------------- 1 | -- alfons.look 2 | -- Gets the path for a module, specifically tailored for Alfons 3 | import readMoon, readLua from require "alfons.file" 4 | Path = require "path" 5 | 6 | sanitize = (pattern="") -> pattern\gsub "[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%0" 7 | 8 | dirsep, pathsep, wildcard = package.config\match "^(.)\n(.)\n(.)" 9 | modsep = "%." 10 | swildcard = sanitize wildcard 11 | 12 | makeLook = (gpath=package.path) -> 13 | -- generate lists of paths 14 | paths = [path for path in gpath\gmatch "[^#{pathsep}]+"] 15 | moonpaths = [path\gsub "%.lua$", ".moon" for path in gpath\gmatch "[^#{pathsep}]+"] 16 | -- return 17 | (name) -> 18 | mod = name\gsub modsep, dirsep 19 | file = false 20 | for path in *paths 21 | pt = path\gsub swildcard, mod 22 | file = pt if Path.exists pt 23 | for path in *moonpaths 24 | pt = path\gsub swildcard, mod 25 | file = pt if Path.exists pt 26 | -- 27 | if file 28 | read = (file\match "%.lua$") and readLua or readMoon 29 | content, contentErr = read file 30 | if content 31 | return content 32 | else 33 | return nil, contentErr 34 | else 35 | return nil, "#{name} not found." 36 | 37 | { :makeLook, look: makeLook! } -------------------------------------------------------------------------------- /alfons/parser.moon: -------------------------------------------------------------------------------- 1 | -- alfons.parser 2 | -- Parses comments and other information in a taskfile 3 | import lines, sanitize, map, filter, split, slice, keys from require "alfons.provide" 4 | import style from require "ansikit.style" 5 | 6 | printerr = (t) -> io.stderr\write t .. "\n" 7 | errors = (code, msg) -> 8 | printerr style "%{red}#{msg}" 9 | os.exit code 10 | --# Comments #-- 11 | -- Comments are untied from the code itself, to avoid having to 12 | -- parse every language with comment ASTs, with MoonScript does 13 | -- not even support (Yuescript does, though?). 14 | -- As such, comments must include directives in them to know 15 | -- what tasks they are referring to. Here is the documentation 16 | -- for that. 17 | -- 18 | -- == Describing a task == 19 | -- --- @task task_name Description 20 | -- --- @task compile Compiles the code. 21 | -- == Describing task option == 22 | -- --- @option task_name [argument] Description 23 | -- --- @option release [version v] Version of the release. 24 | -- --- @option status [info i] Shows status information. 25 | -- == Enabling flags for a task == 26 | -- --- @flag task_name flags 27 | -- --- @flag * hide 28 | -- = Builtin flags = 29 | -- hide - Hides the task from autocompletion and help 30 | 31 | parseDirective = (directive) -> 32 | return false unless directive\match "^@" 33 | operation = directive\match "^@([a-z]+)" 34 | rest = directive\match "^@[a-z]+%s+(.+)" 35 | switch operation 36 | when "task" 37 | parts = split rest, '%s+' 38 | name = parts[1] 39 | description = table.concat (slice parts, 2), ' ' 40 | return "task", name, { :description, options: {} } 41 | when "flag" 42 | parts = split rest, '%s+' 43 | name, flag = parts[1], parts[2] 44 | return (name == '*' and "flag" or "task-flag"), name, flag 45 | when "option" 46 | parts = split rest, '%s+' 47 | task = parts[1] 48 | option_names, option_values, description = {}, {}, "" 49 | in_option_names, in_option_values, maybe_description, in_description = false, false, false, false 50 | for part in *parts[2,] 51 | stripped_part = part\match "([^%[%]%<%>]+)" 52 | -- realize where we are IN 53 | if not in_option_names and part\match "^%[" 54 | in_option_names = true 55 | if not in_option_values and part\match "^%<" 56 | in_option_values = true 57 | if maybe_description and not part\match "^%<" 58 | maybe_description = false 59 | in_description = true 60 | -- add part depending in area 61 | if in_option_names 62 | table.insert option_names, stripped_part 63 | if in_option_values 64 | -- set as optional if ends with ? 65 | part_object = value: stripped_part 66 | if stripped_part\match '%?$' 67 | part_object = 68 | value: (stripped_part\match "([^%?]+)%?$"), 69 | optional: true 70 | table.insert option_values, part_object 71 | if in_description 72 | description ..= part .. " " 73 | -- realize where we are OUT 74 | if in_option_names and part\match "%]$" 75 | in_option_names = false 76 | maybe_description = true 77 | if in_option_values and part\match "%>$" 78 | in_option_values = false 79 | in_description = true 80 | return "option", task, { :option_names, :option_values, :description } 81 | 82 | -- Parses all comments starting with a certain marker '---' 83 | parseComments = (content, marker = '---') -> 84 | comment_lines = filter (lines content), (line) -> 85 | line\match "^%s-#{sanitize marker}%s+" 86 | directives = map comment_lines, (line) -> 87 | line\match "#{sanitize marker}%s+(.+)" 88 | state = 89 | tasks: {} 90 | flags: {} 91 | map directives, (directive) -> 92 | operation, key, value = parseDirective directive 93 | switch operation 94 | when "task" 95 | state.tasks[key] = value 96 | when "flag" 97 | table.insert state.flags, value 98 | when "task-flag" 99 | unless state.tasks[key] 100 | state.tasks[key] = {} 101 | if "table" == type state.tasks[key].flags 102 | table.insert state.tasks[key].flags, value 103 | else 104 | state.tasks[key].flags = {value} 105 | when "option" 106 | unless state.tasks[key] 107 | state.tasks[key] = {} 108 | state.tasks[key].options[value.option_names[1]] = { 109 | names: value.option_names, 110 | values: value.option_values, 111 | description: value.description, 112 | } 113 | return state 114 | 115 | { :parseComments } 116 | -------------------------------------------------------------------------------- /alfons/provide.moon: -------------------------------------------------------------------------------- 1 | -- alfons.provide 2 | -- Functions provided to the environment 3 | import style from require "ansikit.style" 4 | import listAll, glob, iglob from require "alfons.wildcard" 5 | Path = require "path" 6 | fs = require "path.fs" 7 | unpack or= table.unpack 8 | printerr = (t) -> io.stderr\write t .. "\n" 9 | 10 | -- try loading inotify, which is an optional dependancy 11 | inotify = do 12 | ok, inotify = pcall -> require "inotify" 13 | ok and inotify or nil 14 | 15 | --# io #-- 16 | -- prints (...) -> nil 17 | -- Print + style 18 | prints = (...) -> printerr unpack [style arg for arg in *{...}] 19 | 20 | -- printError (text:string) -> nil 21 | -- Prints an error 22 | printError = (text) -> printerr style "%{red}#{text}" 23 | 24 | -- safeOpen (path:string, mode:string) -> io | table 25 | -- Filekit's safeOpen 26 | safeOpen = (path, mode) -> 27 | a, b = io.open path, mode 28 | return a and a or {error: b} 29 | 30 | -- safePopen (path:string, mode:string) -> io | table 31 | safePopen = (path, mode) -> 32 | return {error: "io.popen is not available"} unless io.popen 33 | handle = io.popen path, mode 34 | return handle or {error: "Could not io.popen #{path}"} 35 | 36 | -- readfile (file:string) -> string 37 | -- Returns the contents of a file 38 | readfile = (file) -> 39 | with safeOpen file, "r" 40 | if .error 41 | error .error 42 | else 43 | contents = \read "*a" 44 | \close! 45 | return contents 46 | 47 | -- writefile (file:string, content:string) -> nil 48 | -- Writes into a file 49 | writefile = (file, content) -> 50 | with safeOpen file, "w" 51 | if .error 52 | error .error 53 | else 54 | \write content 55 | \close! 56 | 57 | -- serialize (t:table) -> string 58 | -- Quick and dirty serialize function 59 | serialize = (t) -> 60 | full = "return {\n" 61 | for k, v in pairs t 62 | full ..= " ['#{k}'] = '#{v}'," 63 | full ..= "}" 64 | return full 65 | 66 | -- ask (str:string) -> string 67 | -- Gets input from the user, with a prompt (optionally styled). 68 | ask = (str) -> 69 | io.write style str 70 | return io.read! 71 | 72 | -- show (str:string) -> nil 73 | -- Displays a message, but fancy 74 | show = (str) -> prints "%{cyan}:%{white} #{str}" 75 | 76 | -- env {string:string} 77 | -- Proxy table to os.getenv 78 | env = setmetatable {}, __index: (i) => os.getenv i 79 | 80 | --# commands #-- 81 | -- cmd (str:string) -> number 82 | -- os.execute 83 | cmd = os.execute 84 | sh = cmd 85 | 86 | -- cmdfail (str:string) -> nil 87 | -- os.execute, but quits on fail 88 | cmdfail = (str) -> 89 | code = cmd str 90 | os.exit code unless code == 0 91 | shfail = cmdfail 92 | 93 | -- cmdread (cmd:string) -> string 94 | -- opens a command and returns its output or error message 95 | cmdread = (cmd, raw) -> 96 | with safePopen cmd, "r" 97 | if .error 98 | error .error 99 | return .error 100 | else 101 | contents = \read "*a" 102 | \close! 103 | return contents 104 | shread = cmdread 105 | 106 | --# path #-- 107 | basename = (file) -> file\match "(.+)%..+" -- basename (file:string) -> string 108 | filename = Path.stem -- filename (file:string) -> string 109 | extension = Path.suffix -- extension (file:string) -> string 110 | pathname = Path.parent -- pathname (file:string) -> string 111 | isAbsolute = (path) -> path\match "^/" -- isAbsolute (path:string) -> string 112 | 113 | --# fs #-- 114 | -- wildcard (path:string) -> function (iterator) 115 | -- Implements old wildcard behavior 116 | wildcard = iglob 117 | 118 | -- iwildcard (paths:table) -> function (iterator) 119 | -- Multiple fs.iglob paths 120 | iwildcard = (paths) -> 121 | all = {} 122 | for path in *paths 123 | for globbed in iglob path 124 | table.insert all, globbed 125 | -- 126 | i, n = 0, #all 127 | -> 128 | i += 1 129 | return all[i] if i <= n 130 | 131 | -- isEmpty (path:string) -> boolean 132 | -- Checks if a directory is empty 133 | isEmpty = (path) -> 134 | return false unless Path.isdir path 135 | return 0 == #(listAll path) 136 | 137 | -- delete (loc:string) 138 | -- Recursive delete 139 | delete = (loc) -> 140 | return unless Path.exists loc 141 | if Path.isfile loc or isEmpty loc 142 | --print "DELFILE #{loc}" 143 | fs.remove loc 144 | else 145 | --print "DELDIR #{loc}" 146 | for node in fs.dir loc 147 | --print "SUBDEL #{node}" 148 | continue if node\match "%.%." 149 | --delete Path loc, node 150 | delete node 151 | fs.remove loc 152 | 153 | -- copy (source:string, target:string) 154 | -- Recursive copy 155 | copy = (fr, to) -> 156 | error "copy $ #{fr} does not exist" unless Path.exists fr 157 | if Path.isdir fr 158 | error "copy $ #{to} already exists" if Path.exists to 159 | fs.mkdir to 160 | for node in fs.dir fr 161 | --copy (Path fr, node), (Path to, node) 162 | copy node, (Path to, (Path.name node)) 163 | elseif Path.isfile fr 164 | fs.copy fr, to 165 | 166 | -- glob (glob:string) -> (path:string) -> boolean 167 | -- Curried fs.matchGlob 168 | -- NOTE deleted in 5.0 169 | --glob = (glob) -> (path) -> fs.matchGlob (fs.fromGlob glob), path 170 | 171 | -- build (iter:function, fn:function) -> nil 172 | -- Compares last modification times with a cache, and if the file was 173 | -- modified, it passes the file to fn. 174 | build = (iter, fn) -> 175 | -- get modification times 176 | times = {} 177 | if Path.exists ".alfons" 178 | prints "%{cyan}:%{white} using .alfons" 179 | times = dofile ".alfons" 180 | times = {k, tonumber v for k, v in pairs times} 181 | -- 182 | for file in iter 183 | mtime = fs.mtime file 184 | if times[file] 185 | -- previously built 186 | fn file if mtime > times[file] 187 | times[file] = mtime 188 | else 189 | -- never built before 190 | fn file 191 | times[file] = mtime 192 | -- write back to file 193 | writefile ".alfons", serialize times 194 | 195 | -- EVENTS {string:string} 196 | EVENTS = { 197 | access: "IN_ACCESS" -- "accessed"} 198 | change: "IN_ATTRIB" -- "changed"} 199 | write: "IN_CLOSE_WRITE" -- "written into"} 200 | shut: "IN_CLOSE_NOWRITE" -- "closed without writing"} 201 | close: "IN_CLOSE" -- "closed"} 202 | create: "IN_CREATE" -- "created"} 203 | delete: "IN_DELETE" -- "deleted"} 204 | destruct: "IN_DELETE_SELF" -- "deleted"} 205 | modify: "IN_MODIFY" -- "modified"} 206 | migrate: "IN_MOVE_SELF" -- "migrated"} 207 | move: "IN_MOVE" -- "moved"} 208 | movein: "IN_MOVED_TO" -- "moved here"} 209 | moveout: "IN_MOVED_FROM" -- "moved from here"} 210 | open: "IN_OPEN" -- "opened"} 211 | all: "IN_ALL_EVENTS" -- "updated"} 212 | } 213 | 214 | -- do not export this 215 | -- https://stackoverflow.com/a/32387452 216 | bit_band = (a, b) -> 217 | result, bitval = 0, 1 218 | while a > 0 and b > 0 219 | if a % 2 == 1 and b % 2 == 1 220 | result = result + bitval 221 | bitval = bitval * 2 222 | a = math.floor a/2 223 | b = math.floor b/2 224 | return result 225 | 226 | -- watch1 (iter:function, evf:table/string, fn:function) -> nil 227 | -- Uses inotify to watch for events specified in the event table. 228 | -- evf == "live" -> {"write", "movein", "modify", "create", "migrate"} 229 | -- watch1 = (iter, evf, fn) -> 230 | -- handle = inotify.init! 231 | -- -- do equivalents 232 | -- if evf == "live" 233 | -- evf = {"write", "movein", "create"} 234 | -- --handles = {} 235 | -- -- get file list 236 | -- files = {file, true for file in iter} 237 | -- prints "%{cyan}:%{white} Watching for:" 238 | -- for file, _ in pairs files 239 | -- prints " - %{green}#{file}" 240 | -- -- get directories 241 | -- dirs = {} 242 | -- for file, _ in pairs files 243 | -- parent = pathname file 244 | -- dirs[parent] = true unless dirs[parent] 245 | -- prints "%{cyan}:%{white} inotify directories:" 246 | -- for dir, _ in pairs dirs 247 | -- prints " - %{blue}#{dir}" 248 | -- events = [inotify[EVENTS[ev]] for ev in *evf] 249 | -- -- add file watchers 250 | -- -- note: you can only add dirs here 251 | -- watchers = {} 252 | -- for dir, _ in pairs dirs 253 | -- -- create a main watcher 254 | -- watchers[dir] = handle\addwatch dir, unpack events 255 | -- reversed = {v, k for k, v in pairs watchers} 256 | -- -- now loop 257 | -- while true 258 | -- events = handle\read! 259 | -- break unless events -- error? 260 | -- -- iterate fetched events 261 | -- for ev in *events 262 | -- -- get full path 263 | -- full = reversed[ev.wd] .. (ev.name or "") 264 | -- -- get action names 265 | -- actions = {} 266 | -- for action, evt in pairs EVENTS 267 | -- continue if action == "all" 268 | -- if 0 != bit_band ev.mask, inotify[evt] 269 | -- table.insert actions, action 270 | -- -- execute fn 271 | -- prints "%{cyan}:%{white} Triggered %{magenta}#{table.concat actions, ', '}%{white}: %{yellow}#{full}" 272 | -- fn full 273 | -- -- close it 274 | -- handle\close! 275 | 276 | -- watch (dirs:{string}, exclude:{string}, evf:{string}, pred:(file -> boolean), fn:(file -> nil)) -> nil 277 | watch = (dirs, exclude, evf, pred, fn) -> 278 | error "Could not load inotify" unless inotify 279 | handle = inotify.init! 280 | -- do equivalents 281 | if evf == "live" 282 | evf = {"write", "movein"} 283 | -- convert all into absolute 284 | cdir = Path.cwd! 285 | for i, dir in ipairs dirs 286 | unless isAbsolute dir 287 | --dirs[i] = fs.reduce fs.combine cdir, dir 288 | dirs[i] = Path cdir, dir 289 | for i, dir in ipairs exclude 290 | unless isAbsolute dir 291 | --exclude[i] = fs.reduce fs.combine cdir, dir 292 | exclude[i] = Path cdir, dir 293 | -- recurse into subdirectories 294 | for i, dir in ipairs dirs 295 | for ii, subdir in ipairs listAll dir 296 | doBreak = false 297 | for exclusion in *exclude 298 | doBreak = true if subdir\match "^#{exclusion}" 299 | continue if doBreak 300 | table.insert dirs, subdir if Path.isdir subdir 301 | -- print dirs 302 | prints "%{cyan}:%{white} Watching for:" 303 | for dir in *dirs 304 | prints " - %{green}#{dir}" 305 | -- get events 306 | events = [inotify[EVENTS[ev]] for ev in *evf] 307 | -- add create to event list 308 | -- evf -> full event list 309 | -- uevf -> user event list 310 | uevf = {k, v for k, v in pairs evf} 311 | unless contains evf, "create" 312 | table.insert evf, "create" 313 | table.insert events, inotify.IN_CREATE 314 | -- add watchers 315 | watchers = {} 316 | for dir in *dirs 317 | watchers[dir] = handle\addwatch dir, unpack events 318 | reversed = {v, k for k, v in pairs watchers} 319 | -- now iterate 320 | while true 321 | evts = handle\read! 322 | break unless evts -- error? 323 | -- iterate fetched events 324 | for ev in *evts 325 | -- get full path 326 | full = Path reversed[ev.wd], (ev.name or "") 327 | -- if dir, add watcher 328 | if (Path.isdir full) and (bit_band ev.mask, inotify.IN_CREATE) and not watchers[full] 329 | prints "%{cyan}:%{white} Added to watchlist: %{green}#{full}" 330 | watchers[full] = handle\addwatch full, unpack events 331 | reversed[watchers[full]] = full 332 | -- get action names 333 | actions = {} 334 | for action, evt in pairs EVENTS 335 | continue if action == "all" 336 | if 0 != bit_band ev.mask, inotify[evt] 337 | table.insert actions, action if contains uevf, action 338 | -- skip if we have no matching actions 339 | continue if #actions == 0 340 | -- check that it passes predicate 341 | continue unless pred full, actions 342 | -- execute fn 343 | prints "%{cyan}:%{white} Triggered %{magenta}#{table.concat actions, ', '}%{white}: %{yellow}#{full}" 344 | fn full, actions 345 | -- close it 346 | handle\close! 347 | --watch {"."}, {".git"}, "live", (glob "*.moon"), => sh "moonc #{@}" 348 | 349 | -- npairs (table) -> -> number, * 350 | -- ipairs, but does not stop if nil is found 351 | npairs = (t) -> 352 | keys = [k for k, v in pairs t when "number" == type k] 353 | table.sort keys 354 | i = 0 355 | n = #keys 356 | -> 357 | i += 1 358 | return keys[i], t[keys[i]] if i <= n 359 | 360 | 361 | --# utils #-- 362 | 363 | -- lines (string) -> [string] 364 | -- Split a string into lines 365 | lines = (str) -> [line for line in str\gmatch "[^\r\n]+"] 366 | 367 | -- split (str:string, re:pattern, plain:boolean, n:number) -> [string] 368 | -- str - String to split 369 | -- re - Pattern to split the text by 370 | -- plain - Whether to treat `re` as plaintext or a Lua pattern (defaults to false) 371 | -- n - Maximum matches (defaults to none) 372 | -- https://github.com/lunarmodules/Penlight/blob/master/lua/pl/utils.lua 373 | split = (str, re, plain, n) -> 374 | i1, ls = 1, {} 375 | if not re then re = '%s+' 376 | if re == '' then return { str } 377 | while true 378 | i2, i3 = string.find str, re, i1, plain 379 | if not i2 380 | last = string.sub str, i1 381 | if last != '' then table.insert ls, last 382 | if #ls == 1 and ls[1] == '' 383 | return {} 384 | else 385 | return ls 386 | 387 | table.insert ls, string.sub str, i1, i2-1 388 | 389 | if n and #ls == n then 390 | ls[#ls] = string.sub str, i1 391 | return ls 392 | 393 | i1 = i3+1 394 | 395 | -- filter (arr:[*], predicate:((value:*, key:*) -> boolean)) -> [*] 396 | -- Filters a table using a predicate 397 | filter = (arr, predicate) -> [v for k, v in ipairs arr when predicate v, k] 398 | 399 | -- map (arr:[*], predicate:((value: *, key: *) -> *)) -> [*] 400 | -- Normal map over a table 401 | map = (arr, predicate) -> [predicate v, k for k, v in ipairs arr] 402 | 403 | -- reduce (arr:[*], predicate:((accum:*, value: *) -> *), initial:*) -> * 404 | -- reduce/foldl 405 | reduce = (arr, predicate, initial) -> 406 | accumulator = initial or arr[1] 407 | start = initial and 1 or 2 408 | i = start 409 | while i <= #arr 410 | accumulator = predicate accumulator, arr[i] 411 | i += 1 412 | return accumulator 413 | 414 | -- slice (arr:[*], start:number?, end:number?) -> [*] 415 | -- Creates a slice of an array 416 | slice = (arr, start, _end) -> 417 | if not start and not _end return arr 418 | if start and not _end return [v for v in *arr[start,]] 419 | if not start and _end return [v for v in *arr[,_end]] 420 | return [v for v in *arr[start,_end]] 421 | 422 | -- contains (arr:[*], value:*) -> boolean 423 | -- Check if an array contains a value 424 | contains = (arr, value) -> for v in *arr 425 | return true if v == value 426 | 427 | -- keys (tbl:{*:*}) -> [*] 428 | -- Returns all the keys of a table 429 | keys = (tbl) -> [k for k, v in pairs tbl] 430 | 431 | -- values (tbl:{*:*}) -> [*] 432 | -- Returns all the values of a table 433 | values = (tbl) -> [v for k, v in pairs tbl] 434 | 435 | -- entries (tbl:{*:*}) -> [*,*][] 436 | -- Returns the keys and values of a table as an array of [key, value]s 437 | entries = (tbl) -> [{k, v} for k, v in pairs tbl] 438 | 439 | -- fromEntries (entries:[*,*]) -> {*:*} 440 | -- Turns an array of entries like [key, value]s into a table 441 | fromEntries = (arr) -> {k, v for {k, v} in ipairs arr} 442 | 443 | -- sanitize (string) -> string 444 | -- Pattern-escapes a string 445 | sanitize = (pattern="") -> pattern\gsub "[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%0" 446 | 447 | { 448 | :contains 449 | :prints, :printError 450 | :readfile, :writefile, :serialize 451 | :cmd, :cmdfail, :sh, :shfail, :cmdread, :shread 452 | :wildcard, :iwildcard, :glob 453 | :basename, :filename, :extension, :pathname 454 | :build, :watch 455 | :env, :ask, :show 456 | :npairs 457 | :listAll, :safeOpen, :safePopen 458 | :isEmpty, :delete, :copy 459 | :lines, :split, :filter, :map, :reduce 460 | :slice, :keys, :values, :contains 461 | :entries, :fromEntries 462 | :sanitize 463 | } 464 | -------------------------------------------------------------------------------- /alfons/setfenv.moon: -------------------------------------------------------------------------------- 1 | -- alfons.setfenv 2 | -- Provides setfenv for 5.1 3 | return setfenv or (fn, env) -> 4 | i = 1 5 | while true 6 | name = debug.getupvalue fn, i 7 | if name == "_ENV" 8 | debug.upvaluejoin fn, i, (-> env), 1 9 | elseif not name then break 10 | i += 1 11 | return fn -------------------------------------------------------------------------------- /alfons/tasks/fetch.lua: -------------------------------------------------------------------------------- 1 | return { 2 | tasks = { 3 | fetch = function(self) 4 | local http = require("http.request") 5 | local headers, stream = assert((http.new_from_uri(self.url)):go()) 6 | local body = assert(stream:get_body_as_string()) 7 | if "200" ~= headers:get(":status") then 8 | return error(body) 9 | else 10 | return body 11 | end 12 | end 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /alfons/tasks/fetch.moon: -------------------------------------------------------------------------------- 1 | tasks: 2 | fetch: => 3 | http = require "http.request" 4 | headers, stream = assert (http.new_from_uri @url)\go! 5 | body = assert stream\get_body_as_string! 6 | if "200" != headers\get ":status" 7 | error body 8 | else 9 | return body -------------------------------------------------------------------------------- /alfons/tasks/teal.lua: -------------------------------------------------------------------------------- 1 | return { 2 | tasks = { 3 | always = function(self) 4 | load("fetch") 5 | if not (store.teal_auto == true) then 6 | tasks.install() 7 | return tasks.typings({ 8 | modules = store.typings 9 | }) 10 | end 11 | end, 12 | install = function(self) 13 | if exists("teal_preinstall") then 14 | prints("%{cyan}Teal:%{white} Running pre-install hook.") 15 | tasks.teal_preinstall() 16 | end 17 | prints("%{cyan}Teal:%{white} Installing dependencies.") 18 | local _list_0 = store.dependencies 19 | for _index_0 = 1, #_list_0 do 20 | local dep = _list_0[_index_0] 21 | prints("%{green}+ " .. tostring(dep)) 22 | sh("luarocks install " .. tostring(dep)) 23 | end 24 | if exists("teal_postinstall") then 25 | prints("%{cyan}Teal:%{white} Running post-install hook.") 26 | return tasks.teal_postinstall() 27 | end 28 | end, 29 | build = function(self) 30 | if exists("teal_prebuild") then 31 | prints("%{cyan}Teal:%{white} Running pre-build hook.") 32 | tasks.teal_prebuild() 33 | end 34 | prints("%{cyan}Teal:%{white} Building project.") 35 | sh("tl build") 36 | if exists("teal_postbuild") then 37 | prints("%{cyan}Teal:%{white} Running post-build hook.") 38 | return tasks.teal_postbuild() 39 | end 40 | end, 41 | typings = function(self) 42 | local json = require("dkjson") 43 | local fetchdefs 44 | fetchdefs = function(mod) 45 | prints("%{cyan}Teal:%{white} Fetching type definitions for " .. tostring(mod) .. ".") 46 | local unjson = tasks.fetch({ 47 | url = "https://api.github.com/repos/teal-language/teal-types/contents/types/" .. tostring(mod) 48 | }) 49 | local files = json.decode(unjson) 50 | for _index_0 = 1, #files do 51 | local _continue_0 = false 52 | repeat 53 | local file = files[_index_0] 54 | if not (file.type == "file") then 55 | _continue_0 = true 56 | break 57 | end 58 | local name = file.name 59 | local def = tasks.fetch({ 60 | url = "https://raw.githubusercontent.com/teal-language/teal-types/master/types/" .. tostring(mod) .. "/" .. tostring(name) 61 | }) 62 | writefile(name, def) 63 | _continue_0 = true 64 | until true 65 | if not _continue_0 then 66 | break 67 | end 68 | end 69 | end 70 | local mod = self.m or self.module 71 | local mods = self.modules 72 | if mod then 73 | return fetchdefs(mod) 74 | elseif mods then 75 | local _list_0 = mods 76 | for _index_0 = 1, #_list_0 do 77 | local md = _list_0[_index_0] 78 | fetchdefs(md) 79 | end 80 | end 81 | end 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /alfons/tasks/teal.moon: -------------------------------------------------------------------------------- 1 | tasks: 2 | -- always 3 | always: => 4 | load "fetch" 5 | unless store.teal_auto == true 6 | tasks.install! 7 | tasks.typings modules: store.typings 8 | -- install dependencies 9 | install: => 10 | -- pre-install hook 11 | if exists "teal_preinstall" 12 | prints "%{cyan}Teal:%{white} Running pre-install hook." 13 | tasks.teal_preinstall! 14 | -- install 15 | prints "%{cyan}Teal:%{white} Installing dependencies." 16 | for dep in *store.dependencies 17 | prints "%{green}+ #{dep}" 18 | sh "luarocks install #{dep}" 19 | -- post-install hook 20 | if exists "teal_postinstall" 21 | prints "%{cyan}Teal:%{white} Running post-install hook." 22 | tasks.teal_postinstall! 23 | -- build teal 24 | build: => 25 | -- pre-install hook 26 | if exists "teal_prebuild" 27 | prints "%{cyan}Teal:%{white} Running pre-build hook." 28 | tasks.teal_prebuild! 29 | -- install 30 | prints "%{cyan}Teal:%{white} Building project." 31 | sh "tl build" 32 | -- post-install hook 33 | if exists "teal_postbuild" 34 | prints "%{cyan}Teal:%{white} Running post-build hook." 35 | tasks.teal_postbuild! 36 | -- download typings 37 | typings: => 38 | -- import 39 | json = require "dkjson" -- uses dkjson 40 | -- define helper 41 | fetchdefs = (mod) -> 42 | prints "%{cyan}Teal:%{white} Fetching type definitions for #{mod}." 43 | unjson = tasks.fetch url: "https://api.github.com/repos/teal-language/teal-types/contents/types/#{mod}" 44 | files = json.decode unjson 45 | for file in *files 46 | continue unless file.type == "file" 47 | name = file.name 48 | def = tasks.fetch url: "https://raw.githubusercontent.com/teal-language/teal-types/master/types/#{mod}/#{name}" 49 | writefile name, def 50 | -- get arguments 51 | mod = @m or @module 52 | mods = @modules 53 | if mod -- individual 54 | fetchdefs mod 55 | elseif mods -- multiple 56 | fetchdefs md for md in *mods -------------------------------------------------------------------------------- /alfons/version.moon: -------------------------------------------------------------------------------- 1 | VERSION: "5.3.1" 2 | -------------------------------------------------------------------------------- /alfons/wildcard.moon: -------------------------------------------------------------------------------- 1 | -- alfons.wildcard 2 | -- Reimplements the old filekit wildcard behavior 3 | Path = require "path" 4 | fs = require "path.fs" 5 | 6 | -- listAll (dir:string) -> [string] 7 | -- Filekit's listAll 8 | listAll = (dir) -> [node for node in fs.scandir dir] 9 | 10 | -- Turns a glob into a Lua pattern 11 | -- @tparam string glob Path with globs 12 | -- @treturn string Lua pattern 13 | fromGlob = (glob) -> 14 | sanitize = (pattern) -> pattern\gsub "[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%0" if pattern 15 | saglob = sanitize glob 16 | with saglob 17 | mid = \gsub "%%%*%%%*", ".*" 18 | mid = mid\gsub "%%%*", "[^/]*" 19 | mid = mid\gsub "%%%?", "." -- TODO this should be [^/] 20 | --print "==> #{mid}" 21 | return "#{mid}$" 22 | 23 | -- TODO alias this to testGlob 24 | -- TODO compile the glob here, dont make the user do it 25 | --- Matches a compiled glob with a string 26 | -- @tparam string glob Compiled glob 27 | -- @tparam string path Path to compare to 28 | -- @treturn boolean Whether it matches or not 29 | matchGlob = (glob, path) -> nil != path\match glob 30 | 31 | --- Returns a list of paths matched by the globs 32 | -- @tparam string path Path with globs 33 | -- @treturn table Table of globbed files 34 | glob = (path, all={}) -> 35 | -- Return if there is nothing to glob 36 | return path unless path\match "%*" 37 | -- Get full paths 38 | --currentpath = Path.cwd! 39 | --fullpath = Path currentpath, path 40 | currentpath = "." 41 | fullpath = path 42 | -- Create a correct listing 43 | correctpath = "" 44 | for i=1, #fullpath 45 | if (fullpath\sub i, i) == (currentpath\sub i, i) 46 | correctpath ..= currentpath\sub i, i 47 | -- Create glob 48 | toglob = fromGlob fullpath 49 | -- Iterate files 50 | for node in *listAll correctpath 51 | --print node, toglob 52 | table.insert all, node if node\match toglob 53 | -- Return 54 | return all 55 | 56 | --- Glob as an iterator 57 | -- @tparam string path Path with globs 58 | -- @treturn function Iterator 59 | iglob = (path) -> 60 | globbed = glob path 61 | i = 0 62 | n = #globbed 63 | return -> 64 | i += 1 65 | if i <= n then return globbed[i] 66 | 67 | { 68 | :listAll 69 | :fromGlob, :matchGlob, :glob, :iglob 70 | } -------------------------------------------------------------------------------- /bin/alfons.moon: -------------------------------------------------------------------------------- 1 | -- alfons 5.0 2 | -- Task execution with Lua and MoonScript 3 | -- By daelvn 4 | import VERSION from require "alfons.version" 5 | import style from require "ansikit.style" 6 | Path = require "path" 7 | unpack or= table.unpack 8 | printerr = (t) -> io.stderr\write t .. "\n" 9 | 10 | -- utils 11 | prints = (...) -> printerr unpack [style arg for arg in *{...}] 12 | printError = (text) -> printerr style "%{red}#{text}" 13 | errors = (code, msg) -> 14 | printerr style "%{red}#{msg}" 15 | os.exit code 16 | removeColorCodes = (str) -> str\gsub "%%{[a-z ]-}", "" 17 | 18 | -- get arguments 19 | import getopt from require "alfons.getopt" 20 | args = getopt {...} 21 | 22 | -- List known tasks for autocompletion 23 | ZSH_LIST_TASKS = not not args.zsh_list 24 | BASH_LIST_TASKS = not not args.bash_list 25 | LIST_TASKS = ZSH_LIST_TASKS or BASH_LIST_TASKS or not not args.list 26 | 27 | -- Read task description/arguments of a task for autocompletion 28 | ZSH_LIST_OPTIONS = args.zsh_list_options 29 | BASH_LIST_OPTIONS = args.bash_list_options 30 | LIST_OPTIONS = ZSH_LIST_OPTIONS or BASH_LIST_OPTIONS or args.list_options 31 | 32 | -- Get task argument type for autocompletion 33 | ZSH_GET_OPTION_TYPE = args.zsh_get_option_type 34 | GET_OPTION_TYPE = ZSH_GET_OPTION_TYPE or args.get_option_type 35 | 36 | COMPLETING = LIST_TASKS or LIST_OPTIONS or GET_OPTION_TYPE 37 | 38 | -- Show help message 39 | HELP = args.help 40 | 41 | -- With debug in environment 42 | INCLUDE_DEBUG = args.include_debug 43 | 44 | -- introduction 45 | unless COMPLETING 46 | prints "%{bold blue}Alfons #{VERSION}" 47 | 48 | -- Optionally accept a custom file 49 | FILE = do 50 | if args.f then args.f 51 | elseif args.file then args.file 52 | elseif Path.exists "Alfons.lua" then "Alfons.lua" 53 | elseif Path.exists "Alfons.moon" then "Alfons.moon" 54 | elseif Path.exists "Alfons.tl" then "Alfons.tl" 55 | elseif Path.exists "Alfons.yue" then "Alfons.yue" 56 | else errors 1, "No Taskfile found." 57 | 58 | -- Also accept a custom language 59 | LANGUAGE = do 60 | if FILE\match "moon$" then "moon" 61 | elseif FILE\match "lua$" then "lua" 62 | elseif FILE\match "tl$" then "teal" 63 | elseif FILE\match "yue$" then "yue" 64 | elseif args.type then args.type 65 | else errors 1, "Cannot resolve format for Taskfile." 66 | 67 | unless COMPLETING 68 | printerr "Using #{FILE} (#{LANGUAGE})" 69 | 70 | -- Load string 71 | import readMoon, readLua, readTeal, readYue from require "alfons.file" 72 | content, contentErr = switch LANGUAGE 73 | when "moon" then readMoon FILE 74 | when "lua" then readLua FILE 75 | when "teal" then readTeal FILE 76 | when "yue" then readYue FILE 77 | else errors 1, "Cannot resolve format '#{LANGUAGE}' for Taskfile." 78 | unless content then errors 1, contentErr 79 | 80 | -- Run the taskfile 81 | import runString from require "alfons.init" 82 | alfons, alfonsErr = runString content, nil, true, 0, {}, {}, true, INCLUDE_DEBUG 83 | unless alfons then errors 1, alfonsErr 84 | env = alfons ... 85 | 86 | -- If we have to list tasks, print them and exit 87 | import contains from require "alfons.provide" 88 | 89 | if ZSH_LIST_TASKS 90 | import readFile from require "alfons.file" 91 | import parseComments from require "alfons.parser" 92 | -- Read the file (since MoonScript compiler deletes comments) 93 | raw_content = readFile FILE 94 | -- Parse the content 95 | state = parseComments raw_content 96 | -- Return 97 | tasks = ["#{task_name}:#{removeColorCodes task.description or ''}" for task_name, task in pairs state.tasks when not (task.flag and contains task.flag, 'hide')] 98 | for task in *tasks do print task 99 | undocumented_tasks = [k for k, v in pairs env.tasks when not state.tasks[k]] 100 | for task in *undocumented_tasks 101 | sanitized_task = removeColorCodes task 102 | print sanitized_task 103 | os.exit! 104 | 105 | if LIST_TASKS 106 | import readFile from require "alfons.file" 107 | import parseComments from require "alfons.parser" 108 | -- Read the file (since MoonScript compiler deletes comments) 109 | raw_content = readFile FILE 110 | -- Parse the content 111 | state = parseComments raw_content 112 | -- Return 113 | tasks = ["#{task_name} " for task_name, task in pairs state.tasks when not (task.flag and contains task.flag, 'hide')] 114 | for task in *tasks do io.write task 115 | undocumented_tasks = [k for k, v in pairs env.tasks when not state.tasks[k]] 116 | for task in *undocumented_tasks 117 | io.write task .. ' ' 118 | os.exit! 119 | 120 | -- If we have to list the options, print them and exit 121 | if LIST_OPTIONS 122 | import readFile from require "alfons.file" 123 | import parseComments from require "alfons.parser" 124 | list_options = ZSH_LIST_OPTIONS or LIST_OPTIONS 125 | -- argument needs to be a task 126 | if 'string' != type list_options 127 | errors 2, "Error: --list-options must be used with a task name." 128 | -- Read the file (since MoonScript compiler deletes comments) 129 | raw_content = readFile FILE 130 | -- Parse the content 131 | state = parseComments raw_content 132 | -- Access task 133 | task = state.tasks[list_options] 134 | if not task or (task.flags and contains task.flags, "hide") 135 | errors 2, "Error: Task '#{list_options}' does not exist." 136 | -- Helpers 137 | formatOptionName = (name) -> ((string.len name) > 1) and ('--' .. name) or ('-' .. name) 138 | formatOptionValues = (option) -> (table.concat ( 139 | for value in *option.values 140 | value.value 141 | ), ' ') 142 | -- Print arguments 143 | for option_name, option in pairs task.options 144 | for name in *option.names 145 | if ZSH_LIST_OPTIONS 146 | print "#{formatOptionName name}\\:'#{removeColorCodes option.description}'" 147 | else 148 | io.write (formatOptionName name) .. ' ' 149 | 150 | ZSH_OPTION_TYPES = 151 | file: '_files' 152 | path: '_path_files' 153 | user: '_users' 154 | group: '_groups' 155 | 156 | -- Retrieve option type, if asked 157 | if GET_OPTION_TYPE 158 | import readFile from require "alfons.file" 159 | import parseComments from require "alfons.parser" 160 | task_name, raw_option = GET_OPTION_TYPE\match "([^;]+)::([^;]+)" 161 | needed_option = raw_option\gsub '%-', '' 162 | -- argument needs to be a task 163 | if 'string' != type GET_OPTION_TYPE 164 | errors 2, "Error: --get-option-type must be used with a task name and option in the format `task;option`." 165 | -- Read the file (since MoonScript compiler deletes comments) 166 | raw_content = readFile FILE 167 | -- Parse the content 168 | state = parseComments raw_content 169 | -- Access task 170 | task = state.tasks[task_name] 171 | if not task or (task.flags and contains task.flags, "hide") 172 | errors 2, "Error: Task '#{task_name}' does not exist." 173 | -- Find matching option 174 | for option_name, option in pairs task.options 175 | if contains option.names, needed_option 176 | for value in *option.values 177 | print ZSH_OPTION_TYPES[value.value] or "" 178 | os.exit! 179 | 180 | -- If we have to show the help message, print that and exit 181 | if HELP 182 | import readFile from require "alfons.file" 183 | import parseComments from require "alfons.parser" 184 | import Paragraph, Spacer, Columns, Row, Cells, generateHelp from require "alfons.help" 185 | -- Read the file (since MoonScript compiler deletes comments) 186 | raw_content = readFile FILE 187 | -- Parse the content 188 | state = parseComments raw_content 189 | -- Helper generators 190 | Option = (command, description) -> (Row Cells { 191 | { {color: '%{bold green}'}, command } 192 | { {}, description } 193 | }) 194 | Task = (command, description) -> (Row Cells { 195 | { {color: '%{bold cyan}'}, command } 196 | { {}, description } 197 | }) 198 | formatOptions = (option) -> (table.concat ( 199 | for name in *option.names 200 | ((string.len name) > 1) and ('--' .. name) or ('-' .. name) 201 | ), ' ') .. ' ' .. (table.concat ( 202 | for option_value in *option.values 203 | option_value.optional and "[#{option_value.value}]" or "<#{option_value.value}>" 204 | ), ' ') 205 | 206 | -- Create help message 207 | help_message = { 208 | (Paragraph 'Built-in options:') 209 | (Columns {padding: 2}, { 210 | (Option '--help [task]', 'Displays this help message, or for a specific task') 211 | (Option '--file -f ', 'Loads a custom Taskfile') 212 | (Option '--list', 'Lists all the tasks available for the loaded Taskfile') 213 | (Option '--list-options ', 'Lists all the options available to a task') 214 | }) 215 | } 216 | -- If everything is hidden, just print and exit 217 | if state.flags.hide 218 | print generateHelp help_message 219 | os.exit! 220 | -- If we are asking help for a certain task, add that 221 | extra_message = {} 222 | if HELP != true 223 | task = state.tasks[HELP] 224 | if not task or (task.flags and contains task.flags, "hide") 225 | errors 2, "Error: Task '#{HELP}' does not exist." 226 | -- NOTE: We are purposefully replacing the original 227 | help_message = { 228 | (Paragraph "%{bold cyan}#{HELP} %{reset}- #{task.description}") 229 | (Columns {padding: 2}, ( 230 | for option_name, option in pairs task.options 231 | Option (formatOptions option), option.description 232 | )) 233 | } 234 | -- Include tasks 235 | if HELP == true 236 | all_tasks = [k for k, v in pairs env.tasks] 237 | undocumented_tasks = [k for k, v in pairs env.tasks when not state.tasks[k]] 238 | extra_message = { 239 | (Spacer!) 240 | (Paragraph 'Loaded tasks: (Use %{magenta}`alfons --help task`%{reset} to know more about said task)') 241 | (Columns {padding: 2}, [( 242 | Task task_name, task.description 243 | ) for task_name, task in pairs state.tasks when not (task.flags and contains task.flags, 'hide')]) 244 | (Spacer!) 245 | (Paragraph 'Undocumented tasks:') 246 | (Paragraph " %{cyan}#{table.concat undocumented_tasks, ' '}") 247 | } 248 | -- Add rest to help message 249 | for section in *extra_message 250 | table.insert help_message, section 251 | -- Display and exit 252 | print generateHelp help_message 253 | os.exit! 254 | 255 | -- run tasks, and teardown after each of them 256 | for command in *args.commands 257 | env.tasks[command] args[command] 258 | (rawget env.tasks, "teardown") if rawget env.tasks, "teardown" 259 | 260 | -- finalize 261 | env.finalize! 262 | -------------------------------------------------------------------------------- /bin/completion.bash: -------------------------------------------------------------------------------- 1 | # alfons completion -*- shell-script -*- 2 | 3 | _alfons_completions() { 4 | local cur prev opts 5 | COMPREPLY=() 6 | cur="${COMP_WORDS[COMP_CWORD]}" 7 | prev="${COMP_WORDS[COMP_CWORD-1]}" 8 | opts="--help --file -f --bash-list --bash-list-options" 9 | 10 | echo "cur: ${cur}\nprev: ${prev}" >> /tmp/alfons.log 11 | 12 | tasks=($(compgen -W "$(alfons --bash-list)" -- "$cur")) 13 | if [[ ${COMP_CWORD} -gt 1 ]] ; then 14 | task_options=($(compgen -W "$(alfons --bash-list-options $prev)" -- "$cur")) 15 | COMPREPLY+=( "${task_options[@]}" ) 16 | fi 17 | COMPREPLY+=( "${tasks[@]}" ) 18 | } 19 | 20 | complete -o nosort -F _alfons_completions alfons 21 | 22 | # ex: filetype=sh 23 | -------------------------------------------------------------------------------- /bin/completion.fish: -------------------------------------------------------------------------------- 1 | # clear completions 2 | complete -e alfons 3 | 4 | # remove file completion 5 | complete -c alfons -f 6 | 7 | # simple completions for --help --list --zsh-list --bash-list 8 | complete -c alfons -l help -d 'Show help' 9 | complete -c alfons -l list -d 'List tasks' 10 | complete -c alfons -l zsh-list -d 'List tasks (zsh/fish completion)' 11 | complete -c alfons -l bash-list -d 'List tasks (bash completion)' 12 | 13 | # complete -f and --file with paths 14 | complete -c alfons -s f -l file -r -F -d 'Use a specific task file' 15 | 16 | # function to find the used taskfile 17 | function __alfons_find_taskfile 18 | set -l taskfile '' 19 | set -l next 0 20 | for arg in (commandline -o) 21 | if [ $next = 1 ] 22 | set taskfile "$arg" 23 | break 24 | end 25 | if [ "$arg" = "-f" ]; or [ "$arg" = "--file" ] 26 | set next 1 27 | end 28 | end 29 | echo "$taskfile" 30 | end 31 | 32 | # function to get the command invocation for alfons with the taskfile 33 | function __alfons_invoke 34 | set -l taskfile (__alfons_find_taskfile) 35 | echo alfons 36 | if [ -n "$taskfile" ] 37 | echo -f 38 | echo "$taskfile" 39 | end 40 | end 41 | 42 | # function to complete the available tasks in the taskfile 43 | function __alfons_complete_tasks 44 | set -l alfons (__alfons_invoke) 45 | $alfons --zsh-list 2>/dev/null | sed s/:/\t/ 46 | end 47 | 48 | # function to list the available tasks in the taskfile 49 | function __alfons_list_tasks 50 | set -l alfons (__alfons_invoke) 51 | $alfons --list 2>/dev/null | sed 's/ /\n/g' 52 | end 53 | 54 | # function to list the available options for all tasks 55 | function __alfons_list_all_options 56 | set -l alfons (__alfons_invoke) 57 | for task in ($alfons --list 2>/dev/null | sed 's/ /\n/g') 58 | for option in ($alfons --list-options "$task" 2>/dev/null | sed 's/ /\n/g') 59 | echo "$task::$option" 60 | end 61 | end 62 | end 63 | 64 | # function to find the currently selected task 65 | function __alfons_selected_task 66 | set -l skip 0 67 | set -l task '' 68 | set -l first 1 69 | for arg in (commandline -o) 70 | if [ $first = 1 ]; or [ $skip = 1 ] 71 | set skip 0 72 | set first 0 73 | continue 74 | end 75 | if [ "$arg" = --list ] 76 | continue 77 | end 78 | if [ "$arg" = -f ]; or [ "$arg" = --file ]; or [ "$arg" = --help ] 79 | set skip 1 80 | set task '' 81 | else if [ (string sub -s1 -e1 -- "$arg") = '-' ] 82 | set skip 1 83 | else 84 | set task "$arg" 85 | end 86 | end 87 | echo "$task" 88 | end 89 | 90 | # function to complete options for the selected task 91 | function __alfons_complete_options 92 | set -l alfons (__alfons_invoke) 93 | set -l task (__alfons_selected_task) 94 | for option in ($alfons --zsh-list-options $task 2>/dev/null) 95 | set -l parts (string split -m1 -- '\:' "$option") 96 | printf '%s' $parts[1] 97 | if [ -n "$parts[2]" ] 98 | printf '\t' 99 | string sub -s2 -e-2 -- "$parts[2]" 100 | else 101 | echo 102 | end 103 | end 104 | 105 | end 106 | 107 | # function to check if we are in an option 108 | function __alfons_get_option 109 | set -l args (commandline -o) 110 | if [ (string sub -s1 -e1 -- "$args[-1]") = '-' ] 111 | printf '%s' "$args[-1]" 112 | end 113 | end 114 | 115 | # function to actually complete files if option asks for it 116 | function __alfons_needs_option 117 | set -l task (__alfons_selected_task) 118 | if [ -z "$task" ] 119 | return 1 120 | end 121 | set -l option (__alfons_get_option) 122 | if [ -z "$option" ] 123 | return 1 124 | end 125 | set -l alfons (__alfons_invoke) 126 | set -l type ($alfons --zsh-get-option-type "$task::$option" 2>/dev/null) 127 | for arg in $argv 128 | if [ "$type" = "$arg" ] 129 | return 0 130 | end 131 | end 132 | return 1 133 | end 134 | 135 | # complete the available tasks for the selected taskfile 136 | complete -c alfons -n '[ -z (__alfons_get_option) ]' -a '(__alfons_complete_tasks)' -d 'Run the task' 137 | 138 | # complete the help function with the available tasks 139 | complete -c alfons -l help -f -r -a '(__alfons_complete_tasks)' -d 'Show help for a task' 140 | 141 | # complete the list-options / zsh-list-options / bash-list-options function with the available tasks 142 | complete -c alfons -l list-options -f -r -a '(__alfons_list_tasks)' -d 'List options for a task' 143 | complete -c alfons -l zsh-list-options -f -r -a '(__alfons_list_tasks)' -d 'List options for a task (zsh/fish completion)' 144 | complete -c alfons -l bash-list-options -f -r -a '(__alfons_list_tasks)' -d 'List options for a task (bash completion)' 145 | 146 | # complete the get-option-type / zsh-get-option-type function 147 | complete -c alfons -l get-option-type -f -r -a '(__alfons_list_all_options)' -d 'Get the type of an option' 148 | complete -c alfons -l zsh-get-option-type -f -r -a '(__alfons_list_all_options)' -d 'Get the type of an option (zsh/fish completion)' 149 | 150 | # complete the task options for the selected task 151 | complete -c alfons -n '[ -n (__alfons_selected_task) ]; and [ -z (__alfons_get_option) ]' -a '(__alfons_complete_options)' -d 'Options for the task' 152 | 153 | # complete files if task option asks for file 154 | complete -c alfons -n '__alfons_needs_option _files _path_files' -F 155 | 156 | # complete users/groups if task option asks for it 157 | complete -c alfons -n '__alfons_needs_option _users' -a '(__fish_complete_users)' 158 | complete -c alfons -n '__alfons_needs_option _groups' -a '(__fish_complete_groups)' -------------------------------------------------------------------------------- /bin/completion.zsh: -------------------------------------------------------------------------------- 1 | #compdef alfons 2 | 3 | _alfons() { 4 | local state 5 | 6 | _arguments \ 7 | '--help[Show help message or help for a task]:help:->help' \ 8 | '(--file -f)'{--file=,-f}"[Taskfile to use]:taskfile:_files" \ 9 | '--zsh-list[List loaded tasks]' \ 10 | '--zsh-list-options[List loaded tasks for an option (ZSH)]' \ 11 | '--zsh-get-option-type[Get option completion for an option (ZSH)]' \ 12 | '*:Tasks:->task' 13 | 14 | case "$state" in 15 | task) 16 | # Task values 17 | taskvals="$(alfons --zsh-get-option-type ${words[-3]}::${words[-2]})" 18 | if [[ ! $(echo $taskvals | sed s/\n//g | sed s/\ //g) == "" ]]; then 19 | _arguments "*:Values for ${words[-2]}:$taskvals" 20 | fi 21 | # Task options 22 | taskopts=($(alfons --zsh-list-options ${words[-2]})) 23 | _arguments "*:Task options:(($taskopts))" 24 | # Tasks 25 | tasks=("${(@f)$(alfons --zsh-list)}") 26 | _describe -t tasks 'Tasks' tasks 27 | return 0 28 | ;; 29 | esac 30 | } 31 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Alfons 4 Documentation 2 | 3 | - [Tutorial](tutorial.md) 4 | - [Recipes](recipes.md) 5 | - [Arguments](arguments.md) 6 | - [Functions](provide.md) 7 | - [Environment](environment.md) 8 | - [Loading](loading.md) 9 | - [Teal support](teal.md) 10 | - [API](api.md) 11 | - [`build`](build.md) 12 | - [`watch`](watch.md) -------------------------------------------------------------------------------- /docs/api.md: -------------------------------------------------------------------------------- 1 | # Alfons API 2 | 3 | Starting with 4.2, Alfons provides an API to embed Alfons functionality in your programs. 4 | 5 | ## Contents 6 | - [Alfons API](#alfons-api) 7 | - [Contents](#contents) 8 | - [Installation](#installation) 9 | - [alfons.env](#alfonsenv) 10 | - [alfons.file](#alfonsfile) 11 | - [alfons.getopt](#alfonsgetopt) 12 | - [Argument parsing](#argument-parsing) 13 | - [alfons.look](#alfonslook) 14 | - [alfons.provide](#alfonsprovide) 15 | - [alfons.setfenv](#alfonssetfenv) 16 | - [alfons.version](#alfonsversion) 17 | - [alfons.help](#alfonshelp) 18 | - [alfons.parser](#alfonsparser) 19 | - [alfons.init](#alfonsinit) 20 | - [initEnv](#initenv) 21 | - [runString](#runstring) 22 | - [Understanding the global environment](#understanding-the-global-environment) 23 | - [Creating your own alfons clone](#creating-your-own-alfons-clone) 24 | - [Arguments](#arguments) 25 | - [Loading](#loading) 26 | - [Running](#running) 27 | - [Executing tasks](#executing-tasks) 28 | - [Finalize](#finalize) 29 | - [Finish](#finish) 30 | 31 | ## Installation 32 | 33 | You need to install the development rock instead of the upstream one. For that, follow these steps: 34 | 35 | ```sh 36 | # Clone project 37 | $ git clone https://github.com/daelvn/alfons.git 38 | # Install dependencies 39 | $ luarocks install moonscript 40 | $ luarocks install rockbuild 41 | $ luarocks install amalg 42 | # Create the runnable file 43 | $ alfons produce 44 | # Build the rockspec locally 45 | $ rockbuild -f rock-dev.yml -m --delete 4.4 # or change the version if you want 46 | ``` 47 | 48 | If there is enough demand, I'll upload the dev rockspec to LuaRocks with every release in form of an `alfons-extra` package or similar. 49 | 50 | The rock also installs optional dependencies for Alfons like `http` or `linotify`. If you do not wish to install them, feel free to edit the development rockframe. 51 | 52 | ## alfons.env 53 | 54 | `alfons.env` provides the default environment table (`ENVIRONMENT`), which does not include the functions in `alfons.provide`, and a function called `loadEnv` which takes a string of Lua code and a table, and will load the Lua code with the table as its environment. This function uses different mechanisms on different versions, due to `loadstring` being deprecated. 55 | 56 | ## alfons.file 57 | 58 | Contains a generic function `readFile` that reads a file content and loads it, an alias `readLua`, and then `readMoon` which compiles MoonScript content from a file before returning the Lua value, and `readTeal` for a Teal equivalent. 59 | ## alfons.getopt 60 | 61 | Contains a single function, `getopt`, which takes a list of arguments, and returns a table of parsed options. 62 | 63 | ### Argument parsing 64 | 65 | See [arguments.md](arguments.md) 66 | 67 | ## alfons.look 68 | 69 | `alfons.look` introduces a `require`-style module lookup function that instead of running them and returning its results, it returns the contents of the file. It returns a table with a function `makeLook`, which takes a package path (defaults to `package.path`) and returns a lookup function. This function takes a module name and returns the contents of the file found, or `nil` and an error otherwise. 70 | 71 | ## alfons.provide 72 | 73 | `provide` includes all the helper functions used in Taskfiles. 74 | 75 | See [Functions](provide.md). 76 | 77 | ## alfons.setfenv 78 | 79 | Returns a function (not a table). The function is simply a reimplementation of setfenv for Lua 5.2+ 80 | 81 | ## alfons.version 82 | 83 | Returns a table with a field `VERSION` which contains the current Alfons version. 84 | 85 | ## alfons.help 86 | 87 | Contains functions to generate help messages, including a column formatter. 88 | 89 | ## alfons.parser 90 | 91 | Contains the comment parser for documenting Taskfiles. 92 | 93 | ## alfons.init 94 | 95 | Provides the main functions required to run a Taskfile. 96 | 97 | ### initEnv 98 | 99 | `initEnv` takes a `run` function (see below), a base environment (defaults to `alfons.env`'s `ENVIRONMENT`), a private global environment table (referred to as `genv`), and a module name (defaults to `main`). It returns an environment ready to use in Taskfiles. This function is internal and should not really be used, so I will not explain it. 100 | 101 | ### runString 102 | 103 | `runString` takes: 104 | 105 | 1. either a string of Lua code or a module to perform lookup on (using `alfons.look`) as its first argument. 106 | 2. Then it takes a base environment (defaults to `alfons.env`'s `ENVIRONMENT`) 107 | 3. A boolean flag `runAlways` which determines whether the `always` task should be run or not. 108 | 4. A numeric `child` argument (actually unused) that determines how deep into the loaded Taskfiles you are (defaults to `0` for the main file and increments for children taskfiles when `load` is called). 109 | 5. A `genv`, where the tasks for all modules are neatly stored. Although you can set a starting value for this table (defaults to an empty one), you will not be able to access it again (unless you create the table before passing it and store the reference). 110 | 6. A reverse queue `rqueue` that determines the order in which the `default`, `teardown` and `finalize` tasks should be run. This queue should be reversed before running each task in it. 111 | 7. A boolean value that determines whether to pretty-print errors or not. 112 | 113 | It loads the contents of the Taskfile without executing it. 114 | 115 | It returns either the environment table (for accessing tasks and `store`) if it was already loaded or a function for running the Taskfile with arguments. These arguments will be processed by `alfons.getopt`. 116 | 117 | The function returned adds the `args` function to the environment, local to each taskfile. It also adds the function `uses`, for checking the argument list for commands. 118 | 119 | It runs the Alfons file and loads all tasks to `env.tasks`, where `env` represents the environment table. It wraps all tasks in a `run` function, which essentially pre-passes the name of the task (`@name`), and the task itself (`@task`). 120 | 121 | It also adds the `load` function to load taskfiles inside taskfiles. 122 | 123 | It runs the `always` task if the `runAlways` argument is enabled (defaults to `true`). 124 | 125 | Then it adds a trigger to run the `default` and `finalize` tasks. 126 | 127 | Finally, it returns the environment of the taskfile. It looks something like this, irrelevant parts skipped for convenience. These are the only things you will need to know. 128 | 129 | ```lua 130 | env = { 131 | tasks = {}, -- table to access all tasks 132 | store = {}, -- global storage 133 | finalize = function() end -- calls the `default` and `finalize` tasks. 134 | } 135 | ``` 136 | 137 | ### Understanding the global environment 138 | 139 | In the last section we mentioned `genv` and how you could initially set its value but not access it later. Lets look at its structure. 140 | 141 | ```lua 142 | genv = { 143 | ["main"] = {} -- this is main's environment 144 | ["fetch"] = {} -- environment for a subtaskfile 145 | } 146 | = { 147 | store = {} -- global storage is here 148 | } 149 | ``` 150 | 151 | Task lookup in the `env.tasks` table happens by looking at all the loaded taskfiles in `genv`. By adding more fields to `genv` initially, you can pre-load taskfiles without really loading them. 152 | 153 | The global storage is in `genv`'s metatable, which you can also preload values at. 154 | 155 | ### Creating your own alfons clone 156 | 157 | `bin/alfons.moon` is written in just a few lines of code, let's write a simplified version of it: 158 | 159 | #### Arguments 160 | 161 | First, lets get the list of tasks that we should run: 162 | 163 | ```moon 164 | import getopt from require "alfons.getopt" 165 | args = getopt {...} 166 | ``` 167 | 168 | #### Loading 169 | 170 | The official program supports custom taskfile locations, but for the sake of simplicity, we'll skip that and only allow loading `Alfons.lua`. 171 | 172 | ```moon 173 | import readLua from require "alfons.file" 174 | content, contentErr = readLua "Alfons.lua" 175 | unless content then error contentErr 176 | ``` 177 | 178 | #### Running 179 | 180 | This is a straightforward step to get the environment. 181 | 182 | ```moon 183 | import runString from require "alfons.init" 184 | alfons, alfonsErr = runString content 185 | unless alfons then error alfonsErr 186 | env = alfons ... 187 | ``` 188 | 189 | #### Executing tasks 190 | 191 | Now we need to run the tasks we have been asked for, with their respective arguments, and run `teardown` after each of them. 192 | 193 | ```moon 194 | for command in *args.commands 195 | env.tasks[command] args[command] if env.tasks[command] 196 | (rawget env.tasks, "teardown") if rawget env.tasks, "teardown" 197 | ``` 198 | 199 | #### Finalize 200 | 201 | Finally, simply call the trigger to run `default` tasks if no other task in each taskfile has been run, and `finalize` tasks. 202 | 203 | ```moon 204 | env.finalize! 205 | ``` 206 | 207 | #### Finish 208 | 209 | And just like that, we have implemented Alfons! It is a pretty simple tool, despite the looks of it, really. 210 | -------------------------------------------------------------------------------- /docs/arguments.md: -------------------------------------------------------------------------------- 1 | # Arguments 2 | 3 | Arguments can be a bit weird due to the nature of tasks. This is different from how it used to be in Alfons 3. 4 | 5 | Arguments that do not start with a hyphen (`-`) will be considered to be tasks to run. Every task will get its own set of arguments, passed after the task was called. Options in the format `-x` will be set as `{x = }`. Flags in the format `-ab` will be set as `{a = true, b = true}`. Options in the format `--abc` will be set as `{abc = }`. 6 | 7 | Let's see this with an example. This is our Alfonsfile: 8 | 9 | **MoonScript** 10 | 11 | ```moon 12 | tasks: 13 | first: => print @a 14 | second: => print @b 15 | ``` 16 | 17 | **Lua** 18 | 19 | ```lua 20 | function first(self) print(self.a) end 21 | function second(self) print(self.b) end 22 | ``` 23 | 24 | And if we call it like this, we will get the following output: 25 | 26 | ```sh 27 | $ alfons first -a Hello second -b World! 28 | Hello 29 | World! 30 | ``` 31 | 32 | The tasks don't have access to other tasks' arguments in their `self` variable. However, you can access the whole argument table with `args`. This makes the following snippet equivalent. 33 | 34 | **MoonScript** 35 | 36 | ```moon 37 | tasks: 38 | first: => print args.first.a 39 | second: => print args.second.b 40 | ``` 41 | 42 | **Lua** 43 | 44 | ```lua 45 | function first(self) print(args.first.a) end 46 | function second(self) print(args.second.b) end 47 | ``` 48 | 49 | ## Uses 50 | 51 | When running from the command line, a new function is provided (`uses`) that is effectively a shortcut for `contains args.commands, "task"`. It will check if another task was called. The task does not have to exist. You can use this for "subtasks", like `alfons docs serve`, instead of having to do `alfons docs --serve`, which is considerably *uglier*. 52 | 53 | **MoonScript** 54 | 55 | ```moon 56 | tasks: 57 | task: => 58 | if uses "subtask" 59 | print "subtask was called!" 60 | ``` 61 | 62 | **Lua** 63 | 64 | ```lua 65 | function task() 66 | if uses "subtask" then 67 | print "subtask was called!" 68 | end 69 | end 70 | ``` 71 | 72 | **Result** 73 | 74 | ``` 75 | $ alfons task subtask 76 | subtask was called! 77 | ``` 78 | 79 | ## Argument parsing 80 | 81 | Using `getopt`, you get a table `args` which contains the following information: 82 | 83 | ### Commands 84 | 85 | Commands are the tasks to be executed in Alfons. They can be found at the following places: 86 | 87 | `getopt {"task1"}` or `alfons task1` 88 | 89 | ```lua 90 | args = { 91 | task1 = {}, -- task arguments go here, name of field varies. 92 | commands = { "task1" } -- in order of use. 93 | } 94 | ``` 95 | 96 | ### Flags 97 | 98 | Flags are arguments without a value. They are all set to `true`. 99 | 100 | `getopt {"task", "-a"}` or `alfons task -a` 101 | 102 | ```lua 103 | args = { 104 | task = { 105 | ["a"] = true 106 | }, 107 | commands = { "task" } 108 | } 109 | ``` 110 | 111 | ### Options 112 | 113 | Options are arguments with a value. They are all set to their value. 114 | 115 | `getopt {"task", "--opt", "value"}` or `getopt {"task", "--opt=value"}` or `alfons task --opt value` or `alfons task --opt=value` 116 | 117 | ```lua 118 | args = { 119 | task = { 120 | ["opt"] = "value" 121 | }, 122 | commands = { "task" } 123 | } 124 | ``` 125 | 126 | ### Interpreting arguments 127 | 128 | - `--` alone passes the arguments that come after it as they are. 129 | - `x` will be treated as a **command** and all arguments after it are arguments to it. 130 | - `-x` will be paired with the argument after it as an **option** unless it is last in the list, in which case it is just a **flag**. 131 | - `-abc` represents three **flags**: `a`, `b` and `c`. 132 | - `--xa` will be paired with the next argument as an **option** unless it is last in the list, in which case it is just a **flag**. 133 | - `--xa=val` uses `val` as a value to an **option** `xa`. -------------------------------------------------------------------------------- /docs/autocompletion.md: -------------------------------------------------------------------------------- 1 | # Autocompletion 2 | 3 | Alfons 5.2 introduced dynamic shell autocompletion. That means that on most shells (but especially Zsh), you will get completions for tasks, task options and maybe even task values. 4 | 5 | ## Bash 6 | 7 | The Bash completion script is very poor. This is because Bash's autocompletion is very poor. It will list the available tasks, and if it can detect a task, also suggest the options for that task. 8 | 9 | ### Installing 10 | 11 | ``` 12 | # cp bin/completion.bash /etc/bash_completion.d/alfons 13 | ``` 14 | 15 | ## Zsh 16 | 17 | Zsh will autocomplete tasks, task options, and for certain task options, also suggest values. 18 | 19 | If a task option has a value of ``, ``, `` or ``, it will use Zsh's internal resolvers to complete suggestions. 20 | 21 | ### Installing 22 | 23 | Move the completion file to anywhere in your `$FPATH`. 24 | 25 | ```sh 26 | # Oh my Zsh! 27 | $ cp bin/completion.zsh $HOME/.oh-my-zsh/completions/_alfons 28 | # Hopefully cross platform 29 | $ sudo cp bin/completion.zsh /usr/share/zsh/functions/Completion/_alfons 30 | ``` 31 | 32 | ## Fish 33 | 34 | Fish will autocomplete arguments, tasks, task options and will suggest values for some task option types (same as zsh). 35 | 36 | It will use the currently selected taskfile (according to -f / --file) for the completion. 37 | 38 | ### Installing 39 | 40 | Move the completion file to your `$fish_complete_path` (typically `~/.config/fish/completions`), under the name `alfons.fish`. 41 | 42 | ```sh 43 | # Create the completion directory if it doesnt exist 44 | $ mkdir -p $HOME/.config/fish/completions 45 | # Add the completion file, with the correct name, so that fish finds it 46 | $ cp bin/completion.fish $HOME/.config/fish/completions/alfons.fish 47 | ``` -------------------------------------------------------------------------------- /docs/branding.md: -------------------------------------------------------------------------------- 1 | # Branding 2 | 3 | The Alfons Gradient goes, left to right, `#ffca05` to `#faac18`. 4 | The Alfons logo is a Bold, Oblique "A" in Cantarell font, with an arrow that comes from the middle and outwards to the left. 5 | 6 | -------------------------------------------------------------------------------- /docs/build.md: -------------------------------------------------------------------------------- 1 | # build 2 | 3 | `build` takes an iterator and a function. It gets all the files from the iterator, 4 | checks their modification time, compares it to a cache, and passes the filename to the function if the file was modified. 5 | 6 | ## Behavior 7 | 8 | The cache is stored in an `.alfons` file. If it does not exist, then all filenames will be passed to the function, and then stored in cache. If it does exist, then the comparison happens. 9 | 10 | ## Examples 11 | 12 | ### Compiling MoonScript 13 | 14 | ```lua 15 | compile = function(self) 16 | build((wildcard "**.moon"), function(file) 17 | sh "moonc " .. file 18 | end) 19 | end 20 | ``` 21 | 22 | ```moon 23 | tasks: 24 | compile: => 25 | build (wildcard "**.moon"), -> sh "moonc #{file}" 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/documenting.md: -------------------------------------------------------------------------------- 1 | # Documenting 2 | 3 | In Alfons 5.2, a new feature was implemented to document your own Taskfiles. Previously, there was no way to generate a help message, or to have shell completion. Thanks to the docstrings, and a little bit of magic, this is now possible. 4 | 5 | ## Docstrings 6 | 7 | Docstrings are comments in the Taskfile that begin with `---`. These are followed by a tag (`@task`, `@argument`, `@flag`) that determines how the rest of the comment will be parsed. 8 | 9 | The docstrings are untied from the actual code since it needs to be language-agnostic, and there are many ways within a single language to define tasks. As such, the tasks displayed in the new help message are a mix between documented tasks, and undocumented tasks read from the Taskfile. 10 | 11 | ## Declaring a task 12 | 13 | `--- @task name Description of the task.` 14 | 15 | A task is declared using the docstring above. 16 | 17 | ## Declaring an option for a task 18 | 19 | `--- @option task [long s] Description of the option.` 20 | `--- @option task [long s] Description of the flag (no value).` 21 | 22 | The docstring above has several parts. First, the name of the task that you are referencing. Then, between square brackets, you have to put all the forms of the option, the long preferrably first. Between the angle brackets, you can put each of the expected values. Everything that comes afterward is the description of the option. 23 | 24 | ## Flagging 25 | 26 | `--- @flag * hide` 27 | `--- @flag task hide` 28 | 29 | As of right now, the only flag available is `hide`, which makes either all tasks (`*`) or a task invisible to autocompletion and the help message. 30 | -------------------------------------------------------------------------------- /docs/environment.md: -------------------------------------------------------------------------------- 1 | # Environment 2 | 3 | This is the environment being passed to Alfonsfiles, along with everything on `provide`. 4 | 5 | ```moon 6 | -- environment for alfons files 7 | ENVIRONMENT = { 8 | :_VERSION 9 | :assert, :error, :pcall, :xpcall 10 | :tonumber, :tostring 11 | :select, :type, :pairs, :ipairs, :next, :unpack 12 | :require 13 | :print, :style -- from ansikit 14 | :io, :math, :string, :table, :os 15 | :fs -- fs is either CC/fs or lpath.fs 16 | :path, :env, :fsinfo -- lpath, lpath.env and lpath.info respectively 17 | } 18 | ``` 19 | 20 | ## Accessing tasks 21 | 22 | Any defined task can be called using the `tasks` table. Just do `task.name!` to call it or pass a table if you want to use arguments. You can access any task, anywhere; it is allowed to call tasks from taskfiles you included, and those taskfiles will be able to use tasks of the parent taskfile. Metatable magic is used to that "local" tasks are always preferred over tasks from other taskfiles. 23 | 24 | You can check if a task exists by using the `exists` function, that takes a string (the requested task name). 25 | 26 | ### Global tasks 27 | 28 | The `tasks` table can only access tasks that are at the same level or below it (subtasks). Because of how Alfons' internals work, it is possible to access higher tasks. As of 4.4, you can do this via the magic table `gtasks`. It appears to be empty, but indexing it will return the first task that has the same name. To check if a task exists globally, use `gexists` (takes a string, the requested task name). 29 | 30 | ```moon 31 | tasks: 32 | always: => gtasks.example! 33 | ``` 34 | 35 | ## Store 36 | 37 | `store` is a table shared across all tables that you can use to pass data to other taskfiles or generally just create configuration fields. 38 | 39 | ### Callstack 40 | 41 | Starting in Alfons 4.3, a new predefined field in `store` named `callstack` contains a stack of the currently executing functions. Peeking the stack (`store.callstack[#store.callstack]`) will return the function that is currently being executed, and should be equivalent to `@name`. This was necessary to implement [`calls`](docs/provide.md#calls). 42 | -------------------------------------------------------------------------------- /docs/loading.md: -------------------------------------------------------------------------------- 1 | # Loading other taskfiles 2 | 3 | You can load other taskfiles using `load`, which takes a taskfile *module path* and loads it. They are loaded such as to the main taskfile, there is no distinction between them, and it can access the subtasks just as well as its own. 4 | 5 | ## Placement 6 | 7 | Trying to use a task `project.taskfile` will look for a module `alfons.tasks.project.taskfile`. We implemented our own path search function that uses `package.path`, so it should load them identically to how `require` does. We needed to implement this function since taskfiles are loaded using the content string, and require would pre-load it. 8 | 9 | As such, you can place your tasks in a local directory `alfons/tasks/`, or anywhere on your Lua path. You can also create LuaRocks rockspecs that supply their own taskfiles in that module path. 10 | 11 | ## Loading 12 | 13 | You should always (eheheh) load your taskfiles in the `always` task. 14 | 15 | ```lua 16 | function always() 17 | load "fetch" 18 | end 19 | 20 | function default() 21 | print(tasks.fetch("https://example.com")) 22 | end 23 | ``` 24 | 25 | ```moon 26 | tasks: 27 | always: => load "fetch" 28 | default: => print tasks.fetch "https://example.com" 29 | ``` 30 | 31 | ## Scope 32 | 33 | Your tasks will automatically be available from all other taskfiles that have been loaded and the main one. 34 | 35 | ![Dependency Graph](../.github/dependency-graph.png) 36 | 37 | Rather than writing a linear stream of code here to display what I mean, I decided to just use a graph. These are all loaded taskfiles. 38 | 39 | The main taskfile is able to access all of its children's tasks. `a` is not only able to access the main tasks and tasks from `d` and `e`, but also from *every other* taskfile that has been loaded. 40 | 41 | This does not hold true for the `always` task, where it will depend on loading order, but since the rest of the tasks are called only once all taskfiles have been loaded, tasks that are not `always` can access any other task. -------------------------------------------------------------------------------- /docs/provide.md: -------------------------------------------------------------------------------- 1 | # Functions 2 | 3 | This is the documentation for the functions provided in the Alfons environment. 4 | 5 | To see the documentation for `build` and `watch`, check out their respective markdown files. 6 | 7 | ## Table of Contents 8 | 9 | - [Functions](#functions) 10 | - [Table of Contents](#table-of-contents) 11 | - [Tables](#tables) 12 | - [npairs](#npairs) 13 | - [env](#env) 14 | - [keys](#keys) 15 | - [values](#values) 16 | - [entries](#entries) 17 | - [fromEntries](#fromentries) 18 | - [Arrays](#arrays) 19 | - [map](#map) 20 | - [reduce](#reduce) 21 | - [filter](#filter) 22 | - [slice](#slice) 23 | - [contains](#contains) 24 | - [Strings](#strings) 25 | - [lines](#lines) 26 | - [split](#split) 27 | - [sanitize](#sanitize) 28 | - [IO](#io) 29 | - [prints](#prints) 30 | - [printError](#printerror) 31 | - [safeOpen](#safeopen) 32 | - [safePopen](#safepopen) 33 | - [readfile](#readfile) 34 | - [writefile](#writefile) 35 | - [serialize](#serialize) 36 | - [ask](#ask) 37 | - [show](#show) 38 | - [cmd](#cmd) 39 | - [cmdfail](#cmdfail) 40 | - [cmdread](#cmdread) 41 | - [FS](#fs) 42 | - [isEmpty](#isempty) 43 | - [delete](#delete) 44 | - [copy](#copy) 45 | - [wildcard](#wildcard) 46 | - [iwildcard](#iwildcard) 47 | - [listAll](#listall) 48 | - [Path](#path) 49 | - [basename](#basename) 50 | - [extension](#extension) 51 | - [filename](#filename) 52 | - [pathname](#pathname) 53 | - [load](#load) 54 | - [style](#style) 55 | - [Importable](#importable) 56 | - [fetch](#fetch) 57 | 58 | ## Tables 59 | 60 | ### npairs 61 | 62 | Exactly like [ipairs](https://www.lua.org/manual/5.4/manual.html#pdf-ipairs), but it does not stop after a `nil` value. 63 | 64 | ### env 65 | 66 | If you run Alfons as: 67 | 68 | ```sh 69 | $ TEST=5 alfons 70 | ``` 71 | 72 | You can access `TEST` by using `env.TEST`. 73 | 74 | ### keys 75 | 76 | `keys (table:{*:*}) -> [*]` 77 | 78 | Returns all the keys in a table. 79 | 80 | ### values 81 | 82 | `values (table:{*:*}) -> [*]` 83 | 84 | Returns all the values in a table. 85 | 86 | ### entries 87 | 88 | `entries (table:{*:*}) -> [{*,*}]` 89 | 90 | Returns an array of `{key, value}` tuples made from the keys and values of a table. 91 | 92 | ### fromEntries 93 | 94 | `fromEntries (entries:[{*,*}]) -> {*:*}` 95 | 96 | Reverses the process of `entries`. 97 | 98 | ## Arrays 99 | 100 | ### map 101 | 102 | `map (arr:[*], predicate:(value:*, key:*) -> *) -> [*]` 103 | 104 | Maps over an array. 105 | 106 | ### reduce 107 | 108 | `reduce (arr:[*], predicate:(accumulator:*, value:*) -> *, initial: *?) -> *` 109 | 110 | Reduces an array to a single value using an accumulator. Equivalent to `foldl`. 111 | 112 | ### filter 113 | 114 | `filter (arr:[*], predicate:(value:*, key: *) -> boolean) -> [*]` 115 | 116 | Creates a new array with only the values that pass the predicate. 117 | 118 | ### slice 119 | 120 | `slice (arr:[*], start:number?, end:number?) -> [*]` 121 | 122 | Creates a slice of an array that starts at `start` and ends at `end`. 123 | 124 | ### contains 125 | 126 | `contains (arr:[*], value:*) -> boolean` 127 | 128 | Checks if an array contains a certain value. 129 | 130 | ## Strings 131 | 132 | ### lines 133 | 134 | `lines (string) -> [string]` 135 | 136 | Splits a string into lines. 137 | 138 | ### split 139 | 140 | `split (str:string, re:string, plain:boolean, matches:number) -> [string]` 141 | 142 | Splits a string `str` into parts by a pattern `re`, which is interpreted as a Lua pattern except if the `plain` flag is set to true. Additionally, a maximum number of matches can be set with the `matches` argument. 143 | 144 | ### sanitize 145 | 146 | `sanitize (string) -> string` 147 | 148 | Makes sure that a string is safe to use in patterns without magic characters. 149 | 150 | ## IO 151 | 152 | ### prints 153 | 154 | `prints (...) -> nil` 155 | 156 | `print` and `style` (from [ansikit](https://git.daelvn.com/ansikit)) together. 157 | 158 | ### printError 159 | 160 | `printError (text:string) -> nil` 161 | 162 | Prints a string in red. 163 | 164 | ### safeOpen 165 | 166 | `safeOpen (file:string, mode:string) -> io | {["error"]:string}` 167 | 168 | Returns a table with an error string if the file could not be opened properly. 169 | 170 | ### safePopen 171 | 172 | `safePopen (command:string, mode:string) -> io | {["error"]:string}` 173 | 174 | Equivalent to `safeOpen`, but for `io.popen`. 175 | 176 | ### readfile 177 | 178 | `readfile (file:string) -> string` 179 | 180 | Takes a filename and returns its contents. 181 | 182 | ### writefile 183 | 184 | `writefile (file:string, content:string) -> nil` 185 | 186 | Takes a filename and a string, and writes the string to it. 187 | 188 | ### serialize 189 | 190 | `serialize (t:table) -> string` 191 | 192 | Quick table serializing, not useful in most cases. Used in `build`. 193 | 194 | ### ask 195 | 196 | `ask (str:string) -> string` 197 | 198 | Gets input from the user, with a prompt (optionally styled). 199 | 200 | ### show 201 | 202 | `show (str:string) -> nil` 203 | 204 | Displays a message, but fancy. 205 | 206 | ### cmd 207 | 208 | `cmd (str:string) -> number` 209 | 210 | `cmd`/`sh` as an alias to `os.execute`. 211 | 212 | ### cmdfail 213 | 214 | `cmdfail (str:string) -> nil` 215 | 216 | `cmdfail`/`shfail` is a wrapper around `os.execute` that will exit the program with the code returned by `os.execute` if it is not 0. For example, trying to run a program that does not exist will exit alfons with code 127. 217 | 218 | ### cmdread 219 | 220 | `cmdread (command:string) -> string` 221 | 222 | `cmdread` uses `safePopen` (`io.popen`) to execute a command and return all of its output. If `popen` did not work, it returns the error as a string. 223 | 224 | ## FS 225 | 226 | ### isEmpty 227 | 228 | `isEmpty (dir:string) -> boolean` 229 | 230 | Checks if a directory is empty 231 | 232 | ### delete 233 | 234 | `delete (path:string)` 235 | 236 | Deletes a file or folder recursively. 237 | 238 | ### copy 239 | 240 | `copy (fr:string, to:string)` 241 | 242 | Copies a file or folder recursively. 243 | 244 | ### wildcard 245 | 246 | `wildcard (path:string) -> function (iterator)` 247 | 248 | Iterable globbing that lets you do things such as: 249 | 250 | ```moon 251 | compileall: => 252 | for file in wildcard "*.moon" 253 | sh "moonc #{file}" 254 | ``` 255 | 256 | ### iwildcard 257 | 258 | `iwildcard (paths:table) -> function (iterator)` 259 | 260 | A wrapper around `wildcard`, that lets you use several globs. 261 | 262 | ```moon 263 | seeall: => 264 | for file in iwildcard {"*.moon", "*.lua"} 265 | sh "cat #{file}" 266 | ``` 267 | 268 | ### listAll 269 | 270 | `listAll (path:string) -> [string]` 271 | 272 | Returns a list of all nodes in `path` recursively. 273 | 274 | ## Path 275 | 276 | ### basename 277 | 278 | `basename (file:string) -> string` 279 | 280 | Returns everything but the extension of a file. 281 | 282 | ### extension 283 | 284 | `extension (file:string) -> string` 285 | 286 | Returns only the extension of a file without the dot. 287 | 288 | ### filename 289 | 290 | `filename (file:string) -> string` 291 | 292 | Returns only the filename without extension and parent path. `/home/daelvn/test.txt` becomes `test`. 293 | 294 | ### pathname 295 | 296 | `pathname (file:string) -> string` 297 | 298 | Returns the parent path of a file or folder. 299 | 300 | ### load 301 | 302 | `load (name)` imports tasks defined in `alfons.tasks.name` and lets you access them from the tasks table, so you can run them from the command line and from other tasks. You can create your own LuaRocks modules which export something as `alfons.tasks.*` to add custom tasks, or just create a local folder `alfons/tasks/` and it will load from them too. 303 | 304 | Please look at [Loading](loading.md) for more detailed documentatin. 305 | 306 | ### style 307 | 308 | As it is imported/defined from Alfons, it is now available to the environment. You can now use the [`style` function from Ansikit](https://git.daelvn.com/ansikit/module/style/#style) in Alfons. 309 | 310 | ```moon 311 | tasks 312 | pretty: => print style "%{blue}#{@name}" 313 | ``` 314 | 315 | ## Importable 316 | 317 | These are tasks that can be imported with `load "task"`. 318 | 319 | ### fetch 320 | 321 | `fetch` will return the contents of a URL over HTTP. It uses [lua-http](https://github.com/daurnimator/lua-http) 322 | 323 | ```sh 324 | $ luarocks install http 325 | ``` 326 | 327 | The task gets an URL, and simply returns the contents as a string: 328 | 329 | ```lua 330 | function always () 331 | load "fetch" 332 | end 333 | function printurl (self) 334 | print(tasks.fetch{url="https://example.com"}) 335 | end 336 | ``` 337 | 338 | ```moon 339 | tasks: 340 | always: => load "fetch" 341 | printurl: => print tasks.fetch url: "https://example.com" 342 | ``` 343 | 344 | If you need to write the contents to a file, you can use `writefile`: 345 | 346 | ```lua 347 | function always () 348 | load "fetch" 349 | end 350 | function download (self) 351 | writefile(self.file, tasks.fetch{url = self.url}) 352 | end 353 | function main (self) 354 | tasks.download{url="https://example.com", file="index.html"} 355 | end 356 | ``` 357 | 358 | ```moon 359 | tasks: 360 | always: => 361 | load "fetch" 362 | download: => 363 | writefile @file, tasks.fetch url: @url 364 | main: => 365 | tasks.download url:"https://example.com", file: "index.html" 366 | ``` 367 | -------------------------------------------------------------------------------- /docs/recipes.md: -------------------------------------------------------------------------------- 1 | # Recipes 2 | 3 | ## Amalg.lua 4 | 5 | Requires [amalg.lua](rockbuild -m -t #{@v} u) 6 | 7 | ### Pack 8 | 9 | ```lua 10 | function pack(self) 11 | show("Packing using amalg.lua") 12 | -- options 13 | self.o = self.o or self.output or "out.lua" 14 | self.s = self.s or self.entry or "src/main.lua" 15 | -- collect modules 16 | local modules = {} 17 | for file in wildcard "src/*.lua" do modules[#modules+1] = "src." .. filename(file) end 18 | -- pack 19 | sh("amalg.lua -o " .. self.o .. " -s " .. self.s .. " " .. table.concat(modules, " ")) 20 | ``` 21 | 22 | ```moon 23 | pack: => 24 | show "Packing using amalg.lua" 25 | @o or= @output or "alfons.lua" 26 | @s or= @entry or "bin/alfons.lua" 27 | modules = for file in wildcard "alfons/*.moon" do "alfons.#{filename file}" 28 | sh "amalg.lua -o #{@o} -s #{@s} #{table.concat modules, ' '}" 29 | ``` 30 | 31 | ## Rockbuild 32 | 33 | Requires [rockbuild](https://github.com/daelvn/rockbuild) 34 | 35 | ### Make 36 | 37 | ```lua 38 | function make(self) 39 | if self.v 40 | sh("rockbuild -m --delete " .. v) 41 | end 42 | end 43 | ``` 44 | 45 | ### Release 46 | 47 | ```lua 48 | function release(self) 49 | if self.v 50 | sh("rockbuild -m -t " .. v .. " u") 51 | end 52 | end 53 | ``` 54 | 55 | ## MoonScript 56 | 57 | ### Compile 58 | 59 | ```moon 60 | compile: => for file in wildcard "**.moon" 61 | sh "moonc #{file}" unless file == "Alfons.moon" 62 | ``` 63 | 64 | ### Build 65 | 66 | ```moon 67 | build: => build (wildcard "**.moon"), (file) -> sh "moonc #{file}" 68 | ``` 69 | 70 | ### Watch 71 | 72 | Requires `inotify` LuaRocks package. 73 | 74 | ```moon 75 | -- WATCH dirs, exclude, mode, match, process 76 | watch: => watch {"."}, {".git"}, "live", (glob "*.moon"), (file, ev) -> sh "moonc #{file}" 77 | ``` 78 | 79 | ### Clean 80 | 81 | ```moon 82 | clean: => delete file for file in wildcard "**.lua" 83 | ``` 84 | -------------------------------------------------------------------------------- /docs/teal.md: -------------------------------------------------------------------------------- 1 | # Teal support 2 | 3 | > **WARNING:** Teal support is **experimental** and relies on the Teal Compiler API that is subject to change. Use this at your own risk. It may be deprecated at any moment. To use, install the `tl` rock. 4 | 5 | ## Taskfiles 6 | 7 | Taskfiles can be written in Teal, and you can use an `Alfons.tl` file just as you would an `Alfons.lua` or an `Alfons.moon` file. You may have some trouble with `tl check` warning you about unknown variables like `tasks` or `store`, as well as the many functions that are not specified as types. Teal support is **experimental** and it will still take time to accomodate Alfons to the type system. 8 | 9 | ### Defining a taskfile 10 | 11 | While you can just define it as a Lua taskfile, feel free to use this template if you really, really care about types. Remember that you must declare your functions as globals! 12 | 13 | ```lua 14 | -- This definition is optional. Feel free to use `self:table` 15 | -- instead. 16 | -- If you are from the Teal team, and know how to include this 17 | -- type automatically, let me know! 18 | local record Self 19 | metamethod __index: {string:any} 20 | name: string 21 | task: function -- it takes nothing and returns nothing 22 | end 23 | 24 | global function always(self:Self) 25 | print(self.name) 26 | end 27 | ``` 28 | 29 | ## Teal plugin 30 | 31 | The `alfons-teal` rock (included in this repo but installed separately) provides a `teal` plugin that you can use via `load` (see more [here](loading.md)). The functionality for that plugin is described here. 32 | 33 | This plugin exports the following commands, which you should not overwrite: **`install`, `build`, `typings`**. 34 | 35 | ### Installing LuaRocks dependencies 36 | 37 | > **WARNING:** LuaRocks does **not** have an official updated API, so this task resorts to running `sh "luarocks install dependency"`. LuaRocks must therefore be a command available in your PATH. If you are a LuaRocks developer and know how to fix this, PRs welcome! 38 | 39 | Upon calling the `install` task, it will install all dependencies from `store.dependencies`, which must be a list of strings, each a valid LuaRocks package. You can make it execute automatically by doing `store.teal_auto = true`. 40 | 41 | ```lua 42 | global function always() 43 | load "teal" 44 | store.dependencies = {"tl", "busted"} 45 | end 46 | ``` 47 | 48 | ### Building 49 | 50 | The `build` task is simply a wrapper for `tl build`, since I figured that implementing this as an Alfons plugin would be way overkill. 51 | 52 | ### Hooks 53 | 54 | The `teal` plugin can run several kinds of hooks: 55 | 56 | - Pre-install (`teal_preinstall`) 57 | - Post-install (`teal_postinstall`) 58 | - Pre-build (`teal_prebuild`) 59 | - Post-build (`teal_postbuild`) 60 | 61 | Simply define these tasks, and they will be run accordingly! 62 | 63 | ### Downloading typings. 64 | 65 | > **WARNING:** This task requires the `dkjson` and `http` packages, which you must install before using this. Otherwise, there would be no way of fetching the content. 66 | 67 | The `alfons-teal` can download type definitions from the [teal-types](//github.com/teal-language/teal-types) repository and into your current working directory, using the `typings` task. 68 | 69 | ### CLI 70 | 71 | You can do this from the CLI by just loading the `teal` plugin and doing: 72 | 73 | ``` 74 | $ alfons typings -m 75 | ``` 76 | 77 | ### Taskfile 78 | 79 | When you call `tasks.typings()`, it will automatically try to use `store.typings` (a list of strings) as a source for what rocks to fetch type definitions for. You can make it do this automatically by setting `store.teal_auto` to `true`. 80 | 81 | ```lua 82 | -- Lua 83 | tasks.typings{ modules = {"..."} } 84 | -- MoonScript 85 | tasks.typings modules: {"..."} 86 | ``` 87 | 88 | ## Showcase 89 | 90 | This is a short "tutorial" on how to use the `teal` plugin. 91 | 92 | ### Loading 93 | 94 | Like any other module, you put the load declaration in the `always` task. 95 | 96 | ```lua 97 | global function always() 98 | load "teal" 99 | end 100 | ``` 101 | 102 | ### Defining dependencies 103 | 104 | Simply set `store.dependencies` to a table containing strings, each a valid LuaRocks package before calling the `tasks.install()` tasks in the Taskfile (or `alfons install` in the command-line). You can make it do this automatically every time you open Alfons by setting `store.teal_auto = true`. 105 | 106 | ### Building 107 | 108 | `alfons build` (or `tasks.build()`) becomes an alias to `tl build` on the command-line. 109 | 110 | ### Downloading type definitions 111 | 112 | See [Downloading typings](#downloading-typings). 113 | 114 | ### Declaring hooks 115 | 116 | To define a hook, simply define another global function with the names specified in [Hooks](#hooks). 117 | 118 | ```lua 119 | global function always() 120 | store.install = false 121 | load "teal" 122 | end 123 | 124 | global function teal_postinstall() 125 | prints "Dependencies installed!" 126 | end 127 | ``` -------------------------------------------------------------------------------- /docs/tutorial.md: -------------------------------------------------------------------------------- 1 | # Alfons for The Inexperienced Alfonsnsner 2 | 3 | Hello, traveller! In this tutorial, I will be assuming this is your first time using Alfons. I will make it as easy to follow as possible. Put on your best programming socks and follow me into this deep abyss that Alfons represents. 4 | 5 | - [Alfons for The Inexperienced Alfonsnsner](#alfons-for-the-inexperienced-alfonsnsner) 6 | - [Installing](#installing) 7 | - [Familiarizing with the interface](#familiarizing-with-the-interface) 8 | - [Taskfiles](#taskfiles) 9 | - [Two tasks?!?!?!](#two-tasks) 10 | - [Introspection](#introspection) 11 | - [Task arguments](#task-arguments) 12 | - [Calling other tasks](#calling-other-tasks) 13 | - [Storing data](#storing-data) 14 | - [Exploring](#exploring) 15 | 16 | ## Installing 17 | 18 | The proper way of installing Alfons is through LuaRocks. If you're on Linux, you're smart enough to know how to install LuaRocks. If you're on Windows, may a higher force save you. If you're on neither, I'm sorry. 19 | 20 | ``` 21 | $ luarocks install alfons 22 | ``` 23 | 24 | Of course, the fancy way of installing Alfons would be through Alfons! But Alfons is not a package manager... yet. Stay tuned for Alfons 27. 25 | 26 | Make sure that Alfons is installed ok and most importantly, that I didn't fuck up the build. If you get this message, you're good to go. 27 | 28 | ``` 29 | $ alfons 30 | Alfons 4.2 31 | No Taskfile found. 32 | ``` 33 | 34 | ## Familiarizing with the interface 35 | 36 | When Alfons is run, it looks for `Alfons.lua` first, and then `Alfons.moon`. That's right, Alfons works with both Lua and MoonScript (as long as you have MoonScript installed). I know, I know, MoonScript sucks, that's why I'm writing this tutorial for Lua only. No, I'm not dropping MoonScript support. 37 | 38 | If you want to change the file used, you can pass an `-f` or `--file` option to Alfons, and it will use that instead. Unless the file ends in `lua` or `moon`, you will have to tell it the type of language it is using the `--type` option, which accept values `moon` and `lua`. 39 | 40 | ``` 41 | $ alfons --file example.txt --type lua 42 | Alfons 4.2 43 | Using example.txt (lua) 44 | Could not open example.txt: example.txt: No such file or directory 45 | ``` 46 | 47 | ## Taskfiles 48 | 49 | Now, the moment we were all waiting for. What does this piece of garbage _actually_ do? It just runs defined and named snippets of code. Tasks, if you will. It runs tasks. It takes the names of the tasks you want to run, and runs them. You can make tasks depend on other tasks. You can have tasks for practically anything. We put them in a Taskfile. We will be using `Alfons.lua`. Create that file and then just put this in it: 50 | 51 | ```lua 52 | function hello() 53 | print("Hello, world!") 54 | end 55 | ``` 56 | 57 | Now, when you run Alfons, nothing will happen. We need to tell it to run your task. This is quite simple, just do `alfons hello`: 58 | 59 | ``` 60 | $ alfons hello 61 | Alfons 4.2 62 | Using Alfons.lua (lua) 63 | Hello, world! 64 | ``` 65 | 66 | Good! You got your first taskfile running. 67 | 68 | ## Two tasks?!?!?! 69 | 70 | Let's say, hypothetically, that you wanted a task to build and another to clean. Let's say, hypothetically, that Alfons could do that. Just kidding, of course it can. The only thing it can't do is bring back my kids. Just write as many functions as you'd like right beside each other. The order is actually irrelevant. 71 | 72 | ```lua 73 | function build() 74 | writefile("build.txt", "build information here") 75 | end 76 | 77 | function clean() 78 | delete("build.txt") 79 | end 80 | ``` 81 | 82 | Here there are two functions that you might not recognize. You can read about `writefile` [here](provide.md#writefile) and `fs` [here](provide.md#delete). It's recommended that you familiarize yourself with the functions that come with Alfons as they will make your life much easier. 83 | 84 | Now you can just call them one after each other: `alfons build clean` 85 | 86 | ## Introspection 87 | 88 | All functions accept a single argument called `self`. Admittedly it's a bit empty and underused, but it does an honest job. It contains a field `name` with the name of the task, in case you're procedurally generating them or something. It also contains a field `task` that contains the task itself, if you want to call it recursively. That function takes a table of arguments instead of varargs. 89 | 90 | ```lua 91 | function myself(self) 92 | print("I am " .. self.name) 93 | end 94 | ``` 95 | 96 | ## Task arguments 97 | 98 | Now, for a spin, you can make a task take arguments, like flags and options. To see specifically how they are parsed, look at [this manual page](arguments.md). The arguments can be anything you want, and they will be passed as a table to the functions through the `self` table. Write a task like this: 99 | 100 | ```lua 101 | function word(self) 102 | print("My favorite word is " .. self.word) 103 | end 104 | ``` 105 | 106 | Now, if you call it with the `word` option, it will speak back to you! 107 | 108 | ``` 109 | $ alfons word --word oboe 110 | Alfons 4.2 111 | Using Alfons.lua (lua) 112 | My favorite word is oboe 113 | ``` 114 | 115 | ## Calling other tasks 116 | 117 | Writing many tasks is fun until you start to have to reuse code. You could still make local functions, there's nothing stopping you from doing that, I promise, but chances are that at one point you will want to call another task. In Lua, I _think_ you might be able to call the function directly? It won't have the `name` and `task` fields that's for sure. I also think it won't count towards the total tasks-run number. For your own protection, please use the following method, which is just the `tasks` table: 118 | 119 | ```lua 120 | function main() 121 | tasks.another() 122 | end 123 | 124 | function another() 125 | print "It worked!" 126 | end 127 | ``` 128 | 129 | Now just run `alfons main` and try it out! 130 | 131 | ## Storing data 132 | 133 | A way to store data and make it available to all tasks at any given time is using the `store` table. It's just a normal table, but available across every Taskfile that you load. 134 | 135 | ```lua 136 | function stores() 137 | store.field = true 138 | end 139 | 140 | function gets() 141 | print(store.field) 142 | end 143 | ``` 144 | 145 | Running `alfons stores gets` will get you `true`! 146 | 147 | ## Exploring 148 | 149 | Those are pretty much the basics to Alfons. From here, it's just exploring! Check out the [Recipes](recipes.md) page for some cool tasks for Alfons. 150 | -------------------------------------------------------------------------------- /docs/watch.md: -------------------------------------------------------------------------------- 1 | # watch 2 | 3 | Watch uses `inotify` to listen for filesystem events and call the function with the path and event name. Its signature is this: 4 | 5 | `watch (dirs:{string}, exclude:{string}, evf:{string}, pred:(file -> boolean), fn:(file -> nil)) -> nil` 6 | 7 | ## dirs 8 | 9 | `dirs` is a list of directories to watch files in. 10 | 11 | ## exclude 12 | 13 | `exclude` is a list of directories to exclude from the first list. If you have `.` in the first, you might want to exclude `.git`, for example. 14 | 15 | ## evf 16 | 17 | List of events to listen for. This is the full list. Check the [inotify manpage](https://linux.die.net/man/7/inotify) for more info. Optionally you can pass a string instead of a table, accepting only one value as of now; `"live"`, which is equivalent to `{"write", "movein", "create"}` 18 | 19 | ```moon 20 | EVENTS = { 21 | access: "IN_ACCESS" 22 | change: "IN_ATTRIB" 23 | write: "IN_CLOSE_WRITE" 24 | shut: "IN_CLOSE_NOWRITE" 25 | close: "IN_CLOSE" 26 | create: "IN_CREATE" 27 | delete: "IN_DELETE" 28 | destruct: "IN_DELETE_SELF" 29 | modify: "IN_MODIFY" 30 | migrate: "IN_MOVE_SELF" 31 | move: "IN_MOVE" 32 | movein: "IN_MOVED_TO" 33 | moveout: "IN_MOVED_FROM" 34 | open: "IN_OPEN" 35 | all: "IN_ALL_EVENT" 36 | } 37 | ``` 38 | 39 | ## pred 40 | 41 | The predicate function, which takes in a filename and the triggered event list(as separate arguments), and should return a boolean deciding whether to accept the event or not. 42 | 43 | ## fn 44 | 45 | The processor function, which takes the filename and triggered event list, and is basically what should do things like compiling and such. 46 | 47 | ## Examples 48 | 49 | ### Watching MoonScript files 50 | 51 | ```moon 52 | tasks: 53 | compile: => 54 | watch {"."}, {".git"}, "live", (glob "*.moon"), (file, ev) -> sh "moonc #{file}" 55 | ``` -------------------------------------------------------------------------------- /rock-dev.yml: -------------------------------------------------------------------------------- 1 | package: alfons-dev 2 | source: 3 | url: git://github.com/daelvn/alfons 4 | description: 5 | summary: Unpacked Alfons modules for development 6 | detailed: > 7 | The normal 'alfons' package is bundled, making all 8 | modules unavailable. 'alfons-dev' installs them 9 | without bundling. 10 | homepage: https://github.com/daelvn/alfons 11 | dependencies: 12 | - lpath 13 | - ansikit 14 | - lua >= 5.1 15 | - inotify 16 | - http 17 | build: 18 | type: builtin 19 | modules: 20 | alfons.tasks.fetch: alfons/tasks/fetch.lua 21 | alfons.tasks.teal: alfons/tasks/teal.lua 22 | alfons.setfenv: alfons/setfenv.lua 23 | alfons.env: alfons/env.lua 24 | alfons.file: alfons/file.lua 25 | alfons.getopt: alfons/getopt.lua 26 | alfons.provide: alfons/provide.lua 27 | alfons.wildcard: alfons/wildcard.lua 28 | alfons.version: alfons/version.lua 29 | alfons.look: alfons/look.lua 30 | alfons.init: alfons/init.lua 31 | alfons.help: alfons/help.lua 32 | alfons.parser: alfons/parser.lua 33 | install: 34 | bin: 35 | alfons: bin/alfons.lua 36 | -------------------------------------------------------------------------------- /rock.yml: -------------------------------------------------------------------------------- 1 | package: alfons 2 | source: 3 | url: git://github.com/daelvn/alfons 4 | description: 5 | summary: Small program to run tasks for your project 6 | detailed: > 7 | alfons is a small script utility that lets you run tasks 8 | from a file (Lua or MoonScript), to better manage your 9 | project with tasks such as clean, compile, etc. To run 10 | tasks from a MoonScript file, you will need the 11 | moonscript rock. 12 | homepage: https://github.com/daelvn/alfons 13 | dependencies: 14 | - lpath 15 | - ansikit 16 | - lua >= 5.1 17 | build: 18 | type: builtin 19 | modules: 20 | alfons.tasks.fetch: alfons/tasks/fetch.lua 21 | install: 22 | bin: 23 | alfons: alfons.lua 24 | -------------------------------------------------------------------------------- /rockspecs/alfons-4.0-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "filekit >= 1.3", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v4.0", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "4.0-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-4.0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "filekit >= 1.3", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v4.0.1", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "4.0.1-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-4.0.2-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "filekit >= 1.3", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v4.0.2", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "4.0.2-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-4.1-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "filekit >= 1.3", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v4.1", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "4.1-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-4.1.1-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "filekit >= 1.3", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v4.1.1", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "4.1.1-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-4.1.3-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "filekit >= 1.3", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v4.1.3", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "4.1.3-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-4.1.4-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "filekit >= 1.3", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v4.1.4", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "4.1.4-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-4.2-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "filekit >= 1.3", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v4.2", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "4.2-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-4.2.1-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "filekit >= 1.3", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v4.2.1", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "4.2.1-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-4.2.2-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "filekit >= 1.3", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v4.2.2", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "4.2.2-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-4.3-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "filekit >= 1.3", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v4.3", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "4.3-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-4.4-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "filekit >= 1.3", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v4.4", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "4.4-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-4.4.1-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "filekit >= 1.3", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v4.4.1", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "4.4.1-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-5.0.0-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "filekit >= 1.3", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v5.0.0", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "5.0.0-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-5.0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "lpath", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v5.0.1", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "5.0.1-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-5.0.2-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "lpath", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v5.0.2", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "5.0.2-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-5.1-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "lpath", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v5.1", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "5.1-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-5.2-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "lpath", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v5.2", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "5.2-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-5.2.1-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "lpath", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v5.2.1", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "5.2.1-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-5.2.2-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "lpath", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v5.2.2", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "5.2.2-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-5.3-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "lpath", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v5.3", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "5.3-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-5.3.1-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua" 9 | }, 10 | type = "builtin" 11 | } 12 | dependencies = { 13 | "lpath", 14 | "ansikit", 15 | "lua >= 5.1" 16 | } 17 | description = { 18 | detailed = "alfons is a small script utility that lets you run tasks from a file (Lua or MoonScript), to better manage your project with tasks such as clean, compile, etc. To run tasks from a MoonScript file, you will need the moonscript rock.\n", 19 | homepage = "https://github.com/daelvn/alfons", 20 | summary = "Small program to run tasks for your project" 21 | } 22 | package = "alfons" 23 | rockspec_format = "3.0" 24 | source = { 25 | tag = "v5.3.1", 26 | url = "git://github.com/daelvn/alfons" 27 | } 28 | version = "5.3.1-1" 29 | -------------------------------------------------------------------------------- /rockspecs/alfons-dev-5.0.2-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "bin/alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.env"] = "alfons/env.lua", 9 | ["alfons.file"] = "alfons/file.lua", 10 | ["alfons.getopt"] = "alfons/getopt.lua", 11 | ["alfons.init"] = "alfons/init.lua", 12 | ["alfons.look"] = "alfons/look.lua", 13 | ["alfons.provide"] = "alfons/provide.lua", 14 | ["alfons.setfenv"] = "alfons/setfenv.lua", 15 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua", 16 | ["alfons.tasks.teal"] = "alfons/tasks/teal.lua", 17 | ["alfons.version"] = "alfons/version.lua", 18 | ["alfons.wildcard"] = "alfons/wildcard.lua" 19 | }, 20 | type = "builtin" 21 | } 22 | dependencies = { 23 | "lpath", 24 | "ansikit", 25 | "lua >= 5.1", 26 | "inotify", 27 | "http" 28 | } 29 | description = { 30 | detailed = "The normal 'alfons' package is bundled, making all modules unavailable. 'alfons-dev' installs them without bundling.\n", 31 | homepage = "https://github.com/daelvn/alfons", 32 | summary = "Unpacked Alfons modules for development" 33 | } 34 | package = "alfons-dev" 35 | rockspec_format = "3.0" 36 | source = { 37 | tag = "v5.0.2", 38 | url = "git://github.com/daelvn/alfons" 39 | } 40 | version = "5.0.2-1" 41 | -------------------------------------------------------------------------------- /rockspecs/alfons-dev-5.1-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "bin/alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.env"] = "alfons/env.lua", 9 | ["alfons.file"] = "alfons/file.lua", 10 | ["alfons.getopt"] = "alfons/getopt.lua", 11 | ["alfons.init"] = "alfons/init.lua", 12 | ["alfons.look"] = "alfons/look.lua", 13 | ["alfons.provide"] = "alfons/provide.lua", 14 | ["alfons.setfenv"] = "alfons/setfenv.lua", 15 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua", 16 | ["alfons.tasks.teal"] = "alfons/tasks/teal.lua", 17 | ["alfons.version"] = "alfons/version.lua", 18 | ["alfons.wildcard"] = "alfons/wildcard.lua" 19 | }, 20 | type = "builtin" 21 | } 22 | dependencies = { 23 | "lpath", 24 | "ansikit", 25 | "lua >= 5.1", 26 | "inotify", 27 | "http" 28 | } 29 | description = { 30 | detailed = "The normal 'alfons' package is bundled, making all modules unavailable. 'alfons-dev' installs them without bundling.\n", 31 | homepage = "https://github.com/daelvn/alfons", 32 | summary = "Unpacked Alfons modules for development" 33 | } 34 | package = "alfons-dev" 35 | rockspec_format = "3.0" 36 | source = { 37 | tag = "v5.1", 38 | url = "git://github.com/daelvn/alfons" 39 | } 40 | version = "5.1-1" 41 | -------------------------------------------------------------------------------- /rockspecs/alfons-dev-5.2-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "bin/alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.env"] = "alfons/env.lua", 9 | ["alfons.file"] = "alfons/file.lua", 10 | ["alfons.getopt"] = "alfons/getopt.lua", 11 | ["alfons.help"] = "alfons/help.lua", 12 | ["alfons.init"] = "alfons/init.lua", 13 | ["alfons.look"] = "alfons/look.lua", 14 | ["alfons.parser"] = "alfons/parser.lua", 15 | ["alfons.provide"] = "alfons/provide.lua", 16 | ["alfons.setfenv"] = "alfons/setfenv.lua", 17 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua", 18 | ["alfons.tasks.teal"] = "alfons/tasks/teal.lua", 19 | ["alfons.version"] = "alfons/version.lua", 20 | ["alfons.wildcard"] = "alfons/wildcard.lua" 21 | }, 22 | type = "builtin" 23 | } 24 | dependencies = { 25 | "lpath", 26 | "ansikit", 27 | "lua >= 5.1", 28 | "inotify", 29 | "http" 30 | } 31 | description = { 32 | detailed = "The normal 'alfons' package is bundled, making all modules unavailable. 'alfons-dev' installs them without bundling.\n", 33 | homepage = "https://github.com/daelvn/alfons", 34 | summary = "Unpacked Alfons modules for development" 35 | } 36 | package = "alfons-dev" 37 | rockspec_format = "3.0" 38 | source = { 39 | tag = "v5.2", 40 | url = "git://github.com/daelvn/alfons" 41 | } 42 | version = "5.2-1" 43 | -------------------------------------------------------------------------------- /rockspecs/alfons-dev-5.2.1-1.rockspec: -------------------------------------------------------------------------------- 1 | build = { 2 | install = { 3 | bin = { 4 | alfons = "bin/alfons.lua" 5 | } 6 | }, 7 | modules = { 8 | ["alfons.env"] = "alfons/env.lua", 9 | ["alfons.file"] = "alfons/file.lua", 10 | ["alfons.getopt"] = "alfons/getopt.lua", 11 | ["alfons.help"] = "alfons/help.lua", 12 | ["alfons.init"] = "alfons/init.lua", 13 | ["alfons.look"] = "alfons/look.lua", 14 | ["alfons.parser"] = "alfons/parser.lua", 15 | ["alfons.provide"] = "alfons/provide.lua", 16 | ["alfons.setfenv"] = "alfons/setfenv.lua", 17 | ["alfons.tasks.fetch"] = "alfons/tasks/fetch.lua", 18 | ["alfons.tasks.teal"] = "alfons/tasks/teal.lua", 19 | ["alfons.version"] = "alfons/version.lua", 20 | ["alfons.wildcard"] = "alfons/wildcard.lua" 21 | }, 22 | type = "builtin" 23 | } 24 | dependencies = { 25 | "lpath", 26 | "ansikit", 27 | "lua >= 5.1", 28 | "inotify", 29 | "http" 30 | } 31 | description = { 32 | detailed = "The normal 'alfons' package is bundled, making all modules unavailable. 'alfons-dev' installs them without bundling.\n", 33 | homepage = "https://github.com/daelvn/alfons", 34 | summary = "Unpacked Alfons modules for development" 35 | } 36 | package = "alfons-dev" 37 | rockspec_format = "3.0" 38 | source = { 39 | tag = "v5.2.1", 40 | url = "git://github.com/daelvn/alfons" 41 | } 42 | version = "5.2.1-1" 43 | -------------------------------------------------------------------------------- /test/alfons/dusubalf.moon: -------------------------------------------------------------------------------- 1 | tasks: 2 | dusubloaded: => print @name 3 | dusubcallup: => 4 | print @name 5 | tasks.subbelow! 6 | dusubcalltop: => 7 | print @name 8 | tasks.subcallup! -------------------------------------------------------------------------------- /test/alfons/graph-proof/a.moon: -------------------------------------------------------------------------------- 1 | tasks: 2 | always: => 3 | load "graph-proof.d" 4 | load "graph-proof.e" 5 | a: => print @name 6 | doa: => 7 | tasks.a! 8 | tasks.b! 9 | tasks.c! 10 | tasks.d! 11 | tasks.e! 12 | tasks.f! -------------------------------------------------------------------------------- /test/alfons/graph-proof/b.moon: -------------------------------------------------------------------------------- 1 | tasks: 2 | b: => print @name 3 | dob: => 4 | tasks.a! 5 | tasks.b! 6 | tasks.c! 7 | tasks.d! 8 | tasks.e! 9 | tasks.f! -------------------------------------------------------------------------------- /test/alfons/graph-proof/c.moon: -------------------------------------------------------------------------------- 1 | tasks: 2 | always: => load "graph-proof.f" 3 | c: => print @name 4 | doc: => 5 | tasks.a! 6 | tasks.b! 7 | tasks.c! 8 | tasks.d! 9 | tasks.e! 10 | tasks.f! -------------------------------------------------------------------------------- /test/alfons/graph-proof/d.moon: -------------------------------------------------------------------------------- 1 | tasks: 2 | d: => print @name 3 | dod: => 4 | tasks.a! 5 | tasks.b! 6 | tasks.c! 7 | tasks.d! 8 | tasks.e! 9 | tasks.f! -------------------------------------------------------------------------------- /test/alfons/graph-proof/e.moon: -------------------------------------------------------------------------------- 1 | tasks: 2 | e: => print @name 3 | doe: => 4 | tasks.a! 5 | tasks.b! 6 | tasks.c! 7 | tasks.d! 8 | tasks.e! 9 | tasks.f! -------------------------------------------------------------------------------- /test/alfons/graph-proof/f.moon: -------------------------------------------------------------------------------- 1 | tasks: 2 | f: => print @name 3 | dof: => 4 | tasks.a! 5 | tasks.b! 6 | tasks.c! 7 | tasks.d! 8 | tasks.e! 9 | tasks.f! -------------------------------------------------------------------------------- /test/alfons/graph-proof/main.moon: -------------------------------------------------------------------------------- 1 | tasks: 2 | always: => 3 | load "graph-proof.a" 4 | load "graph-proof.b" 5 | load "graph-proof.c" 6 | main: => print @name -------------------------------------------------------------------------------- /test/alfons/lua.lua: -------------------------------------------------------------------------------- 1 | function always() 2 | print "Hello from Lua!" 3 | load "subalf" 4 | end 5 | 6 | function runTask() 7 | print "Running from Lua!" 8 | end 9 | 10 | function fromMoon() 11 | tasks.subloaded() 12 | end -------------------------------------------------------------------------------- /test/alfons/main.moon: -------------------------------------------------------------------------------- 1 | tasks: 2 | always: => load "subalf" 3 | hello: => print @name 4 | shello: => sh "echo 'Hello from sh!'" 5 | execute: => 6 | print @name 7 | tasks.subloaded! -------------------------------------------------------------------------------- /test/alfons/predet.moon: -------------------------------------------------------------------------------- 1 | tasks: 2 | always: => load "predet2" 3 | first: => print @name 4 | default: => print @name 5 | finalize: => print @name -------------------------------------------------------------------------------- /test/alfons/predet2.moon: -------------------------------------------------------------------------------- 1 | tasks: 2 | second: => print @name 3 | default: => print @name .. "2" 4 | finalize: => print @name .. "2" -------------------------------------------------------------------------------- /test/alfons/sidea.moon: -------------------------------------------------------------------------------- 1 | tasks: 2 | always: => load "sideb" 3 | helloa: => print @name -------------------------------------------------------------------------------- /test/alfons/sideb.moon: -------------------------------------------------------------------------------- 1 | tasks: 2 | always: => load "sidea" 3 | hellob: => print @name -------------------------------------------------------------------------------- /test/alfons/storea.moon: -------------------------------------------------------------------------------- 1 | tasks: 2 | always: => 3 | store.test = "Hello World!" 4 | load "storeb" -------------------------------------------------------------------------------- /test/alfons/storeb.moon: -------------------------------------------------------------------------------- 1 | tasks: 2 | test: => print store.test -------------------------------------------------------------------------------- /test/alfons/subalf.moon: -------------------------------------------------------------------------------- 1 | tasks: 2 | subloaded: => print @name 3 | subdirect: => print @name 4 | subbelow: => print @name 5 | subcallup: => 6 | print @name 7 | tasks.hello! 8 | subdual: => 9 | print @name 10 | load "dusubalf" -------------------------------------------------------------------------------- /test/alfons/teal-table.tl: -------------------------------------------------------------------------------- 1 | return { tasks = { 2 | always = function() 3 | print "Hello from Teal!" 4 | load "subalf" 5 | end, 6 | runTask = function() 7 | print "Running from Teal!" 8 | end, 9 | fromMoon = function() 10 | tasks.subloaded() 11 | end 12 | }} -------------------------------------------------------------------------------- /test/alfons/teal.tl: -------------------------------------------------------------------------------- 1 | global function always() 2 | print "Hello from Teal!" 3 | load "subalf" 4 | end 5 | 6 | global function runTask() 7 | print "Running from Teal!" 8 | end 9 | 10 | global function fromMoon() 11 | tasks.subloaded() 12 | end -------------------------------------------------------------------------------- /test/graph-proof.moon: -------------------------------------------------------------------------------- 1 | import runString from require "alfons" 2 | import readMoon from require "alfons.file" 3 | inspect = require "inspect" 4 | 5 | -- testing the graph in docs/loading.md 6 | alfons, err = runString readMoon "test/alfons/graph-proof/main.moon" 7 | error err if err 8 | env = alfons! 9 | 10 | print "-> (main)" 11 | env.tasks.a! 12 | env.tasks.b! 13 | env.tasks.c! 14 | env.tasks.d! 15 | env.tasks.e! 16 | env.tasks.f! 17 | print "-> a" 18 | env.tasks.doa! 19 | print "-> b" 20 | env.tasks.dob! 21 | print "-> c" 22 | env.tasks.doc! 23 | print "-> d" 24 | env.tasks.dod! 25 | print "-> e" 26 | env.tasks.doe! 27 | print "-> f" 28 | env.tasks.dof! -------------------------------------------------------------------------------- /test/lua.moon: -------------------------------------------------------------------------------- 1 | import runString from require "alfons" 2 | import readLua from require "alfons.file" 3 | inspect = require "inspect" 4 | 5 | -- testing lua taskfiles 6 | alfons, err = runString readLua "test/alfons/lua.lua" 7 | error err if err 8 | env = alfons! 9 | 10 | env.tasks.runTask! 11 | env.tasks.fromMoon! -------------------------------------------------------------------------------- /test/predet.moon: -------------------------------------------------------------------------------- 1 | import runString from require "alfons" 2 | import readMoon from require "alfons.file" 3 | inspect = require "inspect" 4 | 5 | -- testing default and finalize tasks 6 | alfons, err = runString readMoon "test/alfons/predet.moon" 7 | error err if err 8 | env = alfons! 9 | 10 | -- check count 11 | print env.__ran -- 0 12 | env.tasks.first! 13 | print env.__ran -- 1 14 | -- reset 15 | alfons, err = runString readMoon "test/alfons/predet.moon" 16 | env = alfons! 17 | print "---" 18 | 19 | -- finalize (2 defaults and 2 finalizes) 20 | env.finalize! 21 | -- reset 22 | alfons, err = runString readMoon "test/alfons/predet.moon" 23 | env = alfons! 24 | print "---" 25 | 26 | -- finalize, one default 27 | env.tasks.first! 28 | env.finalize! 29 | -- reset 30 | alfons, err = runString readMoon "test/alfons/predet.moon" 31 | env = alfons! 32 | print "---" 33 | 34 | -- finalize, another default 35 | env.tasks.second! 36 | env.finalize! 37 | -- reset 38 | alfons, err = runString readMoon "test/alfons/predet.moon" 39 | env = alfons! 40 | print "---" -------------------------------------------------------------------------------- /test/runString.moon: -------------------------------------------------------------------------------- 1 | import runString from require "alfons" 2 | import readMoon from require "alfons.file" 3 | inspect = require "inspect" 4 | 5 | -- testing depths 6 | print "== TESTING DEPTHS ==" 7 | alfons, err = runString readMoon "test/alfons/main.moon" 8 | error err if err 9 | env = alfons! 10 | 11 | -- Always is nowalready run 12 | --env.tasks.always! 13 | 14 | -- normal task in main 15 | env.tasks.hello! 16 | print "---" 17 | -- call task once-below main from task in main 18 | env.tasks.execute! 19 | print "---" 20 | -- call task once-below main directly 21 | env.tasks.subdirect! 22 | print "---" 23 | -- call task once-below main directly which calls a task once-above it (in main) 24 | env.tasks.subcallup! 25 | print "---" 26 | -- loads a taskfile (twice-below main) from a taskfile once-below main 27 | env.tasks.subdual! 28 | print "---" 29 | -- calls a task twice-below main 30 | env.tasks.dusubloaded! 31 | print "---" 32 | -- calls a task twice-below main which calls a task once-below main 33 | env.tasks.dusubcallup! 34 | print "---" 35 | -- calls a task twice-below main which calls a task once-below main, which 36 | -- calls a task in main 37 | env.tasks.dusubcalltop! 38 | print "---" 39 | 40 | -- testing load 41 | print "== TESTING LOAD ==" 42 | alfons, err = runString readMoon "test/alfons/sidea.moon" 43 | error err if err 44 | env = alfons! 45 | 46 | env.tasks.helloa! 47 | env.tasks.hellob! -------------------------------------------------------------------------------- /test/store.moon: -------------------------------------------------------------------------------- 1 | import runString from require "alfons" 2 | import readMoon from require "alfons.file" 3 | inspect = require "inspect" 4 | 5 | -- testing store table 6 | alfons, err = runString readMoon "test/alfons/storea.moon" 7 | error err if err 8 | env = alfons! 9 | 10 | env.tasks.test! -------------------------------------------------------------------------------- /test/teal.moon: -------------------------------------------------------------------------------- 1 | import runString from require "alfons" 2 | import readTeal from require "alfons.file" 3 | 4 | -- testing teal taskfiles 5 | print "teal (globals)" 6 | alfons, err = runString readTeal "test/alfons/teal.tl" 7 | error err if err 8 | env = alfons! 9 | 10 | env.tasks.runTask! 11 | env.tasks.fromMoon! 12 | 13 | -- 14 | print "teal (table)" 15 | alfons, err = runString readTeal "test/alfons/teal-table.tl" 16 | error err if err 17 | env = alfons! 18 | 19 | env.tasks.runTask! 20 | env.tasks.fromMoon! --------------------------------------------------------------------------------