Run a command when files change

Reflex

Reflex is a small tool to watch a directory and rerun a command when certain files change. It's great for automatically running compile/lint/test tasks and for reloading your application when the code changes.

A simple example

# Rerun make whenever a .c file changes
reflex -r '\.c$' make

Installation

You'll need Go 1.11+ installed:

$ go get github.com/cespare/reflex

Reflex probably only works on Linux and Mac OS.

TODO: provide compiled downloads for linux/darwin amd64.

Usage

The following is given by running reflex -h:

Usage: reflex [OPTIONS] [COMMAND]

COMMAND is any command you'd like to run. Any instance of {} will be replaced
with the filename of the changed file. (The symbol may be changed with the
--substitute flag.)

OPTIONS are given below:
      --all=false:
            Include normally ignored files (VCS and editor special files).
  -c, --config="":
            A configuration file that describes how to run reflex
            (or '-' to read the configuration from stdin).
  -d, --decoration="plain":
            How to decorate command output. Choices: none, plain, fancy.
  -g, --glob=[]:
            A shell glob expression to match filenames. (May be repeated.)
  -G, --inverse-glob=[]:
            A shell glob expression to exclude matching filenames.
            (May be repeated.)
  -R, --inverse-regex=[]:
            A regular expression to exclude matching filenames.
            (May be repeated.)
      --only-dirs=false:
            Only match directories (not files).
      --only-files=false:
            Only match files (not directories).
  -r, --regex=[]:
            A regular expression to match filenames. (May be repeated.)
  -e, --sequential=false:
            Don't run multiple commands at the same time.
  -t, --shutdown-timeout=500ms:
            Allow services this long to shut down.
  -s, --start-service=false:
            Indicates that the command is a long-running process to be
            restarted on matching changes.
      --substitute="{}":
            The substitution symbol that is replaced with the filename
            in a command.
  -v, --verbose=false:
            Verbose mode: print out more information about what reflex is doing.

Examples:

    # Print each .txt file if it changes
    $ reflex -r '\.txt$' echo {}

    # Run 'make' if any of the .c files in this directory change:
    $ reflex -g '*.c' make

    # Build and run a server; rebuild and restart when .java files change:
    $ reflex -r '\.java$' -s -- sh -c 'make && java bin/Server'

Overview

Reflex watches file changes in the current working directory and re-runs the command that you specify. The flags change what changes cause the command to be rerun and other behavior.

Patterns

You can specify files to match using either shell glob patterns (-g) or regular expressions (-r). If you don't specify either, reflex will run your command after any file changes. (Reflex ignores some common editor and version control files; see Ignored files, below.)

You can specify inverse matches by using the --inverse-glob (-G) and --inverse-regex (-R) flags.

