Permalink
Browse files

Initial commit.

  • Loading branch information...
0 parents commit 931995518b6739dd5698a61a77daddfde29075dd @zeekay committed Apr 27, 2014
Showing with 2,298 additions and 0 deletions.
  1. +3 −0 .gitignore
  2. +16 −0 .travis.yml
  3. +20 −0 LICENSE
  4. +21 −0 Makefile
  5. +204 −0 README.md
  6. +15 −0 bin/ellipsis
  7. +31 −0 comp/_ellipsis
  8. +80 −0 scripts/install.sh
  9. +25 −0 scripts/shim.sh
  10. +119 −0 src/cli.sh
  11. +317 −0 src/ellipsis.sh
  12. +83 −0 src/git.sh
  13. +45 −0 src/github.sh
  14. +36 −0 src/init.sh
  15. +21 −0 src/log.sh
  16. +197 −0 src/pkg.sh
  17. +27 −0 src/registry.sh
  18. +75 −0 src/utils.sh
  19. +1 −0 src/version.sh
  20. +15 −0 test/_helper.bash
  21. +27 −0 test/cli.bats
  22. +29 −0 test/ellipsis.bats
  23. +821 −0 test/fixtures/github.json
  24. +70 −0 test/utils.bats
3 .gitignore
@@ -0,0 +1,3 @@
+packages
+deps
+.DS_Store
16 .travis.yml
@@ -0,0 +1,16 @@
+language: node_js
+node_js:
+ - 0.10
+script: make test
+env:
+ - TEST_OPTS=--tap
+cache:
+ directories:
+ - deps
+ - node_modules
+notifications:
+ email:
+ on_success: change
+ on_failure: always
+after_sucess:
+ - npm install brief && node_modules/.bin/brief
20 LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2011-2014 Zach Kelling
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Makefile
@@ -0,0 +1,21 @@
+# ellipsis - shell script package manager
+
+all: test
+
+gh-pages:
+ brief
+
+tag:
+ @echo ELLIPSIS_VERSION=$(version) > src/version.sh
+ @git add src/version.sh
+ @git commit -m v$(version)
+ @git tag v$(version)
+
+test: deps/bats
+ deps/bats/bin/bats test $(TEST_OPTS)
+
+deps/bats:
+ @mkdir -p deps
+ git clone --depth 1 git://github.com/sstephenson/bats.git deps/bats
+
+.PHONY: all tag test
204 README.md
@@ -0,0 +1,204 @@
+## ellipsis [![Build Status](https://travis-ci.org/zeekay/ellipsis.svg?branch=master)](https://travis-ci.org/zeekay/ellipsis)
+
+```
+ _ _ _
+/\_\ /\_\ /\_\
+\/_/ \/_/ \/_/ …because $HOME is where the <3 is!
+```
+
+ellipsis is a package manager for dotfiles.
+
+### Features
+- Creating new packages is trivial (any git repository is already a package).
+- Ellipsis packages make it easy to share specific bits of your dotfiles. Say a
+ friend wants to test out your ZSH setup but doesn't want to adopt the madness
+ that is your Vim config? No problem, he can just `ellipsis install
+ github-user/dot-zsh`
+- Quickly see which dotfiles have been modified, and keep them updated and in
+ sync across systems.
+- Cross platform, known to work on Mac OS X, Linux, FreeBSD and even Cygwin.
+- Completely customizable.
+
+### Install
+Clone and symlink or use handy-dandy installer:
+
+```bash
+$ curl -sL ellipsis.sh | sh
+```
+
+You can also specify which packages to install by setting the `PACKAGES` variable, i.e.:
+
+```bash
+$ curl -sL ellipsis.sh | PACKAGES='vim zsh' sh
+```
+
+I recommend adding `~/.ellipsis/bin` to your `$PATH`, but you can also just
+symlink `~/.ellipsis/bin/ellipsis` somewhere convenient.
+
+### Usage
+Ellipsis comes with no dotfiles out of the box. To add a dotfiles packages, use
+`ellipsis install`. Packages to install can be specified by github-user/repo or
+full ssh/git/http(s) urls:
+
+```bash
+$ ellipsis install ssh://github.com/zeekay/private.git
+$ ellipsis install zeekay/vim
+$ ellipsis install zsh
+```
+
+...all work.
+
+Full usage available via `ellipsis` executable:
+
+```
+$ ellipsis -h
+Usage: ellipsis <command>
+ Options:
+ -h, --help show help
+ -v, --version show version
+
+ Commands:
+ new create a new package
+ edit edit an installed package
+ install install new package
+ uninstall uninstall package
+ unlink unlink package
+ broken list any broken symlinks
+ clean rm broken symlinks
+ list list installed packages
+ links show symlinks installed by package(s)
+ pull git pull package(s)
+ push git push package(s)
+ status show status of package(s)
+ publish publish package to repository
+ search search package repository
+```
+
+### Configuration
+You can customize ellipsis by exporting a few different variables.
+
+#### ELLIPSIS_USER
+Customize whose dotfiles are installed when you `ellipsis install` without
+specifiying user or a full repo url.
+
+#### ELLIPSIS_REPO
+Customize location of ellipsis repo cloned during a curl-based install.
+
+#### ELLIPSIS_PACKAGES_URL
+Customizes which url is used to display available packages.
+
+```bash
+export ELLIPSIS_USER="zeekay"
+export ELLIPSIS_REPO="https://github.com/zeekay/ellipsis"
+export ELLIPSIS_PACKAGES_URL="https://raw.githubusercontent.com/zeekay/ellipsis/master/available-packages.txt"
+```
+
+### Packages
+A package is any repo with files you want to symlink into `$HOME`. By default a
+given repo's non-hidden files (read: not beginning with a `.`) will naively be
+linked into `$HOME`. Of course this isn't sufficient for a lot of cases, so you
+can customize how ellipsis treats your package by defining hooks in an
+`ellipsis.sh` file at the root of your repository.
+
+### Hooks
+Hooks allow you to customize how ellipsis interacts with your package. For
+instance if you want to change how your package is installed you can define
+`pkg.install` and specifiy exactly which files are symlinked into `$HOME`,
+compile any libraries, etc.
+
+The follow hooks/variables are available in your `ellipsis.sh`:
+
+#### pkg.install
+Customize how package is installed. By default all files are symlinked into
+`$HOME`.
+
+#### pkg.uninstall
+Customize how package is uninstalled. By default all symlinks are removed from
+`$HOME`.
+
+#### pkg.push
+Customize how how changes are pushed `ellipsis push` is used.
+
+#### pkg.pull
+Customize how how changes are pulled in when `ellipsis pull` is used.
+
+#### pkg.status
+Customize output of `ellipsis status`.
+
+#### $PKG_NAME
+Name of your package.
+
+#### $PKG_PATH
+Path to your package.
+
+### API
+There are a number of functions ellipsis exposes which can be useful in your
+package's hooks:
+
+#### ellipsis.backup
+Moves existing file `$1` to `$1.bak`, taking care not to overwrite any existing
+backups.
+
+#### ellipsis.link_file
+Link a single file `$1` into `$HOME`, taking care to backup an existing file.
+
+#### ellipsis.link_files
+Links files in `$1` into `$HOME`, taking care to backup any existing files.
+
+#### ellipsis.run_installer
+Download an installation script from url `$1` with `curl` and execute it.
+
+#### utils.platform
+Platform detection, returns lowercase result of `uname`.
+
+#### git.[command]
+There are also several wrappers around common git operations which can be used
+for consistency with the rest of ellipsis: **git.clone**, **git.pull**,
+**git.push**, and **git.status**.
+
+### Available packages
+
+#### [zeekay/dot-alfred][alfred]
+Alfred configuration files.
+
+#### [zeekay/dot-atom][atom]
+Atom configuration files.
+
+#### [zeekay/dot-emacs][emacs]
+Emacs configuration files.
+
+#### [zeekay/dot-files][files]
+Default dotfiles for ellipsis.
+
+#### [zeekay/dot-irssi][irssi]
+Irssi configuration.
+
+#### [zeekay/dot-iterm2][iterm2]
+iTerm2 configuration files.
+
+#### [zeekay/dot-vim][vim]
+Vim configuration based on vice framework.
+
+#### [zeekay/dot-xmonad][xmonad]
+Xmonad configuration.
+
+#### [zeekay/dot-zsh][zsh]
+Zsh configuration using zeesh! framework.
+
+### Development
+Pull requests welcome! New code should follow [Google's style
+guide][style-guide]. To run tests you need to install [bats][bats].
+
+To suggest a feature or report a bug: http://github.com/zeekay/ellipsis/issues.
+
+[alfred]: https://github.com/zeekay/dot-alfred
+[atom]: https://github.com/zeekay/dot-atom
+[emacs]: https://github.com/zeekay/dot-emacs
+[files]: https://github.com/zeekay/dot-files
+[irssi]: https://github.com/zeekay/dot-irssi
+[iterm2]: https://github.com/zeekay/dot-iterm2
+[vim]: https://github.com/zeekay/dot-vim
+[xmonad]: https://github.com/zeekay/dot-xmonad
+[zsh]: https://github.com/zeekay/dot-zsh
+[style-guide]: https://google-styleguide.googlecode.com/svn/trunk/shell.xml
+[bats]: https://github.com/sstephenson/bats
15 bin/ellipsis
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+source "$(dirname "${BASH_SOURCE[0]}")/../src/init.sh"
+
+load cli
+
+# check for controlling terminal
+if [ -t 1 ]; then
+ cli.run $@
+ exit $?
+else
+ # strip ansi colors
+ cli.run $@ | sed -e 's/\[[^m]*m//g'
+ exit $PIPESTATUS # exit with result of first command in pipe, i.e., cli.run
+fi
31 comp/_ellipsis
@@ -0,0 +1,31 @@
+#compdef ellipsis
+
+_ellipsis() {
+ local -a commands
+ commands=(
+ 'broken:list any broken symlinks'
+ 'clean:rm broken symlinks'
+ 'edit:edit an installed package'
+ 'help:show this usage'
+ 'install:install new package'
+ 'links:show symlinks installed by package(s)'
+ 'list:list installed packages'
+ 'new:create a new package'
+ 'publish:publish package to repository'
+ 'pull:git pull package(s)'
+ 'push:git push package(s)'
+ 'search:search package repository'
+ 'status:show status of package(s)'
+ 'uninstall:uninstall package'
+ 'unlink:unlink package'
+ 'version:show current version'
+ )
+
+ if (( CURRENT == 2 )); then
+ _describe -t commands 'commands' commands
+ fi
+
+ return 0
+}
+
+_ellipsis
80 scripts/install.sh
@@ -0,0 +1,80 @@
+#!/usr/bin/env bash
+#
+# scripts/install.sh
+# Installer for ellipsis (http://ellipsis.sh).
+
+# Ensure dependencies are installed.
+deps=(bash curl git)
+
+for dep in ${deps[*]}; do
+ hash $dep 2>/dev/null || { echo >&2 "ellipsis requires $dep to be installed."; exit 1; }
+done
+
+# Create temp dir.
+tmp_dir=$(mktemp -d ${TMPDIR:-tmp}-XXXXXX)
+
+# Clone ellipsis into $tmp_dir.
+git clone --depth 1 git://github.com/zeekay/ellipsis.git $tmp_dir/ellipsis
+
+# Save reference to specified ELLIPSIS_PATH (if any) otherwise final
+# destination: $HOME/.ellipsis.
+FINAL_ELLIPSIS_PATH=${ELLIPSIS_PATH:-$HOME/.ellipsis}
+
+# Temporarily set ellipsis PATH so we can load other files.
+ELLIPSIS_PATH="$tmp_dir/ellipsis"
+
+# Initialize ellipsis.
+source $tmp_dir/ellipsis/src/init.sh
+
+# Load modules.
+load ellipsis
+load git
+load pkg
+load registry
+load utils
+
+ELLIPSIS_PATH="$FINAL_ELLIPSIS_PATH"
+
+# Backup existing ~/.ellipsis if necessary and move project into place.
+ellipsis.backup $ELLIPSIS_PATH
+mv $tmp_dir/ellipsis $ELLIPSIS_PATH
+
+# Clean up (only necessary on cygwin, really).
+rm -rf $tmp_dir
+
+# Backwards compatability, originally referred to packages as modules.
+PACKAGES="${PACKAGES:-$MODULES}"
+
+if [ -z "$PACKAGES" ]; then
+ # List available packages.
+ registry.available
+
+ # List default packages for this platform.
+ if [ "$(utils.platform)" = "darwin" ]; then
+ default="zeekay/dot-files zeekay/dot-vim zeekay/dot-zsh zeekay/dot-alfred zeekay/dot-iterm2"
+ else
+ default="zeekay/dot-files zeekay/dot-vim zeekay/dot-zsh"
+ fi
+
+ echo "default: $default"
+
+ # allow user to override defaults
+ read packages < /dev/tty
+ packages="${packages:-$default}"
+else
+ # user already provided packages list to install
+ packages="$PACKAGES"
+fi
+
+# install selected packages.
+for pkg in ${packages[*]}; do
+ ellipsis.install "$pkg"
+done
+
+echo
+echo 'Note: export PATH=~/.ellipsis/bin:$PATH to add ellipsis to your $PATH '
+echo
+echo ' _ _ _'
+echo ' /\_\ /\_\ /\_\'
+echo ' \/_/ \/_/ \/_/ …because $HOME is where the <3 is!'
+echo
25 scripts/shim.sh
@@ -0,0 +1,25 @@
+
+EOF
+
+# shim for ellipsis install.sh
+#
+# This is used on ellipsis.sh to bootstrap the full installer, which you
+# otherwise can't curl and pipe to sh (as it requires bash). Not meant to be
+# run standalone.
+
+# wait for curl output to finish
+sleep 0.5
+
+# Ensure dependencies are installed.
+deps=(bash curl git)
+
+for dep in ${deps[@]}; do
+ hash $dep 2>/dev/null || { echo >&2 "ellipsis requires $dep to be installed."; exit 1; }
+done
+
+# Download full installer and execute with bash
+curl -sL https://raw.githubusercontent.com/zeekay/ellipsis/master/scripts/install.sh > install-$$.sh
+bash install-$$.sh
+
+# Clean up
+rm install-$$.sh
119 src/cli.sh
@@ -0,0 +1,119 @@
+#!/usr/bin/env bash
+#
+# cli.sh
+# Command line interface for ellipsis.
+
+# Initialize ourselves if we haven't yet.
+if [[ $ELLIPSIS_INIT -ne 1 ]]; then
+ source "$(dirname "${BASH_SOURCE[0]}")"/init.sh
+fi
+
+# Source deps.
+load ellipsis
+load git
+load github
+load log
+load pkg
+load registry
+load utils
+
+# prints usage for ellipsis
+cli.usage() {
+ cat <<-EOF
+Usage: ellipsis <command>
+ Options:
+ -h, --help show help
+ -v, --version show version
+
+ Commands:
+ new create a new package
+ edit edit an installed package
+ install install new package
+ uninstall uninstall package
+ unlink unlink package
+ broken list any broken symlinks
+ clean rm broken symlinks
+ list list installed packages
+ links show symlinks installed by package(s)
+ pull git pull package(s)
+ push git push package(s)
+ status show status of package(s)
+ publish publish package to repository
+ search search package repository
+ EOF
+}
+
+# prints ellipsis version
+cli.version() {
+ local cwd="$(pwd)"
+ cd $HOME/.ellipsis
+
+ local sha1=$(git rev-parse --short HEAD)
+ echo -e "\033[1mv$ELLIPSIS_VERSION\033[0m ($sha1)"
+
+ cd $cwd
+}
+
+# run ellipsis
+cli.run() {
+ case "$1" in
+ new)
+ ellipsis.new $2
+ ;;
+ edit)
+ ellipsis.edit $2
+ ;;
+ install|in|add)
+ ellipsis.install $2
+ ;;
+ uninstall|remove|rm)
+ ellipsis.uninstall $2
+ ;;
+ broken)
+ ellipsis.broken $2
+ ;;
+ clean)
+ ellipsis.clean $2
+ ;;
+ unlink)
+ ellipsis.unlink $2
+ ;;
+ list|ls|installed)
+ ellipsis.list
+ ;;
+ links|symlinks)
+ ellipsis.symlinks $2
+ ;;
+ status|st)
+ ellipsis.status $2
+ ;;
+ pull|update|up)
+ ellipsis.pull $2
+ ;;
+ push)
+ ellipsis.push $2
+ ;;
+ available)
+ registry.available
+ ;;
+ publish)
+ registry.publish $2
+ ;;
+ search)
+ registry.search $2
+ ;;
+ help|--help|-h)
+ cli.usage
+ ;;
+ version|--version|-v)
+ cli.version
+ ;;
+ *)
+ if [ $# -gt 0 ]; then
+ echo ellipsis: invalid command -- $1
+ fi
+ cli.usage
+ return 1
+ ;;
+ esac
+}
317 src/ellipsis.sh
@@ -0,0 +1,317 @@
+#!/usr/bin/env bash
+#
+# ellipsis.sh
+# Core ellipsis interface.
+
+# Initialize ourselves if we haven't yet.
+if [[ $ELLIPSIS_INIT -ne 1 ]]; then
+ source "$(dirname "${BASH_SOURCE[0]}")/init.sh"
+fi
+
+
+# symlink a single file into $HOME
+ellipsis.link_file() {
+ local name="${1##*/}"
+ local dest="$HOME/.$name"
+
+ ellipsis.backup "$dest"
+
+ echo linking "$dest"
+ ln -s "$1" "$dest"
+}
+
+# find all files in dir excluding the dir itself, hidden files, README,
+# LICENSE, *.rst, *.md, and *.txt and symlink into $HOME.
+ellipsis.link_files() {
+ for file in $(find "$1" -maxdepth 1 -name '*' \
+ ! -name '.*' \
+ ! -name 'README' \
+ ! -name 'LICENSE' \
+ ! -name '*.md' \
+ ! -name '*.rst' \
+ ! -name '*.txt' \
+ ! -wholename "$1" \
+ ! -name "ellipsis.sh" | sort); do
+ ellipsis.link_file $file
+ done
+}
+
+# backup existing file, ensuring you don't overwrite existing backups
+ellipsis.backup() {
+ local original="$1"
+ local backup="$original.bak"
+ local name="${original##*/}"
+
+ # check for broken symlinks
+ if [ "$(find -L "$original" -maxdepth 0 -type l 2>/dev/null)" != "" ]; then
+ local broken=$(readlink "$original")
+
+ if [ "$(echo "$broken" | grep .ellipsis)" != "" ]; then
+ # silently remove old broken ellipsis symlinks
+ rm "$original"
+ else
+ # notify user we're removing a broken link
+ echo "rm ~/$name (broken link to $broken)"
+ rm "$original"
+ fi
+
+ return
+ fi
+
+ if [ -e "$original" ]; then
+ # remove, not backup old ellipsis symlinked files
+ if [ "$(readlink "$original" | grep .ellipsis)" != "" ]; then
+ rm "$original"
+ return
+ fi
+
+ if [ -e "$backup" ]; then
+ n=1
+ while [ -e "$backup.$n" ]; do
+ n=$((n+1))
+ done
+ backup="$backup.$n"
+ fi
+
+ echo "mv ~/$name $backup"
+ mv "$original" "$backup"
+ fi
+}
+
+# Run web-based installers
+ellipsis.run_installer() {
+ # save reference to current dir
+ local cwd=$(pwd)
+ # create temp dir and cd to it
+ local tmp_dir=$(mktemp -d $TMPDIR.XXXXXX) && cd $tmp_dir
+ # download installer
+ curl -sL "$url" > "tmp-$$.sh"
+ # run with ELLIPSIS env var set
+ ELLIPSIS=1 sh "tmp-$$.sh"
+ # change back to original dir and clean up
+ cd $cwd
+ rm -rf $tmp_dir
+}
+
+# Installs new ellipsis package, using install hook if one exists. If no hook is
+# defined, all files are symlinked into $HOME using `ellipsis.link_files`.
+ellipsis.install() {
+ case "$1" in
+ http:*|https:*|git:*|ssh:*)
+ PKG_NAME="$(echo $1 | rev | cut -d '/' -f 1 | rev)"
+ PKG_PATH="$(pkg.name_to_path $PKG_NAME)"
+ PKG_URL="$1"
+ ;;
+ */*)
+ PKG_USER=$(echo $1 | cut -d '/' -f1)
+ PKG_NAME=$(echo $1 | cut -d '/' -f2)
+ PKG_PATH="$(pkg.name_to_path $PKG_NAME)"
+ PKG_URL="$ELLIPSIS_PROTO://github.com/$PKG_USER/$PKG_NAME"
+ ;;
+ *)
+ PKG_NAME="$1"
+ PKG_PATH="$(pkg.name_to_path $PKG_NAME)"
+ PKG_URL="$ELLIPSIS_PROTO://github.com/$ELLIPSIS_USER/$PKG_NAME"
+ ;;
+ esac
+
+ git.clone "$PKG_URL" "$PKG_PATH"
+
+ pkg.init "$PKG_PATH"
+ pkg.run pkg.install
+ pkg.del
+}
+
+# Uninstall package, using uninstall hook if one exists. If no hook is
+# defined, all symlinked files in $HOME are removed and package is rm -rf'd.
+ellipsis.uninstall() {
+ pkg.init "$1"
+ pkg.run pkg.uninstall
+ pkg.del
+}
+
+# Unlink package, using unlink hooks, using unlink hook if one exists. If no
+# hook is defined, all symlinked files in $HOME are removed.
+ellipsis.unlink() {
+ pkg.init "$1"
+ pkg.run pkg.unlink
+ pkg.del
+}
+
+# List installed packages.
+ellipsis.list() {
+ if utils.cmd_exists column; then
+ ellipsis.each pkg.list | column -t -s $'\t'
+ else
+ ellipsis.each pkg.list
+ fi
+}
+
+# Scaffold a new package.
+ellipsis.new() {
+ # If no-argument is passed, use cwd as package path.
+ if [ $# -eq 1 ]; then
+ pkg.init_globals "$1"
+ else
+ pkg.init_globals "$(pwd)"
+ fi
+
+ # Create package dir if necessary.
+ mkdir -p $PKG_PATH
+
+ # If path is not empty, ensure they are serious.
+ if ! utils.folder_empty $PKG_PATH; then
+ utils.prompt "destination is not empty, continue? [y/n]" || exit 1
+ fi
+
+ # Template variables.
+ local _PKG_PATH='$PKG_PATH'
+ local _PROMPT='$'
+ local _FENCE=\`\`\`
+
+ # Generate ellipsis.sh for package.
+ cat > $PKG_PATH/ellipsis.sh <<EOF
+#!/usr/bin/env bash
+#
+# $PKG_NAME ellipsis package
+
+# The following hooks can be defined to customize behavior of your package:
+# pkg.install() {
+# ellipsis.link_files $_PKG_PATH
+# }
+
+# pkg.push() {
+# git.push
+# }
+
+# pkg.pull() {
+# git.pull
+# }
+
+# pkg.status() {
+# git.status
+# }
+EOF
+
+ # Generate README.md for package.
+ cat > $PKG_PATH/README.md <<EOF
+# $PKG_NAME
+Just a bunch of dotfiles.
+
+## Install
+Clone and symlink or install with [ellipsis][ellipsis]:
+
+$_FENCE
+$_PROMPT ellipsis install $PKG_NAME
+$_FENCE
+
+[ellipsis]: http://ellipsis.sh
+EOF
+
+ cd $PKG_PATH
+ git init
+ git add README.md ellipsis.sh
+ git commit -m "Initial commit"
+ echo new package created at ${utils.relative_path $PKG_PATH}
+}
+
+# Edit ellipsis.sh for package, or open ellipsis dir in $EDITOR.
+ellipsis.edit() {
+ if [ $# -eq 1 ]; then
+ # Edit package's ellipsis.sh file.
+ pkg.init "$1"
+ $EDITOR $PKG_PATH/ellipsis.sh
+ else
+ # Open ellipsis dir in editor.
+ $EDITOR $ELLIPSIS_PATH
+ fi
+}
+
+# Run commands across all packages.
+ellipsis.each() {
+ # execute command for ellipsis first
+ pkg.init $ELLIPSIS_PATH
+ pkg.run "$@"
+ pkg.del
+
+ # loop over packages, excecuting command
+ for pkg in $(ellipsis.list_packages); do
+ pkg.init "$pkg"
+ pkg.run "$@"
+ pkg.del
+ done
+}
+
+# List all installed packages.
+ellipsis.list_packages() {
+ if ! utils.folder_empty $ELLIPSIS_PATH/packages; then
+ echo $ELLIPSIS_PATH/packages/*
+ fi
+}
+
+# List all symlinks (slightly optimized over calling pkg.list_symlinks for each
+# package.
+ellipsis.list_symlinks() {
+ for file in $(utils.list_symlinks); do
+ local link="$(readlink $file)"
+ if [[ "$link" == $ELLIPSIS_PATH* ]]; then
+ echo "$(utils.strip_packages_dir $link) -> $(utils.relative_path $file)";
+ fi
+ done
+}
+
+# List all symlinks, or just symlinks for a given package
+ellipsis.symlinks() {
+ if [ $# -eq 1 ]; then
+ pkg.init "$1"
+ pkg.run pkg.symlinks
+ pkg.del
+ else
+ ellipsis.list_symlinks | sort | column -t
+ fi
+}
+
+# List broken symlinks in HOME
+ellipsis.broken() {
+ for file in $(find -L ~ -type l -maxdepth 1); do
+ echo "$(utils.strip_packages_dir $(readlink $file)) -> $(utils.relative_path $file)";
+ done
+}
+
+# List broken symlinks in HOME
+ellipsis.clean() {
+ find -L ~ -type l -maxdepth 1 | xargs rm
+}
+
+# List(s) package git status.
+ellipsis.status() {
+ if [ $# -eq 1 ]; then
+ pkg.init "$1"
+ pkg.run pkg.status
+ pkg.del
+ else
+ ellipsis.each pkg.status
+ fi
+}
+
+# Updates package(s) with git pull.
+ellipsis.pull() {
+ if [ $# -eq 1 ]; then
+ pkg.init "$1"
+ pkg.run pkg.pull
+ pkg.del
+ else
+ ellipsis.each pkg.pull
+ fi
+}
+
+# Push updated package(s) with git push.
+ellipsis.push() {
+ if [ $# -eq 1 ]; then
+ pkg.init "$1"
+ pkg.run pkg.push
+ pkg.del
+ else
+ ellipsis.each pkg.push
+ fi
+}
83 src/git.sh
@@ -0,0 +1,83 @@
+#!/usr/bin/env bash
+#
+# git.sh
+# Assorted git utility functions. These functions all require us to cd into the
+# git repo we want to operate on first. These exist mostly for aesthetic
+# reasons, i.e., pretty output in the various ellipsis commands and can be used
+# by package authors for consistency with them.
+
+# Initialize ourselves if we haven't yet.
+if [[ $ELLIPSIS_INIT -ne 1 ]]; then
+ source "$(dirname "${BASH_SOURCE[0]}")"/init.sh
+fi
+
+# Clone a Git repo.
+git.clone() {
+ git clone --depth 1 "$@" 2>&1 | grep 'Cloning into'
+}
+
+# Pull git repo.
+git.pull() {
+ pkg.init_globals ${1:-$PKG_NAME}
+ echo -e "\033[1mupdating $PKG_NAME\033[0m"
+ git pull
+}
+
+# Push git repo.
+git.push() {
+ pkg.init_globals ${1:-$PKG_NAME}
+ echo -e "\033[1mpushing $PKG_NAME\033[0m"
+ git push
+}
+
+# Tab delimited package listing with commit/last update time.
+git.list() {
+ pkg.init_globals ${1:-$PKG_NAME}
+ local sha1=$(git.sha1)
+ local last_updated=$(git.last_updated)
+
+ echo -e "\033[1m$PKG_NAME\033[0m\t$sha1\t(updated $last_updated)"
+}
+
+# Pretty status with diff.
+git.status() {
+ pkg.init_globals ${1:-$PKG_NAME}
+ local ahead="$(git.ahead)"
+
+ # Return unless there are changes or we are behind.
+ ! git.has_changes && [ -z "$ahead" ] || return
+
+ local sha1="$(git.sha1)"
+ local last_updated=$(git.last_updated)
+
+ echo -e "\033[1m$PKG_NAME\033[0m $sha1 (updated $last_updated) $ahead"
+ git.diffstat
+}
+
+# Print last commit's sha1 hash.
+git.sha1() {
+ git rev-parse --short HEAD
+}
+
+# Print last commit's relative update time.
+git.last_updated() {
+ git --no-pager log --pretty="format:%ad" --date=relative -1
+}
+
+# Print how far ahead git repo is
+git.ahead() {
+ git status -sb --porcelain | grep --color=no -o '\[.*\]'
+}
+
+# Check whether get repo has changes.
+git.has_changes() {
+ if git diff-index --quiet HEAD --; then
+ return 0
+ fi
+ return 1
+}
+
+# Print diffstat for git repo
+git.diffstat() {
+ git --no-pager diff --stat --color=always
+}
45 src/github.sh
@@ -0,0 +1,45 @@
+#!/usr/bin/env bash
+#
+# github.sh
+# Assorted functions for querying Github for package information and formatting
+# responses.
+
+# Initialize ourselves if we haven't yet.
+if [[ $ELLIPSIS_INIT -ne 1 ]]; then
+ source "$(dirname "${BASH_SOURCE[0]}")"/init.sh
+fi
+
+# Search epmi org on Github for a given package.
+github.search() {
+ curl -s https://api.github.com/search/repositories\?q\=$1+user:epmi+fork:only
+}
+
+# List packages forked to epmi org on Github.
+github.list_repos() {
+ curl -s https://api.github.com/orgs/epmi/repos\?type\=forks
+}
+
+# Parses Github JSON API responses into:
+# name zeekay/dot-alfred
+# description My alfred dotfiles, ellipsis.sh compatible.
+# homepage https://github.com/zeekay/dot-alfred
+# forks 0
+# watchers 0
+github.format_json() {
+ grep -e '"description": "[^"]*[^"]' \
+ -e '"name": "[^"]*[^"]' \
+ -e '"homepage": "[^"]*[^"]' \
+ -e '"watchers": [^"]*[^"]' \
+ -e '"forks": [^"]*[^"]' \
+ -e '"default_branch": "[^"]*[^"]' \
+ | sed -e 's/"default_branch":.*//' \
+ | cut -f2- -d '"' \
+ | sed -e 's/name": "/name \'$'\033[1m/' \
+ -e 's/-/\//' \
+ -e 's/description": "/\'$'\033[0mdesc /' \
+ -e 's/homepage": "/url /' \
+ -e 's/watchers": /watchers /' \
+ -e 's/forks": /forks /' \
+ -e 's/,$//' \
+ -e 's/"$//'
+}
36 src/init.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+#
+# init.sh
+# Setup initial globals and load function used to source other modules.
+
+# These globals can be set by a user to use a custom ellipsis fork/set of packages/etc
+
+# git config returns 1 if key isn't found, so we pipe to cat to squash that in
+# the case it's not-defined.
+if [[ -z "$ELLIPSIS_USER" ]]; then
+ GITHUB_USER=$(git config github.user | cat)
+ ELLIPSIS_USER=${GITHUB_USER:-zeekay}
+fi
+
+# Repostitory defaults.
+ELLIPSIS_PROTO="${ELLIPSIS_PROTO:-https}"
+ELLIPSIS_REPO="${ELLIPSIS_REPO:-https://github.com/$ELLIPSIS_USER/ellipsis}"
+
+# Default locations for ellipsis and packages.
+ELLIPSIS_HOME="$HOME"
+ELLIPSIS_PATH="${ELLIPSIS_PATH:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
+
+# Ellipsis is the default package.
+PKG_PATH=${PKG_PATH:-$ELLIPSIS_PATH}
+PKG_NAME=${PKG_NAME:-${PKG_PATH##*/.}}
+
+# Utility to load other modules.
+load() {
+ source $ELLIPSIS_PATH/src/$1.sh
+}
+
+# Load version info.
+load version
+
+# Set flag that we've been sourced already.
+ELLIPSIS_INIT=1
21 src/log.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+#
+# log.sh
+# Logging utilities.
+
+# Initialize ourselves if we haven't yet.
+if [[ $ELLIPSIS_INIT -ne 1 ]]; then
+ source "$(dirname "${BASH_SOURCE[0]}")"/init.sh
+fi
+
+log.info() {
+ echo -e "\033[33minfo\033[0m" "$@"
+}
+
+log.error() {
+ echo -e "\033[31merror\033[0m" "$@"
+}
+
+log.warn() {
+ echo -e "\033[33mwarn\033[0m" "$@"
+}
197 src/pkg.sh
@@ -0,0 +1,197 @@
+#!/usr/bin/env bash
+#
+# pkg.sh
+# Ellipsis package interface. Encapsulates various useful functions for working
+# with packages.
+
+# Initialize ourselves if we haven't yet.
+if [[ $ELLIPSIS_INIT -ne 1 ]]; then
+ source "$(dirname "${BASH_SOURCE[0]}")"/init.sh
+fi
+
+# List of hooks available to package authors.
+PKG_HOOKS=(install uninstall unlink symlinks pull push status list)
+
+# Convert package name to path.
+pkg.name_to_path() {
+ echo "$ELLIPSIS_PATH/packages/$1"
+}
+
+# Convert package path to name, stripping any leading dots.
+pkg.path_to_name() {
+ echo ${1##*/} | sed -e "s/^\.//"
+}
+
+# Set PKG_NAME, PKG_PATH. If $1 has a slash it's assumed to be
+# PKG_PATH and not PKG_NAME, otherwise assume PKG_NAME.
+pkg.init_globals() {
+ if utils.has_slash "$1"; then
+ PKG_PATH="$1"
+ PKG_NAME="$(pkg.path_to_name $PKG_PATH)"
+ else
+ PKG_NAME="$1"
+ PKG_PATH="$(pkg.name_to_path $PKG_NAME)"
+ fi
+}
+
+# Initialize a package and it's hooks.
+pkg.init() {
+ pkg.init_globals ${1:-$PKG_PATH}
+
+ # Exit if we're asked to operate on an unknown package.
+ if [ ! -d "$PKG_PATH" ]; then
+ log.error "Unkown package $PKG_NAME, $(utils.relative_path $PKG_PATH) missing!"
+ exit 1
+ fi
+
+ # Source ellipsis.sh if it exists to initialize package's hooks.
+ if [ -f "$PKG_PATH/ellipsis.sh" ]; then
+ source "$PKG_PATH/ellipsis.sh"
+ fi
+}
+
+# List symlinks associated with package.
+pkg.list_symlinks() {
+ for file in $(utils.list_symlinks); do
+ if [[ "$(readlink $file)" == *packages/$PKG_NAME* ]]; then
+ echo $file
+ fi
+ done
+}
+
+# Print file -> symlink mapping
+pkg.symlinks_mappings() {
+ for file in $(utils.list_symlinks); do
+ local link=$(readlink $file)
+
+ if [[ "$link" == *packages/$PKG_NAME* ]]; then
+ echo "$(utils.strip_packages_dir $link) -> $(utils.relative_path $file)";
+ fi
+ done
+}
+
+# Run hook or command inside PKG_PATH.
+pkg.run() {
+ local cwd="$(pwd)"
+
+ # change to package dir
+ cd "$PKG_PATH"
+
+ # run hook or command
+ case $1 in
+ pkg.*)
+ pkg.run_hook $1
+ ;;
+ *)
+ $1
+ ;;
+ esac
+
+ # return after running command
+ cd "$cwd"
+}
+
+# run hook if it's defined, otherwise use default implementation
+pkg.run_hook() {
+ # Run packages's hook.
+ if utils.cmd_exists $1; then
+ $1
+ else
+ # Run default hook.
+ case $1 in
+ pkg.install)
+ pkg.hooks.install
+ ;;
+ pkg.unlink)
+ pkg.hooks.unlink
+ ;;
+ pkg.uninstall)
+ pkg.hooks.uninstall
+ ;;
+ pkg.symlinks)
+ pkg.hooks.symlinks
+ ;;
+ pkg.pull)
+ pkg.hooks.pull
+ ;;
+ pkg.push)
+ pkg.hooks.push
+ ;;
+ pkg.list)
+ pkg.hooks.list
+ ;;
+ pkg.status)
+ pkg.hooks.status
+ ;;
+ *)
+ echo Unknown hook!
+ ;;
+ esac
+ fi
+}
+
+# Clear globals, hooks.
+pkg.del() {
+ pkg._unset_vars
+ pkg._unset_hooks
+}
+
+# Unset global packages.
+pkg._unset_vars() {
+ unset PKG_NAME
+ unset PKG_PATH
+}
+
+# Unset any hooks that might have been defined by package.
+pkg._unset_hooks() {
+ for hook in ${PKG_HOOKS[@]}; do
+ unset -f pkg.$hook
+ done
+}
+
+# Hooks
+
+# Symlink files in $PKG_PATH into $HOME
+pkg.hooks.install() {
+ ellipsis.link_files $PKG_PATH
+}
+
+# Remove package's symlinks in $HOME.
+pkg.hooks.unlink() {
+ for symlink in $(pkg.list_symlinks); do
+ rm $symlink
+ done
+}
+
+# Remove package's symlinks then remove package.
+pkg.hooks.uninstall() {
+ pkg.run_hook pkg.unlink
+ rm -rf $PKG_PATH
+}
+
+# Show symlink mapping for package.
+pkg.hooks.symlinks() {
+ echo -e "\033[1m$PKG_NAME\033[0m"
+
+ pkg.symlinks_mappings | sort | column -t
+}
+
+# Do git pull from package
+pkg.hooks.pull() {
+ pkg.run git.pull
+}
+
+# Do git push from package
+pkg.hooks.push() {
+ pkg.run git.push
+}
+
+# List repo status.
+pkg.hooks.list() {
+ pkg.run git.list
+}
+
+# List repo status if it's changed and show git diffstat.
+pkg.hooks.status() {
+ pkg.run git.status
+}
27 src/registry.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+#
+# registry.sh
+# Interface to ellipsis package manager index. Uses github under the covers.
+
+# Initialize ourselves if we haven't yet.
+if [[ $ELLIPSIS_INIT -ne 1 ]]; then
+ source "$(dirname "${BASH_SOURCE[0]}")"/init.sh
+fi
+
+# Load deps.
+load github
+
+# Search registry for ellipsis packages.
+registry.search() {
+ github.search $1 | github.format_json
+}
+
+# List ellipsis packages in registry.
+registry.available() {
+ github.list_repos | github.format_json
+}
+
+# Publish packge to repository.
+registry.publish() {
+ echo TODO
+}
75 src/utils.sh
@@ -0,0 +1,75 @@
+#!/usr/bin/env bash
+#
+# utils.sh
+# Various file/folder/utility functions used by Ellipsis.
+
+# Initialize ourselves if we haven't yet.
+if [[ $ELLIPSIS_INIT -ne 1 ]]; then
+ source "$(dirname "${BASH_SOURCE[0]}")"/init.sh
+fi
+
+# platform detection
+utils.platform() {
+ uname | tr '[:upper:]' '[:lower:]'
+}
+
+# check if a command or function exists
+utils.cmd_exists() {
+ if hash $1 2>/dev/null; then
+ return 0
+ fi
+ return 1
+}
+
+# return true if folder is empty
+utils.folder_empty() {
+ if [ $(find $1 -prune -empty) ]; then
+ return 0
+ fi
+ return 1
+}
+
+# prompt with message and return true if yes/YES, otherwise false
+utils.prompt() {
+ read -r -p "$1 " answer
+ case $answer in
+ y*|Y*)
+ return 0
+ ;;
+ *)
+ return 1
+ ;;
+ esac
+}
+
+# List symlinks in a folder, defaulting to $HOME.
+utils.list_symlinks() {
+ find ${1:-$HOME} -maxdepth 1 -type l
+}
+
+# dunno how this isn't part of POSIX
+utils.abs_path() {
+ echo $(cd $(dirname $1); pwd)/$(basename $1)
+}
+
+# return path to file relative to $HOME (if possible)
+utils.relative_path() {
+ echo ${1/$HOME/\~}
+}
+
+# return path to file in packages dir
+utils.strip_packages_dir() {
+ echo ${1/$ELLIPSIS_PATH\/packages\//}
+}
+
+# detects slash in string
+utils.has_slash() {
+ case $1 in
+ */*)
+ return 0
+ ;;
+ *)
+ return 1
+ ;;
+ esac
+}
1 src/version.sh
@@ -0,0 +1 @@
+ELLIPSIS_VERSION=1.1.4
15 test/_helper.bash
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+#
+# test/_helper.bash
+# Just a little helper file for bats.
+
+export TESTS_DIR="$(cd `dirname "${BASH_SOURCE[0]}"` && pwd)"
+export PATH="$TESTS_DIR/../bin:$PATH"
+
+# Initialize ellipsis, which replaces bat's `load` function with ours.
+source $TESTS_DIR/../src/init.sh
+
+# Install ourselves for Travis CI
+if [ "$TRAVIS" ] && [ ! -e "/home/travis/.ellipsis" ]; then
+ ln -s /home/travis/build/zeekay/ellipsis /home/travis/.ellipsis
+fi
27 test/cli.bats
@@ -0,0 +1,27 @@
+#!/usr/bin/env bats
+
+load _helper
+
+@test "cli.run without command prints usage" {
+ run ellipsis
+ [ "$status" -eq 1 ]
+ [ "${lines[0]}" = "Usage: ellipsis <command>" ]
+}
+
+@test "cli.run with invalid command prints usage" {
+ run ellipsis invalid_command
+ [ "$status" -eq 1 ]
+ [ "${lines[1]}" = "Usage: ellipsis <command>" ]
+}
+
+@test "cli.run --help prints usage" {
+ run ellipsis --help
+ [ "$status" -eq 0 ]
+ [ "${lines[0]}" = "Usage: ellipsis <command>" ]
+}
+
+@test "cli.run --version prints version" {
+ run ellipsis --version
+ [ "$status" -eq 0 ]
+ [ $(expr "$output" : "v[0-9][0-9.]*") -ne 0 ]
+}
29 test/ellipsis.bats
@@ -0,0 +1,29 @@
+#!/usr/bin/env bats
+
+load _helper
+load ellipsis
+load utils
+
+# setup() {
+# }
+#
+# teardown() {
+# }
+
+@test "ellipsis.backup should make a backup of a file that exists" {
+ skip
+ run ellipsis.backup some_file
+ [ $status -eq 0 ]
+}
+
+@test "ellipsis.link_file should link a file into HOME" {
+ skip
+ run ellipsis.link some_file
+ [ $status -eq 0 ]
+}
+
+@test "ellipsis.link_files should link all the files in folder into HOME" {
+ skip
+ run utils.link_files folder
+ [ $status -eq 0 ]
+}
821 test/fixtures/github.json
@@ -0,0 +1,821 @@
+[
+ {
+ "id": 19005953,
+ "name": "zeekay-dot-vim",
+ "full_name": "epmi/zeekay-dot-vim",
+ "owner": {
+ "login": "epmi",
+ "id": 7350679,
+ "avatar_url": "https://avatars.githubusercontent.com/u/7350679?",
+ "gravatar_id": null,
+ "url": "https://api.github.com/users/epmi",
+ "html_url": "https://github.com/epmi",
+ "followers_url": "https://api.github.com/users/epmi/followers",
+ "following_url": "https://api.github.com/users/epmi/following{/other_user}",
+ "gists_url": "https://api.github.com/users/epmi/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/epmi/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/epmi/subscriptions",
+ "organizations_url": "https://api.github.com/users/epmi/orgs",
+ "repos_url": "https://api.github.com/users/epmi/repos",
+ "events_url": "https://api.github.com/users/epmi/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/epmi/received_events",
+ "type": "Organization",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/epmi/zeekay-dot-vim",
+ "description": "My vim dotfiles, ellipsis.sh compatible.",
+ "fork": true,
+ "url": "https://api.github.com/repos/epmi/zeekay-dot-vim",
+ "forks_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/forks",
+ "keys_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/teams",
+ "hooks_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/hooks",
+ "issue_events_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/events",
+ "assignees_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/tags",
+ "blobs_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/languages",
+ "stargazers_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/stargazers",
+ "contributors_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/contributors",
+ "subscribers_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/subscribers",
+ "subscription_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/subscription",
+ "commits_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/merges",
+ "archive_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/downloads",
+ "issues_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/labels{/name}",
+ "releases_url": "https://api.github.com/repos/epmi/zeekay-dot-vim/releases{/id}",
+ "created_at": "2014-04-21T20:29:30Z",
+ "updated_at": "2014-04-21T21:42:44Z",
+ "pushed_at": "2014-04-21T08:14:41Z",
+ "git_url": "git://github.com/epmi/zeekay-dot-vim.git",
+ "ssh_url": "git@github.com:epmi/zeekay-dot-vim.git",
+ "clone_url": "https://github.com/epmi/zeekay-dot-vim.git",
+ "svn_url": "https://github.com/epmi/zeekay-dot-vim",
+ "homepage": "https://github.com/zeekay/dot-vim",
+ "size": 148,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "VimL",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "permissions": {
+ "admin": false,
+ "push": false,
+ "pull": true
+ }
+ },
+ {
+ "id": 19006114,
+ "name": "zeekay-dot-iterm2",
+ "full_name": "epmi/zeekay-dot-iterm2",
+ "owner": {
+ "login": "epmi",
+ "id": 7350679,
+ "avatar_url": "https://avatars.githubusercontent.com/u/7350679?",
+ "gravatar_id": null,
+ "url": "https://api.github.com/users/epmi",
+ "html_url": "https://github.com/epmi",
+ "followers_url": "https://api.github.com/users/epmi/followers",
+ "following_url": "https://api.github.com/users/epmi/following{/other_user}",
+ "gists_url": "https://api.github.com/users/epmi/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/epmi/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/epmi/subscriptions",
+ "organizations_url": "https://api.github.com/users/epmi/orgs",
+ "repos_url": "https://api.github.com/users/epmi/repos",
+ "events_url": "https://api.github.com/users/epmi/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/epmi/received_events",
+ "type": "Organization",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/epmi/zeekay-dot-iterm2",
+ "description": "My iterm2 dotfiles, ellipsis.sh compatible. ",
+ "fork": true,
+ "url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2",
+ "forks_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/forks",
+ "keys_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/teams",
+ "hooks_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/hooks",
+ "issue_events_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/events",
+ "assignees_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/tags",
+ "blobs_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/languages",
+ "stargazers_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/stargazers",
+ "contributors_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/contributors",
+ "subscribers_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/subscribers",
+ "subscription_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/subscription",
+ "commits_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/merges",
+ "archive_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/downloads",
+ "issues_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/labels{/name}",
+ "releases_url": "https://api.github.com/repos/epmi/zeekay-dot-iterm2/releases{/id}",
+ "created_at": "2014-04-21T20:35:11Z",
+ "updated_at": "2014-04-21T22:18:43Z",
+ "pushed_at": "2014-04-21T05:31:26Z",
+ "git_url": "git://github.com/epmi/zeekay-dot-iterm2.git",
+ "ssh_url": "git@github.com:epmi/zeekay-dot-iterm2.git",
+ "clone_url": "https://github.com/epmi/zeekay-dot-iterm2.git",
+ "svn_url": "https://github.com/epmi/zeekay-dot-iterm2",
+ "homepage": " https://github.com/zeekay/dot-iterm2",
+ "size": 0,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": null,
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": false,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "permissions": {
+ "admin": false,
+ "push": false,
+ "pull": true
+ }
+ },
+ {
+ "id": 19006191,
+ "name": "zeekay-dot-atom",
+ "full_name": "epmi/zeekay-dot-atom",
+ "owner": {
+ "login": "epmi",
+ "id": 7350679,
+ "avatar_url": "https://avatars.githubusercontent.com/u/7350679?",
+ "gravatar_id": null,
+ "url": "https://api.github.com/users/epmi",
+ "html_url": "https://github.com/epmi",
+ "followers_url": "https://api.github.com/users/epmi/followers",
+ "following_url": "https://api.github.com/users/epmi/following{/other_user}",
+ "gists_url": "https://api.github.com/users/epmi/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/epmi/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/epmi/subscriptions",
+ "organizations_url": "https://api.github.com/users/epmi/orgs",
+ "repos_url": "https://api.github.com/users/epmi/repos",
+ "events_url": "https://api.github.com/users/epmi/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/epmi/received_events",
+ "type": "Organization",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/epmi/zeekay-dot-atom",
+ "description": "My atom dotfiles, ellipsis.sh compatible.",
+ "fork": true,
+ "url": "https://api.github.com/repos/epmi/zeekay-dot-atom",
+ "forks_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/forks",
+ "keys_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/teams",
+ "hooks_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/hooks",
+ "issue_events_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/events",
+ "assignees_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/tags",
+ "blobs_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/languages",
+ "stargazers_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/stargazers",
+ "contributors_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/contributors",
+ "subscribers_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/subscribers",
+ "subscription_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/subscription",
+ "commits_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/merges",
+ "archive_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/downloads",
+ "issues_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/labels{/name}",
+ "releases_url": "https://api.github.com/repos/epmi/zeekay-dot-atom/releases{/id}",
+ "created_at": "2014-04-21T20:37:52Z",
+ "updated_at": "2014-04-21T22:18:53Z",
+ "pushed_at": "2014-04-20T21:17:50Z",
+ "git_url": "git://github.com/epmi/zeekay-dot-atom.git",
+ "ssh_url": "git@github.com:epmi/zeekay-dot-atom.git",
+ "clone_url": "https://github.com/epmi/zeekay-dot-atom.git",
+ "svn_url": "https://github.com/epmi/zeekay-dot-atom",
+ "homepage": " https://github.com/zeekay/dot-atom",
+ "size": 0,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Shell",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "permissions": {
+ "admin": false,
+ "push": false,
+ "pull": true
+ }
+ },
+ {
+ "id": 19006248,
+ "name": "zeekay-dot-zsh",
+ "full_name": "epmi/zeekay-dot-zsh",
+ "owner": {
+ "login": "epmi",
+ "id": 7350679,
+ "avatar_url": "https://avatars.githubusercontent.com/u/7350679?",
+ "gravatar_id": null,
+ "url": "https://api.github.com/users/epmi",
+ "html_url": "https://github.com/epmi",
+ "followers_url": "https://api.github.com/users/epmi/followers",
+ "following_url": "https://api.github.com/users/epmi/following{/other_user}",
+ "gists_url": "https://api.github.com/users/epmi/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/epmi/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/epmi/subscriptions",
+ "organizations_url": "https://api.github.com/users/epmi/orgs",
+ "repos_url": "https://api.github.com/users/epmi/repos",
+ "events_url": "https://api.github.com/users/epmi/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/epmi/received_events",
+ "type": "Organization",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/epmi/zeekay-dot-zsh",
+ "description": "My zsh configuration, ellipsis.sh compatible.",
+ "fork": true,
+ "url": "https://api.github.com/repos/epmi/zeekay-dot-zsh",
+ "forks_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/forks",
+ "keys_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/teams",
+ "hooks_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/hooks",
+ "issue_events_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/events",
+ "assignees_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/tags",
+ "blobs_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/languages",
+ "stargazers_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/stargazers",
+ "contributors_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/contributors",
+ "subscribers_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/subscribers",
+ "subscription_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/subscription",
+ "commits_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/merges",
+ "archive_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/downloads",
+ "issues_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/labels{/name}",
+ "releases_url": "https://api.github.com/repos/epmi/zeekay-dot-zsh/releases{/id}",
+ "created_at": "2014-04-21T20:40:17Z",
+ "updated_at": "2014-04-21T22:19:03Z",
+ "pushed_at": "2014-04-20T19:34:38Z",
+ "git_url": "git://github.com/epmi/zeekay-dot-zsh.git",
+ "ssh_url": "git@github.com:epmi/zeekay-dot-zsh.git",
+ "clone_url": "https://github.com/epmi/zeekay-dot-zsh.git",
+ "svn_url": "https://github.com/epmi/zeekay-dot-zsh",
+ "homepage": " https://github.com/zeekay/dot-zsh",
+ "size": 144,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Shell",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "permissions": {
+ "admin": false,
+ "push": false,
+ "pull": true
+ }
+ },
+ {
+ "id": 19006551,
+ "name": "zeekay-dot-xmonad",
+ "full_name": "epmi/zeekay-dot-xmonad",
+ "owner": {
+ "login": "epmi",
+ "id": 7350679,
+ "avatar_url": "https://avatars.githubusercontent.com/u/7350679?",
+ "gravatar_id": null,
+ "url": "https://api.github.com/users/epmi",
+ "html_url": "https://github.com/epmi",
+ "followers_url": "https://api.github.com/users/epmi/followers",
+ "following_url": "https://api.github.com/users/epmi/following{/other_user}",
+ "gists_url": "https://api.github.com/users/epmi/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/epmi/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/epmi/subscriptions",
+ "organizations_url": "https://api.github.com/users/epmi/orgs",
+ "repos_url": "https://api.github.com/users/epmi/repos",
+ "events_url": "https://api.github.com/users/epmi/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/epmi/received_events",
+ "type": "Organization",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/epmi/zeekay-dot-xmonad",
+ "description": "My xmonad dotfiles, ellipsis.sh compatible. ",
+ "fork": true,
+ "url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad",
+ "forks_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/forks",
+ "keys_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/teams",
+ "hooks_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/hooks",
+ "issue_events_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/events",
+ "assignees_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/tags",
+ "blobs_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/languages",
+ "stargazers_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/stargazers",
+ "contributors_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/contributors",
+ "subscribers_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/subscribers",
+ "subscription_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/subscription",
+ "commits_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/merges",
+ "archive_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/downloads",
+ "issues_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/labels{/name}",
+ "releases_url": "https://api.github.com/repos/epmi/zeekay-dot-xmonad/releases{/id}",
+ "created_at": "2014-04-21T20:50:42Z",
+ "updated_at": "2014-04-21T22:19:13Z",
+ "pushed_at": "2014-04-20T06:52:08Z",
+ "git_url": "git://github.com/epmi/zeekay-dot-xmonad.git",
+ "ssh_url": "git@github.com:epmi/zeekay-dot-xmonad.git",
+ "clone_url": "https://github.com/epmi/zeekay-dot-xmonad.git",
+ "svn_url": "https://github.com/epmi/zeekay-dot-xmonad",
+ "homepage": " https://github.com/zeekay/dot-xmonad",
+ "size": 128,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Haskell",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "permissions": {
+ "admin": false,
+ "push": false,
+ "pull": true
+ }
+ },
+ {
+ "id": 19006553,
+ "name": "zeekay-dot-files",
+ "full_name": "epmi/zeekay-dot-files",
+ "owner": {
+ "login": "epmi",
+ "id": 7350679,
+ "avatar_url": "https://avatars.githubusercontent.com/u/7350679?",
+ "gravatar_id": null,
+ "url": "https://api.github.com/users/epmi",
+ "html_url": "https://github.com/epmi",
+ "followers_url": "https://api.github.com/users/epmi/followers",
+ "following_url": "https://api.github.com/users/epmi/following{/other_user}",
+ "gists_url": "https://api.github.com/users/epmi/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/epmi/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/epmi/subscriptions",
+ "organizations_url": "https://api.github.com/users/epmi/orgs",
+ "repos_url": "https://api.github.com/users/epmi/repos",
+ "events_url": "https://api.github.com/users/epmi/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/epmi/received_events",
+ "type": "Organization",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/epmi/zeekay-dot-files",
+ "description": "My dotfiles, ellipsis.sh compatible.",
+ "fork": true,
+ "url": "https://api.github.com/repos/epmi/zeekay-dot-files",
+ "forks_url": "https://api.github.com/repos/epmi/zeekay-dot-files/forks",
+ "keys_url": "https://api.github.com/repos/epmi/zeekay-dot-files/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/epmi/zeekay-dot-files/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/epmi/zeekay-dot-files/teams",
+ "hooks_url": "https://api.github.com/repos/epmi/zeekay-dot-files/hooks",
+ "issue_events_url": "https://api.github.com/repos/epmi/zeekay-dot-files/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/epmi/zeekay-dot-files/events",
+ "assignees_url": "https://api.github.com/repos/epmi/zeekay-dot-files/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/epmi/zeekay-dot-files/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/epmi/zeekay-dot-files/tags",
+ "blobs_url": "https://api.github.com/repos/epmi/zeekay-dot-files/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/epmi/zeekay-dot-files/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/epmi/zeekay-dot-files/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/epmi/zeekay-dot-files/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/epmi/zeekay-dot-files/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/epmi/zeekay-dot-files/languages",
+ "stargazers_url": "https://api.github.com/repos/epmi/zeekay-dot-files/stargazers",
+ "contributors_url": "https://api.github.com/repos/epmi/zeekay-dot-files/contributors",
+ "subscribers_url": "https://api.github.com/repos/epmi/zeekay-dot-files/subscribers",
+ "subscription_url": "https://api.github.com/repos/epmi/zeekay-dot-files/subscription",
+ "commits_url": "https://api.github.com/repos/epmi/zeekay-dot-files/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/epmi/zeekay-dot-files/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/epmi/zeekay-dot-files/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/epmi/zeekay-dot-files/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/epmi/zeekay-dot-files/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/epmi/zeekay-dot-files/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/epmi/zeekay-dot-files/merges",
+ "archive_url": "https://api.github.com/repos/epmi/zeekay-dot-files/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/epmi/zeekay-dot-files/downloads",
+ "issues_url": "https://api.github.com/repos/epmi/zeekay-dot-files/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/epmi/zeekay-dot-files/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/epmi/zeekay-dot-files/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/epmi/zeekay-dot-files/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/epmi/zeekay-dot-files/labels{/name}",
+ "releases_url": "https://api.github.com/repos/epmi/zeekay-dot-files/releases{/id}",
+ "created_at": "2014-04-21T20:50:46Z",
+ "updated_at": "2014-04-21T22:19:22Z",
+ "pushed_at": "2014-04-20T06:50:51Z",
+ "git_url": "git://github.com/epmi/zeekay-dot-files.git",
+ "ssh_url": "git@github.com:epmi/zeekay-dot-files.git",
+ "clone_url": "https://github.com/epmi/zeekay-dot-files.git",
+ "svn_url": "https://github.com/epmi/zeekay-dot-files",
+ "homepage": " https://github.com/zeekay/dot-files",
+ "size": 0,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Ruby",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "permissions": {
+ "admin": false,
+ "push": false,
+ "pull": true
+ }
+ },
+ {
+ "id": 19006555,
+ "name": "zeekay-dot-emacs",
+ "full_name": "epmi/zeekay-dot-emacs",
+ "owner": {
+ "login": "epmi",
+ "id": 7350679,
+ "avatar_url": "https://avatars.githubusercontent.com/u/7350679?",
+ "gravatar_id": null,
+ "url": "https://api.github.com/users/epmi",
+ "html_url": "https://github.com/epmi",
+ "followers_url": "https://api.github.com/users/epmi/followers",
+ "following_url": "https://api.github.com/users/epmi/following{/other_user}",
+ "gists_url": "https://api.github.com/users/epmi/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/epmi/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/epmi/subscriptions",
+ "organizations_url": "https://api.github.com/users/epmi/orgs",
+ "repos_url": "https://api.github.com/users/epmi/repos",
+ "events_url": "https://api.github.com/users/epmi/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/epmi/received_events",
+ "type": "Organization",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/epmi/zeekay-dot-emacs",
+ "description": "My emacs dotfiles, ellipsis.sh compatible. ",
+ "fork": true,
+ "url": "https://api.github.com/repos/epmi/zeekay-dot-emacs",
+ "forks_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/forks",
+ "keys_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/teams",
+ "hooks_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/hooks",
+ "issue_events_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/events",
+ "assignees_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/tags",
+ "blobs_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/languages",
+ "stargazers_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/stargazers",
+ "contributors_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/contributors",
+ "subscribers_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/subscribers",
+ "subscription_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/subscription",
+ "commits_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/merges",
+ "archive_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/downloads",
+ "issues_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/labels{/name}",
+ "releases_url": "https://api.github.com/repos/epmi/zeekay-dot-emacs/releases{/id}",
+ "created_at": "2014-04-21T20:50:50Z",
+ "updated_at": "2014-04-21T22:19:33Z",
+ "pushed_at": "2014-04-20T06:47:57Z",
+ "git_url": "git://github.com/epmi/zeekay-dot-emacs.git",
+ "ssh_url": "git@github.com:epmi/zeekay-dot-emacs.git",
+ "clone_url": "https://github.com/epmi/zeekay-dot-emacs.git",
+ "svn_url": "https://github.com/epmi/zeekay-dot-emacs",
+ "homepage": " https://github.com/zeekay/dot-emacs",
+ "size": 732,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Emacs Lisp",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "permissions": {
+ "admin": false,
+ "push": false,
+ "pull": true
+ }
+ },
+ {
+ "id": 19006560,
+ "name": "zeekay-dot-irssi",
+ "full_name": "epmi/zeekay-dot-irssi",
+ "owner": {
+ "login": "epmi",
+ "id": 7350679,
+ "avatar_url": "https://avatars.githubusercontent.com/u/7350679?",
+ "gravatar_id": null,
+ "url": "https://api.github.com/users/epmi",
+ "html_url": "https://github.com/epmi",
+ "followers_url": "https://api.github.com/users/epmi/followers",
+ "following_url": "https://api.github.com/users/epmi/following{/other_user}",
+ "gists_url": "https://api.github.com/users/epmi/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/epmi/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/epmi/subscriptions",
+ "organizations_url": "https://api.github.com/users/epmi/orgs",
+ "repos_url": "https://api.github.com/users/epmi/repos",
+ "events_url": "https://api.github.com/users/epmi/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/epmi/received_events",
+ "type": "Organization",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/epmi/zeekay-dot-irssi",
+ "description": "My irssi dotfiles, ellipsis.sh compatible. ",
+ "fork": true,
+ "url": "https://api.github.com/repos/epmi/zeekay-dot-irssi",
+ "forks_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/forks",
+ "keys_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/teams",
+ "hooks_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/hooks",
+ "issue_events_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/events",
+ "assignees_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/tags",
+ "blobs_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/languages",
+ "stargazers_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/stargazers",
+ "contributors_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/contributors",
+ "subscribers_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/subscribers",
+ "subscription_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/subscription",
+ "commits_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/issues/comments/{number}",
+ "contents_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/merges",
+ "archive_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/downloads",
+ "issues_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/labels{/name}",
+ "releases_url": "https://api.github.com/repos/epmi/zeekay-dot-irssi/releases{/id}",
+ "created_at": "2014-04-21T20:50:56Z",
+ "updated_at": "2014-04-21T22:19:43Z",
+ "pushed_at": "2014-04-20T06:43:40Z",
+ "git_url": "git://github.com/epmi/zeekay-dot-irssi.git",
+ "ssh_url": "git@github.com:epmi/zeekay-dot-irssi.git",
+ "clone_url": "https://github.com/epmi/zeekay-dot-irssi.git",
+ "svn_url": "https://github.com/epmi/zeekay-dot-irssi",
+ "homepage": " https://github.com/zeekay/dot-irssi",
+ "size": 244,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": "Perl",
+ "has_issues": false,
+ "has_downloads": true,
+ "has_wiki": true,
+ "forks_count": 0,
+ "mirror_url": null,
+ "open_issues_count": 0,
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "permissions": {
+ "admin": false,
+ "push": false,
+ "pull": true
+ }
+ },
+ {
+ "id": 19006565,
+ "name": "zeekay-dot-alfred",
+ "full_name": "epmi/zeekay-dot-alfred",
+ "owner": {
+ "login": "epmi",
+ "id": 7350679,
+ "avatar_url": "https://avatars.githubusercontent.com/u/7350679?",
+ "gravatar_id": null,
+ "url": "https://api.github.com/users/epmi",
+ "html_url": "https://github.com/epmi",
+ "followers_url": "https://api.github.com/users/epmi/followers",
+ "following_url": "https://api.github.com/users/epmi/following{/other_user}",
+ "gists_url": "https://api.github.com/users/epmi/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/epmi/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/epmi/subscriptions",
+ "organizations_url": "https://api.github.com/users/epmi/orgs",
+ "repos_url": "https://api.github.com/users/epmi/repos",
+ "events_url": "https://api.github.com/users/epmi/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/epmi/received_events",
+ "type": "Organization",
+ "site_admin": false
+ },
+ "private": false,
+ "html_url": "https://github.com/epmi/zeekay-dot-alfred",
+ "description": "My alfred dotfiles, ellipsis.sh compatible. ",
+ "fork": true,
+ "url": "https://api.github.com/repos/epmi/zeekay-dot-alfred",
+ "forks_url": "https://api.github.com/repos/epmi/zeekay-dot-alfred/forks",
+ "keys_url": "https://api.github.com/repos/epmi/zeekay-dot-alfred/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/epmi/zeekay-dot-alfred/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/epmi/zeekay-dot-alfred/teams",
+ "hooks_url": "https://api.github.com/repos/epmi/zeekay-dot-alfred/hooks",