Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,7 @@
],
// Mount the parent as /workspaces so we can pip install peers as editable
"workspaceMount": "source=${localWorkspaceFolder}/..,target=/workspaces,type=bind",
"initializeCommand": "mkdir -p ${localEnv:HOME}/.config/devcontainer_rc"
// Create the config folder for the bash-config feature
"initializeCommand": "mkdir -p ${localEnv:HOME}/.config/bash-config",
"remoteUser": "root"
}
59 changes: 40 additions & 19 deletions .devcontainer/features/bash-config/README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,47 @@
# Lightweight, Configurable BASH Eternal History
# Lightweight, Configurable BASH Config with Eternal History

## Defaults
Intended as a lightweight alternative to common-utils.

When this feature is first called, onCreateCommand.sh is created and called in `devcontainer-feature`.
This creates and installs a default bash terminal configuration from `feature_settings_rc` which contains opinionated default BASH terminal settings such as:
* A minimalist, blue bash prompt.
* Eternal, shared history between containers using this feature.
## Installation

## Customisation
To use this feature in an individual devcontainer, add the following to your `.devcontainer/devcontainer.json`:

```json
"features": {
"ghcr.io/diamondlightsource/devcontainer-features/bash-config:1": {}
},
"initializeCommand": "mkdir -p ${localEnv:HOME}/.config/bash-config",
```

The initializeCommand is required to create the directory for the bash-config folder in your home folder on the host, the very first time this is executed. Features do not have an InitializeCommand, so the devcontainer.json must do this.

## Global Installation

To use this feature in all devcontainers on your workstation, add the following to User setting.json:

```json
"dev.containers.defaultFeatures": {
"ghcr.io/gilesknap/devcontainer-features/bash-config:1.1.0"
}
```

The user can specify their own terminal preferences in `$CONFIG_STAGING/bashrc`, which defaults to `/devcontainer_staging/bashrc`.
Then the container is rebuilt, if `bashrc` already exists it won't be overwritten, preserving changes. If the container has been built once already, the existing bashrc must be deleted in order for your changes to be applied.
Also, one time only, make sure the host folder for bash-config is created:

```bash
mkdir -p $HOME/.config/bash-config
```


creates staging folder in container
creates onCreateCommand.sh in the staging folder
inputrc and bashrc are also created in the staging folder, containing incremental history searching and user customisations respectively
feature_settings_rc is created in the staging fodler, which contains a PS1 setup and opinionated terminal features
"onCreateCommand" is then exectuted inside the container during finalisation of container setup.
- This copies the contents of feature_settings_rc into devcontainer_rc
- then copies bashrc and inputrc into the container, unless they exist already to prevent overwriting user edits
- then adds root permissions.
A symbolic link to /root/ is created The items in the CONFIG_FOLDER
our bashrc is called by /root/.bashrc
## features

The default, opinionated configuration can be found in `$HOME/.config/bash-config/bash-config-rc` and includes the following:

- Persistent history across all devcontainers that use this feature
- The MS devcontainer bash prompt with git branch and status
- history search with up/down arrows (.inputrc)
- ctrl-left or right arrow for word navigation (.inputrc)
- git autocomplete

## Customisation

Can be customized by editing `$HOME/.config/bash-config/bashrc`
23 changes: 23 additions & 0 deletions .devcontainer/features/bash-config/config/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# bash-config configuration files

## introduction

The files in this folder are copied out of the bash-config feature and
into the users config folder on the host at ~/.config/bash-config

## files

- bashrc: The entry point for the bash-config feature. User editable
- inputrc: The readline configuration file. User editable
- bash-config-rc: The configuration file for the bash-config feature. Not
user editable. Replaced with the latest version on each rebuild of the
developer container.

## Stages

1. At build time all the files in this folder are copied to a staging folder
in the container filesystem.
1. At container runtime the files are copied from the staging folder to the
users config folder on the host.
1. The file onCreateCommand.sh is executed at container creation time in order
to facilitate the above copy.
46 changes: 46 additions & 0 deletions .devcontainer/features/bash-config/config/bash-config-rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/bin/bash

# default opinioned bash configuration

# set the prompt
export PS1="\[\033[1;34m\]\W \[\033[0m\]# "

# enable enternal shared history
export HISTCONTROL=ignoreboth:erasedups
export HISTSIZE=-1
export HISTFILESIZE=-1
export SAVEHIST=-1
export HISTFILE=$CONFIG_FOLDER/.bash_eternal_history

