{"id":18581941,"url":"https://github.com/coder/nfy","last_synced_at":"2025-04-30T15:47:18.432Z","repository":{"id":65978627,"uuid":"222148361","full_name":"coder/nfy","owner":"coder","description":"EXPERIMENTAL: Pumped up install scripts","archived":false,"fork":false,"pushed_at":"2020-05-14T02:49:18.000Z","size":45,"stargazers_count":6,"open_issues_count":5,"forks_count":1,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-04-30T15:47:08.019Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/coder.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}},"created_at":"2019-11-16T19:23:12.000Z","updated_at":"2025-03-03T05:39:13.000Z","dependencies_parsed_at":"2023-02-19T19:01:23.127Z","dependency_job_id":null,"html_url":"https://github.com/coder/nfy","commit_stats":null,"previous_names":["cdr/nfy"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coder%2Fnfy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coder%2Fnfy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coder%2Fnfy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coder%2Fnfy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coder","download_url":"https://codeload.github.com/coder/nfy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251734170,"owners_count":21635081,"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":[],"created_at":"2024-11-07T00:08:29.537Z","updated_at":"2025-04-30T15:47:18.406Z","avatar_url":"https://github.com/coder.png","language":"Go","readme":"\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n**Table of Contents**  *generated with [DocToc](https://github.com/thlorenz/doctoc)*\n\n- [nfy](#nfy)\n  - [Install](#install)\n  - [Introduction](#introduction)\n    - [The Problem](#the-problem)\n    - [The Goal](#the-goal)\n  - [Basic Example](#basic-example)\n    - [Build Container Image](#build-container-image)\n      - [Advanced Example](#advanced-example)\n  - [Parallelism](#parallelism)\n  - [Recipes](#recipes)\n  - [Code Structure](#code-structure)\n    - [Import Statements](#import-statements)\n  - [Dependencies](#dependencies)\n    - [Target Evaluation](#target-evaluation)\n    - [Target Overloading](#target-overloading)\n      - [Use Cases](#use-cases)\n    - [Locking](#locking)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n# nfy\n\n`nfy` is an **experimental** configuration management that aims to u**n**i**fy** the concept of the `Dockerfile`,\nthe install script, and the configuration manager.\n\nYou can think of it as a bridge between bare metal configuration and containers.\n\nThere are no compatibility or reliability guarantees until we're v1.0.0.\n\n## Install\n```\ngo get -u cdr.dev/nfy/cmd/nfy\n```\n\n## Introduction\n\n### The Problem\n1. **Dockerfiles don't scale.**\n    1. As Dockerfiles become large, developers begin moving installation to scripts and installers, undermining layer caching.\n        1. Smaller files are more readable. \n        1. Small scripts can be tested independently.\n1. **Dockerfiles are constrained by their linear import graph.**\n    1. Software tool images (e.g rust, nginx) force an operating system on the user.\n    1. Multiple images can't be used at the same time.\n        1. If you want an image with `go` and `rust`, you use one as your `FROM`, and write\n        `RUN` statements to simulate what the image already does.\n1. **Dockerfiles can't be applied to the local system.**\n    1. Development workstations are long-lived and bare metal, where production servers are ephemeral and containerized.\n    Software management diverges greatly between the two.\n    \n### The Goal\n1. **Containerization**\n    - Build container images from your install scripts.\n    - Update software in environments without recreating the environment.\n        - Run `nfy install` to apply the configuration to your local machine.\n        - Run `nfy build` to create a container with the install scripts.\n1. **Speed**\n    - Automatically parallelize installation.\n    - Stop duplication computation by coupling each install target with an explicit check.\n1. **Portability**\n    - Install the same target on different systems based on what requirements are available.\n1. **Reusability**\n    - Share installers and configuration via GitHub imports.\n    - Use some of your personal dotfiles on your development machine or workstation.\n\n## Basic Example\n\nIn order to install `wget` and vim, create a file called `nfy.yml` with the following contents:\n\n```yaml\nwget:\n  comment: \"wget lets us grab files from HTTP servers.\"\n  install: \"apt-get -y install wget\"\n  check: \"wget -h\"\n# Delegate vim to Ammar's personal dotfiles.\nvim:\n    deps:\n      - github.com/ammario/dotfiles:vim\n```\n\nthen run `sudo nfy install`, which installs every target by default.\n\nIf `wget` is already installed, the `check` step will pass and `install` won't run.\n\n### Build Container Image\n\nRun `sudo nfy build -b ubuntu nfy-ubuntu` to build an Ubuntu container image called `nfy-ubuntu` with `wget` and my vim\nconfiguration.\n\nThe Dockerfile looks like:\n\n```\nFROM ubuntu\n# wget: wget lets us grab files from HTTP servers.\nRUN apt-get -y install wget\n```\n\n#### Advanced Example\n\n```yaml\napt-get:\n  check: \"apt-get -h\"\napt-update:\n  comment: \"Ensure the package cache is up to date.\"\n  install: \"apt-get update -y\"\n  build_only: true\n  deps:\n    - apt-get\napt:\n  deps:\n    - apt-get\n    - apt-update\nhtop:\n  install: \"apt-get install -y htop\"\n  check: \"htop -h\"\n  deps:\n    - apt\nwget:\n  install: \"apt-get install -y wget\"\n  check: \"wget -h\"\n  deps:\n    - apt\n```\n\nproduces\n\n```Dockerfile\nFROM ubuntu\n# Ensure the \"apt-get\" dependency exists:\nRUN apt-get -h\n# apt-update: Ensure the package cache is up to date.\nRUN apt-get update -y\nRUN apt-get install -y wget\nRUN apt-get install -y htop\n```\n(those comments are generated automatically)\n\n## Parallelism\n\n`nfy` creates a tree of files and external dependencies rooted in your `nfy.yaml`. The tree is a directed acyclic graph\nand evaluated with automatic parallelism. Take this example (`X -\u003e Y` means X depends on Y):\n\n```\nA -\u003e B\nA -\u003e C\nB -\u003e D\n```\n\nIs converted into 2 threads that look like:\n\n```\nCompute D\nWait C\nCompute B\n```\n\n```\nCompute C\nWait B\nCompute A\n```\n\nThis parallelism is active during apply and build, meaning `nfy` can perform much faster than Docker.\n\n## Recipes\nEach recipe has a name or a _target_. For example:\n\n```\ncurl:\n    install: \"...\"\n```\n\nhas the target `curl`.\n\nThe target can be used to reference the recipe later.\n\nRecipes support the following parameters:\n\n| Name | Usage |\n| ---- | ----- |\n| install |  An executable command or script to install. |\n| check |  An executable command or script location to check if installation is necessary. |\n| fast_install |  If \"yes\", indicates that the install is fast enough and running check is unnecessary. |\n| deps |  A list of targets which must exist before this can install. |\n| build_only | Specify whether command will only run in container builds. |\n| comment | Include a comment in the Dockerfile. |\n| files |  A list of files which must be available in the working directory. |\n\nA target must implement one of `check` or `install`. A target with `install` and no `check` will print a warning when\nit is evaluated, unless `fast_install` is set.\n\nA target with a `check` but no install can be used to represent hard requirements, such as\n\n```yaml\n# Ensures apt-get exists\napt-get:\n    check: \"apt-get -h\"\n```\n\n## Code Structure\n\n### Import Statements\nAn `import` directive loads in recipes from a file. The configuration is evaluated in order, so the list of imports\nmust be before the imported target is referenced. Example:\n\n```yaml\nimport:\n    - \"apt.yml\"\nhtop:\n    install: \"sudo apt -y install htop\"\n    deps:\n      - apt\n```\n\nEvery import is processed before recipe evaluation begins.\n\nYou can also import entire directories via globbing. For example:\n\n```yaml\nimport:\n    - \"nfy/*.yml\"\n```\n\n## Dependencies\nDependencies can exist on a per recipe and per file basis. Dependencies on a file are automatically added to each\nrecipe in the file.\n\nDependencies in the `nfy.yml` file can make hard, global requirements about the system, for example:\n\n```yaml\napt-get:\n    check: \"apt-get -h\"\ndeps:\n    - apt-get\n```\n\n### Target Evaluation\n\nA target can be provided in one of three formats:\n\n- `wget` references a local target somewhere in the source tree\n- `github.com/user/repo:wget` references a remote target named `wget` hosted on git.\n\n### Target Overloading\nWhat if you want to install `htop` in your Macbook or Linux server?\n\n```yaml\nhtop:\n    check: \"htop -h\"\n    install: \"apt-get install -h htop\"\ndeps:\n    - apt-get\n```\n\nwill obviously fail because apt-get is not installed. Instead, you should _overload_ the target with multiple\ninstallers. For example:\n\n```yaml\nhtop:\n  check: \"htop -h\"\n  install_apt:\n    script: \"apt-get install -y htop\"\n    deps:\n      - apt\n  install_brew:\n    script: \"brew install htop\"\n    deps:\n      - brew\n\n```\n\nWe cannot simply provide multiple `install` directives because it is illegal YAML for keys to conflict.\n\nThe suffix is nice for debugging nfy execution, too.\n\n#### Use Cases\n\n- Targetting multiple operating systems\n- Tolerating different dependencies (e.g using \"curl\" instead of \"wget\")\n\n#### Docker\nThe first target is always used in Docker images. The first is assumed the default.\n\n### Locking\n\n**Unimplemented**\n\nEach external dependency is locked to a particular commit in the `nfy.lock` file.\n\nYou can update the repository with `nfy update github.com/\u003cuser\u003e/\u003crepo\u003e@\u003ctag\u003e`.\n\nThe locking mechanism offers security and stability to your config. You should check in your lock file.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoder%2Fnfy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoder%2Fnfy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoder%2Fnfy/lists"}