├── .env ├── .github └── workflows │ ├── build.yml │ ├── publish.yml │ └── test.yml ├── .gitignore ├── Dockerfile ├── Gemfile ├── Gemfile.lock ├── LICENSE.md ├── Makefile ├── README.md ├── bin ├── homer ├── homer-alias ├── homer-grep ├── homer-help ├── homer-init ├── homer-plugin ├── homer-save ├── homer-script ├── homer-update └── homer-version ├── docs ├── _config.yml ├── homer-thinking.gif ├── index.md ├── install.sh └── manual │ ├── edit.1.html │ ├── homer.1.html │ ├── index.md │ └── page.1.html ├── package.json ├── share ├── doc │ ├── homer │ │ ├── USAGE.txt │ │ ├── alias.txt │ │ ├── grep.txt │ │ ├── init.txt │ │ ├── plugin.txt │ │ ├── save.txt │ │ ├── script.txt │ │ ├── update.txt │ │ └── version.txt │ └── man │ │ ├── edit.1.md │ │ ├── homer.1.md │ │ └── page.1.md ├── homer.zsh └── homer │ ├── VERSION │ ├── cli.zsh │ ├── command │ ├── bin.sh │ ├── doc.txt │ └── test.bats │ ├── profile.d │ ├── editing.zsh │ ├── paths.zsh │ ├── shell.zsh │ ├── terminal.zsh │ └── vcsinfo.zsh │ └── template │ ├── .gitignore │ ├── .zshenv │ ├── .zshrc │ ├── README.md │ ├── bin │ └── .keep │ └── etc │ ├── aliases.zsh │ ├── plugins.zsh │ └── profile.d │ └── .keep └── test ├── homer-alias-test.bats ├── homer-grep-test.bats ├── homer-help-test.bats ├── homer-init-test.bats ├── homer-install-test.bats ├── homer-plugin-test.bats ├── homer-save-test.bats ├── homer-script-test.bats ├── homer-test.bats ├── homer-update-test.bats ├── homer-version-test.bats └── test_helper.bash /.env: -------------------------------------------------------------------------------- 1 | # Development configuration for Homer. This configuration is 2 | # automatically run with the dotenv shell extension, and will add the 3 | # paths in $PWD/bin and the bundle's bin directory to your $PATH for 4 | # easy command execution. Any commands executed within this directory 5 | # will be looked for in the current directory bin, always ensuring 6 | # you're using the commands that you're editing. 7 | 8 | export HOMER_PATH=$PWD 9 | export PATH=$PWD/bin:$PWD/vendor/bundle/bin:$PATH 10 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | branches: [master] 5 | jobs: 6 | build: 7 | name: Build Signed Package 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout Source Code 11 | uses: actions/checkout@v1 12 | - name: Setup Ruby 13 | uses: actions/setup-ruby@v1 14 | - name: Install Dependencies 15 | run: | 16 | sudo apt-get update -qq 17 | sudo apt-get install -qqyy zsh 18 | gem install bundler 19 | - name: Configure GPG 20 | run: | 21 | echo "${{ secrets.gpg_public_key }}" | gpg --import 22 | echo "${{ secrets.gpg_private_key }}" | gpg --import 23 | - name: Find Current Version 24 | id: get_version 25 | run: echo ::set-output name=VERSION::$(echo $GITHUB_REF | cut -d / -f 3) 26 | - name: Build Project 27 | run: make 28 | env: 29 | BUNDLE_PATH: vendor/bundle 30 | - name: Upload Tarball 31 | uses: actions/upload-artifact@v1 32 | with: 33 | path: dist/homer-${{ steps.get_version.outputs.VERSION }}.tar.gz 34 | name: homer-${{ steps.get_version.outputs.VERSION }}.tar.gz 35 | - name: Upload Signature 36 | uses: actions/upload-artifact@v1 37 | with: 38 | path: dist/homer-${{ steps.get_version.outputs.VERSION }}.tar.gz.asc 39 | name: homer-${{ steps.get_version.outputs.VERSION }}.tar.gz.asc 40 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | on: 3 | push: 4 | tags: [v*] 5 | jobs: 6 | build: 7 | name: Build Signed Package 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout Source Code 11 | uses: actions/checkout@v1 12 | - name: Setup Ruby 13 | uses: actions/setup-ruby@v1 14 | - name: Install Dependencies 15 | run: | 16 | sudo apt-get update -qq 17 | sudo apt-get install -qqyy zsh 18 | gem install bundler 19 | - name: Configure GPG 20 | run: | 21 | echo "${{ secrets.gpg_public_key }}" | gpg --import 22 | echo "${{ secrets.gpg_private_key }}" | gpg --import 23 | - name: Find Current Version 24 | id: get_version 25 | run: echo ::set-output name=VERSION::$(echo $GITHUB_REF | cut -d / -f 3) 26 | - name: Build Project 27 | run: make 28 | env: 29 | BUNDLE_PATH: vendor/bundle 30 | - name: Upload Artifacts 31 | uses: actions/upload-artifact@v1 32 | with: 33 | path: dist 34 | name: homer-${{ steps.get_version.outputs.VERSION }} 35 | release: 36 | name: Create New Release 37 | runs-on: ubuntu-latest 38 | needs: build 39 | steps: 40 | - name: Find Current Version 41 | id: get_version 42 | run: echo ::set-output name=VERSION::$(echo $GITHUB_REF | cut -d / -f 3) 43 | - name: Download Artifacts 44 | uses: actions/download-artifact@v1 45 | with: 46 | name: homer-${{ steps.get_version.outputs.VERSION }} 47 | - name: Create GitHub Release 48 | id: create_release 49 | uses: actions/create-release@v1.0.0 50 | env: 51 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 52 | with: 53 | tag_name: ${{ steps.get_version.outputs.VERSION }} 54 | release_name: Release ${{ steps.get_version.outputs.VERSION }} 55 | draft: false 56 | prerelease: false 57 | - name: Publish Tarball 58 | uses: actions/upload-release-asset@v1.0.1 59 | env: 60 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 61 | with: 62 | upload_url: ${{ steps.create_release.outputs.upload_url }} 63 | asset_path: ./homer-${{ steps.get_version.outputs.VERSION }}/homer-${{ steps.get_version.outputs.VERSION }}.tar.gz 64 | asset_name: homer-${{ steps.get_version.outputs.VERSION }}.tar.gz 65 | asset_content_type: application/tar+gzip 66 | - name: Publish Signature 67 | uses: actions/upload-release-asset@v1.0.1 68 | env: 69 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 70 | with: 71 | upload_url: ${{ steps.create_release.outputs.upload_url }} 72 | asset_path: ./homer-${{ steps.get_version.outputs.VERSION }}/homer-${{ steps.get_version.outputs.VERSION }}.tar.gz.asc 73 | asset_name: homer-${{ steps.get_version.outputs.VERSION }}.asc 74 | asset_content_type: text/plain 75 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: [push] 3 | jobs: 4 | test: 5 | name: Run Automated Tests 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Checkout Source Code 9 | uses: actions/checkout@v1 10 | - name: Setup NodeJS 11 | uses: actions/setup-node@v1 12 | - name: Install Dependencies 13 | run: | 14 | sudo apt-get update -qq 15 | sudo apt-get install -qqyy zsh 16 | - name: Configure Git 17 | run: | 18 | git config --global user.email "test@example.com" 19 | git config --global user.name "Lester Tester" 20 | - name: Run BATS 21 | run: make check 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | tags 3 | /vendor 4 | docs/_site 5 | node_modules 6 | yarn.lock 7 | /dist 8 | /share/man/man1 9 | /.wiki 10 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Docker image that comes with Homer pre-installed. This is used for 3 | # "integration" tests of the installer script to make sure it will 4 | # automatically install everything correctly without having to blow away 5 | # an existing install on a machine. 6 | # 7 | 8 | # Use the latest version of Ubuntu 9 | FROM ubuntu:latest 10 | 11 | # Build dependencies 12 | RUN apt-get update -qq && apt-get install build-essential sudo curl zsh git -yy 13 | 14 | # Ensure the $PATH has /usr/local at the beginning 15 | ENV PATH=/usr/local/bin:$PATH PREFIX=/usr/local 16 | 17 | # Configure Git 18 | RUN git config --global user.email "test@example.com" 19 | RUN git config --global user.name "Lester Tester" 20 | 21 | # Install Homer 22 | COPY docs/install.sh install.sh 23 | RUN bash install.sh 24 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Use Kramdown to generate Man pages. 4 | gem 'kramdown-man' 5 | 6 | # Use ronn to convert Man pages into HTML 7 | gem 'ronn' 8 | 9 | # Use Jekyll and GitHub Pages for the documentation site. 10 | gem 'jekyll' 11 | gem 'jekyll-theme-hacker', group: :jekyll_plugins 12 | gem 'github-pages', group: :jekyll_plugins 13 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | activesupport (4.2.11.1) 5 | i18n (~> 0.7) 6 | minitest (~> 5.1) 7 | thread_safe (~> 0.3, >= 0.3.4) 8 | tzinfo (~> 1.1) 9 | addressable (2.7.0) 10 | public_suffix (>= 2.0.2, < 5.0) 11 | coffee-script (2.4.1) 12 | coffee-script-source 13 | execjs 14 | coffee-script-source (1.11.1) 15 | colorator (1.1.0) 16 | commonmarker (0.17.13) 17 | ruby-enum (~> 0.5) 18 | concurrent-ruby (1.1.5) 19 | dnsruby (1.61.3) 20 | addressable (~> 2.5) 21 | em-websocket (0.5.1) 22 | eventmachine (>= 0.12.9) 23 | http_parser.rb (~> 0.6.0) 24 | ethon (0.12.0) 25 | ffi (>= 1.3.0) 26 | eventmachine (1.2.7) 27 | execjs (2.7.0) 28 | faraday (0.15.4) 29 | multipart-post (>= 1.2, < 3) 30 | ffi (1.11.1) 31 | forwardable-extended (2.6.0) 32 | gemoji (3.0.1) 33 | github-pages (198) 34 | activesupport (= 4.2.11.1) 35 | github-pages-health-check (= 1.16.1) 36 | jekyll (= 3.8.5) 37 | jekyll-avatar (= 0.6.0) 38 | jekyll-coffeescript (= 1.1.1) 39 | jekyll-commonmark-ghpages (= 0.1.5) 40 | jekyll-default-layout (= 0.1.4) 41 | jekyll-feed (= 0.11.0) 42 | jekyll-gist (= 1.5.0) 43 | jekyll-github-metadata (= 2.12.1) 44 | jekyll-mentions (= 1.4.1) 45 | jekyll-optional-front-matter (= 0.3.0) 46 | jekyll-paginate (= 1.1.0) 47 | jekyll-readme-index (= 0.2.0) 48 | jekyll-redirect-from (= 0.14.0) 49 | jekyll-relative-links (= 0.6.0) 50 | jekyll-remote-theme (= 0.3.1) 51 | jekyll-sass-converter (= 1.5.2) 52 | jekyll-seo-tag (= 2.5.0) 53 | jekyll-sitemap (= 1.2.0) 54 | jekyll-swiss (= 0.4.0) 55 | jekyll-theme-architect (= 0.1.1) 56 | jekyll-theme-cayman (= 0.1.1) 57 | jekyll-theme-dinky (= 0.1.1) 58 | jekyll-theme-hacker (= 0.1.1) 59 | jekyll-theme-leap-day (= 0.1.1) 60 | jekyll-theme-merlot (= 0.1.1) 61 | jekyll-theme-midnight (= 0.1.1) 62 | jekyll-theme-minimal (= 0.1.1) 63 | jekyll-theme-modernist (= 0.1.1) 64 | jekyll-theme-primer (= 0.5.3) 65 | jekyll-theme-slate (= 0.1.1) 66 | jekyll-theme-tactile (= 0.1.1) 67 | jekyll-theme-time-machine (= 0.1.1) 68 | jekyll-titles-from-headings (= 0.5.1) 69 | jemoji (= 0.10.2) 70 | kramdown (= 1.17.0) 71 | liquid (= 4.0.0) 72 | listen (= 3.1.5) 73 | mercenary (~> 0.3) 74 | minima (= 2.5.0) 75 | nokogiri (>= 1.8.5, < 2.0) 76 | rouge (= 2.2.1) 77 | terminal-table (~> 1.4) 78 | github-pages-health-check (1.16.1) 79 | addressable (~> 2.3) 80 | dnsruby (~> 1.60) 81 | octokit (~> 4.0) 82 | public_suffix (~> 3.0) 83 | typhoeus (~> 1.3) 84 | hpricot (0.8.6) 85 | html-pipeline (2.12.0) 86 | activesupport (>= 2) 87 | nokogiri (>= 1.4) 88 | http_parser.rb (0.6.0) 89 | i18n (0.9.5) 90 | concurrent-ruby (~> 1.0) 91 | jekyll (3.8.5) 92 | addressable (~> 2.4) 93 | colorator (~> 1.0) 94 | em-websocket (~> 0.5) 95 | i18n (~> 0.7) 96 | jekyll-sass-converter (~> 1.0) 97 | jekyll-watch (~> 2.0) 98 | kramdown (~> 1.14) 99 | liquid (~> 4.0) 100 | mercenary (~> 0.3.3) 101 | pathutil (~> 0.9) 102 | rouge (>= 1.7, < 4) 103 | safe_yaml (~> 1.0) 104 | jekyll-avatar (0.6.0) 105 | jekyll (~> 3.0) 106 | jekyll-coffeescript (1.1.1) 107 | coffee-script (~> 2.2) 108 | coffee-script-source (~> 1.11.1) 109 | jekyll-commonmark (1.3.1) 110 | commonmarker (~> 0.14) 111 | jekyll (>= 3.7, < 5.0) 112 | jekyll-commonmark-ghpages (0.1.5) 113 | commonmarker (~> 0.17.6) 114 | jekyll-commonmark (~> 1) 115 | rouge (~> 2) 116 | jekyll-default-layout (0.1.4) 117 | jekyll (~> 3.0) 118 | jekyll-feed (0.11.0) 119 | jekyll (~> 3.3) 120 | jekyll-gist (1.5.0) 121 | octokit (~> 4.2) 122 | jekyll-github-metadata (2.12.1) 123 | jekyll (~> 3.4) 124 | octokit (~> 4.0, != 4.4.0) 125 | jekyll-mentions (1.4.1) 126 | html-pipeline (~> 2.3) 127 | jekyll (~> 3.0) 128 | jekyll-optional-front-matter (0.3.0) 129 | jekyll (~> 3.0) 130 | jekyll-paginate (1.1.0) 131 | jekyll-readme-index (0.2.0) 132 | jekyll (~> 3.0) 133 | jekyll-redirect-from (0.14.0) 134 | jekyll (~> 3.3) 135 | jekyll-relative-links (0.6.0) 136 | jekyll (~> 3.3) 137 | jekyll-remote-theme (0.3.1) 138 | jekyll (~> 3.5) 139 | rubyzip (>= 1.2.1, < 3.0) 140 | jekyll-sass-converter (1.5.2) 141 | sass (~> 3.4) 142 | jekyll-seo-tag (2.5.0) 143 | jekyll (~> 3.3) 144 | jekyll-sitemap (1.2.0) 145 | jekyll (~> 3.3) 146 | jekyll-swiss (0.4.0) 147 | jekyll-theme-architect (0.1.1) 148 | jekyll (~> 3.5) 149 | jekyll-seo-tag (~> 2.0) 150 | jekyll-theme-cayman (0.1.1) 151 | jekyll (~> 3.5) 152 | jekyll-seo-tag (~> 2.0) 153 | jekyll-theme-dinky (0.1.1) 154 | jekyll (~> 3.5) 155 | jekyll-seo-tag (~> 2.0) 156 | jekyll-theme-hacker (0.1.1) 157 | jekyll (~> 3.5) 158 | jekyll-seo-tag (~> 2.0) 159 | jekyll-theme-leap-day (0.1.1) 160 | jekyll (~> 3.5) 161 | jekyll-seo-tag (~> 2.0) 162 | jekyll-theme-merlot (0.1.1) 163 | jekyll (~> 3.5) 164 | jekyll-seo-tag (~> 2.0) 165 | jekyll-theme-midnight (0.1.1) 166 | jekyll (~> 3.5) 167 | jekyll-seo-tag (~> 2.0) 168 | jekyll-theme-minimal (0.1.1) 169 | jekyll (~> 3.5) 170 | jekyll-seo-tag (~> 2.0) 171 | jekyll-theme-modernist (0.1.1) 172 | jekyll (~> 3.5) 173 | jekyll-seo-tag (~> 2.0) 174 | jekyll-theme-primer (0.5.3) 175 | jekyll (~> 3.5) 176 | jekyll-github-metadata (~> 2.9) 177 | jekyll-seo-tag (~> 2.0) 178 | jekyll-theme-slate (0.1.1) 179 | jekyll (~> 3.5) 180 | jekyll-seo-tag (~> 2.0) 181 | jekyll-theme-tactile (0.1.1) 182 | jekyll (~> 3.5) 183 | jekyll-seo-tag (~> 2.0) 184 | jekyll-theme-time-machine (0.1.1) 185 | jekyll (~> 3.5) 186 | jekyll-seo-tag (~> 2.0) 187 | jekyll-titles-from-headings (0.5.1) 188 | jekyll (~> 3.3) 189 | jekyll-watch (2.2.1) 190 | listen (~> 3.0) 191 | jemoji (0.10.2) 192 | gemoji (~> 3.0) 193 | html-pipeline (~> 2.2) 194 | jekyll (~> 3.0) 195 | kramdown (1.17.0) 196 | kramdown-man (0.1.6) 197 | kramdown (~> 1.0) 198 | liquid (4.0.0) 199 | listen (3.1.5) 200 | rb-fsevent (~> 0.9, >= 0.9.4) 201 | rb-inotify (~> 0.9, >= 0.9.7) 202 | ruby_dep (~> 1.2) 203 | mercenary (0.3.6) 204 | mini_portile2 (2.4.0) 205 | minima (2.5.0) 206 | jekyll (~> 3.5) 207 | jekyll-feed (~> 0.9) 208 | jekyll-seo-tag (~> 2.1) 209 | minitest (5.11.3) 210 | multipart-post (2.1.1) 211 | mustache (1.1.0) 212 | nokogiri (1.10.8) 213 | mini_portile2 (~> 2.4.0) 214 | octokit (4.14.0) 215 | sawyer (~> 0.8.0, >= 0.5.3) 216 | pathutil (0.16.2) 217 | forwardable-extended (~> 2.6) 218 | public_suffix (3.1.1) 219 | rb-fsevent (0.10.3) 220 | rb-inotify (0.10.0) 221 | ffi (~> 1.0) 222 | rdiscount (2.2.0.1) 223 | ronn (0.7.3) 224 | hpricot (>= 0.8.2) 225 | mustache (>= 0.7.0) 226 | rdiscount (>= 1.5.8) 227 | rouge (2.2.1) 228 | ruby-enum (0.7.2) 229 | i18n 230 | ruby_dep (1.5.0) 231 | rubyzip (2.0.0) 232 | safe_yaml (1.0.5) 233 | sass (3.7.4) 234 | sass-listen (~> 4.0.0) 235 | sass-listen (4.0.0) 236 | rb-fsevent (~> 0.9, >= 0.9.4) 237 | rb-inotify (~> 0.9, >= 0.9.7) 238 | sawyer (0.8.2) 239 | addressable (>= 2.3.5) 240 | faraday (> 0.8, < 2.0) 241 | terminal-table (1.8.0) 242 | unicode-display_width (~> 1.1, >= 1.1.1) 243 | thread_safe (0.3.6) 244 | typhoeus (1.3.1) 245 | ethon (>= 0.9.0) 246 | tzinfo (1.2.5) 247 | thread_safe (~> 0.1) 248 | unicode-display_width (1.6.0) 249 | 250 | PLATFORMS 251 | ruby 252 | 253 | DEPENDENCIES 254 | github-pages 255 | jekyll 256 | jekyll-theme-hacker 257 | kramdown-man 258 | ronn 259 | 260 | BUNDLED WITH 261 | 2.1.0 262 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Tom Scott 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Build scripts for Homer. These tasks will generate documentation, 2 | # commands, and of course install the Homer scripts themselves to an 3 | # executable location. 4 | # 5 | # Shoutouts to @postmodern and @isaacs, I lifted most of their ideas to 6 | # make this... 7 | 8 | .PHONY: all build test check install uninstall clean command release verify 9 | 10 | PROGRAM=homer 11 | SHELL=/usr/bin/env zsh 12 | PREFIX?=$(DESTDIR)/usr/local 13 | HOMER_PATH?=$(PWD) 14 | SOURCE_PATH=$(PWD) 15 | DIRS=bin share 16 | INSTALL_DIRS=`find $(DIRS) -type d` 17 | INSTALL_FILES=`find $(DIRS) -type f` 18 | GITHUB_REF?=$(shell git show-ref $(git branch | grep '*') | head -n 1 | awk '{ print $2 }') 19 | VERSION?=$(shell echo $(GITHUB_REF) | cut -d / -f 3) 20 | DOCS=$(shell find share/doc/man/*.md -type f | sed 's/doc\/man/man\/man1/g' | sed 's/\.md//g') 21 | 22 | PKG_DIR=dist 23 | PKG_NAME=$(PROGRAM)-$(VERSION) 24 | PKG=$(PKG_DIR)/$(PKG_NAME).tar.gz 25 | TAG=.git/refs/tags/$(VERSION) 26 | SIG=$(PKG).asc 27 | 28 | # Build the documentation and tarball, then sign the package with GPG 29 | all: $(DOCS) $(PKG) $(SIG) 30 | build: all 31 | 32 | # Install manpages generator 33 | vendor/bundle: 34 | @bundle check || bundle install 35 | 36 | # Remove all generated files 37 | clean: 38 | @rm -rf tmp share/man/man1 dist 39 | 40 | # Install the testing framework 41 | node_modules: 42 | @yarn 43 | 44 | # Run all tests 45 | check: node_modules 46 | @node_modules/.bin/bats test 47 | test: check 48 | 49 | # Generate man pages from markdown 50 | share/man/man1: 51 | @mkdir -p share/man/man1 52 | docs/manual: 53 | @mkdir -p docs/manual 54 | share/man/man1/%.1: vendor/bundle share/man/man1 docs/manual 55 | @bundle exec ronn --date="2014-11-01" --manual="User Manual" --organization="$(PROGRAM)" --style=dark share/doc/man/$(@F).md 56 | @mv share/doc/man/$(@F) share/man/man1/$(@F) 57 | @mv share/doc/man/$(@F).html docs/manual/$(@F).html 58 | 59 | # Move scripts to /usr/local. Typically requires `sudo` access. 60 | install: 61 | @for dir in $(INSTALL_DIRS); do mkdir -p $(DESTDIR)$(PREFIX)/$$dir; done 62 | @for file in $(INSTALL_FILES); do cp $$file $(DESTDIR)$(PREFIX)/$$file; done 63 | 64 | # Remove scripts from /usr/local. Typically requires `sudo` access. 65 | uninstall: 66 | @for file in $(INSTALL_FILES); do echo $$file; done 67 | 68 | # Generate a new command 69 | command: 70 | @cp share/homer/command/bin.sh bin/homer-${NAME} 71 | @cp share/homer/command/doc.txt share/doc/homer/${NAME}.txt 72 | @cp share/homer/command/test.bats test/homer-${NAME}-test.bats 73 | @chmod +x bin/homer-${NAME} 74 | 75 | # Tag the current state of the codebase as a released version 76 | $(TAG): 77 | @git tag $(VERSION) -m "Release $(VERSION)" 78 | 79 | # Generate ctags 80 | tags: 81 | @ctags -R . 82 | 83 | # Create a package for the current version of the codebase. This 84 | # omits developer-centric files like tests and build manifests for the 85 | # released version of the package. 86 | $(PKG_DIR): 87 | @mkdir -p $(PKG_DIR) 88 | $(PKG): $(PKG_DIR) 89 | @git archive --output=$(PKG) --prefix=$(PKG_NAME)/ HEAD $(DIRS) ./Makefile 90 | 91 | # Cryptographically sign the package so its contents can be verified at 92 | # a later date 93 | $(SIG): $(PKG) 94 | @gpg --batch --sign --detach-sign --armor $(PKG) 95 | 96 | # Release the latest version of Homer to GitHub. 97 | release: $(TAG) 98 | @git push origin --tags 99 | @git push origin master 100 | 101 | # Verify the contents of a package 102 | verify: $(PKG) $(SIG) 103 | @gpg --verify $(SIG) $(PKG) 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Homer 2 | 3 | [][ci] 4 | [][ci] 5 | [][ci] 6 | 7 |  8 | 9 | Homer is a home directory manager for your shell. Using [Git][git], it 10 | tracks changes in your home directory configuration from anywhere on 11 | your machine. Its goal is to uncover the IDE-like possibilities of the 12 | shell and make such features more approachable to newer users, while 13 | still retaining its usefulness to power users. 14 | 15 | Homer is an opinionated, but minimal, framework. While most of what 16 | it assumes about your environment is strongly enforced across the 17 | framework, it attempts to assume little about your system, instead 18 | allowing you to customize your shell the way you see fit. Homer's main 19 | philosophy is that having a stellar shell configuration should be 20 | much easier than it is today. 21 | 22 | ## How It Works 23 | 24 | Homer is effectively a Git repo and shell extension manager that is accessible 25 | from anywhere on the machine. It's written entirely in [ZSH][] shell 26 | script, but you don't have to use ZSH to gain its benefits. Homer is actually 27 | nothing more than a set of conventions, some shell scripts to make 28 | complex tasks easier, and some useful/sane defaults for ZSH. Homer's 29 | components are tools that wrap a Git repository and your ZSH 30 | configuration. 31 | 32 | Homer is comparable with tools like [GNU Stow][stow], its main 33 | difference is that instead of keeping a directory separate from 34 | `$HOME` and symlinking the necessary files over from some 35 | version-controlled directory when asked, Homer uses the home 36 | directory as a Git repository and ignores any files it doesn't explicitly 37 | track. It also provides ZSH-specific alias and plugin management, which 38 | Stow as a more generalized system does not do. Homer is essentially a tool for 39 | managing any file in your home directory you wish to keep with Git. 40 | 41 | ## Features 42 | 43 | - Syncs home directory configuration with a Git repository 44 | - Manages shell aliases and custom shell scripts 45 | - Manages OS packages and custom package repositories 46 | - Exposes useful attributes and contains a small CLI plugin API that 47 | allows for hooking into Homer and adding your own commands. 48 | 49 | ## Installation 50 | 51 | The easiest way to install Homer is with the one-liner install script: 52 | 53 | ```bash 54 | $ curl -o- -L https://homer.psychedeli.ca/install.sh | bash 55 | ``` 56 | 57 | It's a good practice to always [view the source code][installer] before 58 | running a command like this, but if you're busy, here's a short 59 | description of what the installer script does: 60 | 61 | 1. Downloads the latest `.tar.gz` release of Homer 62 | 2. Extracts the source code to a directory in `/tmp` 63 | 3. Runs `sudo make` in the source code directory, this will require you 64 | to type in your root password 65 | 4. Removes all files in the `/tmp` directory created by the installer. 66 | 67 | ### From a Package Manager 68 | 69 | As a package, Homer is available on [Homebrew][brew]: 70 | 71 | ```bash 72 | $ brew tap tubbo/homebrew-tap 73 | $ brew install homer 74 | ``` 75 | 76 | You can also install the edge version of Homer, which is the latest 77 | commit of 'master' branch, by applying the **--HEAD** switch: 78 | 79 | ```bash 80 | $ brew install homer --HEAD 81 | ``` 82 | 83 | ### From Source 84 | 85 | Before installing from source, make sure you have the following hard 86 | dependencies installed: 87 | 88 | - zsh 89 | - antigen 90 | - keychain 91 | - bats (if you're developing on the project) 92 | 93 | Once they're all installed, run the following commands to install to 94 | `/usr/local`... 95 | 96 | ```bash 97 | $ git clone https://github.com/tubbo/homer.git 98 | $ cd homer 99 | $ make && sudo make install 100 | ``` 101 | 102 | When its installed, run the setup command: 103 | 104 | ```bash 105 | $ homer init 106 | ``` 107 | 108 | This will create a Git repo in your home directory, add 109 | a `~/.gitignore` file to control it, and some 110 | default ZSH configuration. 111 | 112 | If you already have a home directory repo that was initialized using 113 | Homer, you can copy it down to your machine with the following command: 114 | 115 | ```bash 116 | $ homer init https://url.to/your/home/directory/repo.git 117 | ``` 118 | 119 | This will clone the Git repo at the URL provided to `/tmp/homer` without 120 | actually checking out a working copy. After copying the `.git` directory 121 | (the actual data contents of the repo) to your home directory, it will 122 | run `git reset --hard HEAD` to "rehydrate" all the files of the working 123 | copy in the home directory rather than in the place it was checked out. 124 | This is to ensure that any overwritten files will have a diff to show 125 | you what changed, and none of your files that currently exist in the 126 | home directory will be accidentally deleted. 127 | 128 | ## Usage 129 | 130 | Homer is primarily used to track files which are located in your home 131 | directory to your Git repository. You can add files that are currently 132 | untracked with the `homer save` command: 133 | 134 | ```bash 135 | $ homer save .vimrc -m "Removed vim-rails" 136 | ``` 137 | 138 | This will begin tracking the file at `~/.vimrc` in your home directory 139 | repo. A commit will be added using the message in `-m`, and you can run 140 | `homer update` to sync with the remote at any time. 141 | 142 | If you wish to stop tracking a given configuration file, run `homer 143 | save` with the `-r` flag: 144 | 145 | ```bash 146 | $ homer save -r .vimrc 147 | ``` 148 | 149 | This removes the `~/.vimrc` file from your repo (but retains it in your 150 | home directory) and stops tracking it. When no `-m` is given for a 151 | message, the message is derived from the action, command, and filename. 152 | 153 | ### Idempotency 154 | 155 | Homer is designed to keep your local machine's configuration in sync 156 | with the configuration that may be stored on a remote Git repository. 157 | This could have changes that are not yet on your machine, and Homer 158 | can pull those changes down, cleanly, without affecting any files that 159 | you may have locally edited. 160 | 161 | To update the current home directory with the remote: 162 | 163 | ```bash 164 | $ homer update 165 | ``` 166 | 167 | You can also update Homer itself, which is basically re-running the 168 | installer script. To do so, run: 169 | 170 | ```bash 171 | $ homer upgrade 172 | ``` 173 | 174 | ### Plugins 175 | 176 | Homer provides an easy way to manage ZSH plugins with [Antigen][]. 177 | These plugins are automatically installed when you `init` your home 178 | directory on a new machine. Antigen is installed automatically upon 179 | initialization if it's not already installed. The plugin manifest can be 180 | found in `~/etc/plugins.zsh`. 181 | 182 | To install a new plugin: 183 | 184 | ```bash 185 | $ homer plugin zsh-users/zsh-syntax-highlighting 186 | ``` 187 | 188 | As well as remove them. 189 | 190 | ```bash 191 | $ homer plugin zsh-users/zsh-syntax-highlighting -r 192 | ``` 193 | 194 | ### Aliases 195 | 196 | Homer can add aliases and save them for later use. These aliases are 197 | stored in `~/etc/aliases.zsh`, and tracked by Git so they can be shared 198 | in your home directory repository. 199 | 200 | To add a new alias: 201 | 202 | ```bash 203 | $ homer alias gc 'git commit' 204 | ``` 205 | 206 | Reload your shell, and you can now use `gc` as an alias to `git commit`: 207 | 208 | ```bash 209 | $ gc -m "wow this is cool" 210 | ``` 211 | 212 | To delete an alias: 213 | 214 | ```bash 215 | $ homer alias -d gc 216 | ``` 217 | 218 | ### User Scripts 219 | 220 | If you write a useful shell script or executable, Homer can copy this 221 | file to a directory in your `$PATH`. Homer uses the `~/bin` directory 222 | for this purpose, and keeps files in this directory checked in to Git so 223 | you can share them in your home directory repo. Upon initialization, 224 | Homer will also `chmod +x` this entire directory to ensure that files 225 | created within it will default to be executable by the current user. 226 | 227 | ```bash 228 | $ homer script bin/find-and-replace-in-project 229 | $ find-and-replace-in-project 230 | ``` 231 | 232 | You can also remove commands from this directory: 233 | 234 | ```bash 235 | $ homer script bin/find-and-replace-in-project -r 236 | ``` 237 | 238 | ### Text Editing and Paging 239 | 240 | Homer uses the `$EDITOR` and `$PAGER` variables as the backbone for the 241 | `edit` and `page` (or `e` and `v`) commands used to edit and view text 242 | files, respectively. Text editing and viewing files with a page are two 243 | of the most common tasks performed within the shell, and Homer helps 244 | integrate whatever editor you choose to use seamlessly within your shell 245 | environment. 246 | 247 | To edit text with your `$EDITOR`, run: 248 | 249 | ```bash 250 | $ edit some/file.txt 251 | ``` 252 | 253 | You can also view files with the `$PAGER` by running: 254 | 255 | ```bash 256 | $ page /var/log/system.log 257 | ``` 258 | 259 | The `$EDITOR` is set to `vi` by default, and the `$PAGER` is set to 260 | `less`, but you can change these values in your **~/.zshenv**: 261 | 262 | ```bash 263 | export EDITOR='vim' 264 | export PAGER='less -r' 265 | ``` 266 | 267 | ### Conventions 268 | 269 | Homer establishes useful conventions on your home directory. It 270 | uses the **~/bin/** directory to store user-made scripts which are 271 | available in the `$PATH`. It creates an **~/etc/** directory and uses that to 272 | store files such as **~/etc/plugins.zsh** for defining shell plugins and 273 | **~/etc/aliases.zsh** for storing shell aliases you wish to recall later. 274 | Note that you should not edit the manifest files mentioned above manually, the 275 | `homer alias` and `homer plugin` tools should manage the files for 276 | you. Place any ZSH code you wish to load when the shell launches 277 | in "initializer" files within **~/etc/profile.d**, keeping **~/.zshrc** and 278 | **~/.zshenv** clear. 279 | 280 | As well as creating these initial files, it also runs `git init` in your 281 | home directory, effectively making the entire thing a Git repository. In order 282 | to prevent massive repo sizes and checking in unsafe credentials, 283 | Homer does not initially add any files to this repo, except for the ones 284 | it generates. One of these generated files is a `.gitignore`, which ignores all 285 | files in the home directory by default. To add files to the repo, you need to use 286 | `homer save` or run `git add -f` in your home directory. 287 | 288 | ## Development 289 | 290 | Homer is written entirely in [ZSH][] shell script. It uses [BATS][bats] to 291 | run its tests, and a Makefile is provided to run the tests as well as 292 | build/install the project. 293 | 294 | To run tests: 295 | 296 | ```bash 297 | $ make test 298 | ``` 299 | 300 | You can also use the Makefile to generate a new command: 301 | 302 | ```bash 303 | $ make command NAME=foo 304 | ``` 305 | 306 | This will generate `bin/homer-foo`, `share/doc/homer/foo.txt`, and 307 | `test/homer-foo-test.bats` with given templates. 308 | 309 | The Makefile is also used to create releases, which are mostly handled 310 | by [GitHub Actions][ci]. To create a new release, generate its tag by running: 311 | 312 | ```bash 313 | $ make release VERSION=foo 314 | ``` 315 | 316 | This will create a new tag and push it to GitHub, where the package will 317 | be built, signed, and uploaded as an artifact to a new [GitHub Release][] 318 | 319 | ### License 320 | 321 | Homer uses the MIT License, as described below: 322 | 323 | ``` 324 | The MIT License (MIT) 325 | 326 | Copyright (c) 2014-2019 Tom Scott 327 | 328 | Permission is hereby granted, free of charge, to any person obtaining a copy 329 | of this software and associated documentation files (the "Software"), to deal 330 | in the Software without restriction, including without limitation the rights 331 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 332 | copies of the Software, and to permit persons to whom the Software is 333 | furnished to do so, subject to the following conditions: 334 | 335 | The above copyright notice and this permission notice shall be included in 336 | all copies or substantial portions of the Software. 337 | 338 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 339 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 340 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 341 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 342 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 343 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 344 | THE SOFTWARE. 345 | ``` 346 | 347 | [git]: http://git-scm.com 348 | [brew]: http://brew.sh 349 | [bats]: https://github.com/sstephenson/bats 350 | [stow]: http://www.gnu.org/software/stow/ 351 | [ci]: https://github.com/tubbo/homer/actions 352 | [Antigen]: https://github.com/zsh-users/antigen 353 | [ZSH]: http://zsh.sourceforge.net/ 354 | [installer]: https://github.com/tubbo/homer/blob/master/docs/install.sh 355 | [GitHub Release]: https://github.com/tubbo/homer/releases 356 | -------------------------------------------------------------------------------- /bin/homer: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | # 3 | # Executes Homer commands 4 | 5 | # All variables are based off this single key, which is the location of 6 | # this particular file. 7 | case $0 in 8 | /*) HOMER_SCRIPT_FILE=$0;; 9 | *) HOMER_SCRIPT_FILE=$PWD/$0;; 10 | esac 11 | 12 | # Load global configuration 13 | export HOMER_SCRIPT_PATH=$(dirname $HOMER_SCRIPT_FILE) 14 | export HOMER_PATH=$(dirname $HOMER_SCRIPT_PATH) 15 | export HOMER_COMMAND=$1 16 | export HOMER_EXECUTABLE=$HOMER_SCRIPT_PATH/homer-$HOMER_COMMAND 17 | 18 | if [ -z $HOMER_HOME ]; then 19 | export HOMER_HOME=$HOME 20 | fi 21 | 22 | pushd $HOMER_PATH 23 | export HOMER_PREFIX=$PWD 24 | popd 25 | 26 | # Execute the command or run `homer help` if not found. 27 | if [[ -e $HOMER_EXECUTABLE ]]; then 28 | source "$HOMER_EXECUTABLE" 29 | else 30 | source "$HOMER_SCRIPT_PATH/homer-help" 31 | fi 32 | -------------------------------------------------------------------------------- /bin/homer-alias: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | # 3 | # Add an alias to future shell sessions. 4 | 5 | source "$HOMER_PATH/share/homer/cli.zsh" 6 | 7 | name=$2 8 | cmd=$3 9 | 10 | if [[ -z $name || -z $cmd ]]; then 11 | homer_error "You must enter a name and command." 12 | exit 1 13 | fi 14 | 15 | zparseopts -D -E -- r=remove m:=message 16 | 17 | if [[ "$remove" == "-r" ]]; then 18 | action='Remove' 19 | else 20 | action='Add' 21 | fi 22 | 23 | if [[ -z $message ]]; then 24 | message="${action} alias ${name}" 25 | fi 26 | 27 | case "$action" in 28 | Add) 29 | line="alias ${name}='${cmd}'" 30 | echo "${line}" >> $HOMER_HOME/etc/aliases.zsh 31 | homer_add $HOMER_HOME/etc/aliases.zsh $message 32 | ;; 33 | Remove) 34 | sed "s/alias ${line}=.*$//" $HOMER_HOME/etc/aliases.zsh > /tmp/aliases 35 | mv /tmp/aliases $HOMER_HOME/aliases.zsh 36 | homer_add $HOMER_HOME/etc/aliases.zsh $message 37 | ;; 38 | esac 39 | -------------------------------------------------------------------------------- /bin/homer-grep: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | # 3 | # Run `git grep` on your home directory repo and Homer shared scripts 4 | # simultaneously. 5 | 6 | shift 7 | 8 | pushd $HOMER_HOME 9 | results=$(git grep --color='always' $*) 10 | popd 11 | 12 | for file in $(find $HOMER_PATH/share/homer/**/*.zsh); do 13 | results+=$(grep --color='always' -I $* $file /dev/null) 14 | done 15 | 16 | echo $results | less -r 17 | -------------------------------------------------------------------------------- /bin/homer-help: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | # 3 | # Show usage information or help with a particular command. 4 | 5 | # Set up the path at which we look for txt files describing each 6 | # command. 7 | HOMER_DOC_PATH=$HOMER_PREFIX/share/doc/homer 8 | 9 | # Determine the command to look up, defaults to USAGE if unspecified or 10 | # not found. 11 | if [[ -e $HOMER_DOC_PATH/$2.txt ]]; then 12 | docfile=$2 13 | else 14 | docfile="USAGE" 15 | fi 16 | 17 | echo "" 18 | cat $HOMER_DOC_PATH/$docfile.txt 19 | echo "" 20 | -------------------------------------------------------------------------------- /bin/homer-init: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | # 3 | # Copy home directory template files to the user's home directory and 4 | # initialize it as a Git repository. 5 | 6 | source "$HOMER_PATH/share/homer/cli.zsh" 7 | 8 | if [[ -e "$HOMER_HOME/.git" ]]; then 9 | homer_error "There is already an existing Git repository in $HOMER_HOME." 10 | exit 1 11 | fi 12 | 13 | zparseopts -K -- m:=message 14 | 15 | if [ -z "$message[2]" ]; then 16 | message="Initialize home directory." 17 | else 18 | message=$message[2] 19 | fi 20 | 21 | if [ ! -z "$2" ]; then 22 | repository=$2 23 | git clone --no-checkout $repository /tmp/homer 24 | pushd $HOMER_HOME 25 | mv /tmp/homer/.git .git 26 | git reset --hard HEAD 27 | popd 28 | else 29 | git init $HOMER_HOME 30 | cp -a $HOMER_PREFIX/share/homer/template/** $HOMER_HOME 31 | cp -a $HOMER_PREFIX/share/homer/template/.* $HOMER_HOME 32 | homer_add_all $message 33 | fi 34 | -------------------------------------------------------------------------------- /bin/homer-plugin: -------------------------------------------------------------------------------- 1 | #!zsh 2 | # 3 | # Install a shell plugin with Antigen, and save it in the 4 | # ~/etc/plugins file. 5 | 6 | plugin=$2 7 | file=$HOMER_HOME/etc/plugins.zsh 8 | 9 | source "$HOMER_PATH/share/homer/cli.zsh" 10 | 11 | if [[ -z $plugin ]]; then 12 | homer_error "You must specify a plugin." 13 | exit 1 14 | fi 15 | 16 | zparseopts -K -- m:=message r:=remove 17 | 18 | if [ -n "${remove+x}" ]; then 19 | action='Remove' 20 | else 21 | action='Add' 22 | fi 23 | 24 | if [[ -z $message ]]; then 25 | message="${action} ZSH plugin ${plugin}" 26 | fi 27 | 28 | case "$action" in 29 | Add) 30 | antigen bundle $plugin 31 | echo "antigen bundle $plugin" >> $file 32 | homer_add $file $message 33 | ;; 34 | Remove) 35 | sed "/antigen bundle $plugin/,/" $file 36 | source $file 37 | homer_remove $file $message 38 | ;; 39 | esac 40 | -------------------------------------------------------------------------------- /bin/homer-save: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | # 3 | # Save a dotfile, either adding it for the first time or updating its 4 | # contents. 5 | 6 | file=$2 7 | 8 | source "$HOMER_PATH/share/homer/cli.zsh" 9 | 10 | zparseopts -E -- m:=message r=remove 11 | 12 | if [ $remove ]; then 13 | homer_remove $file $message[2] 14 | else 15 | homer_add $file $message[2] 16 | fi 17 | -------------------------------------------------------------------------------- /bin/homer-script: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | # 3 | # Copy a script to an executable $PATH 4 | 5 | source "$HOMER_PATH/share/homer/cli.zsh" 6 | 7 | script=$2 8 | 9 | zparseopts -D -E -- r=remove m:=message 10 | 11 | if [[ $remove == "-r" ]]; then 12 | action='Remove' 13 | else 14 | action='Add' 15 | fi 16 | 17 | if [[ -z $script ]]; then 18 | homer_error "You must enter the path to a script" 19 | exit 1 20 | fi 21 | 22 | name=$(basename $script) 23 | 24 | echo "msg: $message[2]" 25 | 26 | if [[ -z $message ]]; then 27 | message="${action} script ${name}" 28 | fi 29 | 30 | case "$action" in 31 | Add) 32 | cp $script $HOMER_HOME/bin/$name 33 | chmod +x $HOMER_HOME/bin/$name 34 | homer_add bin/$name $message 35 | ;; 36 | Remove) 37 | homer_remove bin/$name $message 38 | ;; 39 | esac 40 | -------------------------------------------------------------------------------- /bin/homer-update: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | # 3 | # Save a dotfile, either adding it for the first time or updating its 4 | # contents. 5 | 6 | source "$HOMER_PATH/share/homer/cli.zsh" 7 | 8 | homer_update_repo 9 | 10 | echo "Updated home directory $HOMER_HOME with the latest changes." 11 | -------------------------------------------------------------------------------- /bin/homer-version: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | # 3 | # Print the current version of Homer 4 | 5 | cat $HOMER_PATH/share/homer/VERSION 6 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | theme: jekyll-theme-hacker 3 | title: homer 4 | description: the home directory manager for zsh 5 | -------------------------------------------------------------------------------- /docs/homer-thinking.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tubbo/homer/c6b5826ece60b192cbc616927d8030d864afbd6f/docs/homer-thinking.gif -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: homer 3 | layout: default 4 | --- 5 | 6 | Homer is a home directory manager for your shell. Using Git, it 7 | tracks changes in your home directory configuration from anywhere on 8 | your machine. Its goal is to uncover the IDE-like possibilities of the 9 | shell and make such features more approachable to newer users, while 10 | still retaining its usefulness to power users. 11 | 12 | Homer is an opinionated, but minimal, framework. While most of what 13 | it assumes about your environment is strongly enforced across the 14 | framework, it attempts to assume little about your system, instead 15 | allowing you to customize your shell the way you see fit. Homer's main 16 | philosophy is that having a stellar shell configuration should be 17 | much easier. 18 | 19 | The only requirement to run Homer is that you have the [Z Shell][zsh] 20 | installed. Homer is written entirely in ZSH shell script, and works best 21 | in a ZSH environment since it takes advantage of a number of its 22 | features. 23 | 24 | ## Features 25 | 26 | - **Conventional Directories:** Homer establishes a number of 27 | directories in your home directory, like `~/bin` and `~/etc`, for 28 | storing executable scripts and shell configuration. Drop new `.zsh` files in 29 | `~/etc/profile.d` to have them apply automatically when your shell is 30 | loaded. Homer ensures that `~/bin` is in your `$PATH` so the 31 | executable scripts in that directory are always available as extra 32 | commands in your shell. 33 | - **Dotfiles:** Save your configuration files directly where they need 34 | to be in your home directory from anywhere on the system. No need to 35 | mess around with symlink. 36 | - **Aliases:** Remembering long commands can be tough, and shell aliases 37 | are a built-in solution to that problem. Homer makes it easier to 38 | manage aliases from the `~/etc/aliases.zsh` directory, loaded in your 39 | shell automatically. 40 | - **ZSH Plugins:** One benefit to using ZSH is the vast amount of 41 | plugins that can be installed using Antigen, but managing these 42 | plugins can be somewhat difficult. Homer comes bundled with Antigen 43 | and manages the plugins you wish to install from your `~/etc/plugins.zsh` 44 | manifest file. 45 | - **Idempotency:** Homer can self-update, sync with a remote repository, 46 | and cleanly rehydrate the contents of a cloned repository into your home 47 | directory upon new installations. 48 | 49 | ## Installation 50 | 51 | Install with our handy-dandy script: 52 | 53 | ```bash 54 | $ curl -o- -L https://tubbo.github.io/homer/install.sh | bash 55 | ``` 56 | 57 | If you're on macOS, you can also install with Homebrew: 58 | 59 | ```bash 60 | $ brew tap tubbo/homebrew-tap 61 | $ brew install homer 62 | ``` 63 | 64 | ## Setup 65 | 66 | Once Homer is installed, you can use it to either create a new 67 | repository for persisting your configuration, or you can pull down an 68 | existing repository and extract it on top of the existing home directory 69 | on your machine. 70 | 71 | To create a new home directory repo: 72 | 73 | ```bash 74 | $ homer init 75 | ``` 76 | 77 | Otherwise, provide the URL to your existing home directory repo: 78 | 79 | ```bash 80 | $ homer init https://github.com/your/home-dir.git 81 | ``` 82 | 83 | After these commands are run, your home directory will be set up for use 84 | with Homer! 85 | 86 | ## Usage 87 | 88 | To learn how to use Homer, check out the [README][], run `man homer` 89 | to view command-line documentation, or view the manpages online: 90 | 91 | - [homer(1)][] 92 | - [edit(1)][] 93 | - [page(1)][] 94 | 95 | [README]: https://github.com/tubbo/homer#homer 96 | [homer(1)]: manual/homer.1.html 97 | [edit(1)]: manual/edit.1.html 98 | [page(1)]: manual/page.1.html 99 | -------------------------------------------------------------------------------- /docs/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Install Homer on the system. Note that this is _not_ a ZSH script, 4 | # because ZSH may not actually be on the system yet. We can be pretty 5 | # sure that Bash will be there, though, so that's why this script is 6 | # written in Bash instead of ZSH. 7 | 8 | # Find latest released version from GitHub API 9 | repo="https://api.github.com/repos/tubbo/homer/releases/latest" 10 | version=$(curl --silent "$repo" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') 11 | tmpdir=$(mktemp -d) 12 | sourcedir="homer-${version:1}" 13 | filename="homer-$version.tar.gz" 14 | 15 | pushd "$tmpdir" > /dev/null 2>&1 16 | 17 | # Ensure source code is in place 18 | echo "Downloading Homer $version from GitHub..." 19 | curl -sL "https://github.com/tubbo/homer/archive/$version.tar.gz" -o "$filename" 20 | 21 | # Extract source code from tarball 22 | tar -zxf "$filename" 23 | 24 | # Install homer from source to /usr/local and capture exit code 25 | pushd "$sourcedir" > /dev/null 2>&1 26 | echo "Installing Homer..." 27 | make install 28 | code=$? 29 | 30 | # Print whether Homer was installed or not 31 | if [[ "$code" == 0 ]]; then 32 | echo "Homer $version has been installed!" 33 | echo "Get started by running \`homer init [REPO]\`" 34 | echo "Or, run \`homer\` to see the full list of commands" 35 | else 36 | echo "Error installing Homer" 37 | fi 38 | 39 | # Clean up the source directory 40 | popd > /dev/null 2>&1 41 | popd > /dev/null 2>&1 42 | rm -rf "$tmpdir" 43 | 44 | exit $code 45 | -------------------------------------------------------------------------------- /docs/manual/edit.1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |
85 | edit
- Open files for editing and manipulating
86 |
edit
ARGUMENTS
The edit utility is used to open and edit files using your 95 | configured editor. It's a quick time-saver that uses the configured 96 | $EDITOR in your shell for editing files. All arguments passed into 97 | this utility will be passed onward to the configured shell editor 98 | program.
99 | 100 |edit is provided by homer. For more information, check out:
101 | 102 |https://github.com/tubbo/homer#readme
103 | 104 |ARGUMENTS 107 | Arguments passed to the editor.
108 | 109 |Open a file with your editor:
112 | 113 |edit path/to/my/file.txt
114 |
115 |
116 | To configure which program is opened when the edit
command is run, set
119 | the $EDITOR variable in your shell like so:
export EDITOR=vim
122 |
123 |
124 | (Homer will do this for you in ~/.zshenv
)
Tom Scott http://psychedeli.ca
129 | 130 |homer(1) 133 | page(1)
134 | 135 | 136 |
85 | homer
- your home directory manager
86 |
homer
COMMAND ARGUMENTS
Homer is a command-line utility to manage your shell's home directory. 95 | It turns your entire home directory into a Git repo so you can 96 | version control non-sensitive configuration and data and synchronize 97 | them across machines. It also includes provisions for installing custom 98 | shell scripts, aliases and hooks for package management tooling. Homer 99 | is designed around the Unix philosophy, and stays out of your way as 100 | much as possible. It is written entirely in ZSH shell script.
101 | 102 |For more information, check out:
103 | 104 |https://github.com/tubbo/homer#readme
105 | 106 |COMMAND 109 | The command you wish to run.
110 | 111 |ARGUMENTS 112 | Arguments for said command.
113 | 114 |Initialize your home directory as a new repo:
117 | 118 |homer init
119 |
120 |
121 | Or, clone an existing home directory repo:
122 | 123 |homer init -c https://github.com/me/home.git
124 |
125 |
126 | You can now save dotfiles to the repo:
127 | 128 |homer save .vimrc -m "Removed vim-rails"
129 |
130 |
131 | Or, sync with your Git repo if you made changes elsewhere:
132 | 133 |homer update
134 |
135 |
136 | Homer can even upgrade itself using the latest GitHub release:
137 | 138 |homer upgrade
139 |
140 |
141 | Homer also provides an easy way to manage ZSH plugins with Antigen.
144 | These plugins are automatically installed when you init
your home
145 | directory on a new machine.
homer plugin zsh-users/zsh-syntax-highlighting
148 |
149 |
150 | You can also remove shell plugins from the manifest:
151 | 152 |homer plugin zsh-users/zsh-syntax-highlighting -r
153 |
154 |
155 | Homer manages an ~/etc/aliases
file that includes your shell aliases.
156 | To add one, run the following command:
homer alias gc 'git commit'
159 |
160 |
161 | Or, forget an alias:
162 | 163 |homer alias gc -r
164 |
165 |
166 | NOTE: The shell will need to be reloaded in order for alias changes 167 | to take effect.
168 | 169 |Homer establishes a ~/bin
directory for useful scripts that you might
172 | need access to as commands. This directory is added to $PATH
so that
173 | its executable contents can be used as commands across the system.
Adding a new command
176 | 177 |homer script path/to/your/script/find-and-replace-in-project
178 |
179 |
180 | You can now use the script as if it was a command:
181 | 182 |find-and-replace-in-project
183 |
184 |
185 | To remove the script from ~/bin
:
homer script find-and-replace-in-project -r
188 |
189 |
190 | The following files are generated when you run the homer init
193 | command...
~/bin: User scripts directory. Added to your $PATH
automatically.
~/etc/profile.d/: User configs directory
198 | 199 |~/etc/plugins.zsh: Plugins configuration
200 | 201 |~/etc/aliases.zsh: User aliases configuration
202 | 203 |Tom Scott http://psychedeli.ca
206 | 207 |antigen(1) 210 | zsh(1) 211 | git(1)
212 | 213 | 214 |
85 | page
- Open files for viewing and reading in realtime
86 |
page
ARGUMENTS
The page command is used to open files for viewing using your
95 | configured pager program, such as less
. It's a quick time-saver that
96 | uses the $PAGER variable in your shell for viewing files quickly, or
97 | in real-time as they are updated. All arguments passed into this utility
98 | will be passed onward to the configured shell pager program.
page is provided by homer. For more information, check out:
101 | 102 |https://github.com/tubbo/homer#readme
103 | 104 |ARGUMENTS 107 | Arguments passed to the pager.
108 | 109 |Open a file with your pager:
112 | 113 |page /var/log/system.log
114 |
115 |
116 | To configure which program is opened when the page
command is run, set
119 | the $PAGER variable in your shell like so:
export PAGER="less -r"
122 |
123 |
124 | (Homer will do this for you in ~/.zshenv
)
Tom Scott http://psychedeli.ca
129 | 130 |homer(1) 133 | edit(1)
134 | 135 | 136 |