# bash theme - partly inspired by https://github.com/ohmyzsh/ohmyzsh/blob/master/themes/robbyrussell.zsh-theme
# from https://github.com/devcontainers/features/blob/main/src/common-utils/scripts/bash_theme_snippet.sh
__bash_prompt() {
local userpart='`export XIT=$? \
&& [ ! -z "${GITHUB_USER:-}" ] && echo -n "\[\033[0;32m\]@${GITHUB_USER:-} " || echo -n "\[\033[0;32m\]\u " \
&& [ "$XIT" -ne "0" ] && echo -n "\[\033[1;31m\]➜" || echo -n "\[\033[0m\]➜"`'
local gitbranch='`\
if [ "$(git config --get devcontainers-theme.hide-status 2>/dev/null)" != 1 ] && [ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ]; then \
export BRANCH="$(git --no-optional-locks symbolic-ref --short HEAD 2>/dev/null || git --no-optional-locks rev-parse --short HEAD 2>/dev/null)"; \
if [ "${BRANCH:-}" != "" ]; then \
echo -n "\[\033[0;36m\](\[\033[1;31m\]${BRANCH:-}" \
&& if [ "$(git config --get devcontainers-theme.show-dirty 2>/dev/null)" = 1 ] && \
git --no-optional-locks ls-files --error-unmatch -m --directory --no-empty-directory -o --exclude-standard ":/*" > /dev/null 2>&1; then \
echo -n " \[\033[1;33m\]✗"; \
fi \
&& echo -n "\[\033[0;36m\]) "; \
fi; \
fi`'
local lightblue='\[\033[1;34m\]'
local removecolor='\[\033[0m\]'
PS1="${userpart} ${lightblue}\w ${gitbranch}${removecolor}\$ "
unset -f __bash_prompt
}
__bash_prompt
export PROMPT_DIRTRIM=4

# enable bash completion for git
if [[ -f /usr/share/bash-completion/completions/git ]]; then
source /usr/share/bash-completion/completions/git
elif [[ -f /etc/bash_completion.d/git ]]; then
source /etc/bash_completion.d/git
fi
19 changes: 19 additions & 0 deletions .devcontainer/features/bash-config/config/bashrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/bash

# This bashrc will be source from /root/.bashrc upon launch of every terminal
# in a devcontainer that uses the bash-config feature from
# https://github.com/DiamondLightSource/devcontainer-features

# This file is initialized by bash-config, but you are then free to edit it

# execute default, opinionated settings - delete this line to remove defaults
source $CONFIG_FOLDER/bash-config-rc

if [ ! -f /one-time ]; then

# add your personal one time only (container creation) commands here

touch /one-time
fi

# add your personal settings for every shell below
10 changes: 10 additions & 0 deletions .devcontainer/features/bash-config/config/inputrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Readline configuration for bash shell.

# Incremental history searching with up and down arrows (C-P and C-N for old
# style navigation).
"\e[A": history-search-backward
"\e[B": history-search-forward

# Control left and right for word movement
"\e[5C": forward-word
"\e[5D": backward-word
16 changes: 16 additions & 0 deletions .devcontainer/features/bash-config/config/onCreateCommand.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/bash

# this script is run once inside the developer container at creation time

# copy in the opinionated default settings from the feature
cp $CONFIG_STAGING/bash-config-rc $CONFIG_FOLDER

# copy in the user editable settings unless they already exist
if [[ ! -f $CONFIG_FOLDER/bashrc ]] ; then
cp $CONFIG_STAGING/bashrc $CONFIG_FOLDER
cp $CONFIG_STAGING/inputrc $CONFIG_FOLDER
fi

# hook in the config to the root account
ln -s $CONFIG_FOLDER/inputrc /root/.inputrc
echo "source $CONFIG_FOLDER/bashrc" >> /root/.bashrc
17 changes: 9 additions & 8 deletions .devcontainer/features/bash-config/devcontainer-feature.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@
"name": "Lightweight and configurable BASH eternal history",
//ID *must* match parent folder name *exactly*
"id": "bash-config",
"version": "1.0.0",
// a default beta version that is replaced by CI when doing tagged releases
"version": "0.0.1-b1",
"description": "Lightweight BASH setup with eternal history and PS1 tweaks. Fully configurable.",
"documentationURL": "https://github.com/DiamondRC/devcontainer-features/refs/heads/main/.devcontainer/features/bash-config/README.md",
"documentationURL": "https://github.com/DiamondLightSource/devcontainer-features/refs/heads/main/.devcontainer/features/bash-config/README.md",
"containerEnv": {
"CONFIG_FOLDER": "/devcontainer_rc",
"CONFIG_STAGING": "/devcontainer_staging"
"CONFIG_FOLDER": "/bash-config",
"CONFIG_STAGING": "/bash-config-staging"
},
"mounts": [
{
"source": "${localEnv:HOME}/.config/devcontainer_rc",
"target": "/devcontainer_rc",
"source": "${localEnv:HOME}/.config/bash-config",
"target": "/bash-config",
"type": "bind"
}
],
"onCreateCommand": "bash /devcontainer_staging/onCreateCommand.sh"
}
"onCreateCommand": "bash /bash-config-staging/onCreateCommand.sh"
}
79 changes: 16 additions & 63 deletions .devcontainer/features/bash-config/install.sh
Original file line number Diff line number Diff line change
@@ -1,71 +1,24 @@
#!/bin/bash
set -e

