☁️ Live reload for Go apps

Overview

Air Go Codacy Badge Go Report Card codecov

☁️ Live reload for Go apps

air

Motivation

When I get started with developing websites in Go and gin framework, it's a pity that gin lacks live-reloading function. In fact, I tried fresh and it seems not much flexible, so I intended to rewrite it in a better way. Finally, Air's born. In addition, great thanks to pilu, no fresh, no air :)

Air is yet another live-reloading command line utility for Go applications in development. Just air in your project root directory, leave it alone, and focus on your code.

NOTE: This tool has nothing to do with hot-deploy for production.

Features

  • Colorful log output
  • Customize build or binary command
  • Support excluding subdirectories
  • Allow watching new directories after Air started
  • Better building process

Installation

Go

The classic way to install

go get -u github.com/cosmtrek/air

macOS, Linux, Windows

# binary will be $(go env GOPATH)/bin/air
curl -sSfL https://raw.githubusercontent.com/cosmtrek/air/master/install.sh | sh -s -- -b $(go env GOPATH)/bin

# or install it into ./bin/
curl -sSfL https://raw.githubusercontent.com/cosmtrek/air/master/install.sh | sh -s

air -v

P.S. Great thanks mattn's PR for supporting Windows platform.

Docker way

Please pull this docker image cosmtrek/air.

docker run -it --rm \
    -w "<PROJECT>" \
    -e "air_wd=<PROJECT>" \
    -v $(pwd):<PROJECT> \
    -p <PORT>:<APP SERVER PORT> \
    cosmtrek/air
    -c <CONF>

For example, one of my project runs in docker:

docker run -it --rm \
    -w "/go/src/github.com/cosmtrek/hub" \
    -v $(pwd):/go/src/github.com/cosmtrek/hub \
    -p 9090:9090 \
    cosmtrek/air

Usage

For less typing, you could add alias air='~/.air' to your .bashrc or .zshrc.

First enter into your project

cd /path/to/your_project

The simplest usage is run

# firstly find `.air.toml` in current directory, if not found, use defaults
air -c .air.toml

While I prefer the second way

# 1. create a new file
touch .air.toml

# 2. paste `air_example.toml` into this file, and **modify it** to satisfy your needs.

# 3. run air with your config. If file name is `.air.toml`, just run `air`.
air

See the complete air_example.toml

Debug

air -d prints all logs.

Development

Please note that it requires Go 1.13+ since I use go mod to manage dependencies.

# 1. fork this project

# 2. clone it
mkdir -p $GOPATH/src/github.com/cosmtrek
cd $GOPATH/src/github.com/cosmtrek
git clone [email protected]:<YOUR USERNAME>/air.git

# 3. install dependencies
cd air
make ci

# 4. explore it and happy hacking!
make install

BTW: Pull requests are welcome~

Sponsor

Buy Me A Coffee

Huge thanks to the following supporters. I've always been remembering your kindness.

  • Peter Aba
  • Apostolis Anastasiou
  • keita koga

License

GNU General Public License v3.0

