{"id":16138658,"url":"https://github.com/astromechza/spiro","last_synced_at":"2025-08-20T20:06:34.674Z","repository":{"id":147651739,"uuid":"81603546","full_name":"astromechza/spiro","owner":"astromechza","description":"A simple binary to do project templating","archived":false,"fork":false,"pushed_at":"2019-07-31T13:05:38.000Z","size":1305,"stargazers_count":5,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-09T03:41:24.708Z","etag":null,"topics":["cli","golang","stencil","template"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/astromechza.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-02-10T20:22:17.000Z","updated_at":"2023-02-12T18:45:57.000Z","dependencies_parsed_at":"2023-04-09T07:15:38.335Z","dependency_job_id":null,"html_url":"https://github.com/astromechza/spiro","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astromechza%2Fspiro","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astromechza%2Fspiro/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astromechza%2Fspiro/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astromechza%2Fspiro/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/astromechza","download_url":"https://codeload.github.com/astromechza/spiro/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243940088,"owners_count":20372045,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","golang","stencil","template"],"created_at":"2024-10-09T23:44:47.289Z","updated_at":"2025-03-18T16:30:56.357Z","avatar_url":"https://github.com/astromechza.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `spiro` - a project template generator\n\n![travis ci badge](https://travis-ci.org/astromechza/spiro.svg?branch=master)\n\nSpiro is an template structure generator that uses Golangs text/template library. It accepts both single files as well as directory trees as input and will interpret any template calls found inside the files and the file/directory names.\n\n#### Quick Example\n\n**{{ .name }}.txt.templated:**\n\n```\n{{ if .enabled }}x = {{ .x }}\ny = {{ .y }}\n{{ end }}\nFooter content. Generated at {{ now.Format \"2006-01-02\" }}\n```\n\n**spec.yaml**:\n\n```yaml\nname: example\nenabled: true\nx: 10\ny: hello world\n```\n\nThen you can execute `spiro '{{ .name }}.txt.templated' spec.yaml .` in order to generate a file called `example.txt` that contains:\n\n```\nx = 10\ny = hello world\n\nFooter content. Generated at 2018-03-18\n```\n\n---\n\nThe rule-set is probably a bit complex to display here, but the following links are useful:\n\n- https://golang.org/pkg/text/template\n- https://gohugo.io/templates/go-templates/\n\nThe only additional rule is the rule that controls whether a file or directory is processed or not. If a file name is templated like `{{ if .blah }}filename.txt{{ end }}` then that file will only be processed _if_ the name evaluates to a non-empty string.\n\nThe contents of a file will only be treated as templated if the file name has a `.templated` suffix. If it does, the contents will be evaluated and the `.templated` suffix will be removed.\n\nTemplating _inside_ the file is evaluated after any template in the file name. So if you want an optional file that has templated content you'll need to use a name like `{{ if .blah }}filename.txt.templated{{ end }}`. If the `.templated` declaration is outside the condition the behaviour should be similar but is probably not the convention.\n\nSome additional template functions are supplied:\n\n- `title`: capitalise string `(string) -\u003e (string)`\n- `upper`: convert string to upper case `(string) -\u003e (string)`\n- `lower`: convert string to lower case `(string) -\u003e (string)`\n- `now`: return current time object `() -\u003e (time.Time)`\n- `json`: output a structure as json `(object) -\u003e (string)`\n- `jsonindent`: output a structure as indented json `(object) -\u003e (string)`\n- `unescape`: unescape escaped html characters `(string) -\u003e (string)`\n- `stringreplace`: basic string replace `(subject, old, new) -\u003e (string)`\n- `regexreplace`: regular expression based string replace `(subject, pattern, repl) -\u003e (string)`\n- `add`: Calculate the sum of two numbers `(int, int) -\u003e (int)`\n\nThe spec file should be in JSON or Yaml form and will be passed to each template invocation. The specfile can be \"-\" to indicate that YAML should be read from stdin.\n\nPermission bits for any files, including `.templated` ones, **will** be copied to the destination files.\n\n### Basic example of features:\n\nYou have a file on disk called `{{ lower .projectname }}.md.templated` with the following content:\n\n```\n# Heading for {{ .projectname }}\n\nThis project was started on {{ now.Format \"2006-01-02\" }} by {{ .author }}.\n```\n\nAnd if you feed it the following spec JSON:\n\n```json\n{\n    \"projectname\": \"HelloWorld\",\n    \"author\": \"Joe Soap\"\n}\n```\n\nYou'll end up with a file called `helloworld.md` containing:\n\n```\n# Heading for HelloWorld\n\nThis project was started on 2017-02-11 by Joe Soap.\n```\n\n### Overriding the template characters\n\nBy default the normal Golang template characters `{{` are used but sometimes the files you're working with containing and you have to laboriously escape them.\n\nYou can provide the special key `_spiro_delimiters_` in your spec file in order to override them:\n\n```yaml\n_spiro_delimiters_:\n  - \"\u003c\u003c\u003c\"\n  - \"\u003e\u003e\u003e\"\n```\n\n### Enforcing a `spiro` version\n\nSometimes new features are added to Spiro which are not supported by earlier versions. Sometimes templates rely on these features. By specifying a `_spiro_min_version_` in your spec file, an error will be thrown if an earlier version of `spiro` is used to build the template.\n\n```yaml\n_sprio_min_version_: 1.5\n```\n\nThe version rules work as follows:\n\n- 3 numbers are allowed (`major.minor.patch`)\n- `X.Y` == `X.Y.0` and `X` == `X.0.0`\n- `X.Z` \u003e= `X.0`\n\n### What should you use this project for:\n\n- Does your team have a template project that gets copied and modified by hand? Use `spiro`!\n\n## Demo\n\nSome demos exist in the `/demo` directory. Run them as follows:\n\n```\n$ rm -rfv demo/output/project\n\n$ ./spiro demo/example1 demo/example1.yml demo/output\nProcessing 'demo/example1/' -\u003e 'demo/output/example1/'\nProcessing 'demo/example1/demo-{{upper .animal}}.templated' -\u003e 'demo/output/example1/demo-BEAR'\nProcessing 'demo/example1/{{ if .x }}dontskip.txt{{ end }}' -\u003e 'demo/output/example1/dontskip.txt'\nSkipping 'demo/example1/{{ if not .x }}skipthis.txt{{ end }}' since the name evaluated to ''\nProcessing 'demo/example1/{{.subdir}}-thing/' -\u003e 'demo/output/example1/Elephant-thing/'\nProcessing 'demo/example1/{{.subdir}}-thing/noop' -\u003e 'demo/output/example1/Elephant-thing/noop'\nProcessing 'demo/example1/{{.subdir}}-thing/{{.subfile.name}}.{{.subfile.type}}' -\u003e 'demo/output/example1/Elephant-thing/snake.xml'\n\n$ find demo/output\ndemo/output\ndemo/output/example1\ndemo/output/example1/demo-BEAR\ndemo/output/example1/dontskip.txt\ndemo/output/example1/Elephant-thing\ndemo/output/example1/Elephant-thing/noop\ndemo/output/example1/Elephant-thing/snake.xml\n```\n\n## Download \u0026 Installation\n\nThe best option is to download the latest binaries from the [releases page](https://github.com/astromechza/spiro/releases). Extract the one for your platform and put it in any directory where you have access.\n\nAlternatively, use the install script which will do this for you:\n\n```\n$ curl https://raw.githubusercontent.com/astromechza/spiro/master/install.sh | sh\n```\n\nIf a binary is not available for your platform, you'll need to build one yourself.\n\n## Changelog\n\n**v1.8**\n\n- Added `-edit` option to the CLI\n\n**v1.7**\n\n- Allow spec to be read from stdin when `-` is given ([#5](https://github.com/astromechza/spiro/issues/5))\n\n**v1.6.0**\n\n- ...\n\n## Future features\n\n- More useful template functions (need feedback from users)\n- Syntax to split a single file into multiple\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fastromechza%2Fspiro","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fastromechza%2Fspiro","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fastromechza%2Fspiro/lists"}