If you specify multiple globs/regexes (e.g. -r foo -r bar -R baz -G x/*/y), only files that match all patterns and none of the inverse patterns are selected.

The shell glob syntax is described here, while the regular expression syntax is described here.

The path that is matched against the glob or regular expression does not have a leading ./. For example, if there is a file ./foobar.txt that changes, then it will be matched by the regular expression ^foobar. If the path is a directory, it has a trailing /.

--start-service

The --start-service flag (short version: -s) inverts the behavior of command running: it runs the command when reflex starts and kills/restarts it each time files change. This is expected to be used with an indefinitely-running command, such as a server. You can use this flag to relaunch the server when the code is changed.

Substitution

Reflex provides a way for you to determine, inside your command, what file changed. This is via a substitution symbol. The default is {}. Every instance of the substitution symbol inside your command is replaced by the filename.

As a simple example, suppose you're writing Coffeescript and you wish to compile the CS files to Javascript when they change. You can do this with:

$ reflex -r '\.coffee$' -- coffee -c {}

In case you need to use {} for something else in your command, you can change the substitution symbol with the --substitute flag.

Configuration file

What if you want to run many watches at once? For example, when writing web applications I often want to rebuild/rerun the server when my code changes, but also build SCSS and Coffeescript when those change as well. Instead of running multiple reflex instances, which is cumbersome (and inefficient), you can give reflex a configuration file.

The configuration file syntax is simple: each line is a command, and each command is composed of flags and arguments -- just like calling reflex but without the initial reflex. Lines that start with # are ignored. Commands can span multiple lines if they're \-continued, or include multi-line strings. Here's an example:

# Rebuild SCSS when it changes
-r '\.scss$' -- \
   sh -c 'sass {} `basename {} .scss`.css'

# Restart server when ruby code changes
-sr '\.rb$' -- \
    ./bin/run_server.sh

If you want to change the configuration file and have reflex reload it on the fly, you can run reflex inside reflex:

reflex -s -g reflex.conf -- reflex -c reflex.conf

This tells reflex to run another reflex process as a service that's restarted whenever reflex.conf changes.

--sequential

When using a config file to run multiple simultaneous commands, reflex will run them at the same time (if appropriate). That is, a particular command can only be run once a previous run of that command finishes, but two different commands may run at the same time. This is usually what you want (for speed).

As a concrete example, consider this config file:

-- sh -c 'for i in `seq 1 5`; do sleep 0.1; echo first; done'
-- sh -c 'for i in `seq 1 5`; do sleep 0.1; echo second; done'

When this runs, you'll see something like this:

[01] second
[00] first
[01] second
[00] first
[00] first
[01] second
[01] second
[00] first
[01] second
[00] first

Note that the output is interleaved. (Reflex does ensure that each line of output is not interleaved with a different line.) If, for some reason, you need to ensure that your commands don't run at the same time, you can do this with the --sequential (-e) flag. Then the output would look like (for example):

[01] second
[01] second
[01] second
[01] second
[01] second
[00] first
[00] first
[00] first
[00] first
[00] first

Decoration

By default, each line of output from your command is prefixed with something like [00], which is simply an id that reflex assigns to each command. You can use --decoration (-d) to change this output: --decoration=none will print the output as is; --decoration=fancy will color each line differently depending on which command it is, making it easier to distinguish the output.

Ignored files

Reflex ignores a variety of version control and editor metadata files by default. If you wish for these to be included, you can provide reflex with the --all flag.

You can see a list of regular expressions that match the files that reflex ignores by default here.

Notes and Tips

If you don't use -r or -g, reflex will match every file.

Reflex only considers file creation and modification changes. It does not report attribute changes nor deletions.

For ignoring directories, it's easiest to use a regular expression: -R '^dir/'.

Many regex and glob characters are interpreted specially by various shells. You'll generally want to minimize this effect by putting the regex and glob patterns in single quotes.

If your command has options, you'll probably need to use -- to separate the reflex flags from your command flags. For example: reflex -r '.*\.txt' -- ls -l.

If you're going to use shell things, you need to invoke a shell as a parent process:

reflex -- sh -c 'sleep 1 && echo {}'

If your command is running with sudo, you'll need a passwordless sudo, because you cannot enter your password in through reflex.

It's not difficult to accidentally make an infinite loop with certain commands. For example, consider this command: reflex -r '\.txt' cp {} {}.bak. If foo.txt changes, then this will create foo.txt.bak, foo.txt.bak.bak, and so forth, because the regex \.txt matches each file. Reflex doesn't have any kind of infinite loop detection, so be careful with commands like cp.

The restart behavior works as follows: if your program is still running, reflex sends it SIGINT; after 1 second if it's still alive, it gets SIGKILL. The new process won't be started up until the old process is dead.

Batching

Part of what reflex does is apply some heuristics to batch together file changes. There are many reasons that files change on disk, and these changes frequently come in large bursts. For instance, when you save a file in your editor, it probably makes a tempfile and then copies it over the target, leading to several different changes. Reflex hides this from you by batching some changes together.

One thing to note, though, is that the the batching is a little different depending on whether or not you have a substitution symbol in your command. If you do not, then updates for different files that all match your pattern can be batched together in a single update that only causes your command to be run once.

If you are using a substitution symbol, however, each unique matching file will be batched separately.

Argument list splitting

When you give reflex a command from the commandline (i.e., not in a config file), that command is split into pieces by whatever shell you happen to be using. When reflex parses the config file, however, it must do that splitting itself. For this purpose, it uses this library which attempts to match sh's argument splitting rules.

This difference can lead to slightly different behavior when running commands from a config file. If you're confused, it can help to use --verbose (-v) which will print out each command as interpreted by reflex.

Open file limits

Reflex currently must hold an open file descriptor for every directory it's watching, recursively. If you run reflex at the top of a big directory tree, you can easily run into file descriptor limits. You might see an error like this:

open some/path: too many open files

There are several things you can do to get around this problem.

  1. Run reflex in the most specific directory possible. Don't run reflex -g path/to/project/*.c ... from $HOME; instead run reflex in path/to/project.
  2. Ignore large subdirectories. Reflex already ignores, for instance, .git/. If you have other large subdirectories, you can ignore those yourself: reflex -R '^third_party/' ... ignores everything under third_party/ in your project directory.
  3. Raise the fd limit using ulimit or some other tool. On some systems, this might default to a restrictively small value like 256.

See issue #6 for some more background on this issue.

The competition

Why you should use reflex instead

  • Reflex has no dependencies. No need to install Ruby or anything like that.
  • Reflex uses an appropriate file watching mechanism to watch for changes efficiently on your platform.
  • Reflex gives your command the name of the file that changed.
  • No DSL to learn -- just give it a shell command.
  • No plugins.
  • Not tied to any language, framework, workflow, or editor.

Authors

Owner
Caleb Spare
I make Go servers fast at @liftoffio.
Caleb Spare
Comments
  • Crash with error message read: interrupted system call

    Crash with error message read: interrupted system call

    How to reproduce

    Rapidly save changes to a file, reflex crashes fairly soon (After 5-10 saves).

    Error message

    read: interrupted system call
    

    Expected behavior

    Reflex shouldn’t crash on interrupted system calls

    Environment

    | | Value | | --- | --- | | OS | Debian GNU/Linux 7 (wheezy) | | Architecture | i386 | | Go version | 1.4 | | Hosting provider | BlueVM |

  • Binary downloads

    Binary downloads

    One of this repository's proposed benefits as written in the readme: "Reflex has no dependencies. No need to install Ruby or anything like that." Yet the instillation reads:

    $ go get github.com/cespare/reflex
    

    I don't want to install go to use this library. Could this dependency be removed with binary downloads?

  • Not working with http server

    Not working with http server

    I'm trying to use reflex to compile, stop and then restart a http server written in Go. But after http server listening in some port, suppose :8080 the reflex does nothing. In a simple hello-world function works fine, but after start a http server not working.

    I have a Make file:

    build:
    	GOOS=linux go build -o ./build/api ./main.go
    
    start:
    	make build
    	echo "Starting build/api"
    	./build/api
    	reflex -r \.go make restart
    
    restart: stop build start
    
    stop:
    	echo "Stopping ./build/api if it's running"
    	kill -9 `cat ./tmp/.pid`
    

    So I just need to run make start and server will start fine, but never will execute the line reflex -r \.go make restart.

    The .pid file on stop command is generated by my go program before start the server. And is working fine. Just the restart command is never executed by reflex.

    Someone already had this behavior before?

  • Watch specific paths

    Watch specific paths

    Change

    Allow paths to be watched to be specified.

    Rational

    While working on a project, I realized that I needed to watch directories outside the current path. Trying to exclude all other paths would be impractical, so I wrote this patch to allow only specific directories to be watched.

    This change is backwards compatible with the current reflex and adds a command line switch to specify the paths that will be included.

    New usage:

    reflex -p ../path_to_lib -p path_to_files echo "file changed is {}"

    If a path is not specified, the the current directory will be used (as with current reflex).

  • Prevent duplicate command runs with intermediate file states

    Prevent duplicate command runs with intermediate file states

    Currently, reflex will sometimes run a command twice when I save a file, with one of those runs being on an empty file, and the other with the rest of the save.

    This is because reflex batches change events for 300 milliseconds from the first change event. But if a change series takes longer than 300 milliseconds to complete (e.g. saving or rsyncing a large file over a slow network connection) the command will be run multiple times, while seeing possibly-corrupt intermediate states of the filesystem.

    This change alters the batching logic so that instead of waiting 300 milliseconds after the first change event, reflex will instead wait 300 milliseconds after the last change. This avoids running a single-file command while a file is still changing, or running a multi-file command while a directory's contents are still in flux. The command will instead run after the changed file(s) have stopped changing for at least 300ms.

    This ensures that duplicate commands aren't run, nor do the commands operate on data that is in flux.

  • Discussion: Option to coalesce backlog

    Discussion: Option to coalesce backlog

    It is sometimes advantageous to have a command digest all changed files, rather than being invoked separately several times. Reflex's internal backlog maps a burst of changes into multiple commands, such that running touch 1 2 3 will generate the following output:

    $ reflex echo {}
    [00] 1
    [00] 2
    [00] 3
    

    As implemented, any system would have to be tolerant of rapid-fire invokations and do its own batching. It would be nice to have a non-default option to run the command once per backlog flush:

    $ reflex --combined-changes echo {}
    [00] 1 2 3
    

    I have implemented a quick & dirty proof of concept on my fork's combined-changes branch. Hopefully this can be used as a base to get a better implementation merged in.

    The good:

    • Basic functionality works, defaults are unchanged
    • Config option, config subsitution check, and help text added

    The bad / ugly:

    • Backlog interface modified; an All() function was added.
    • The functions batch and runEach had to be modified, so right now they're copies for combined & default behavior. Not exactly DRY.
    • Due to the particular way select is used for signaling, this could inflate a set of strings arbitrarily many times. This could be a performance problem if I'm correctly understanding the RTL implications of case out <- r.backlog.All().
    • Code style guide / gofmt not applied yet.
    • Right now, this passes the paths set as a single space-delimited parameter to the command. Arguably it should pass N many parameters instead.
  • Add goreleaser support

    Add goreleaser support

    This PR adds support for the minimum needed goreleaser config to generate releases with binaries. This resolves #31 and is an alternative to #67.

    An example on my fork of a release is: https://github.com/kpurdon/reflex/releases/tag/v0.2.1

    This can currently be run by doing the following:

    1. Do some work, commit it, push it, create and push a tag.
    2. Make sure GITHUB_TOKEN="a_repo_scope_github_token" is set.
    3. Run goreleaser.

    This is more or less from the example here: https://goreleaser.com/quick-start/.

    I avoided adding any automation (TravisCI, Github Actions, ...) since that would be difficult for me to test, but those things are supported:

    • https://goreleaser.com/ci/
    • https://goreleaser.com/actions/

    The process for this would be to merge, tag a new release, and run goreleaser (following my steps above) to create a new release with binaries.

  • Why the negative 1?

    Why the negative 1?

    For gosh sake's I've been trying to debug my own code for a while now, and I look to your code for inspiration, and the thing that fixed it was changing

    syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
    
    syscall.Kill(-1*cmd.Process.Pid, syscall.SIGKILL)
    

    as you did in your code. I just thought it looked odd and there must be a reason for it, so I tried it and it fixed my code!!!

    So, I just have to ask why on earth. I guess it's casting it to an int? But why does that matter?

  • Reflex using 100% CPU

    Reflex using 100% CPU

    This has happened to me a few times on OSX. I'm using the latest reflex and Go 1.9.

    I'm not sure yet how to reproduce but I'll update if I get more information. I've pasted a goroutine dump below.

    The config file is just watching resource files and calling make.

    -r '^resources/assets/.*\.(coffee|js)$' -- make js
    -r '^resources/assets/.*\.(less|css)$' -- make css
    

    Goroutine dump:

    PC=0x1056bd3 m=2 sigcode=0
    
    goroutine 0 [idle]:
    runtime.mach_semaphore_timedwait(0x3c00001e03, 0x0, 0x70000f831cf4, 0x3c, 0x0, 0xc420000900, 0x70000f831d28, 0x1051173, 0xdf8475800, 0x0, ...)
    	/usr/local/Cellar/go/1.9/libexec/src/runtime/sys_darwin_amd64.s:455 +0x13
    runtime.semasleep1(0xdf8475800, 0x0)
    	/usr/local/Cellar/go/1.9/libexec/src/runtime/os_darwin.go:402 +0xdf
    runtime.semasleep.func1()
    	/usr/local/Cellar/go/1.9/libexec/src/runtime/os_darwin.go:432 +0x33
    runtime.systemstack(0x70000f831d50)
    	/usr/local/Cellar/go/1.9/libexec/src/runtime/asm_amd64.s:360 +0xab
    runtime.semasleep(0xdf8475800, 0x1033b73)
    	/usr/local/Cellar/go/1.9/libexec/src/runtime/os_darwin.go:431 +0x44
    runtime.notetsleep_internal(0x11f0b18, 0xdf8475800, 0xc420000900, 0x742c47f3603, 0xc400000014)
    	/usr/local/Cellar/go/1.9/libexec/src/runtime/lock_sema.go:218 +0x112
    runtime.notetsleep(0x11f0b18, 0xdf8475800, 0x7188aae1b01)
    	/usr/local/Cellar/go/1.9/libexec/src/runtime/lock_sema.go:269 +0x75
    runtime.sysmon()
    	/usr/local/Cellar/go/1.9/libexec/src/runtime/proc.go:3866 +0x14d
    runtime.mstart1()
    	/usr/local/Cellar/go/1.9/libexec/src/runtime/proc.go:1172 +0x11e
    runtime.mstart()
    	/usr/local/Cellar/go/1.9/libexec/src/runtime/proc.go:1142 +0x64
    
    goroutine 1 [chan receive]:
    main.main()
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/main.go:201 +0x8ff
    
    goroutine 5 [syscall]:
    os/signal.signal_recv(0x0)
    	/usr/local/Cellar/go/1.9/libexec/src/runtime/sigqueue.go:131 +0xa7
    os/signal.loop()
    	/usr/local/Cellar/go/1.9/libexec/src/os/signal/signal_unix.go:22 +0x22
    created by os/signal.init.0
    	/usr/local/Cellar/go/1.9/libexec/src/os/signal/signal_unix.go:28 +0x41
    
    goroutine 6 [select, locked to thread]:
    runtime.gopark(0x11473a0, 0x0, 0x113e929, 0x6, 0x18, 0x1)
    	/usr/local/Cellar/go/1.9/libexec/src/runtime/proc.go:277 +0x12c
    runtime.selectgo(0xc420046f50, 0xc4200244e0)
    	/usr/local/Cellar/go/1.9/libexec/src/runtime/select.go:395 +0x1138
    runtime.ensureSigM.func1()
    	/usr/local/Cellar/go/1.9/libexec/src/runtime/signal_unix.go:511 +0x1fe
    runtime.goexit()
    	/usr/local/Cellar/go/1.9/libexec/src/runtime/asm_amd64.s:2337 +0x1
    
    goroutine 7 [chan receive]:
    main.main.func1(0xc42006a540)
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/main.go:175 +0x4b
    created by main.main
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/main.go:174 +0x55b
    
    goroutine 8 [syscall]:
    syscall.Syscall6(0x16b, 0x3, 0x0, 0x0, 0xc42005fe88, 0xa, 0x120ede0, 0x0, 0x0, 0x0)
    	/usr/local/Cellar/go/1.9/libexec/src/syscall/asm_darwin_amd64.s:41 +0x5
    github.com/cespare/reflex/vendor/golang.org/x/sys/unix.kevent(0x3, 0x0, 0x0, 0xc42005fe88, 0xa, 0x120ede0, 0x0, 0x0, 0x0)
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go:207 +0x83
    github.com/cespare/reflex/vendor/golang.org/x/sys/unix.Kevent(0x3, 0x0, 0x0, 0x0, 0xc42005fe88, 0xa, 0xa, 0x120ede0, 0x0, 0x0, ...)
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/vendor/golang.org/x/sys/unix/syscall_bsd.go:448 +0x71
    github.com/cespare/reflex/vendor/github.com/fsnotify/fsnotify.read(0x3, 0xc42005fe88, 0xa, 0xa, 0x120ede0, 0xc42005fe88, 0x0, 0xa, 0x0, 0x0)
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/vendor/github.com/fsnotify/fsnotify/kqueue.go:493 +0x78
    github.com/cespare/reflex/vendor/github.com/fsnotify/fsnotify.(*Watcher).readEvents(0xc42006a600)
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/vendor/github.com/fsnotify/fsnotify/kqueue.go:284 +0x572
    created by github.com/cespare/reflex/vendor/github.com/fsnotify/fsnotify.NewWatcher
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/vendor/github.com/fsnotify/fsnotify/kqueue.go:62 +0x293
    
    goroutine 9 [select]:
    main.watch(0x113e2d8, 0x1, 0xc42006a600, 0xc4200246c0, 0xc420024720, 0xc42004e7e0, 0x2, 0x2)
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/watch.go:23 +0x2b0
    created by main.main
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/main.go:193 +0x7d2
    
    goroutine 10 [chan receive]:
    main.broadcast(0xc42004e800, 0x2, 0x2, 0xc4200246c0)
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/main.go:205 +0xa0
    created by main.main
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/main.go:194 +0x818
    
    goroutine 11 [chan receive]:
    main.printOutput(0xc42006a060, 0x11da520, 0xc42000e018)
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/print.go:65 +0xa7
    created by main.main
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/main.go:195 +0x854
    
    goroutine 12 [chan receive]:
    main.(*Reflex).filterMatching(0xc4200a0a00, 0xc420024840, 0xc420024780)
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/reflex.go:130 +0x4e
    created by main.(*Reflex).Start
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/reflex.go:298 +0x9d
    
    goroutine 13 [chan receive]:
    main.(*Reflex).batch(0xc4200a0a00, 0xc4200248a0, 0xc420024840)
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/reflex.go:156 +0x292
    created by main.(*Reflex).Start
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/reflex.go:299 +0xd3
    
    goroutine 14 [chan receive]:
    main.(*Reflex).runEach(0xc4200a0a00, 0xc4200248a0)
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/reflex.go:184 +0x4b
    created by main.(*Reflex).Start
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/reflex.go:300 +0xff
    
    goroutine 15 [chan receive]:
    main.(*Reflex).filterMatching(0xc4200a0be0, 0xc420024900, 0xc4200247e0)
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/reflex.go:130 +0x4e
    created by main.(*Reflex).Start
    
    
    [gumtwo] Fix tests
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/reflex.go:298 +0x9d
    
    goroutine 16 [chan receive]:
    main.(*Reflex).batch(0xc4200a0be0, 0xc420024960, 0xc420024900)
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/reflex.go:156 +0x292
    created by main.(*Reflex).Start
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/reflex.go:299 +0xd3
    
    goroutine 18 [chan receive]:
    main.(*Reflex).runEach(0xc4200a0be0, 0xc420024960)
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/reflex.go:184 +0x4b
    created by main.(*Reflex).Start
    	/Users/mikeq/dev/go/src/github.com/cespare/reflex/reflex.go:300 +0xff
    
    rax    0xe
    rbx    0x3c
    rcx    0x70000f831cc8
    rdx    0x0
    rdi    0x1e03
    rsi    0x3c
    rbp    0x70000f831d00
    rsp    0x70000f831cc8
    r8     0x70000f831dc0
    r9     0x6d
    r10    0x603d27dc
    r11    0x202
    r12    0x6029408d5610
    r13    0xb03
    r14    0x102cf10
    r15    0x1400000
    rip    0x1056bd3
    rflags 0x202
    cs     0x7
    fs     0x0
    gs     0x0
    
  • Entr

    Entr

    Hello, there is a similar program called Entr, I think it would be helpful to do some comparisons and explain why reflex was made and how it is different / better than Entr.

  • Command not being run in Linux

    Command not being run in Linux

    Reflex is able to watch files for changes but it doesn't run the commands in my Linux computer. Here is the verbose output of a simple ./bin/reflex -v -g '.' echo {} command:

      λ  ./bin/reflex -v  -g '.' echo {}                                                                                                                                         
    Globals set at commandline                                                                                                                                                   
    | --glob (-g) '[.]' (default: '[]')
    | --verbose (-v) 'true' (default: 'false')
    +---------
    Reflex from [commandline]
    | ID: 0
    | Inverted regex match: "(^|/)\\.git/"
    | Inverted regex match: "(^|/)\\.hg/"
    | Inverted regex match: "~$"
    | Inverted regex match: "\\.swp$"
    | Inverted regex match: "\\.#"
    | Inverted regex match: "(^|/)#.*#$"
    | Inverted regex match: "(^|/)\\.DS_Store$"
    | Glob match: "."
    | Substitution symbol {}
    | Command: [echo <filename>]
    +---------
    
    [info] fsnotify event: "./Makefile": WRITE 
    
  • Enforce group naming or Apply alias

    Enforce group naming or Apply alias

    Currently we have these pattern

    [01] second
    [00] first
    [01] second
    [00] first
    [00] first
    [01] second
    [01] second
    [00] first
    [01] second
    [00] first
    

    is there anyway we can name those 00 / 01 for easy and traceable coding?

    [go] second
    [reactjs] first
    ...
    
  • Feature Request: Support for LiveReload Protocol?

    Feature Request: Support for LiveReload Protocol?

    Would be cool to implement in browser live reloading whenever reflex detects an update... The LiveReload protocol has already got a lot of nuances of browser reloading figured out and has been around for a long time. Here are some GoLang implementations.

    Basic GoLang implementation of live-reload that exists:

    https://github.com/omeid/go-livereload

    For a server only version, there's:

    https://github.com/jaschaephraim/lrserver

    And Hugo (golang static site generator) has an implementation:

    https://github.com/gohugoio/hugo/tree/master/livereload

    There are live reload browser extensions for Firefox, Chrome

    Reflex is so much faster than similar tools that I've tried... Would be amazing if it also supported this websocket based LiveReload... Almost like magic - bypassing the need to integrate LiveReload directly into applications!

  • stdin is ignored

    stdin is ignored

    I'm using reflex to compile a Java program that gets input from stdin. I'm running the command using:

    # Build and run a server; rebuild and restart when .java files change:
        $ reflex -r '\.java$' -s -- sh -c 'make && java bin/Server'
    

    However, the input from stdin gets ignored.

    Is there something I can do? If not, where, in the code, can I try to fix it?

  • Use default config file if exists

    Use default config file if exists

    Fixes #41

    I was going through my issues list and saw that I had opened a feature request (2.5 years ago, sorry) for a "rc file" in the current directory, such that if it exists, it is automatically used if --config flag is not set. I believe we settled on a straightforward name for the config file: reflex.conf. This PR implements that in a very simple, straightforward way:

    Before the config flag is processed, we check if it's empty and if reflex.conf exists. If it does, the flag is quietly set to that value before rest of the flag processing takes place. I also modified the wording of an error to indicate that the flag validation behavior is the same whether --config flag is specified or assumed (to be =reflex.conf).

    I tested this by building the reflex binary and running it in a directory with and without a reflex.conf file and it seems to meet the expectations in this rudimentary, manual test. I'm not sure how to add an automated test for this. Contents of main() do not seem to be autotested anyway.

    I should also update the documentation before this is ready for review.

    Edit: Also, prefer not to add my name to authors list. This is extremely trivial and I don't feel that I deserve the credit.

Related tags
Split text files into gzip files with x lines

hakgzsplit split lines of text into multiple gzip files

Jun 21, 2022
Easily create Go files from stub files

go-stubs Easily create .go files from stub files in your projects. Usage go get github.com/nwby/go-stubs Create a stub file: package stubs type {{.Mo

Jan 27, 2022
app-services-go-linter plugin analyze source tree of Go files and validates the availability of i18n strings in *.toml files

app-services-go-linter app-services-go-linter plugin analyze source tree of Go files and validates the availability of i18n strings in *.toml files. A

Nov 29, 2021
Compute message digest for large files in Go

checksum test coverage Compute message digest, like MD5 and SHA256, in golang for potentially large files. Usage package main import ( "fmt" "githu

Dec 28, 2022
copy files for humans

Go-Decent-Copy go-decent-copy provides a copy file for humans Usage package main import "github.com/hugocarreira/go-decent-copy" func main() { e

Sep 26, 2022
Golang wrapper for Exiftool : extract as much metadata as possible (EXIF, ...) from files (pictures, pdf, office documents, ...)

go-exiftool go-exiftool is a golang library that wraps ExifTool. ExifTool's purpose is to extract as much metadata as possible (EXIF, IPTC, XMP, GPS,

Dec 28, 2022
Load GTFS files in golang

go-gtfs Load GTFS files in Go. The project is in maintenance mode. It is kept compatible with changes in the Go ecosystem but no new features will be

Dec 5, 2022
An implementation of the FileSystem interface for tar files.

TarFS A wrapper around tar.Reader. Implements the FileSystem interface for tar files. Adds an Open method, that enables reading of file according to i

Sep 26, 2022
QueryCSV enables you to load CSV files and manipulate them using SQL queries then after you finish you can export the new values to a CSV file
QueryCSV enables you to load CSV files and manipulate them using SQL queries then after you finish you can export the new values to a CSV file

QueryCSV enable you to load CSV files and manipulate them using SQL queries then after you finish you can export the new values to CSV file

Dec 22, 2021
A Go io/fs filesystem implementation for reading files in a Github gists.

GistFS GistFS is an io/fs implementation that enables to read files stored in a given Gist. Requirements This module depends on io/fs which is only av

Oct 14, 2022
Create ePub files from URLs

url2epub Create ePub files from URLs Overview The root directory provides a Go library that creates ePub files out of URLs, with limitations.

Nov 5, 2022
🏵 Gee is tool of stdin to each files and stdout
🏵 Gee is tool of stdin to each files and stdout

Gee is tool of stdin to each files and stdout. It is similar to the tee command, but there are more functions for convenience. In addition, it was written as go. which provides output to stdout and files.

Nov 17, 2022
Golang PDF library for creating and processing PDF files (pure go)

UniPDF - PDF for Go UniDoc UniPDF is a PDF library for Go (golang) with capabilities for creating and reading, processing PDF files. The library is wr

Dec 28, 2022
Format /etc/fstab files.
Format /etc/fstab files.

Format /etc/fstab files. Features and limitations Can format /etc/fstab files. Will use 2 spaces between all fields, if they are of equal length. The

Dec 3, 2022
Go (golang) library for reading and writing XLSX files.

XLSX Introduction xlsx is a library to simplify reading and writing the XML format used by recent version of Microsoft Excel in Go programs. Current s

Jan 5, 2023
Golang library for reading and writing Microsoft Excel™ (XLSX) files.
Golang library for reading and writing Microsoft Excel™ (XLSX) files.

Excelize Introduction Excelize is a library written in pure Go providing a set of functions that allow you to write to and read from XLSX / XLSM / XLT

Dec 31, 2022
Easily create & extract archives, and compress & decompress files of various formats

archiver Introducing Archiver 3.1 - a cross-platform, multi-format archive utility and Go library. A powerful and flexible library meets an elegant CL

Jan 3, 2023
Embed files into a Go executable

statik statik allows you to embed a directory of static files into your Go binary to be later served from an http.FileSystem. Is this a crazy idea? No

Jan 6, 2023
A Go filesystem package for working with files and directories

Stowage A Go filesystem package for working with files and directories, it features a simple API with support for the common files and directories ope

May 28, 2021