Comments
  • Question: Use environment variable in cmd

    Question: Use environment variable in cmd

    Is there a way to do something like:

    cmd = "go build -ldflags '-X github.com/CIDgravity/CIDgravity/backend/controller.version=${GIT_REVISION}' -o cidgravity-backend ."
    

    and use the environment variable GIT_REVISION instead of GIT_REVISION as a string?

    opened by Breigner01 17
  • Process not being killed on Windows

    Process not being killed on Windows

    Hello! First of all, thank you for this awesome package :)

    Due to Air's current implementation of starting processes on Windows (with start /b), the PID returned by cmd.Process.Pid is of a process that already exited (start's PID, not what it started), hence the debug error failed to kill PID ###, error: exit status 128 is returned.

    When trying to run the TASKKILL command manually, I noticed the following error: ERROR: The process "###" was not found., which confirms my suspicion.

    I'm thinking of a good way to fix this, since just TASKKILLing the process by name isn't a good idea.

    Is start /b even necessary? I'll try to modify the code and run some tests without it.

    If that doesn't work, maybe try to get the PID by executable path? Is that even possible? If so, just check it against c.Build.FullBin and use that on TASKKILL.

    I don't think it would be a good idea to try to parse TASKLIST as the language might change per system, etc. (also it doesn't even seem to return the executable path).. but I don't see other alternatives as listing processes in Go seems to be a nightmare..

    Suggestions?

    opened by HeCorr 16
  • Terminal text gets garbled on Windows

    Terminal text gets garbled on Windows

    Whenever running air on windows the text has issues printing.

    λ c:\Users\sonar\.air .
    
                 _
         /\     (_)
        /  \     _   _ __
       / /\ \   | | | '__|
      / ____ \  | | | |
     /_/    \_\ |_| |_|
    
    Live reload for Go apps :)
    
    [19:38:14.574] watching .
    [19:38:14.577] watching protos
    [19:38:14.579] !exclude tmp
    [19:38:14.580] building...
    [19:3[81:91:53.83:2155]. 3!2e6x]c l!uedxec ltumdpe
     tmp[
    19:38:15.329] !exclude tmp
    [19:38:15.341] running...
    

    I get this issue running in git bash as well as cmd.

    help-wanted 
    opened by SonarBeserk 16
  • Go 1.15: failed to build

    Go 1.15: failed to build

    Hello,

    We did try to update to Go 1.15 but we're having this issue starting air:

    failed to build, error: fork/exec /bin/sh: Setctty set but Ctty not valid in child

    just after building... step. We use Go 1.15 alpine docker image.

    Tested with Air v1.12.4

    Thanks

    opened by guyguy333 12
  • Allow output logging from fmt or log packages when executable is running.

    Allow output logging from fmt or log packages when executable is running.

    As noted in issue #50, output logging only shows up when air is closed. This is a bit annoying since you have to close air (and most likely restart it) to see any log messages. This change fixes the output to occur while air is running and thus mirrors the functionality in fresh. I am unsure of any unintended side-effects of this change, but I have not noticed any thus far.

    It looks like this bug/unintended functionality/whatever-you-want-to-call-it is caused by the wrapping of the io.Copy() calls for stdout and stderr into one goroutine and using with the cmd.Process.Wait() call. The Wait() call hangs/blocks endlessly until the binary (i.e. air) is closed/stopped thus not allowing the copying of the stdout or stderr to the terminal you ran air in. However, just removing the Wait() call did not allow logging to work; the Copy() calls had to be split into separate goroutines as well. Thus, at the end of the day, the code to fix this is simply a copying of the code from fresh.

    References:

    • fresh lines https://github.com/gravityblast/fresh/blob/master/runner/runner.go#L28-L29.
    • air lines https://github.com/cosmtrek/air/blob/6f18a44eb4aa1eac4956755d7efc3605fc42f2ac/runner/engine.go#L434-L437
    opened by c9845 11
  • Process tracking can get off-by-one

    Process tracking can get off-by-one

    I've observed that sometimes air fails to kill the previous version of the process and tries to start a new one and fails. Here is a log with the debug flag on:

    make[1]: Entering directory '/app/go'
    event: "/app/go/api-server/app/auth/auth.go": CHMOD
    event: "/app/go/api-server/app/auth/auth.go": WRITE
    api-server/app/auth/auth.go has changed
    event: "/app/go/api-server/app/auth/auth.go": CHMOD
    event: "/app/go/api-server/app/auth/auth.go": WRITE
    api-server/app/auth/auth.go has changed
    flushing events
    api-server/app/auth/auth.go has changed
    make[1]: Leaving directory '/app/go'
    running...
    [GIN-debug] Listening and serving HTTP on :8080
    event: "/app/go/api-server/app/auth/auth.go": CHMOD
    event: "/app/go/api-server/app/auth/auth.go": CHMOD
    event: "/app/go/api-server/app/auth/auth.go": WRITE
    api-server/app/auth/auth.go has changed
    api-server/app/auth/auth.go has changed
    building...
    trying to kill cmd [/bin/sh -c bin/api-server]
    cmd killed, pid: 274
    make[1]: Entering directory '/app/go'
    event: "/app/go/api-server/app/auth/auth.go": CHMOD
    event: "/app/go/api-server/app/auth/auth.go": WRITE
    api-server/app/auth/auth.go has changed
    event: "/app/go/api-server/app/auth/auth.go": CHMOD
    event: "/app/go/api-server/app/auth/auth.go": WRITE
    api-server/app/auth/auth.go has changed
    flushing events
    api-server/app/auth/auth.go has changed
    building...
    make[1]: Entering directory '/app/go'
    make[1]: Leaving directory '/app/go'
    running...
    [GIN-debug] Listening and serving HTTP on :8080
    make[1]: Leaving directory '/app/go'
    running...
    [GIN-debug] Listening and serving HTTP on :8080
    [GIN-debug] [ERROR] listen tcp :8080: bind: address already in use
    
    opened by arya 11
  • Hot reloading does not work when placing main.go inside cmd/ directory

    Hot reloading does not work when placing main.go inside cmd/ directory

    My project structure looks like this: image

    .air.conf

    # Config file for [Air](https://github.com/cosmtrek/air) in TOML format
    
    # Working directory
    # . or absolute path, please note that the directories following must be under root.
    root = "."
    tmp_dir = "tmp"
    
    [build]
    # Just plain old shell command. You could use `make` as well.
    cmd = "go build -o ./tmp/main ./cmd/main.go"
    # Binary file yields from `cmd`.
    bin = "tmp/main"
    # Customize binary.
    full_bin = "APP_ENV=dev APP_USER=air ./tmp/main"
    # Watch these filename extensions.
    include_ext = ["go", "tpl", "tmpl", "html"]
    # Ignore these filename extensions or directories.
    exclude_dir = ["assets", "tmp", "vendor", "frontend/node_modules"]
    # Watch these directories if you specified.
    include_dir = []
    # Exclude files.
    exclude_file = []
    # This log file places in your tmp_dir.
    log = "air.log"
    # It's not necessary to trigger build each time file changes if it's too frequent.
    delay = 1000 # ms
    # Stop running old binary when build errors occur.
    stop_on_error = true
    # Send Interrupt signal before killing process (windows does not support this feature)
    send_interrupt = false
    # Delay after sending Interrupt signal
    kill_delay = 500 # ms
    
    [log]
    # Show log time
    time = false
    
    [color]
    # Customize each part's color. If no color found, use the raw app log.
    main = "magenta"
    watcher = "cyan"
    build = "yellow"
    runner = "green"
    
    [misc]
    # Delete tmp directory on exit
    clean_on_exit = true
    
    bug 
    opened by tmwatchanan 10
  • Permission denied after update from 1.12.1 to 1.12.3

    Permission denied after update from 1.12.1 to 1.12.3

    Just updated air from 1.12.1 to 1.12.3. Now running air in go folder fails as follows:

      __    _   ___
     / /\  | | | |_)
    /_/--\ |_| |_| \_ v1.12.3 // live reload for Go apps, with Go1.14.0
    
    watching .
    !exclude tmp
    building...
    running...
    /bin/sh: [PATH_TO_FOLDER]/tmp/main: Permission denied
    
    opened by kasuskasus1 9
  • build from multiple go files

    build from multiple go files

    Using Windows 10 Pro

    I have code in two files: main.go and handlers.go.

    When I build from the command line, no problem: go build -o ./tmp/main.exe. But when I use that same command within .air.conf, it seems it only builds main.go and ignores handlers.go, because I get the error message:

    .\main.go:14:19: undefined: firstFunc
    .\main.go:15:22: undefined: secondFunc
    

    the exact line in the config file is cmd = "go build -o ./tmp/main.exe"

    How can I run a build within air that includes all the *.go files?

    Note -- this also fails: cmd = "go build -o ./tmp/main.exe main.go handlers.go" However even if this worked, it seems like an unsatisfactory answer, eventually I may have a list of 10, 20, 50 files.

    opened by 2x2xplz 9
  • Runtime error: invalid memory address or nil pointer dereference

    Runtime error: invalid memory address or nil pointer dereference

    Constantly getting the following error after any file amend:

    panic: runtime error: invalid memory address or nil pointer dereference
    [signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x4f1aa2]
    
    goroutine 23 [running]:
    github.com/cosmtrek/air/runner.(*Engine).watching.func1(0xc4200d8780, 0x4b, 0x0, 0x0, 0x553860, 0xc4200d0360, 0x0, 0x0)
            /Users/cosmtrek/Code/go/src/github.com/cosmtrek/air/runner/engine.go:100 +0x32
    path/filepath.walk(0xc420018004, 0x37, 0x5542e0, 0xc4200d3040, 0xc4200de2e0, 0x0, 0x10)
            /usr/local/opt/go/libexec/src/path/filepath/path.go:377 +0x20d
    path/filepath.Walk(0xc420018004, 0x37, 0xc4200de2e0, 0x0, 0xc42003cfc8)
            /usr/local/opt/go/libexec/src/path/filepath/path.go:403 +0x106
    github.com/cosmtrek/air/runner.(*Engine).watching(0xc4200f0000, 0xc420018004, 0x37, 0x0, 0x0)
            /Users/cosmtrek/Code/go/src/github.com/cosmtrek/air/runner/engine.go:98 +0x74
    github.com/cosmtrek/air/runner.(*Engine).watchNewDir.func1(0xc4200f0000, 0xc420018004, 0x37)
            /Users/cosmtrek/Code/go/src/github.com/cosmtrek/air/runner/engine.go:179 +0x43
    created by github.com/cosmtrek/air/runner.(*Engine).watchNewDir
            /Users/cosmtrek/Code/go/src/github.com/cosmtrek/air/runner/engine.go:178 +0x36a
    

    OS: Windows x64 and Ubuntu 16.04 LTS (Windows subsystem)

    opened by lokhman 9
  • Fix command line argument handling for slice configuration parameters

    Fix command line argument handling for slice configuration parameters

    It seems slice configuration parameters such as ExcludeDir cannot be set correctly with command line arguments (nor override default config). The test for --build.exclude_regex only passes because the test value corresponds with the default value (set in defaultConfig), it's not actually set by the parameter in the test.

    I propose to treat the command line arguments for such config parameters as comma separated strings. Setting a value would work as e.g. --build.exclude_dir "templates,build".

    opened by the 8
  • Can't install air via cURL:  cosmtrek/air crit unable to find '' - use 'latest'

    Can't install air via cURL: cosmtrek/air crit unable to find '' - use 'latest'

    Goal

    Installing air with one of the cURL commands described in the README: curl -sSfL https://raw.githubusercontent.com/cosmtrek/air/master/install.sh | sh -s -- -b $(go env GOPATH)/bin curl -sSfL https://raw.githubusercontent.com/cosmtrek/air/master/install.sh | sh -s

    Issue

    Installation fails while logging (both with and without sudo):

    cosmtrek/air info checking GitHub for latest tag cosmtrek/air crit unable to find '' - use 'latest' or see https://github.com/cosmtrek/air/releases for details

    Environment

    • curl 7.86.0
    • go 1.19.4 linux/amd64
    • Ubuntu 22.04.1 LTS
    opened by joweich 0
  • Feat: option to silence verbose air logging using `main_only` in config

    Feat: option to silence verbose air logging using `main_only` in config

    Feat: option to silence verbose air logging using main_only in config

    Hides verbose air logging - (which can get in the way of the target program logs).

    Defaults to false - nothing should change by default, only after a user sets main_only = true in the config.

    Debug mode overrides this option (if debug mode, show all logs).

    Relates to #354 , #201

    opened by hmerritt 0
  • database local volumes gets deleted when docker-compose down is called

    database local volumes gets deleted when docker-compose down is called

    air.toml

    root="."
    tmp_dir="tmp"
    
    [build]
    cmd="go build -gcflags=\"all=-N -l\" -o ./bin/main ."
    bin="/app/bin"
    full_bin="dlv exec --continue --accept-multiclient --listen=:40000 --headless=true --api-version=2 --log /app/bin/main"
    log="air_errors.log"
    include_ext=["go", "yaml"]
    exclude_dir=["tmp"]
    delay=1000
    
    [log]
    time=true
    
    
    [misc]
    clean_on_exit=true
    

    docker-compose.yml

    version: '3'
    
    services:
      db:
        image: postgres
        container_name:db
        ports:
          - "5432:5432"
        environment:
          POSTGRES_USER: "test"
          POSTGRES_PASSWORD: "test"
          POSTGRES_DB: "test"
          TZ: "UTC"
          PGTZ: "UTC"
        healthcheck:
          test: pg_isready -U postgres
        volumes:
          - ./tmp:/var/lib/postgresql/data
    
      app:
        container_name:api
        build:
          context: .
          dockerfile: local.Dockerfile
        ports:
          - "9090:9090"
          - "40000:40000"
        security_opt:
          - "seccomp:unconfined"
        cap_add:
          - SYS_PTRACE
        restart: on-failure
        environment:
          PORT: 9090
          DB_CONN: "postgres://test:[email protected]:5432/chatbot?sslmode=disable"
        volumes:
          - .:/app
        depends_on:
          db:
            condition: service_healthy
        links:
          - db
    
    

    local.Dockerfile

    FROM golang:1.19 as builder
    
    ENV GO111MODULE=on
    
    RUN apt update && apt upgrade -y && \
        apt install -y git \
        make openssh-client
    
    WORKDIR /app
    
    RUN go install github.com/go-delve/delve/cmd/[email protected]
    RUN go install github.com/cosmtrek/[email protected]
    
    COPY go.mod ./
    COPY go.sum ./
    
    RUN go mod download
    
    COPY . .
    
    
    CMD ["air", "-c", ".air.toml"]
    
    

    the postgres local tmp folder gets deleted everytime i stop the container, thus losing all the local data

    opened by jithinlal 0
  • Only build, do not run

    Only build, do not run

    Is there a way to only do a build and not run the code?

    #bin = "./tmp/main" #bin = ""

    I tried commenting out the bin line, making it empty, and even removing it. But it still runs the program when build succeeds.

    opened by sathishvj 0
  • Hot reload does not work with Virtualbox shared folders

    Hot reload does not work with Virtualbox shared folders

    FYI Fsnotify is unable to detect file changes in Virtualbox shared folders(which is my use case, but this probably affects a variety of fs setups) so hot reload would not work

    See relevant discussion https://github.com/fsnotify/fsnotify/issues/152 Talks of adding a polling fallback https://github.com/fsnotify/fsnotify/issues/9 Webpack/Nodemon solved this by polling too, via an option ie poll = 1000ms

    Supposedly working(?) polling implementation from Moby based on Fsnotify https://github.com/moby/moby/commit/c609523a8c006fdd404a8b99be2567401c3ec1b9 used in Hugo https://github.com/gohugoio/hugo/tree/master/watcher/filenotify

    The polling issue in Fsnotify is 8 years old though. Makes sense to use the Moby fix in the meantime?

    opened by komlevv 0
