diff --git a/.gitignore b/.gitignore index 05e53b63..b4d3ae2e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.zwc.old modules/*/cache.zsh contrib +.container diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..db3ca686 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +FROM alpine as prezto-devel +LABEL maintainer="h@hlo.mx" +RUN apk --no-cache update && apk upgrade && \ + apk add util-linux pciutils usbutils coreutils binutils\ + findutils grep man man-pages mdocml-apropos less less-doc \ + make grep zsh zsh-vcs zsh-zftp zsh-calendar zsh-doc git \ + vim git-zsh-completion tmux tmux-zsh-completion tree \ + docker-zsh-completion +RUN addgroup prezto && adduser -D prezto -G prezto -S /bin/zsh +WORKDIR /home/prezto +USER prezto +RUN cd /home/prezto && mkdir src +COPY . src +RUN cp src/Makefile . +RUN make .clone +RUN make src .homercs +RUN rm Makefile +# ENTRYPOINT ["/bin/zsh", "-"] +# CMD ["/bin/zsh","-l","-o","verbose","-o","xtrace","-o","sourcetrace"] +CMD ["/bin/zsh","-l"] + + + + diff --git a/Makefile b/Makefile new file mode 100755 index 00000000..5507073e --- /dev/null +++ b/Makefile @@ -0,0 +1,113 @@ +#!/usr/bin/make shebang +# _ ____ _ +# _ __ _ __ ___ ___| |_ ___ | _ \ ___ ___| | _____ _ __ +# | '_ \| '__/ _ \_ / __/ _ \ _____| | | |/ _ \ / __| |/ / _ \ '__| +# | |_) | | | __// /| || (_) |_____| |_| | (_) | (__| < __/ | +# | .__/|_| \___/___|\__\___/ |____/ \___/ \___|_|\_\___|_| +# |_| +# h@h-lo.me 20191025 004745 -0700 PDT 1571989665 d(-_- )b... +# This makefile automates image building and container management +# for easy development of prezto and prezto-plugins without messing +# up your current configuration. Prezto is installed fresh on an +# alpine container, where you may add your edits +# +####################################################################### +# REPO and IMG define the TAG for our image. this is how it gets named +# when pushed to dockerhum. REPO should be your dockerhub username +# IMG would be nice if its related to the project. +REPO = hlecuanda +IMG = prezto-dev +TAG = $(REPO)/$(IMG) +# ALLCODE recirds all code files so we can have the docker image +# depend on all of them. if any file changes, the image gets rebuilt +ALLCODE != find . -type f | grep -vEe '^\./\.+|*.md' +RUNCOMS != ls runcoms +# The context is the current directory. this is important if you have +# a buildserver, v.gr on gitlab or google cloud. its still needed for +# local builds. so don't touch this, unless you know what you're doing +CONTEXT = . +# All reciipes on this makefile are zsh scripts, not bash or sh +# scripts, so we don't have to be context-switching +SHELL = zsh +# This removes the default build rules for gmake's built in suffixes +# when debugging the Makefile, output is a lot more readable, plus +# if you're not making C programs, it just makes sense to avoid +# mistery bugs +.SUFFIXES = + +# We don't want to fail recipies on error for the targets if .IGNORE +.IGNORE: clean realclean ; + +# These targets don't create files and are defined for convenience. +# note that other targets do create real files which are used to +# determine the state of the build +.PHONY: default run clean realclean ; + +# an empty recipe, to avoid expensive operations if we "make" by +# mistake. it can be made to depend on another target and it will +# become the target of a "make" call with no arguments, vg.r: +# default: image; results in "make" and "make image" doing the same +default: ; + +# a user callable target, depends on .container/image whiech records +# the timestamp of the last successfuly built image +image: .container/image ; + +# we declare .container/image to depend on $(ALLCODE) which contains +# all files in the distribution. thus, if ANY file changes, it makes +# our image obsolete and will be re-made on next make command +.container/image: $(ALLCODE) + docker build -t $(TAG) $(CONTEXT) + [[ ! -d .container ]] && mkdir .container || : + touch $@ + +# NOTE: The following targets ( .homercs clone and .clone ) are +# run inside the container while building a container image. They are +# called from the Dockerfile when you "make image". .homercs creates +# the dotfiles on our home directory and depends on .clone, so .clone +# should be made before .homercs. We're spelling these out explicitly +# for clarity instead of using Makefile enchantments that would make +# this a 2 line recipe +.homercs: .clone + ln -s .zprezto/runcoms/zshenv /home/prezto/.zshenv + ln -s .zprezto/runcoms/zprofile /home/prezto/.zprofile + ln -s .zprezto/runcoms/zshrc /home/prezto/.zshrc + ln -s .zprezto/runcoms/zpreztorc /home/prezto/.zpreztorc + ln -s .zprezto/runcoms/zlogin /home/prezto/.zlogin + ln -s .zprezto/runcoms/zlogout /home/prezto/.zlogout + touch $@ + +# clones the prezto repository we have copied from the build context +# into the container, into a .zprezto directory, as the installation +# instructions recommend. +.clone: + git clone --recursive src .zprezto + touch $@ + +# This runs an interactive (-it) ephemeral (--rm) container named +# $(IMG) created from the image stored at $(TAG) it is made to depend +# on container/image so that it checks whether image is up to # date. +# Given that image depends on $(ALLCODE), calling "make run" will use +# the latest image, unless any code file hasa changed in which case, +# the image is rebuilt and then run. +run: .container/image + docker run -it --rm -h $(IMG) --name $(IMG) $(TAG) + +# Removes the current container and image, so we can build a new one +# from scratch. If you want a real clean slate, then "make realclean" +clean: + docker container rm $(TAG) + docker image rm $(TAG) + rm -fv .container/* + +# Deep cleaning, will remove dangling (intermediate build) images +# and containers for which a final image or container cannot be found +# (i.e has been deleted by clean or removed after usage for ephemeral +# containers. Run every once in a while. +realclean: + $(MAKE) clean + docker rmi $(TAG) + docker container prune + docker image prune + +# vim: set ft=make sw=2 tw=7 fdm=manual noet : diff --git a/container-README.md b/container-README.md new file mode 100644 index 00000000..60108f21 --- /dev/null +++ b/container-README.md @@ -0,0 +1,94 @@ +# Prezto Docker Container + +This branch contains a Dockerfile and a Makefile that hopefully may +prove helpful for prezto development. + +The idea is to have a totally independent and isolated environemnet +in which to test changes to either prezto-core or any plugin that you +may be working on, **without disrupting your environment**, thus enabling +automated testing and even continuous integration. + +This is a proof of concept, it may not be even a good idea to have +this on the main prezto repository. on the other hand, the container +image should depend on the code, so if the team finds this to be a +useful tool, there are choices to be made in that respect. My +intention is to introduce this as a helpful tool for development and +for new users to try prezto easely + +Here is a screencast showing what the container can do so far + +[![asciicast](https://asciinema.org/a/277054.svg)](https://asciinema.org/a/277054) + +The container is a basic install of [alpine linux](https://alpinelinux.org) so the download +is reasonably small at around 200M, since debian based images can +weigh in around 1.5G. + +On the container we have a few utilities and additional software that +prezto has core support for, (tmux, make, etc) and you can try it i +easily by running: + +```bash + docker pull hlecuanda/prezto-dev:latest +``` + +once you have the image, create a container from it: + +```bash + docker run -it --rm -h prezto hlecuanda/prezto-dev:latest +``` + +That will create an interactive (`--it`) ephemeral container (`--rm`) +whose hostname is prezto (`-h prezto`) based on the aforementioned +imag. you should be sitting at the plain sorin prompt in a brand new +prezto instance. + +A development and testing workflow can be achieved by mounting a +project's directory on to the image's filesystem: + +```bash + cd /path/to/project/root + docker run -it --rm -h prezto \ + -v $(pwd):/home/prezto/.zprezto/modules/${:-$(pwd):t} \ + hlecuanda/prezto-dev:latest +``` + +This will mount the current directory on the container's filesystem, +you can develop on your own machine and environnment, and test your +changes running on the container, your actual source will already be +in-place on prezto's directory hierarchy, as if it was just cloned +recursively (v.gr for modules with extenral dependencies) + +Keep in mind that the containers created in this fashion are ephemeral, +so anything you write on the containers filesystem will be lost, +unless you remove the `--rm` option like so: + +```bash + cd /path/to/project/root + docker run -it -h prezto --name prezto \ + -v $(pwd):/home/prezto/.zprezto/modules/${:-$(pwd):t} \ + hlecuanda/prezto-dev:latest +``` +This will create a container named prezto, (`--name prezto`) with it's +hostname set to prezto also (`-h prezto`) that will retain changes +made to it's filesystem. When you detach, the container willi stop and +you can spinit up again using: + +```bash + docker start -ai prezto +``` + +Containers started this way will remember the volume mounts they were +created with, so the project directory we previously mounted with +`-v` on the `docker run` command, will be ready on the image. + +I have found epehermeral containers to be most useful since you get an +untainted, pristine environment for testing every time you spin up the +container. + +Since the docker commands can be a bit verbose, the included Makefile +automates some of the frequent steps in the workflow, although it can +be replaced by [a shell function](https://gist.github.com/hlecuanda/78a6a39877c9753230a11c2d8832f4b6) +quite easily. + + +hope this turns out to be useful. diff --git a/prezto-container.zsh b/prezto-container.zsh new file mode 100755 index 00000000..de290ade --- /dev/null +++ b/prezto-container.zsh @@ -0,0 +1,91 @@ +#!/usr/bin/env zsh + local opts withvals + + zmodload zsh/zutil || { <<< 'Requires zparseopts'; false; return } + + [ -z $commands[docker] ] && { <<< 'Requires Docker'; false; return } + + zparseopts -D -E -M -a opts -A withvals - \ + h=hlp -help=h \ + i: -image=i \ + N: -name=N \ + n -dry-run=n \ + p -persistant=p \ + r -run=r \ + -zdotdir: \ + -zpreztodir: + + if (( $#hlp == 1 )) ; then + <<-USAGE + ${0}: create an ephemeral prezto container using docker + + usage: + ${0} [options] -- [addtl-args] + + options: + -h, --help : print this message + -p, --persistant : make a persistant container + -N NAME, --name=NAME : set container name to NAME (default: prezto) + -n, --dry-run : see what command would be run without doing so + -r 'CMD' --run 'CMD' : run 'CMD' on the container (quote CMD) + -i IMG, --image=IMG : create container from image IMG (default hlecuanda/prezto-dev) + -zdotdir=PATH : use dotfiles from local PATH + -zpreztodir : override default prezto to local PATH + + example: + ${0} -n myruncoms -zdotdir=$HOME + + creates an ephemeral container named myruncoms using + dotfiles found in ${HOME} + + ${0} -n illbeback -p + + creates a persistant container named illbeback if such + container exists, then startit and attach to it + + ${0} -n ivebeenback -r 'apk add python' + + spins up the a container named ivebeenback, and runs + the comand 'apk add python'. the container stops when + done. + + USAGE + fi + + local image="hlecuanda/prezto-dev" + local name="prezto" + local persistant="--rm" + local zdotdir="" + local zpreztodir="" + local dockercmd='docker run' + local dockerpull="" + + for opt in ${(k)withvals} + case $opt in + -i) + image="$withvals[-i]" ;; + -n) + local dryrun="print --" ;; + -N) + name="$withvals[-n]" ;; + -p) + persistant="" ;; + -zdotdir) + zdotdir="-v ${(qq)withvals[-zdotdir]}:/home/prezto/zdotdir -e 'ZDOTDIR=/home/prezto/zdotdir " ;; + -zpreztodir) + zpreztodir="-v ${(qq)withvals[-zpreztodir]}:/home/prezto/zpreztodir -e 'ZPREZTODIR=/home/prezto/zpreztodir " ;; + esac + + docker images \ + | grep prezto-dev \ + &>>! /dev/null || dockerpull="docker pull $image && " + + dockercmd="$dryrun $dockerpull $dockercmd $persistant -h $name " + dockercmd="$dockercmd -name $name $zdotdir $zpreztodir $image" + + cmd=$(echo $dockercmd | tr -s \ ) + + ${(z)cmd} + + +# vim: set ft=zsh sw=2 tw=0 fdm=manual et :