Note: this page can be outdated, please refer to ./src/variables.sh instead.
If it's your first time using dotsh, you can go through an interactive configuration wizard by running dotsh config
.
You can customize the hookable options from ./src/variables.sh.
The UPPERCASE variables inside ./src/variables.sh can be supplied as environment variables as well when needed. That means, for Gitpod you can define them at https://gitpod.io/variables with / scope and for a local machine, you could do: export KEY=value
once before executing install.sh
per session. When exported as environment variables, they will overwrite the static values from your ./src/variables.sh during runtime.
I have only tried this with Kitty and iTerm2, they have built-in capabilities for handling custom protocols. However, it's possible to accomplish the same using a shell-script for terminals lacking built-in handling, but we're not going to get into that here.
- Open iTerm2.
- From the top right macOS menubar, go to iTerm2 > Preferences > Profiles > Default (or a custom profile).
- Select
ssh
from the URL Schemes drop-down option. - Close the Preferences window.
Official documentation: https://iterm2.com/documentation-one-page.html
Kitty by default can handle ssh
protocol. However, on MacOS you would need to register it into the system manually.
See https://sw.kovidgoyal.net/kitty/open_actions/#scripting-the-opening-of-files-with-kitty-on-macos for instructions.
You can use one of the following:
- https://www.gitpod.io/docs/references/ides-and-editors/local-companion - runs in the background (recommended)
- Or this: https://github.com/axonasif/gssh - Wraps the
ssh
command.
If you wish to use
gssh
with iTerm/Kittyssh://
handling, you will need to pass the full$$URL$$
in a custom command that runs:gssh <URL>
.
Dotsh is programmed in plain bash
and is compiled with bashbox.
Check ./src/config/example.sh for example instructions.
Note: There are more, check the source code instead, mainly the ./src/utils/ directory and std.
This let's you easily add settings to the Gitpod workspace VSCode instance. Settings added via this function will not be synced and is scoped to the applied workspaces only.
Usage example:
- Via stdin:
vscode::add_settings /path/to/settings.json <<-'JSON'
{
"terminal.integrated.profiles.linux": {
"tmuxshell": {
"path": "bash",
"args": [
"-c",
"tmux new-session -ds main 2>/dev/null || :; if cpids=$(tmux list-clients -t main -F '#{client_pid}'); then for cpid in $cpids; do [ $(ps -o ppid= -p $cpid)x == ${PPID}x ] && exec tmux new-window -n \"vs:${PWD##*/}\" -t main; done; fi; exec tmux attach -t main"
]
}
},
"terminal.integrated.defaultProfile.linux": "tmuxshell"
}
JSON
Live usage example can be seen here.
- Via file:
vscode::add_settings /path/to/settings.json < /path/to/source_file.json
Automatically clone and symlink from a remote dotfiles
repository tree. It also cleans up broken symlinks from previous apply (useful when used on local PC). You can ignore symlinking files by specifying their paths on a .dotfilesignore
on the repo root of your dotfiles raw tree.
Usage:
REPO="your-repo-link/path-here" dotfiles::initialize [target-dir]
REPO=
accepts URL or local path. (Defaults to https://github.com/axonasif/dotfiles.public)
REPO=
and target-dir
is optional.
target-dir
is the directory/folder where symlinks will be applied from the cloned repo. (Defaults to $HOME
)
If you wish to apply the symlinks to a different directory for example:
REPO="your-repo-link/path-here" dotfiles::initialize "/root/.local/very/deep/location";
Live examples of it's usage can be found on this file
await::until_true <cmd>;
Simple wrapper for awaiting a command to return true
Live usage example can be found here.
await::for_file_existence <file_path>;
Await for a file to appear in the filesystem.
Live usage example can be found here.
await::for_vscode_ide_start;
Await for the Gitpod VSCode window to appear.
Live usage example can be found here.
await::create_shim (Unstable)
await::create_shim /usr/bin/something_fancy
Let's say we're intalling a tool called tmux
but since it's asynchronously installed so if an user tries to execute it before it exists, they'll get an error. In order to avoid such a problem we can place an wrapper script at tmux
's absolute path using await::create_shim
, that way the wrapper script as tmux
will await for the actual command to appear in the filesystem and switch(exec
) to it if someone executes tmux
on their terminal before the actual tmux
binary/program gets fully installed. In other words, if you invoke tmux
on your terminal, the wrapper script at /usr/bin/tmux
will sleep()
until it finds that it itself was overwritten and the actual tmux
binary was installed at /usr/bin/tmux
.
Now, there is another problem, let's say you used await::create_shim /usr/bin/tmux
while tmux
is being installed in the background asynchronously. What if you also need to install/configure additional tmux
plguins/customizations from your dotfiles installation script but the user tried to run tmux
before you installed the additional customization. In this case, tmux
would start up without your customization during the process you may perform the customizations in the background. There is a solution to that. Here's an example below:
# Install tmux asynchronously in the background
sudo apt install tmux & disown;
# Create the awaiting shim for any user execution before apt fully installs tmux, notice the extra `KEEP=true`
KEEP=true await::create_shim /usr/bin/tmux;
## Extra tmux customization/configuration part
git clone --filter=tree:0 https://github.com/tmux-plugins/tpm "$HOME/.tmux/plugins/tpm";
# This script has to execute `tmux` internally multiple times
# But we need it to hit the actual tmux binary but not the wrapper shim script,
# however the wrapper shim script will recognize that it's being called from inside the dotfiles installation script
# and thus it will let us to execute the actual binary of `tmux`
bash "$HOME/.tmux/plugins/tpm/scripts/install_plugins.sh";
# After we're done customizing internally, get rid of the wrapper shim script
# and let everyone directly hit the actual `tmux` binary.
CLOSE=true await::create_shim /usr/bin/tmux;
A live usage of KEEP=true await::create_shim
can be seen here.
What if you want to install tmux
with a much complicated package manager such as nix
for example and that you have to install nix
first. Well, in that case, if you create the placeholder dirs and the shim before installation of nix
and the package that you want to install, then it will cause issues during installation of nix
and the packages that you want to install via it afterwards. So, we can create a shim in a different PATH, which will monitor another path to swap itself with. Here's an example:
# Install nix if missing
USER="$(id -u -n)" && export USER;
if test ! -e /nix; then {
sudo sh -c "mkdir -p /nix && chown -R $USER:$USER /nix";
log::info "Installing nix";
curl -sL https://nixos.org/nix/install | bash -s -- --no-daemon >/dev/null 2>&1;
} fi
source "$HOME/.nix-profile/etc/profile.d/nix.sh" || source /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh;
# Install packages with nix in the background
# This command will eventually install a symlink to `tmux` at $HOME/.nix-profile/bin
nix-env -iA nixpkgs.tmux & disown;
# Notice the SHIM_MIRROR value
KEEP=true SHIM_MIRROR=$HOME/.nix-profile/bin/tmux await::create_shim /usr/bin/tmux;
## Extra tmux customization/configuration part
git clone --filter=tree:0 https://github.com/tmux-plugins/tpm "$HOME/.tmux/plugins/tpm";
# Install tmux plugins
bash "$HOME/.tmux/plugins/tpm/scripts/install_plugins.sh";
# After we're done customizing internally, get rid of the wrapper shim script
# and let everyone directly hit the actual `tmux` binary.
CLOSE=true await::create_shim /usr/bin/tmux;
Let's you await between multiple async commands.
Example:
In function foo
we have:
function foo() {
await::signal get boo_is_cool; # Blocks execution until signal is received
echo "Now we can proceeed!";
# More commands below...
}
In function boo
we have:
function boo() {
# Let's run some random commands
sudo apt install shellcheck;
await::signal send boo_is_cool; # Sends the singal to any awaiting client so that they can continue execution
}