Releases(v1.40.4)
Owner
Rick Yu
Read the fucking code \ʕ◔ϖ◔ʔ/
Rick Yu
Realize is the #1 Golang Task Runner which enhance your workflow by automating the most common tasks and using the best performing Golang live reloading.

#1 Golang live reload and task runner Content - ⭐️ Top Features - ???? Get started - ?? Config sample - ?? Commands List - ?? Support and Suggestions

Oxequa 4.3k Jan 6, 2023
EGo lets you build, debug und run Go apps on Intel SGX - as simple as conventional Go programming!

EGo is a framework for building confidential apps in Go. Confidential apps run in always-encrypted and verifiable enclaves on Intel SGX-enabled ha

Edgeless Systems GmbH 367 Dec 28, 2022
Build and (re)start go web apps after saving/creating/deleting source files.

unmaintained Fresh Fresh is a command line tool that builds and (re)starts your web application everytime you save a Go or template file. If the web f

Andrea Franz 3.5k Jan 2, 2023
🔎 gowatch Live reload for go apps.

Watch ?? gowatch Live reload for go apps Motivation I had no app to live reload my Go programs. Usage Install go install github.com/gelfand/gowatch ◆

Eugene 0 Dec 29, 2021
Live reload for Go web development

livedev livedev is a development proxy server for golang that allows live reloading. It supports multiple server configuration. It uses the request's

