|
1 | 1 | ---
|
2 |
| -title: Customizing the environment shell hooks |
3 |
| -description: Building an enviornment with custom shell hooks. |
| 2 | +title: Customizing the shell environment |
| 3 | +description: Using setup scripts, aliases, and environment variables to improve your workflows. |
4 | 4 | ---
|
5 | 5 |
|
6 |
| -# Customizing the environment shell hook |
| 6 | +# Customizing the shell environment |
7 | 7 |
|
8 |
| -This guide uses the [environment's][environment_concept] |
9 |
| -[shell hooks][hook_concept] to set up a PostgreSQL development database. |
| 8 | +Activating a Flox [environment][environment_concept] places you into a subshell. |
| 9 | +You likely already have some customizations built into your shell from your shell's configuration (`.bashrc`, `.zshrc`, `config.fish`, etc), but it can be convenient to further customize your shell based on the project that you're working on. |
| 10 | +This guide will walk you through leveraging various features of a Flox environment to improve your quality of life when developing a Rust project, but many of the ideas are applicable to other languages as well. |
10 | 11 |
|
11 |
| -## Create a PostgreSQL environment |
| 12 | +## Setup |
12 | 13 |
|
13 |
| -Say your project has a variable it expects to be set and you need to generate |
14 |
| -the value for development. |
15 |
| -This is a great use for the environment's **[shell hooks][hook_concept]**. |
| 14 | +Let's assume you have a Rust project that you regularly work on. |
| 15 | +To do that work you would already have `cargo`, `rustc`, and a few other tools installed. |
| 16 | +For more details on what it looks like to develop in Rust with Flox, see the [Rust language guide][rust_guide]. |
16 | 17 |
|
17 |
| -Let's set up a Flox [environment][environment_concept] using the `postgresql_15` |
18 |
| -package in your environment: |
| 18 | +If you'd like to follow along with a real Flox environment, create an environment via [`flox init`][flox_init] and install the tools as shown below: |
19 | 19 |
|
20 |
| -``` console |
21 |
| -$ flox init --name postgres-example |
| 20 | +```bash |
| 21 | +$ mkdir mycli |
| 22 | +$ cd mycli |
| 23 | +$ flox init |
| 24 | +$ flox install rustc cargo libiconv |
| 25 | +``` |
22 | 26 |
|
23 |
| -✨ Created environment postgres-example (aarch64-darwin) |
| 27 | +Then generate a basic "Hello, World" program using `cargo init` inside the environment: |
24 | 28 |
|
25 |
| -Next: |
26 |
| - $ flox search <package> <- Search for a package |
27 |
| - $ flox install <package> <- Install a package into an environment |
28 |
| - $ flox activate <- Enter the environment |
| 29 | +```bash |
| 30 | +$ flox activate -- cargo init --bin . |
29 | 31 | ```
|
30 | 32 |
|
31 |
| -``` console |
32 |
| -$ flox install postgresql_15 |
33 |
| -✅ 'postgresql_15' installed to environment postgres-example at /Users/youruser |
34 |
| -``` |
| 33 | +## Vars, hook, or profile? |
35 | 34 |
|
36 |
| -## Customize the environment's shell hook |
| 35 | +When customizing your shell environment you have three basic knobs you can turn: |
37 | 36 |
|
38 |
| -Let's add some properties PostgreSQL needs to run properly in this |
39 |
| -[environment][environment_concept]. |
| 37 | +- The `[vars]` section |
| 38 | +- The `hook.on-activate` script |
| 39 | +- The `[profile]` section |
40 | 40 |
|
41 |
| -``` console |
42 |
| -$ flox edit |
43 |
| -``` |
| 41 | +The logic for deciding where a customization should go is application specific, but there are some simple guidelines you can follow. |
| 42 | +For a full discussion of what logic to place in which section and why, see the [activation concept page][activation_concept]. |
| 43 | +Otherwise, try this: |
44 | 44 |
|
45 |
| -Specifically, let's modify the **[hook section][hook_concept]** |
46 |
| -and create a **script**. |
47 |
| -All hook scripts inherit variables defined in the `[vars]` section of the manifest, |
48 |
| -and environment variables set in the `hook.on-activate` script |
49 |
| -are in turn inherited by the `[profile]` scripts that follow. |
| 45 | +<!-- markdownlint-disable MD007 --> |
| 46 | +- Are you setting an environment variable? |
| 47 | + - Is it a constant value? |
| 48 | + - If so, set it in the `[vars]` section. |
| 49 | + - If not, compute and `export` the variable in the `hook.on-activate` script. |
| 50 | +- Are you sourcing a script (like activating a Python virtual environment)? |
| 51 | + - If so, do this in the `[profile]` section. |
| 52 | +- Are you setting shell aliases? |
| 53 | + - If so, set them in the `[profile]` section. |
| 54 | +- Are you doing general project setup actions (like creating a directory, etc)? |
| 55 | + - If so, do that in the `hook.on-activate` script. |
| 56 | +<!-- markdownlint-enable MD007 --> |
50 | 57 |
|
51 |
| -``` toml title="manifest.toml" |
| 58 | +## Adding a directory to PATH |
52 | 59 |
|
53 |
| -[install] |
54 |
| -postgresql_15.pkg-path = "postgresql_15" |
| 60 | +It can be convenient to quickly run commands against the development build of a program you're working on. |
| 61 | +For instance, if you're working on a command line application you might want to check that the help text is formatted properly by interactively running `mycli -h`. |
55 | 62 |
|
56 |
| -... |
57 |
| - |
58 |
| -[hook] |
59 |
| -on-activate = """ |
60 |
| - export PGPORT="${PGPORT:-5432}" |
61 |
| -
|
62 |
| - export PGUSER=pg-example |
63 |
| - export PGPASS=pg-example |
64 |
| - export PGDATABASE=example-database |
65 |
| - export SESSION_SECRET="$USER-session-secret" |
66 |
| -
|
67 |
| - # Postgres environment variables |
68 |
| - export PGDATA=$PWD/postgres_data |
69 |
| - export PGHOST=$PWD/postgres |
70 |
| - export LOG_PATH=$PGHOST/LOG |
71 |
| - export DATABASE_URL="postgresql:///$PGDATABASE?host=$PGHOST&port=$PGPORT" |
72 |
| -... |
| 63 | +In our case, when we build the application `cargo` will place the compiled program in `target/debug`: |
73 | 64 |
|
74 | 65 | ```
|
| 66 | +mycli/ |
| 67 | + .flox |
| 68 | + Cargo.toml |
| 69 | + Cargo.lock |
| 70 | + src/ |
| 71 | + main.rs |
| 72 | + target/ |
| 73 | + debug/ |
| 74 | + mycli |
| 75 | +``` |
| 76 | + |
| 77 | +If we want to run commands with this newly compiled `mycli`, we can either tell `cargo` to build it (again) and then run it, or we can add `target/debug` to `PATH` so that we can run `mycli` like any other program. |
| 78 | +This second option is more convenient, so let's see how you can tell your Flox environment to do that for you automatically. |
75 | 79 |
|
76 |
| -We can also use the **on-activate** hook |
77 |
| -to add initialization logic that runs conditionally. |
| 80 | +If we follow the logic listed above, we're wanting to modify an existing environment variable (`PATH`), so we'll do this in the `hook.on-activate` script. |
| 81 | +Modify your `hook.on-activate` script to look like this: |
78 | 82 |
|
79 |
| -``` toml title="manifest.toml" |
| 83 | +```toml |
80 | 84 | [hook]
|
81 |
| -on-activate = """ |
| 85 | +on-activate = ''' |
| 86 | + export PATH="$PWD/target/debug:$PATH" |
| 87 | +''' |
| 88 | +``` |
| 89 | + |
| 90 | +Now if you activate the environment and build `mycli` for the first time, you should be able to run `mycli` without needing to type out the path to it (e.g. `target/debug/mycli`): |
| 91 | + |
| 92 | +```bash |
| 93 | +$ flox activate |
82 | 94 | ...
|
83 |
| - mkdir -p $PGHOST |
84 |
| - if [ ! -d $PGDATA ]; then |
85 |
| - echo 'Initializing postgresql database...' |
86 |
| - initdb $PGDATA --username $PGUSER -A md5 --pwfile=<(echo $PGPASS) --auth=trust |
87 |
| - echo "listen_addresses='*'" >> $PGDATA/postgresql.conf |
88 |
| - echo "unix_socket_directories='$PGHOST'" >> $PGDATA/postgresql.conf |
89 |
| - echo "unix_socket_permissions=0700" >> $PGDATA/postgresql.conf |
90 |
| - fi |
| 95 | +$ cargo build |
91 | 96 | ...
|
92 |
| -""" |
| 97 | +$ mycli |
| 98 | +Hello, World! |
93 | 99 | ```
|
94 | 100 |
|
95 |
| -!!! note "Note" |
96 |
| - The `hook.on-activate` script is always run in a `bash` shell. |
| 101 | +### Why do I need to exit and re-activate? |
97 | 102 |
|
98 |
| -**Save and exit your editor**, you should see a confirmation after Flox |
99 |
| -validates the environment. |
| 103 | +Any time the Flox CLI detects that you've changed a section of the manifest that it can't automatically make take effect, you'll need to exit and reactivate. |
| 104 | +For instance, when you install a new package via [`flox install`][flox_install], the CLI is able to make that immediately available to you so there's no need to exit and re-activate. |
100 | 105 |
|
101 |
| -``` |
102 |
| -✅ Environment successfully updated. |
103 |
| -``` |
| 106 | +However, editing the `hook.on-activate` script has no effect on the currently activated environment because the `hook.on-activate` script is only run during the activation process (and the same goes for `[profile]`). |
| 107 | +Similarly, editing the `[vars]` section has no effect on the currently activated environment because the `hook.on-activate` and `[profile]` scripts may rely on the values of variables in `[vars]`, so for the sake of correctness it makes sense to re-run those scripts. |
| 108 | + |
| 109 | +## Enabling feature flags |
104 | 110 |
|
105 |
| -## Test the environment |
| 111 | +Now let's say that you've worked on `mycli` for a while and developed some features that aren't publicly available, but can be accessed by setting certain feature flags. |
| 112 | +A common way to enable or disable feature flags is by environment variables. |
| 113 | +If you want to be able to test out those features during development, this sounds like a great thing for Flox to do for you automatically. |
106 | 114 |
|
107 |
| -You can now [`flox activate`][flox_activate] the environment to see the result |
108 |
| -of your hard work! |
| 115 | +Let's say that we have feature flags `MYCLI_ENABLE_COLOR` and `MYCLI_TURBO_MODE` and they're enabled when we set them to `"1"`. |
109 | 116 |
|
| 117 | +Going back to our "vars, hook, or profile" logic, we see that we're trying to set new environment variables with constant values. |
| 118 | +This means we'll want to set these variables in the `[vars]` section. |
| 119 | +Edit your `[vars]` section to look like this: |
| 120 | + |
| 121 | +```toml |
| 122 | +[vars] |
| 123 | +MYCLI_ENABLE_COLOR="1" |
| 124 | +MYCLI_TURBO_MODE="1" |
110 | 125 | ```
|
| 126 | + |
| 127 | +If you're currently in the environment, exit it and activate it again for the changes to take effect, otherwise you can simply activate the environment. |
| 128 | +In the activated environment you should now see that these two variables are set: |
| 129 | + |
| 130 | +```bash |
111 | 131 | $ flox activate
|
112 |
| -✅ You are now using the environment postgres-example at /Users/youruser. |
113 |
| -To stop using this environment, type 'exit' |
| 132 | +... |
| 133 | +$ echo $MYCLI_TURBO_MODE |
| 134 | +1 |
| 135 | +``` |
114 | 136 |
|
115 |
| -Initializing postgresql database... |
116 |
| -The files belonging to this database system will be owned by user "youruser". |
117 |
| -This user must also own the server process. |
| 137 | +## Adding shell aliases |
118 | 138 |
|
119 |
| -The database cluster will be initialized with locale "en_US.UTF-8". |
120 |
| -The default database encoding has accordingly been set to "UTF8". |
121 |
| -The default text search configuration will be set to "english". |
| 139 | +Now let's say that you'd like to use `mycli` from anywhere on your system. |
| 140 | +Let's also say that you have a `$HOME/bin` directory that you add to `PATH` in your shell's config file. |
| 141 | +You might use this as a place to put programs you've compiled yourself that you want to be able to run from anywhere. |
| 142 | +We're going to create an alias for your developer environment that will build `mycli` and copy it to this directory so that it's quick and easy to install `mycli` after completing a feature you've been working on. |
122 | 143 |
|
123 |
| -Data page checksums are disabled. |
| 144 | +Going back to our "vars, hook, or profile" logic, we see that we're creating a shell alias. |
| 145 | +This means that we'll be adding it to the `[profile]` section. |
| 146 | +However, the syntax for defining shell aliases is shell-specific, so we'll need to declare this alias in the subsection that corresponds to our shell. |
| 147 | +For this tutorial we'll assume that you're an enlightened [fish shell][fish_shell] user, meaning that we'll edit our `profile.fish` script. |
124 | 148 |
|
125 |
| -creating directory /Users/youruser/postgres_data ... ok |
126 |
| -creating subdirectories ... ok |
127 |
| -selecting dynamic shared memory implementation ... posix |
128 |
| -selecting default max_connections ... 100 |
129 |
| -selecting default shared_buffers ... 128MB |
130 |
| -selecting default time zone ... America/New_York |
131 |
| -creating configuration files ... ok |
132 |
| -running bootstrap script ... ok |
133 |
| -performing post-bootstrap initialization ... ok |
134 |
| -syncing data to disk ... ok |
| 149 | +We'll call this alias `install-bin` and it will build `mycli` in "release" mode, i.e. with full optimizations so it runs as fast as possible. |
| 150 | +Edit your `[profile]` section to look like this: |
135 | 151 |
|
136 |
| -Success. You can now start the database server using: |
| 152 | +```toml |
| 153 | +[profile] |
| 154 | +fish = ''' |
| 155 | + alias install-bin "cargo build --release && cp $PWD/target/release/mycli $HOME/bin/mycli" |
| 156 | +''' |
| 157 | +``` |
| 158 | + |
| 159 | +Again, if you're currently in the environment, exit it. |
| 160 | +If you want to test this alias you'll also want to create the `$HOME/bin` directory. |
| 161 | +Now if you activate the environment and run `install-bin` you should find a copy of `mycli` in `$HOME/bin`: |
137 | 162 |
|
138 |
| - pg_ctl -D /Users/youruser/postgres_data -l logfile start |
| 163 | +```bash |
| 164 | +$ flox activate |
| 165 | +... |
| 166 | +$ install-bin |
| 167 | +... |
| 168 | +$ ls $HOME/bin |
| 169 | +mycli |
139 | 170 | ```
|
140 | 171 |
|
141 | 172 | ## Where to next?
|
142 | 173 |
|
143 | 174 | - :simple-readme:{ .flox-purple .flox-heart } [Multiple architecture environments][multi-arch-guide]
|
144 | 175 |
|
145 |
| -[flox_edit]: ../reference/command-reference/flox-edit.md |
146 |
| -[flox_search]: ../reference/command-reference/flox-search.md |
| 176 | +[environment_concept]: ../concepts/environments.md |
147 | 177 | [flox_activate]: ../reference/command-reference/flox-activate.md
|
148 |
| -[create_enviornments_guide]: ./creating-environments.md |
149 | 178 | [multi-arch-guide]: ./multi-arch-environments.md
|
150 |
| -[environment_concept]: ../concepts/environments.md |
151 |
| -[hook_concept]: ../reference/command-reference/manifest.toml.md#hook |
| 179 | +[rust_guide]: ../cookbook/languages/rust.md |
| 180 | +[flox_init]: ../reference/command-reference/flox-init.md |
| 181 | +[activation_concept]: ../concepts/activation.md |
| 182 | +[fish_shell]: https://fishshell.com/ |
| 183 | +[flox_install]: ../reference/command-reference/flox-install.md |
0 commit comments