I’ve been using the Windows Subsystem for Linux (WSL) for a while at work. It’s been something of a radical improvement over cygwin for most of my use cases. A couple of weeks ago my installation got borked by the work Antivirus (AV) system. So I’ve created an automated script to set up my environment just how I currently like it.
Before we start lets get one thing out the way. Windows is a perfectly fine development environment. I won’t be tolerating any comments of just use a mac or just install linux. This is not always possible with a corporate machine. If this is of no help to you stop reading and go look at something else.
You have Ubuntu for windows already installed but not yet configured
Step one was to create a directory to keep my initial environment in. Later we will turn it into a git repo as this sort of thing should not be kept on your machine. The times you need it most are when your machine has died and you need to build a new one.
mkdir -p /mnt/c/git/dotfiles/bin cd /mnt/c/git/dotfiles
Next is to create the skeleton of the script that will do all the work for us in future. In the bin folder create a script called
#!/bin/sh # This needs to be run with sudo apt update apt upgrade -y
This updates all the existing packages.
Next we need to install the new things that we want. Add the following underneath:
apt install -y $(cat ../pkglist.txt)
This installs everything listed in a file one level up called
pkglist.txt lets go and create that now. The following is mine:
build-essential git ssh vim tmux make wget curl zip python3 python3-pip xdg-utils dos2unix jq html-xml-utils
Next we will create a directory in our home folder called bin to house all the executable things we need for our user:
mkdir -p ~/bin chown wselwood: ~/bin
We need to change the owner of the bin folder as we are currently running as root
Now my work environment is very mixed. I work in a mixture of almost even parts Scala/Java, Go, and Python. I install python 3 the pkglist.txt already so that is easy enough. Next we will tackle java
There are plenty of guides about installing java on a ubuntu system out there. Digital Ocean have a good one that I usually follow. It boils down to adding a line to the
setup.sh file and one entry in the
setup.sh should now look like this
#!/bin/sh # This needs to be run with sudo add-apt-repository ppa:webupd8team/java apt update apt upgrade -y apt install -y $(cat ../pkglist.txt)
oracle-java8-installer to the
Almost done. One last little trick to make our Java life easier. If we sym-link our WSL
~/.m2 folder to our windows
.m2 folder we can avoid having two sets of libraries and very strange problems if we do
mvn install at any point. Add the following to the bottom of your
ln -s /mnt/c/Users/Wil.Selwood/.m2/ ~/.m2/
Next on to go
Unfortunately at the time of writing the version of Go in the ubuntu package manager is way out of date so we need to go and get the latest version our selves. For this we are going to use a few tricks to make sure we always download the latest version.
First off installing go its self. Unfortunately there isn’t a handy URL I could find that always points to the latest stable build. There is a link on the download page but it changes with each version. So we are going to use the
html-xml-utils package of tools to do some nasty (but better than pure regex) command line foo to get hold of the url from that page. Using chrome inspect the download link we are after. It should have a class of
downloadBox So we can use that to find the one we need
- Get hold of the page. We will use curl (cat url from my understanding) pass it a URL and it returns the text content to stdout.
- Normalise the html into valid XML
- Extract the links with a class of downloadBox
- Find the link that says its for linux-amd64
- Extract the link from that line.
The following line does this and stores the resulting text in a variable for us to download later:
go_url=$(curl --silent "https://golang.org/dl/" | hxnormalize -x | hxselect -s '\n' -i 'a.downloadBox' | grep linux-amd64 | grep -Po 'http[^\"]+')
Thats a bit long and unpleasant but it does the job. Now that we have the download url we can download, extract, and link to our path
wget $go_url -O ~/go-linux.tar.gz tar xzf ~/go-linux.tar.gz -C ~/ ln -s ~/go/bin/go ~/bin/go ln -s ~/go/bin/godoc ~/bin/godoc ln -s ~/go/bin/gofmt ~/bin/gofmt
That should get us go installed. I’ve a few projects that use dep for package management so we need to install that too. This is a little bit easier as dep has its releases in github which provides an api to download them so we can use the
jq command line tool to extract the url we need from the json response.
- Send the query to the github API
- Extract the asset that has a name ending with linux-amd64 and pull out the browser_download_url
dep_url=$(curl --silent "https://api.github.com/repos/golang/dep/releases/latest" | jq -r '.assets | select(.name | endswith("linux-amd64")).browser_download_url')
Now we just need to download that url and make it executable
wget $dep_url -O ~/bin/dep chmod +x ~/bin/dep
There we go. That should be go set up and ready to work.
Now on to some quality of life changes
Quality of life
vim and git default configuration
I have a copy of my
.gitconfig files stored in the dotfiles directory so we need to copy those over to our home directory. The following mess of characters copies everything from the directory above that starts with a dot to our home directory. Note there is no -r flag on the cp command so it will not copy the .git folder that exists in our project.
cp ../.* ~/
My configuration for vim and git are not too complex. I am colour blind and find the default colour schemes of both programs hard to read. So I change them in this config.
I use mrzool’s Sensible bash as a starting point here. Along with a
.bashrc file that I have had for so long I’m not sure where it came from.
sensible.bash file into the bin directory and the entry to source it to your
.bashrc file. There are instructions in the git repo.
I also add an entry to make
~/.local/bin be part of the path.
Next I like to enable
xdg-open to start a web browser. I find this really useful to include at the end of long build processes to open a browser to the server I have just launched so that I get pulled back from what ever I went off to do while the build ran.
The first step is to create a sym-link that points to your windows browser executable. Chrome in my case.
ln -s /mnt/c/Program\ Files\ \(x86\)/Google/Chrome/Application/chrome.exe /usr/bin/chrome
Then in your
.bashrc file add
export BROSWER=chrome and you should now be able to type
xdg-open https://google.com and it will pop open a new chrome tab for you.
The last thing I have added to my
.bashrc file is a thing that starts my ssh agent the first time I open a shell. This actually works way better under WSL than it did under cygwin as it lasts until you logout rather than as long as a single shell is left open. You may not want to do this depending on how paranoid you are about security. However it does mean that I don’t have to type in my ssh key password several hundred times a day.
export SSH_AUTH_SOCK=$HOME/.ssh-socket ssh-add -l ? /dev/null 2>&1 if [ $? = 2 ]; then rm -rf $SSH_AUTH_SOCK ssh-agent -a $SSH_AUTH_SOCK >| /tmp/.ssh-script source /tmp/.ssh-script echo $SSH_AGENT_PID >| ~/.ssh-agent-pid rm /tmp/.ssh-script ssh-add fi
And there we will leave the changes. Now all that we need to do is commit this to a remote repo somewhere. You can find mine on github There are a few tweaks in there I don’t mention here as they are only todo with the way I my disk is layed out.
I hope you have found this useful and have some ideas for your own environment. If you have any questions or comments please let me know on twitter I’d love to see your suggestions and little things you have found that makes your life a bit easier.