null 80 Jun 17, 2022
Live reload utility for Go web servers

gin gin is a simple command line utility for live-reloading Go web applications. Just run gin in your app directory and your web app will be served wi

Jeremy Saenz 4k Jan 4, 2023
Ambiente com Docker de "live-reload" para aplicações Go

Ambiente Go Um ambiente de "live reload", onde as alterações no código são observadas e re-executadas automaticamente, com Docker e Docker Compose. O

Davi Marcondes Moreira 3 Jun 17, 2022
💨 A real time messaging system to build a scalable in-app notifications, multiplayer games, chat apps in web and mobile apps.

Beaver A Real Time Messaging Server. Beaver is a real-time messaging server. With beaver you can easily build scalable in-app notifications, realtime

Ahmed 1.4k Jan 1, 2023
Reload a specified go program automatically by monitoring a directory.

gowatcher A bash script to automatically reload a go program when .go or .html files change in the monitored directory. It uses inotify. Installation

Nick Janetakis 16 Jul 7, 2020
Reload Go code in a running process at function/method level granularity

got reload? Function/method-level stateful hot reloading for Go! Status Very much work in progress.

null 34 Nov 9, 2022
Sidecar to watch a config folder and reload a process when it changes

A small (3MB uncompressed docker image), efficient (via inotify) sidecar to trigger application reloads when configuration changes.

