• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

.gitignoreH A D13-Aug-202020 32

CONTRIBUTING.mdH A D13-Aug-20201,015 3022

LICENSEH A D13-Aug-20201 KiB2016

README.mdH A D13-Aug-202012.5 KiB335251

backlog.goH A D13-Aug-20202.4 KiB10978

backlog_test.goH A D13-Aug-2020768 3834

config.goH A D13-Aug-20204.4 KiB162135

config_test.goH A D13-Aug-20202.1 KiB9081

defaultexclude.goH A D13-Aug-2020418 2718

go.modH A D13-Aug-2020318 1310

go.sumH A D13-Aug-20201.3 KiB1615

main.goH A D13-Aug-20204.9 KiB212180

match.goH A D13-Aug-20205.1 KiB200150

match_test.goH A D13-Aug-20202.5 KiB110100

print.goH A D13-Aug-20201.3 KiB6958

reflex.goH A D13-Aug-20208 KiB342275

watch.goH A D13-Aug-20202.1 KiB8467

README.md

1# Reflex
2
3Reflex is a small tool to watch a directory and rerun a command when certain
4files change. It's great for automatically running compile/lint/test tasks and
5for reloading your application when the code changes.
6
7## A simple example
8
9    # Rerun make whenever a .c file changes
10    reflex -r '\.c$' make
11
12## Installation
13
14You'll need Go 1.11+ installed:
15
16    $ go get github.com/cespare/reflex
17
18Reflex probably only works on Linux and Mac OS.
19
20TODO: provide compiled downloads for linux/darwin amd64.
21
22## Usage
23
24The following is given by running `reflex -h`:
25
26```
27Usage: reflex [OPTIONS] [COMMAND]
28
29COMMAND is any command you'd like to run. Any instance of {} will be replaced
30with the filename of the changed file. (The symbol may be changed with the
31--substitute flag.)
32
33OPTIONS are given below:
34      --all=false:
35            Include normally ignored files (VCS and editor special files).
36  -c, --config="":
37            A configuration file that describes how to run reflex
38            (or '-' to read the configuration from stdin).
39  -d, --decoration="plain":
40            How to decorate command output. Choices: none, plain, fancy.
41  -g, --glob=[]:
42            A shell glob expression to match filenames. (May be repeated.)
43  -G, --inverse-glob=[]:
44            A shell glob expression to exclude matching filenames.
45            (May be repeated.)
46  -R, --inverse-regex=[]:
47            A regular expression to exclude matching filenames.
48            (May be repeated.)
49      --only-dirs=false:
50            Only match directories (not files).
51      --only-files=false:
52            Only match files (not directories).
53  -r, --regex=[]:
54            A regular expression to match filenames. (May be repeated.)
55  -e, --sequential=false:
56            Don't run multiple commands at the same time.
57  -t, --shutdown-timeout=500ms:
58            Allow services this long to shut down.
59  -s, --start-service=false:
60            Indicates that the command is a long-running process to be
61            restarted on matching changes.
62      --substitute="{}":
63            The substitution symbol that is replaced with the filename
64            in a command.
65  -v, --verbose=false:
66            Verbose mode: print out more information about what reflex is doing.
67
68Examples:
69
70    # Print each .txt file if it changes
71    $ reflex -r '\.txt$' echo {}
72
73    # Run 'make' if any of the .c files in this directory change:
74    $ reflex -g '*.c' make
75
76    # Build and run a server; rebuild and restart when .java files change:
77    $ reflex -r '\.java$' -s -- sh -c 'make && java bin/Server'
78```
79
80### Overview
81
82Reflex watches file changes in the current working directory and re-runs the
83command that you specify. The flags change what changes cause the command to be
84rerun and other behavior.
85
86### Patterns
87
88You can specify files to match using either shell glob patterns (`-g`) or
89regular expressions (`-r`). If you don't specify either, reflex will run your
90command after any file changes. (Reflex ignores some common editor and version
91control files; see Ignored files, below.)
92
93You can specify inverse matches by using the `--inverse-glob` (`-G`) and
94`--inverse-regex` (`-R`) flags.
95
96If you specify multiple globs/regexes (e.g. `-r foo -r bar -R baz -G x/*/y`),
97only files that match all patterns and none of the inverse patterns are
98selected.
99
100The shell glob syntax is described
101[here](http://golang.org/pkg/path/filepath/#Match), while the regular expression
102syntax is described [here](https://code.google.com/p/re2/wiki/Syntax).
103
104The path that is matched against the glob or regular expression does not have a
105leading `./`. For example, if there is a file `./foobar.txt` that changes, then
106it will be matched by the regular expression `^foobar`. If the path is a
107directory, it has a trailing `/`.
108
109### --start-service
110
111The `--start-service` flag (short version: `-s`) inverts the behavior of command
112running: it runs the command when reflex starts and kills/restarts it each time
113files change. This is expected to be used with an indefinitely-running command,
114such as a server. You can use this flag to relaunch the server when the code is
115changed.
116
117### Substitution
118
119Reflex provides a way for you to determine, inside your command, what file
120changed. This is via a substitution symbol. The default is `{}`. Every instance
121of the substitution symbol inside your command is replaced by the filename.
122
123As a simple example, suppose you're writing Coffeescript and you wish to compile
124the CS files to Javascript when they change. You can do this with:
125
126    $ reflex -r '\.coffee$' -- coffee -c {}
127
128In case you need to use `{}` for something else in your command, you can change
129the substitution symbol with the `--substitute` flag.
130
131### Configuration file
132
133What if you want to run many watches at once? For example, when writing web
134applications I often want to rebuild/rerun the server when my code changes, but
135also build SCSS and Coffeescript when those change as well. Instead of running
136multiple reflex instances, which is cumbersome (and inefficient), you can give
137reflex a configuration file.
138
139The configuration file syntax is simple: each line is a command, and each
140command is composed of flags and arguments -- just like calling reflex but
141without the initial `reflex`. Lines that start with `#` are ignored. Commands
142can span multiple lines if they're \\-continued, or include multi-line strings.
143Here's an example:
144
145    # Rebuild SCSS when it changes
146    -r '\.scss$' -- \
147       sh -c 'sass {} `basename {} .scss`.css'
148
149    # Restart server when ruby code changes
150    -sr '\.rb$' -- \
151        ./bin/run_server.sh
152
153If you want to change the configuration file and have reflex reload it on the
154fly, you can run reflex inside reflex:
155
156    reflex -s -g reflex.conf -- reflex -c reflex.conf
157
158This tells reflex to run another reflex process as a service that's restarted
159whenever `reflex.conf` changes.
160
161### --sequential
162
163When using a config file to run multiple simultaneous commands, reflex will run
164them at the same time (if appropriate). That is, a particular command can only
165be run once a previous run of that command finishes, but two different commands
166may run at the same time. This is usually what you want (for speed).
167
168As a concrete example, consider this config file:
169
170    -- sh -c 'for i in `seq 1 5`; do sleep 0.1; echo first; done'
171    -- sh -c 'for i in `seq 1 5`; do sleep 0.1; echo second; done'
172
173When this runs, you'll see something like this:
174
175    [01] second
176    [00] first
177    [01] second
178    [00] first
179    [00] first
180    [01] second
181    [01] second
182    [00] first
183    [01] second
184    [00] first
185
186Note that the output is interleaved. (Reflex does ensure that each line of
187output is not interleaved with a different line.) If, for some reason, you need
188to ensure that your commands don't run at the same time, you can do this with
189the `--sequential` (`-e`) flag. Then the output would look like (for example):
190
191    [01] second
192    [01] second
193    [01] second
194    [01] second
195    [01] second
196    [00] first
197    [00] first
198    [00] first
199    [00] first
200    [00] first
201
202### Decoration
203
204By default, each line of output from your command is prefixed with something
205like `[00]`, which is simply an id that reflex assigns to each command. You can
206use `--decoration` (`-d`) to change this output: `--decoration=none` will print
207the output as is; `--decoration=fancy` will color each line differently
208depending on which command it is, making it easier to distinguish the output.
209
210### Ignored files
211
212Reflex ignores a variety of version control and editor metadata files by
213default. If you wish for these to be included, you can provide reflex with the
214`--all` flag.
215
216You can see a list of regular expressions that match the files that reflex
217ignores by default
218[here](https://github.com/cespare/reflex/blob/master/defaultexclude.go#L5).
219
220## Notes and Tips
221
222If you don't use `-r` or `-g`, reflex will match every file.
223
224Reflex only considers file creation and modification changes. It does not report
225attribute changes nor deletions.
226
227For ignoring directories, it's easiest to use a regular expression: `-R '^dir/'`.
228
229Many regex and glob characters are interpreted specially by various shells.
230You'll generally want to minimize this effect by putting the regex and glob
231patterns in single quotes.
232
233If your command has options, you'll probably need to use `--` to separate the
234reflex flags from your command flags. For example: `reflex -r '.*\.txt' -- ls
235-l`.
236
237If you're going to use shell things, you need to invoke a shell as a parent
238process:
239
240    reflex -- sh -c 'sleep 1 && echo {}'
241
242If your command is running with sudo, you'll need a passwordless sudo, because
243you cannot enter your password in through reflex.
244
245It's not difficult to accidentally make an infinite loop with certain commands.
246For example, consider this command: `reflex -r '\.txt' cp {} {}.bak`. If
247`foo.txt` changes, then this will create `foo.txt.bak`, `foo.txt.bak.bak`, and
248so forth, because the regex `\.txt` matches each file. Reflex doesn't have any
249kind of infinite loop detection, so be careful with commands like `cp`.
250
251The restart behavior works as follows: if your program is still running, reflex
252sends it SIGINT; after 1 second if it's still alive, it gets SIGKILL. The new
253process won't be started up until the old process is dead.
254
255### Batching
256
257Part of what reflex does is apply some heuristics to batch together file
258changes. There are many reasons that files change on disk, and these changes
259frequently come in large bursts. For instance, when you save a file in your
260editor, it probably makes a tempfile and then copies it over the target, leading
261to several different changes. Reflex hides this from you by batching some
262changes together.
263
264One thing to note, though, is that the the batching is a little different
265depending on whether or not you have a substitution symbol in your command. If
266you do not, then updates for different files that all match your pattern can be
267batched together in a single update that only causes your command to be run
268once.
269
270If you are using a substitution symbol, however, each unique matching file will
271be batched separately.
272
273### Argument list splitting
274
275When you give reflex a command from the commandline (i.e., not in a config
276file), that command is split into pieces by whatever shell you happen to be
277using. When reflex parses the config file, however, it must do that splitting
278itself. For this purpose, it uses [this library](https://github.com/kballard/go-shellquote)
279which attempts to match `sh`'s argument splitting rules.
280
281This difference can lead to slightly different behavior when running commands
282from a config file. If you're confused, it can help to use `--verbose` (`-v`)
283which will print out each command as interpreted by reflex.
284
285### Open file limits
286
287Reflex currently must hold an open file descriptor for every directory it's
288watching, recursively. If you run reflex at the top of a big directory tree, you
289can easily run into file descriptor limits. You might see an error like this:
290
291    open some/path: too many open files
292
293There are several things you can do to get around this problem.
294
2951. Run reflex in the most specific directory possible. Don't run
296   `reflex -g path/to/project/*.c ...` from `$HOME`; instead run reflex in
297   `path/to/project`.
2982. Ignore large subdirectories. Reflex already ignores, for instance, `.git/`.
299   If you have other large subdirectories, you can ignore those yourself:
300   `reflex -R '^third_party/' ...` ignores everything under `third_party/` in
301   your project directory.
3023. Raise the fd limit using `ulimit` or some other tool. On some systems, this
303   might default to a restrictively small value like 256.
304
305See [issue #6](https://github.com/cespare/reflex/issues/6) for some more
306background on this issue.
307
308## The competition
309
310* https://github.com/guard/guard
311* https://github.com/alexch/rerun
312* https://github.com/mynyml/watchr
313* https://github.com/eaburns/Watch
314* https://github.com/alloy/kicker
315* https://github.com/clibs/entr
316
317### Why you should use reflex instead
318
319* Reflex has no dependencies. No need to install Ruby or anything like that.
320* Reflex uses an appropriate file watching mechanism to watch for changes
321  efficiently on your platform.
322* Reflex gives your command the name of the file that changed.
323* No DSL to learn -- just give it a shell command.
324* No plugins.
325* Not tied to any language, framework, workflow, or editor.
326
327## Authors
328
329* Benedikt Böhm ([hollow](https://github.com/hollow))
330* Caleb Spare ([cespare](https://github.com/cespare))
331* PJ Eby ([pjeby](https://github.com/pjeby))
332* Rich Liebling ([rliebling](https://github.com/rliebling))
333* Seth W. Klein ([sethwklein](https://github.com/sethwklein))
334* Vincent Vanackere ([vanackere](https://github.com/vanackere))
335