echo "Activating feature 'terminal-history'"
echo "User: ${_REMOTE_USER} User home: ${_REMOTE_USER_HOME}"

mkdir -p $CONFIG_STAGING

# -------------------------------------------------------------------------------
cat > $CONFIG_STAGING/onCreateCommand.sh \
<< EOF
#!/bin/bash

# copy in the opinionated default settings from the feature
cp $CONFIG_STAGING/feature_settings_rc $CONFIG_FOLDER/feature_settings_rc

# copy in the user editable settings unless they already exist
if [[ ! -f $CONFIG_FOLDER/bashrc ]] ; then
cp $CONFIG_STAGING/bashrc $CONFIG_FOLDER
cp $CONFIG_STAGING/inputrc $CONFIG_FOLDER
fi

# hook in the config to the root account
ln -s $CONFIG_FOLDER/inputrc /root/.inputrc
echo "source $CONFIG_FOLDER/bashrc" >> /root/.bashrc
EOF

# -------------------------------------------------------------------------------
cat > $CONFIG_STAGING/inputrc \
<< EOF
# Readline configuration for bash shell.

# Incremental history searching with up and down arrows (C-P and C-N for old
# style navigation).
"\e[A": history-search-backward
"\e[B": history-search-forward

# Control left and right for word movement
"\e[5C": forward-word
"\e[5D": backward-word
EOF

# -------------------------------------------------------------------------------
cat > $CONFIG_STAGING/bashrc \
<< EOF
#!/bin/bash
# abort on error
set -e

# execute default opinionated settings - delete this line to remove defaults
source $CONFIG_FOLDER/feature_settings_rc
# discover where this install.sh and its peers have been extracted to
this_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

# add your personal custom settings below
EOF

# -------------------------------------------------------------------------------
cat > $CONFIG_STAGING/feature_settings_rc \
<< EOF
#!/bin/bash
echo "Activating feature 'bash-config'"
echo "User: ${_REMOTE_USER} User home: ${_REMOTE_USER_HOME}"

# default opinioned bash configuration
# This script is run at container build time.
#
# Here we place all the configuration files in a staging area.
#
# Then at container runtime, when the hosts' config folder is mounted in, we
# can copy from the staging area to the mounted host folder
#
# The runtime copy to host folder is performed once only by onCreateCommand.sh

# set the prompt
export PS1="\[\033[1;34m\]\W \[\033[0m\]# "
mkdir -p "$CONFIG_STAGING"
cp -r "$this_dir"/config/* "$CONFIG_STAGING"

# enable enternal shared history
export HISTCONTROL=ignoreboth:erasedups
export HISTSIZE=-1
export HISTFILESIZE=-1
export SAVEHIST=-1
export HISTFILE=$CONFIG_FOLDER/.bash_eternal_history
PROMPT_COMMAND="history -a; $PROMPT_COMMAND"
EOF
27 changes: 27 additions & 0 deletions .github/workflows/_check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
on:
workflow_call:
outputs:
branch-pr:
description: The PR number if the branch is in one
value: ${{ jobs.pr.outputs.branch-pr }}

jobs:
pr:
runs-on: "ubuntu-latest"
outputs:
branch-pr: ${{ steps.script.outputs.result }}
steps:
- uses: actions/github-script@v7
id: script
if: github.event_name == 'push'
with:
script: |
const prs = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
head: context.repo.owner + ':${{ github.ref_name }}'
})
if (prs.data.length) {
console.log(`::notice ::Skipping CI on branch push as it is already run in PR #${prs.data[0]["number"]}`)
return prs.data[0]["number"]
}
19 changes: 16 additions & 3 deletions .github/workflows/release.yaml → .github/workflows/_release.yml
Original file line number Diff line number Diff line change
@@ -1,28 +1,41 @@
name: "Release dev container features & Generate Documentation"
on:
# use this to test releasing of the devcontainer features in a branch
workflow_dispatch:
workflow_call:

jobs:
deploy:
if: ${{ github.ref == 'refs/heads/main' }}
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
packages: write
steps:
- uses: actions/checkout@v4

- name: patch in version tag
# patch the version tag if the version is a valid semver. If not then
# default to 0.0.1-b1 (only when using workflow_dispatch for tests)
run: |
if [[ ${{ github.ref_name }} =~ ^[0-9]+\.[0-9]+.+ ]] ; then
sed -i s/0\.0\.1-b1/${{ github.ref_name }}/ $(find .devcontainer -name devcontainer-feature.json)
# dump the modified json for debugging
cat $(find .devcontainer -name devcontainer-feature.json)
fi

- name: "Publish Features"
uses: devcontainers/action@v1
with:
publish-features: "true"
base-path-to-features: "./src"
generate-docs: "true"

env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# the example features publishes docs like below - I believe this is only
# relevant if publishing to the marketplace?

# - name: Create PR for Documentation
# id: push_image_info
# env:
Expand Down
Loading