Florent Delannoy 25 Dec 29, 2022
A local server with real-time reload function designed for static website preview or development

中文 | English ?? 介绍 reserver 是一款为静态网站预览或开发设计的具有实时重新加载功能的本地服务器。 其主要运用场景为: 单页应用的预览(例如Vue编译之后的项目不可以直接通过file://协议进行访问) 具有ajax请求的页面(因浏览器安全限制,默认禁止file://协议进行

憧憬Licoy 7 Aug 23, 2022
GCP Cloud Functions ready to Go starter with hot reload 🔥

GCP Cloud Functions - Go Starter Features: funcFramework already set up - ready for local development and testing. Hot Reload ready-to-go thanks to th

Eric Crescioni 0 Dec 16, 2021
Golang http&grpc server for gracefully shutdown like nginx -s reload

supervisor Golang http & grpc server for gracefully shutdown like nginx -s reload if you want a server which would be restarted without stopping servi

Terry Fei 0 Jan 8, 2022
This is a hot reload tooling for go

hotpocket This is a hot reload tooling for go Usage First need to have a json file in the root of your project. Name it as a hotpocket.json. It Should

Rasulov Emirlan 4 Jul 17, 2022
Realize is the #1 Golang Task Runner which enhance your workflow by automating the most common tasks and using the best performing Golang live reloading.

#1 Golang live reload and task runner Content - ⭐️ Top Features - ???? Get started - ?? Config sample - ?? Commands List - ?? Support and Suggestions

Oxequa 4.3k Jan 6, 2023
Server-sent live updates: protocol and reference implementation

Protocol and Reference Implementation Mercure is a protocol allowing to push data updates to web browsers and other HTTP clients in a convenient, fast

Kévin Dunglas 3.2k Jan 1, 2023
:rocket: Instant live visualization of your Go application runtime statistics (GC, MemStats, etc.) in the browser

Statsviz Instant live visualization of your Go application runtime statistics (GC, MemStats, etc.). Import "github.com/arl/statsviz" Register statsviz

Aurélien Rainone 2.6k Jan 3, 2023
Parse and generate m3u8 playlists for Apple HTTP Live Streaming (HLS) in Golang (ported from gem https://github.com/sethdeckard/m3u8)

go-m3u8 Golang package for m3u8 (ported m3u8 gem https://github.com/sethdeckard/m3u8) go-m3u8 provides easy generation and parsing of m3u8 playlists d

Tan Quang Ngo 102 Nov 19, 2022
A live-updating version of the UNIX wc command.

lwc A live-updating version of the UNIX wc command. Installation You can get a prebuilt binary for every major platform from the Releases page. Just e

Tim De Pauw 27 Jul 26, 2022